@Override public void receiveFromBlock(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType, int relativityOffset) throws VerificationException { super.receiveFromBlock(tx, block, blockType, relativityOffset); BlockChainTest.this.block[0] = block; if (isTransactionRelevant(tx) && tx.isCoinBase()) { BlockChainTest.this.coinbaseTransaction = tx; } } };
@Test public void testEmptyRandomWallet() throws Exception { // Add a random set of outputs StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, OTHER_ADDRESS), BigInteger.ONE, 1); Random rng = new Random(); for (int i = 0; i < rng.nextInt(100) + 1; i++) { Transaction tx = createFakeTx(PARAMS, Coin.valueOf(rng.nextInt((int) COIN.value)), myAddress); wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); } SendRequest request = SendRequest.emptyWallet(OTHER_ADDRESS); wallet.completeTx(request); wallet.commitTx(request.tx); assertEquals(ZERO, wallet.getBalance()); }
@Nullable protected Transaction sendMoneyToWallet(Wallet wallet, AbstractBlockChain.NewBlockType type, Transaction... transactions) throws VerificationException { if (type == null) { // Pending transaction for (Transaction tx : transactions) if (wallet.isPendingTransactionRelevant(tx)) wallet.receivePending(tx, null); } else { FakeTxBuilder.BlockPair bp = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, transactions); for (Transaction tx : transactions) wallet.receiveFromBlock(tx, bp.storedBlock, type, 0); if (type == AbstractBlockChain.NewBlockType.BEST_CHAIN) wallet.notifyNewBestBlock(bp.storedBlock); } if (transactions.length == 1) return wallet.getTransaction(transactions[0].getHash()); // Can be null if tx is a double spend that's otherwise irrelevant. else return null; }
@Test public void isConsistent_duplicates() throws Exception { // This test ensures that isConsistent catches duplicate transactions, eg, because we submitted the same block // twice (this is not allowed). Transaction tx = createFakeTx(PARAMS, COIN, myAddress); TransactionOutput output = new TransactionOutput(PARAMS, tx, valueOf(0, 5), OTHER_ADDRESS); tx.addOutput(output); wallet.receiveFromBlock(tx, null, BlockChain.NewBlockType.BEST_CHAIN, 0); assertTrue(wallet.isConsistent()); Transaction txClone = PARAMS.getDefaultSerializer().makeTransaction(tx.bitcoinSerialize()); try { wallet.receiveFromBlock(txClone, null, BlockChain.NewBlockType.BEST_CHAIN, 0); fail("Illegal argument not thrown when it should have been."); } catch (IllegalStateException ex) { // expected } }
@Test public void transactionGetFeeTest() throws Exception { // Prepare wallet to spend StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, OTHER_ADDRESS), BigInteger.ONE, 1); Transaction tx = createFakeTx(PARAMS, COIN, myAddress); wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); // Create a transaction SendRequest request = SendRequest.to(OTHER_ADDRESS, CENT); request.feePerKb = Transaction.DEFAULT_TX_FEE; wallet.completeTx(request); assertEquals(Coin.valueOf(11350), request.tx.getFee()); }
@Test public void isConsistent_pools() throws Exception { // This test ensures that isConsistent catches transactions that are in incompatible pools. Transaction tx = createFakeTx(PARAMS, COIN, myAddress); TransactionOutput output = new TransactionOutput(PARAMS, tx, valueOf(0, 5), OTHER_ADDRESS); tx.addOutput(output); wallet.receiveFromBlock(tx, null, BlockChain.NewBlockType.BEST_CHAIN, 0); assertTrue(wallet.isConsistent()); wallet.addWalletTransaction(new WalletTransaction(Pool.PENDING, tx)); assertFalse(wallet.isConsistent()); }
@Test public void doubleSpend() throws Exception { // Check that we can serialize double spends correctly, as this is a slightly tricky case. FakeTxBuilder.DoubleSpends doubleSpends = FakeTxBuilder.createFakeDoubleSpendTxns(PARAMS, myAddress); // t1 spends to our wallet. myWallet.receivePending(doubleSpends.t1, null); // t2 rolls back t1 and spends somewhere else. myWallet.receiveFromBlock(doubleSpends.t2, null, BlockChain.NewBlockType.BEST_CHAIN, 0); Wallet wallet1 = roundTrip(myWallet); assertEquals(1, wallet1.getTransactions(true).size()); Transaction t1 = wallet1.getTransaction(doubleSpends.t1.getHash()); assertEquals(ConfidenceType.DEAD, t1.getConfidence().getConfidenceType()); assertEquals(Coin.ZERO, wallet1.getBalance()); // TODO: Wallet should store overriding transactions even if they are not wallet-relevant. // assertEquals(doubleSpends.t2, t1.getConfidence().getOverridingTransaction()); }
wallet.receiveFromBlock(transactions.get(0), storedBlock, NewBlockType.BEST_CHAIN, 0);
@Test public void testCategory2WithChange() throws Exception { // Specifically target case 2 with significant change // Generate a ton of small outputs StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, OTHER_ADDRESS), BigInteger.ONE, 1); int i = 0; while (i <= CENT.divide(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(10))) { Transaction tx = createFakeTxWithChangeAddress(PARAMS, Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(10), myAddress, OTHER_ADDRESS); tx.getInput(0).setSequenceNumber(i++); // Keep every transaction unique wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); } // The selector will choose 2 with MIN_TX_FEE fee SendRequest request1 = SendRequest.to(OTHER_ADDRESS, CENT.add(SATOSHI)); request1.ensureMinRequiredFee = true; wallet.completeTx(request1); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request1.tx.getFee()); assertEquals(request1.tx.getInputs().size(), i); // We should have spent all inputs assertEquals(2, request1.tx.getOutputs().size()); // and gotten change back }
wallet.receiveFromBlock(doubleSpends.t1, blockPair1.storedBlock, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); wallet.notifyNewBestBlock(blockPair1.storedBlock); assertSpent(doubleSpends.t1); wallet.receiveFromBlock(doubleSpends.t2, blockPair2.storedBlock, AbstractBlockChain.NewBlockType.SIDE_CHAIN, 0); wallet.reorganize(blockPair0.storedBlock, Lists.newArrayList(blockPair1.storedBlock), Lists.newArrayList(blockPair2.storedBlock));
Transaction tx = createFakeTxWithChangeAddress(PARAMS, tenThousand, myAddress, OTHER_ADDRESS); tx.getInput(0).setSequenceNumber(i++); // Keep every transaction unique wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); wallet.receiveFromBlock(tx1, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); wallet.receiveFromBlock(tx2, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); Transaction tx3 = createFakeTxWithChangeAddress(PARAMS, tenThousand, myAddress, OTHER_ADDRESS); tx3.getInput(0).setSequenceNumber(i++); // Keep every transaction unique wallet.receiveFromBlock(tx3, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); wallet.receiveFromBlock(tx4, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i);
wallet.receiveFromBlock(tx1, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); Transaction tx2 = createFakeTx(PARAMS, COIN, myAddress); assertNotEquals(tx1.getHash(), tx2.getHash()); wallet.receiveFromBlock(tx2, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); Transaction tx3 = createFakeTx(PARAMS, CENT, myAddress); wallet.receiveFromBlock(tx3, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 2);
wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); SendRequest request = SendRequest.emptyWallet(OTHER_ADDRESS); wallet.completeTx(request); wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); tx = createFakeTx(PARAMS, CENT, myAddress); wallet.receivePending(tx, null); Coin outputValue = Transaction.MIN_NONDUST_OUTPUT.subtract(SATOSHI); tx = createFakeTx(PARAMS, outputValue, myAddress); wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); try { request = SendRequest.emptyWallet(OTHER_ADDRESS);
wallet.receiveFromBlock(txA1, blockPair1.storedBlock, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); wallet.notifyNewBestBlock(blockPair1.storedBlock); assertSpent(txA1); wallet.receiveFromBlock(txA1, blockPair2.storedBlock, AbstractBlockChain.NewBlockType.SIDE_CHAIN, 0); wallet.receiveFromBlock(txB1, blockPair2.storedBlock, AbstractBlockChain.NewBlockType.SIDE_CHAIN, 1); wallet.reorganize(blockPair0.storedBlock, Lists.newArrayList(blockPair1.storedBlock), Lists.newArrayList(blockPair2.storedBlock)); wallet.receiveFromBlock(txA1, blockPair3.storedBlock, AbstractBlockChain.NewBlockType.SIDE_CHAIN, 0); wallet.receiveFromBlock(txB1, blockPair3.storedBlock, AbstractBlockChain.NewBlockType.SIDE_CHAIN, 1); wallet.receiveFromBlock(txC1, blockPair3.storedBlock, AbstractBlockChain.NewBlockType.SIDE_CHAIN, 2); wallet.reorganize(blockPair0.storedBlock, Lists.newArrayList(blockPair2.storedBlock), Lists.newArrayList(blockPair3.storedBlock)); wallet.receiveFromBlock(txB1, blockPair4.storedBlock, AbstractBlockChain.NewBlockType.SIDE_CHAIN, 0); wallet.reorganize(blockPair0.storedBlock, Lists.newArrayList(blockPair3.storedBlock), Lists.newArrayList(blockPair4.storedBlock)); wallet.receiveFromBlock(txA2, blockPair5.storedBlock, AbstractBlockChain.NewBlockType.SIDE_CHAIN, 0); wallet.reorganize(blockPair0.storedBlock, Lists.newArrayList(blockPair4.storedBlock), Lists.newArrayList(blockPair5.storedBlock));
serverWallet.receiveFromBlock(doubleSpendContract, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0);