Wallet extensions: log errors when deserializing a non-mandatory extension and remove it from the wallet if deserialization throws.

This commit is contained in:
Mike Hearn
2015-04-22 14:53:10 +02:00
parent a0fe912ff0
commit acfc046a08
3 changed files with 38 additions and 5 deletions

View File

@@ -18,6 +18,7 @@
package org.bitcoinj.core;
import com.google.common.annotations.*;
import com.google.common.base.*;
import com.google.common.base.Objects;
import com.google.common.base.Objects.*;
import com.google.common.collect.*;
@@ -4457,7 +4458,8 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
/**
* Deserialize the wallet extension with the supplied data and then install it, replacing any existing extension
* that may have existed with the same ID.
* that may have existed with the same ID. If an exception is thrown then the extension is removed from the wallet,
* if already present.
*/
public void deserializeExtension(WalletExtension extension, byte[] data) throws Exception {
lock.lock();
@@ -4465,6 +4467,10 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
// This method exists partly to establish a lock ordering of wallet > extension.
extension.deserializeWalletExtension(this, data);
extensions.put(extension.getWalletExtensionID(), extension);
} catch (Throwable throwable) {
log.error("Error during extension deserialization", throwable);
extensions.remove(extension.getWalletExtensionID());
Throwables.propagate(throwable);
} finally {
lock.unlock();
}

View File

@@ -519,10 +519,8 @@ public class WalletProtobufSerializer {
wallet.deserializeExtension(extension, extProto.getData().toByteArray());
} catch (Exception e) {
if (extProto.getMandatory() && requireMandatoryExtensions) {
log.error("Error whilst reading extension {}, failing to read wallet", id, e);
log.error("Error whilst reading mandatory extension {}, failing to read wallet", id);
throw new UnreadableWalletException("Could not parse mandatory extension in wallet: " + id);
} else {
log.error("Error whilst reading extension {}, ignoring", id, e);
}
}
}

View File

@@ -332,7 +332,7 @@ public class WalletProtobufSerializerTest {
}
@Test
public void testExtensions() throws Exception {
public void extensions() throws Exception {
myWallet.addExtension(new FooWalletExtension("com.whatever.required", true));
Protos.Wallet proto = new WalletProtobufSerializer().walletToProto(myWallet);
// Initial extension is mandatory: try to read it back into a wallet that doesn't know about it.
@@ -355,6 +355,35 @@ public class WalletProtobufSerializerTest {
assertEquals(0, wallet5.getExtensions().size());
}
@Test
public void extensionsWithError() throws Exception {
WalletExtension extension = new WalletExtension() {
@Override
public String getWalletExtensionID() {
return "test";
}
@Override
public boolean isWalletExtensionMandatory() {
return false;
}
@Override
public byte[] serializeWalletExtension() {
return new byte[0];
}
@Override
public void deserializeWalletExtension(Wallet containingWallet, byte[] data) throws Exception {
throw new NullPointerException(); // Something went wrong!
}
};
myWallet.addExtension(extension);
Protos.Wallet proto = new WalletProtobufSerializer().walletToProto(myWallet);
Wallet wallet = new WalletProtobufSerializer().readWallet(params, new WalletExtension[]{extension}, proto);
assertEquals(0, wallet.getExtensions().size());
}
@Test(expected = UnreadableWalletException.FutureVersion.class)
public void versions() throws Exception {
Protos.Wallet.Builder proto = Protos.Wallet.newBuilder(new WalletProtobufSerializer().walletToProto(myWallet));