From b279c4080105ae61134023e1f64d5b066bda1784 Mon Sep 17 00:00:00 2001 From: Wojciech Langiewicz Date: Thu, 6 Nov 2014 16:10:41 +0100 Subject: [PATCH] Adds Wallet tests, extracts FooWalletExtension for testing. --- .../bitcoinj/testing/FooWalletExtension.java | 40 +++++++ .../bitcoinj/core/WalletExtensionsTest.java | 23 ++++ .../java/org/bitcoinj/core/WalletTest.java | 105 +++++++++++++++++- .../store/WalletProtobufSerializerTest.java | 40 +------ 4 files changed, 170 insertions(+), 38 deletions(-) create mode 100644 core/src/main/java/org/bitcoinj/testing/FooWalletExtension.java create mode 100644 core/src/test/java/org/bitcoinj/core/WalletExtensionsTest.java diff --git a/core/src/main/java/org/bitcoinj/testing/FooWalletExtension.java b/core/src/main/java/org/bitcoinj/testing/FooWalletExtension.java new file mode 100644 index 00000000..764a27c1 --- /dev/null +++ b/core/src/main/java/org/bitcoinj/testing/FooWalletExtension.java @@ -0,0 +1,40 @@ +package org.bitcoinj.testing; + +import org.bitcoinj.core.Wallet; +import org.bitcoinj.core.WalletExtension; + +import java.util.Arrays; + +import static com.google.common.base.Preconditions.checkArgument; + +public class FooWalletExtension implements WalletExtension { + private final byte[] data = new byte[]{1, 2, 3}; + + private final boolean isMandatory; + private final String id; + + public FooWalletExtension(String id, boolean isMandatory) { + this.isMandatory = isMandatory; + this.id = id; + } + + @Override + public String getWalletExtensionID() { + return id; + } + + @Override + public boolean isWalletExtensionMandatory() { + return isMandatory; + } + + @Override + public byte[] serializeWalletExtension() { + return data; + } + + @Override + public void deserializeWalletExtension(Wallet wallet, byte[] data) { + checkArgument(Arrays.equals(this.data, data)); + } +} \ No newline at end of file diff --git a/core/src/test/java/org/bitcoinj/core/WalletExtensionsTest.java b/core/src/test/java/org/bitcoinj/core/WalletExtensionsTest.java new file mode 100644 index 00000000..a268fc61 --- /dev/null +++ b/core/src/test/java/org/bitcoinj/core/WalletExtensionsTest.java @@ -0,0 +1,23 @@ +package org.bitcoinj.core; + +import org.bitcoinj.testing.FooWalletExtension; +import org.bitcoinj.testing.TestWithWallet; +import org.junit.Before; +import org.junit.Test; + +public class WalletExtensionsTest extends TestWithWallet { + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + } + + @Test(expected = java.lang.IllegalStateException.class) + public void duplicateWalletExtensionTest() { + wallet.addExtension(new FooWalletExtension("com.whatever.required", true)); + wallet.addExtension(new FooWalletExtension("com.whatever.required", true)); + } + + +} diff --git a/core/src/test/java/org/bitcoinj/core/WalletTest.java b/core/src/test/java/org/bitcoinj/core/WalletTest.java index 43a7994e..e89fc205 100644 --- a/core/src/test/java/org/bitcoinj/core/WalletTest.java +++ b/core/src/test/java/org/bitcoinj/core/WalletTest.java @@ -1167,6 +1167,22 @@ public class WalletTest extends TestWithWallet { key2.sign(Sha256Hash.ZERO_HASH); } + @Test(expected = ECKey.MissingPrivateKeyException.class) + public void watchingWalletWithCreationTime() throws Exception { + DeterministicKey watchKey = wallet.getWatchingKey(); + String serialized = watchKey.serializePubB58(); + watchKey = DeterministicKey.deserializeB58(null, serialized); + Wallet watchingWallet = Wallet.fromWatchingKey(params, watchKey, 1415282801); + DeterministicKey key2 = watchingWallet.freshReceiveKey(); + assertEquals(myKey, key2); + + ECKey key = wallet.freshKey(KeyChain.KeyPurpose.CHANGE); + key2 = watchingWallet.freshKey(KeyChain.KeyPurpose.CHANGE); + assertEquals(key, key2); + key.sign(Sha256Hash.ZERO_HASH); + key2.sign(Sha256Hash.ZERO_HASH); + } + @Test public void watchingScripts() throws Exception { // Verify that pending transactions to watched addresses are relevant @@ -1267,6 +1283,15 @@ public class WalletTest extends TestWithWallet { assertFalse(wallet.isRequiringUpdateAllBloomFilter()); } + @Test + public void removeWatchedAddress() { + Address watchedAddress = new ECKey().toAddress(params); + wallet.addWatchedAddress(watchedAddress); + wallet.removeWatchedAddress(watchedAddress); + assertFalse(wallet.isAddressWatched(watchedAddress)); + assertFalse(wallet.isRequiringUpdateAllBloomFilter()); + } + @Test public void removeScriptsBloomFilter() throws Exception { List
addressesForRemoval = new ArrayList
(); @@ -1464,9 +1489,10 @@ public class WalletTest extends TestWithWallet { } @Test - public void encryptionDecryptionBasic() throws Exception { + public void encryptionDecryptionAESBasic() throws Exception { assertEquals(EncryptionType.ENCRYPTED_SCRYPT_AES, encryptedWallet.getEncryptionType()); assertTrue(encryptedWallet.checkPassword(PASSWORD1)); + assertTrue(encryptedWallet.checkAESKey(aesKey)); assertFalse(encryptedWallet.checkPassword(WRONG_PASSWORD)); assertTrue("The keyCrypter is missing but should not be", keyCrypter != null); encryptedWallet.decrypt(aesKey); @@ -1480,12 +1506,28 @@ public class WalletTest extends TestWithWallet { } } + @Test + public void encryptionDecryptionPasswordBasic() throws Exception { + assertTrue(encryptedWallet.isEncrypted()); + encryptedWallet.decrypt(PASSWORD1); + assertFalse(encryptedWallet.isEncrypted()); + + // Wallet should now be unencrypted. + assertTrue("Wallet is not an unencrypted wallet", encryptedWallet.getKeyCrypter() == null); + try { + encryptedWallet.checkPassword(PASSWORD1); + fail(); + } catch (IllegalStateException e) { + } + } + @Test public void encryptionDecryptionBadPassword() throws Exception { // Check the wallet is currently encrypted assertTrue("Wallet is not an encrypted wallet", encryptedWallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES); + assertFalse(encryptedWallet.checkAESKey(wrongAesKey)); - // Chek that the wrong password does not decrypt the wallet. + // Check that the wrong password does not decrypt the wallet. try { encryptedWallet.decrypt(wrongAesKey); fail("Incorrectly decoded wallet with wrong password"); @@ -1703,6 +1745,22 @@ public class WalletTest extends TestWithWallet { wallet.completeTx(request); } + @Test + public void sendRequestP2PKTest() { + ECKey key = new ECKey(); + Address notMyAddr = key.toAddress(params); + SendRequest req = SendRequest.to(notMyAddr.getParameters(), key, SATOSHI.multiply(12)); + assertArrayEquals(key.getPubKey(), req.tx.getOutputs().get(0).getScriptPubKey().getPubKey()); + } + + @Test + public void sendRequestP2PKHTest() { + ECKey key = new ECKey(); + Address notMyAddr = key.toAddress(params); + SendRequest req = SendRequest.to(notMyAddr, SATOSHI.multiply(12)); + assertEquals(notMyAddr, req.tx.getOutputs().get(0).getScriptPubKey().getToAddress(params)); + } + @Test public void feeSolverAndCoinSelectionTest() throws Exception { // Tests basic fee solving works @@ -2763,6 +2821,30 @@ public class WalletTest extends TestWithWallet { assertEquals(COIN, wallet.getBalance()); } + @Test + public void transactionInBlockNotification() { + final Transaction tx = createFakeTx(params, COIN, myAddress); + StoredBlock block = createFakeBlock(blockStore, tx).storedBlock; + wallet.receivePending(tx, null); + boolean notification = wallet.notifyTransactionIsInBlock(tx.getHash(), block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); + assertTrue(notification); + + Address notMyAddr = new ECKey().toAddress(params); + final Transaction tx2 = createFakeTx(params, COIN, notMyAddr); + wallet.receivePending(tx2, null); + StoredBlock block2 = createFakeBlock(blockStore, tx2).storedBlock; + boolean notification2 = wallet.notifyTransactionIsInBlock(tx2.getHash(), block2, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); + assertFalse(notification2); + } + + @Test + public void duplicatedBlock() { + final Transaction tx = createFakeTx(params, COIN, myAddress); + StoredBlock block = createFakeBlock(blockStore, tx).storedBlock; + wallet.notifyNewBestBlock(block); + wallet.notifyNewBestBlock(block); + } + @Test public void keyEvents() throws Exception { // Check that we can register an event listener, generate some keys and the callbacks are invoked properly. @@ -2895,4 +2977,23 @@ public class WalletTest extends TestWithWallet { wallet.completeTx(sendRequest); assertEquals(sendRequest.memo, sendRequest.tx.getMemo()); } + + @Test(expected = java.lang.IllegalStateException.class) + public void sendCoinsNoBroadcasterTest() throws InsufficientMoneyException { + ECKey key = ECKey.fromPrivate(BigInteger.ONE); + Address notMyAddr = key.toAddress(params); + SendRequest req = SendRequest.to(notMyAddr.getParameters(), key, SATOSHI.multiply(12)); + wallet.sendCoins(req); + } + + @Test + public void sendCoinsWithBroadcasterTest() throws InsufficientMoneyException, IOException { + ECKey key = ECKey.fromPrivate(BigInteger.ONE); + Address notMyAddr = key.toAddress(params); + receiveATransactionAmount(wallet, myAddress, Coin.COIN); + MockTransactionBroadcaster broadcaster = new MockTransactionBroadcaster(wallet); + wallet.setTransactionBroadcaster(broadcaster); + SendRequest req = SendRequest.to(notMyAddr.getParameters(), key, Coin.CENT); + wallet.sendCoins(req); + } } diff --git a/core/src/test/java/org/bitcoinj/store/WalletProtobufSerializerTest.java b/core/src/test/java/org/bitcoinj/store/WalletProtobufSerializerTest.java index 67c300cc..b0409dee 100644 --- a/core/src/test/java/org/bitcoinj/store/WalletProtobufSerializerTest.java +++ b/core/src/test/java/org/bitcoinj/store/WalletProtobufSerializerTest.java @@ -25,11 +25,11 @@ import org.bitcoinj.params.MainNetParams; import org.bitcoinj.params.UnitTestParams; import org.bitcoinj.script.ScriptBuilder; import org.bitcoinj.testing.FakeTxBuilder; +import org.bitcoinj.testing.FooWalletExtension; import org.bitcoinj.utils.BriefLogFormatter; import org.bitcoinj.utils.Threading; import org.bitcoinj.wallet.DeterministicKeyChain; import org.bitcoinj.wallet.KeyChain; -import com.google.common.collect.ImmutableList; import com.google.protobuf.ByteString; import org.bitcoinj.wallet.MarriedKeyChain; @@ -332,7 +332,7 @@ public class WalletProtobufSerializerTest { @Test public void testExtensions() throws Exception { - myWallet.addExtension(new SomeFooExtension("com.whatever.required", true)); + 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. try { @@ -342,13 +342,13 @@ public class WalletProtobufSerializerTest { assertTrue(e.getMessage().contains("mandatory")); } Wallet wallet = new WalletProtobufSerializer().readWallet(params, - new WalletExtension[]{ new SomeFooExtension("com.whatever.required", true) }, + new WalletExtension[]{ new FooWalletExtension("com.whatever.required", true) }, proto); assertTrue(wallet.getExtensions().containsKey("com.whatever.required")); // Non-mandatory extensions are ignored if the wallet doesn't know how to read them. Wallet wallet2 = new Wallet(params); - wallet2.addExtension(new SomeFooExtension("com.whatever.optional", false)); + wallet2.addExtension(new FooWalletExtension("com.whatever.optional", false)); Protos.Wallet proto2 = new WalletProtobufSerializer().walletToProto(wallet2); Wallet wallet5 = new WalletProtobufSerializer().readWallet(params, null, proto2); assertEquals(0, wallet5.getExtensions().size()); @@ -360,36 +360,4 @@ public class WalletProtobufSerializerTest { proto.setVersion(2); new WalletProtobufSerializer().readWallet(params, null, proto.build()); } - - private static class SomeFooExtension implements WalletExtension { - private final byte[] data = new byte[]{1, 2, 3}; - - private final boolean isMandatory; - private final String id; - - public SomeFooExtension(String id, boolean isMandatory) { - this.isMandatory = isMandatory; - this.id = id; - } - - @Override - public String getWalletExtensionID() { - return id; - } - - @Override - public boolean isWalletExtensionMandatory() { - return isMandatory; - } - - @Override - public byte[] serializeWalletExtension() { - return data; - } - - @Override - public void deserializeWalletExtension(Wallet wallet, byte[] data) { - assertArrayEquals(this.data, data); - } - } }