diff --git a/core/src/main/java/com/google/bitcoin/core/Wallet.java b/core/src/main/java/com/google/bitcoin/core/Wallet.java index 8a0a54796..397277e94 100644 --- a/core/src/main/java/com/google/bitcoin/core/Wallet.java +++ b/core/src/main/java/com/google/bitcoin/core/Wallet.java @@ -232,7 +232,7 @@ public class Wallet implements Serializable { int size2 = unspent.size() + spent.size() + pendingInactive.size() + dead.size(); if (size1 != size2) { log.error("Inconsistent wallet sizes: {} {}", size1, size2); - success = true; + success = false; } for (Transaction tx : unspent.values()) { diff --git a/core/src/test/java/com/google/bitcoin/core/WalletTest.java b/core/src/test/java/com/google/bitcoin/core/WalletTest.java index f1566fa7d..826ffc8ff 100644 --- a/core/src/test/java/com/google/bitcoin/core/WalletTest.java +++ b/core/src/test/java/com/google/bitcoin/core/WalletTest.java @@ -16,6 +16,7 @@ package com.google.bitcoin.core; +import com.google.bitcoin.core.WalletTransaction.Pool; import com.google.bitcoin.store.BlockStore; import com.google.bitcoin.store.MemoryBlockStore; import com.google.bitcoin.store.WalletProtobufSerializer; @@ -263,6 +264,55 @@ public class WalletTest { assertEquals(BigInteger.ZERO.subtract(toNanoCoins(0, 10)), send2.getValue(wallet)); } + @Test + public void isConsistent_duplicates() throws Exception { + // This test ensures that isConsistent catches duplicate transactions. + Transaction tx = createFakeTx(params, Utils.toNanoCoins(1, 0), myAddress); + Address someOtherGuy = new ECKey().toAddress(params); + TransactionOutput output = new TransactionOutput(params, tx, Utils.toNanoCoins(0, 5), someOtherGuy); + tx.addOutput(output); + wallet.receiveFromBlock(tx, null, BlockChain.NewBlockType.BEST_CHAIN); + + assertTrue(wallet.isConsistent()); + + Transaction txClone = new Transaction(params, tx.bitcoinSerialize()); + try { + wallet.receiveFromBlock(txClone, null, BlockChain.NewBlockType.SIDE_CHAIN); + fail(); + } catch (IllegalStateException ex) { + // expected + } + } + + @Test + public void isConsistent_pools() throws Exception { + // This test ensures that isConsistent catches transactions that are in incompatible pools. + Transaction tx = createFakeTx(params, Utils.toNanoCoins(1, 0), myAddress); + Address someOtherGuy = new ECKey().toAddress(params); + TransactionOutput output = new TransactionOutput(params, tx, Utils.toNanoCoins(0, 5), someOtherGuy); + tx.addOutput(output); + wallet.receiveFromBlock(tx, null, BlockChain.NewBlockType.BEST_CHAIN); + + assertTrue(wallet.isConsistent()); + + wallet.addWalletTransaction(new WalletTransaction(Pool.PENDING, tx)); + assertFalse(wallet.isConsistent()); + } + + @Test + public void isConsistent_spent() throws Exception { + // This test ensures that isConsistent catches transactions that are marked spent when + // they aren't. + Transaction tx = createFakeTx(params, Utils.toNanoCoins(1, 0), myAddress); + Address someOtherGuy = new ECKey().toAddress(params); + TransactionOutput output = new TransactionOutput(params, tx, Utils.toNanoCoins(0, 5), someOtherGuy); + tx.addOutput(output); + assertTrue(wallet.isConsistent()); + + wallet.addWalletTransaction(new WalletTransaction(Pool.SPENT, tx)); + assertFalse(wallet.isConsistent()); + } + @Test public void transactions() throws Exception { // This test covers a bug in which Transaction.getValueSentFromMe was calculating incorrectly.