private List<Message> handleGetData(GetDataMessage m) { // Scans the wallets and memory pool for transactions in the getdata message and returns them. // Runs on peer threads. lock.lock(); try { LinkedList<Message> transactions = new LinkedList<Message>(); LinkedList<InventoryItem> items = new LinkedList<InventoryItem>(m.getItems()); Iterator<InventoryItem> it = items.iterator(); while (it.hasNext()) { InventoryItem item = it.next(); // Check the wallets. for (Wallet w : wallets) { Transaction tx = w.getTransaction(item.hash); if (tx == null) continue; transactions.add(tx); it.remove(); break; } } return transactions; } finally { lock.unlock(); } }
@Test public void coinbaseTxns() throws Exception { // Covers issue 420 where the outpoint index of a coinbase tx input was being mis-serialized. Block b = PARAMS.getGenesisBlock().createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, myKey.getPubKey(), FIFTY_COINS, Block.BLOCK_HEIGHT_GENESIS); Transaction coinbase = b.getTransactions().get(0); assertTrue(coinbase.isCoinBase()); BlockChain chain = new BlockChain(PARAMS, myWallet, new MemoryBlockStore(PARAMS)); assertTrue(chain.add(b)); // Wallet now has a coinbase tx in it. assertEquals(1, myWallet.getTransactions(true).size()); assertTrue(myWallet.getTransaction(coinbase.getHash()).isCoinBase()); Wallet wallet2 = roundTrip(myWallet); assertEquals(1, wallet2.getTransactions(true).size()); assertTrue(wallet2.getTransaction(coinbase.getHash()).isCoinBase()); }
private List<Message> handleGetData(GetDataMessage m) { // Scans the wallets and memory pool for transactions in the getdata message and returns them. // Runs on peer threads. lock.lock(); try { LinkedList<Message> transactions = new LinkedList<>(); LinkedList<InventoryItem> items = new LinkedList<>(m.getItems()); Iterator<InventoryItem> it = items.iterator(); while (it.hasNext()) { InventoryItem item = it.next(); // Check the wallets. for (Wallet w : wallets) { Transaction tx = w.getTransaction(item.hash); if (tx == null) continue; transactions.add(tx); it.remove(); break; } } return transactions; } finally { lock.unlock(); } }
@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()); }
private List<Message> handleGetData(GetDataMessage m) { // Scans the wallets and memory pool for transactions in the getdata message and returns them. // Runs on peer threads. lock.lock(); try { LinkedList<Message> transactions = new LinkedList<Message>(); LinkedList<InventoryItem> items = new LinkedList<InventoryItem>(m.getItems()); Iterator<InventoryItem> it = items.iterator(); while (it.hasNext()) { InventoryItem item = it.next(); // Check the wallets. for (Wallet w : wallets) { Transaction tx = w.getTransaction(item.hash); if (tx == null) continue; transactions.add(tx); it.remove(); break; } } return transactions; } finally { lock.unlock(); } }
private List<Message> handleGetData(GetDataMessage m) { // Scans the wallets and memory pool for transactions in the getdata message and returns them. // Runs on peer threads. lock.lock(); try { LinkedList<Message> transactions = new LinkedList<>(); LinkedList<InventoryItem> items = new LinkedList<>(m.getItems()); Iterator<InventoryItem> it = items.iterator(); while (it.hasNext()) { InventoryItem item = it.next(); // Check the wallets. for (Wallet w : wallets) { Transaction tx = w.getTransaction(item.hash); if (tx == null) continue; if (item.type == InventoryItem.Type.Transaction) transactions.add(tx.disableWitnessSerialization()); else transactions.add(tx); it.remove(); break; } } return transactions; } finally { lock.unlock(); } }
@Override public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) { // This will run on the user code thread so we shouldn't do anything too complicated here. // We only want to queue a wallet changed event and auto-save if the number of peers announcing // the transaction has changed, as that confidence change is made by the networking code which // doesn't necessarily know at that point which wallets contain which transactions, so it's up // to us to listen for that. Other types of confidence changes (type, etc) are triggered by us, // so we'll queue up a wallet change event in other parts of the code. if (reason == ChangeReason.SEEN_PEERS) { lock.lock(); try { checkBalanceFuturesLocked(null); Transaction tx = getTransaction(confidence.getTransactionHash()); queueOnTransactionConfidenceChanged(tx); maybeQueueOnWalletChanged(); } finally { lock.unlock(); } } } };
@Override public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) { // This will run on the user code thread so we shouldn't do anything too complicated here. // We only want to queue a wallet changed event and auto-save if the number of peers announcing // the transaction has changed, as that confidence change is made by the networking code which // doesn't necessarily know at that point which wallets contain which transactions, so it's up // to us to listen for that. Other types of confidence changes (type, etc) are triggered by us, // so we'll queue up a wallet change event in other parts of the code. if (reason == ChangeReason.SEEN_PEERS) { lock.lock(); try { checkBalanceFuturesLocked(null); Transaction tx = getTransaction(confidence.getTransactionHash()); queueOnTransactionConfidenceChanged(tx); maybeQueueOnWalletChanged(); } finally { lock.unlock(); } } } };
@Override public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) { // This will run on the user code thread so we shouldn't do anything too complicated here. // We only want to queue a wallet changed event and auto-save if the number of peers announcing // the transaction has changed, as that confidence change is made by the networking code which // doesn't necessarily know at that point which wallets contain which transactions, so it's up // to us to listen for that. Other types of confidence changes (type, etc) are triggered by us, // so we'll queue up a wallet change event in other parts of the code. if (reason == ChangeReason.SEEN_PEERS) { lock.lock(); try { checkBalanceFuturesLocked(null); Transaction tx = getTransaction(confidence.getTransactionHash()); queueOnTransactionConfidenceChanged(tx); maybeQueueOnWalletChanged(); } finally { lock.unlock(); } } } };
@Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { String action = intent.getAction(); if (action != null && action.equalsIgnoreCase(ACTION_BROADCAST_TRANSACTION)) { byte[] hashArray = intent.getByteArrayExtra(ACTION_BROADCAST_TRANSACTION_HASH); Sha256Hash sha256Hash = Sha256Hash.wrap(hashArray); Transaction transaction = wallet.getTransaction(sha256Hash); if (peerGroup != null) { Log.d(TAG, "onStartCommand: broadcast transaction " + transaction.getHashAsString()); peerGroup.broadcastTransaction(transaction); } } } return super.onStartCommand(intent, flags, startId); }
@Override public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) { // This will run on the user code thread so we shouldn't do anything too complicated here. // We only want to queue a wallet changed event and auto-save if the number of peers announcing // the transaction has changed, as that confidence change is made by the networking code which // doesn't necessarily know at that point which wallets contain which transactions, so it's up // to us to listen for that. Other types of confidence changes (type, etc) are triggered by us, // so we'll queue up a wallet change event in other parts of the code. if (reason == ChangeReason.SEEN_PEERS) { lock.lock(); try { checkBalanceFuturesLocked(null); Transaction tx = getTransaction(confidence.getTransactionHash()); queueOnTransactionConfidenceChanged(tx); maybeQueueOnWalletChanged(); } finally { lock.unlock(); } } else if(reason == ChangeReason.IX_TYPE && confidence.getIXType() == TransactionConfidence.IXType.IX_LOCKED) { //save the wallet when an InstantSend transaction is locked saveLater(); } } };
/** Finds if tx is NOT spending other txns which are in the specified confidence type */ private boolean isNotSpendingTxnsInConfidenceType(Transaction tx, ConfidenceType confidenceType) { for (TransactionInput txInput : tx.getInputs()) { Transaction connectedTx = this.getTransaction(txInput.getOutpoint().getHash()); if (connectedTx != null && connectedTx.getConfidence().getConfidenceType().equals(confidenceType)) { return false; } } return true; }
/** Finds if tx is NOT spending other txns which are in the specified confidence type */ private boolean isNotSpendingTxnsInConfidenceType(Transaction tx, ConfidenceType confidenceType) { for (TransactionInput txInput : tx.getInputs()) { Transaction connectedTx = this.getTransaction(txInput.getOutpoint().getHash()); if (connectedTx != null && connectedTx.getConfidence().getConfidenceType().equals(confidenceType)) { return false; } } return true; }
/** Finds if tx is NOT spending other txns which are in the specified confidence type */ private boolean isNotSpendingTxnsInConfidenceType(Transaction tx, ConfidenceType confidenceType) { for (TransactionInput txInput : tx.getInputs()) { Transaction connectedTx = this.getTransaction(txInput.getOutpoint().getHash()); if (connectedTx != null && connectedTx.getConfidence().getConfidenceType().equals(confidenceType)) { return false; } } return true; }
/** Finds if tx is NOT spending other txns which are in the specified confidence type */ private boolean isNotSpendingTxnsInConfidenceType(Transaction tx, ConfidenceType confidenceType) { for (TransactionInput txInput : tx.getInputs()) { Transaction connectedTx = this.getTransaction(txInput.getOutpoint().getHash()); if (connectedTx != null && connectedTx.getConfidence().getConfidenceType().equals(confidenceType)) { return false; } } return true; }
@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 roundtripVersionTwoTransaction() throws Exception { Transaction tx = new Transaction(PARAMS, Utils.HEX.decode( "0200000001d7902864af9310420c6e606b814c8f89f7902d40c130594e85df2e757a7cc301070000006b483045022100ca1757afa1af85c2bb014382d9ce411e1628d2b3d478df9d5d3e9e93cb25dcdd02206c5d272b31a23baf64e82793ee5c816e2bbef251e733a638b630ff2331fc83ba0121026ac2316508287761befbd0f7495ea794b396dbc5b556bf276639f56c0bd08911feffffff0274730700000000001976a91456da2d038a098c42390c77ef163e1cc23aedf24088ac91062300000000001976a9148ebf3467b9a8d7ae7b290da719e61142793392c188ac22e00600")); assertEquals(tx.getVersion(), 2); assertEquals(tx.getHashAsString(), "0321b1413ed9048199815bd6bc2650cab1a9e8d543f109a42c769b1f18df4174"); myWallet.addWalletTransaction(new WalletTransaction(Pool.UNSPENT, tx)); Wallet wallet1 = roundTrip(myWallet); Transaction tx2 = wallet1.getTransaction(tx.getHash()); assertEquals(checkNotNull(tx2).getVersion(), 2); }
@Test public void raiseFeeTx() throws Exception { // Check basic tx serialization. Coin v1 = COIN; Transaction t1 = createFakeTx(PARAMS, v1, myAddress); t1.setPurpose(Purpose.RAISE_FEE); myWallet.receivePending(t1, null); Wallet wallet1 = roundTrip(myWallet); Transaction t1copy = wallet1.getTransaction(t1.getHash()); assertEquals(Purpose.RAISE_FEE, t1copy.getPurpose()); }
@Test public void testSequenceNumber() throws Exception { Wallet wallet = new Wallet(PARAMS); Transaction tx1 = createFakeTx(PARAMS, Coin.COIN, wallet.currentReceiveAddress()); tx1.getInput(0).setSequenceNumber(TransactionInput.NO_SEQUENCE); wallet.receivePending(tx1, null); Transaction tx2 = createFakeTx(PARAMS, Coin.COIN, wallet.currentReceiveAddress()); tx2.getInput(0).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1); wallet.receivePending(tx2, null); Wallet walletCopy = roundTrip(wallet); Transaction tx1copy = checkNotNull(walletCopy.getTransaction(tx1.getHash())); assertEquals(TransactionInput.NO_SEQUENCE, tx1copy.getInput(0).getSequenceNumber()); Transaction tx2copy = checkNotNull(walletCopy.getTransaction(tx2.getHash())); assertEquals(TransactionInput.NO_SEQUENCE - 1, tx2copy.getInput(0).getSequenceNumber()); }
@Test public void testForking5() throws Exception { // Test the standard case in which a block containing identical transactions appears on a side chain. Block b1 = PARAMS.getGenesisBlock().createNextBlock(coinsTo); chain.add(b1); final Transaction t = b1.transactions.get(1); assertEquals(FIFTY_COINS, wallet.getBalance()); // genesis -> b1 // -> b2 Block b2 = PARAMS.getGenesisBlock().createNextBlock(coinsTo); Transaction b2coinbase = b2.transactions.get(0); b2.transactions.clear(); b2.addTransaction(b2coinbase); b2.addTransaction(t); b2.solve(); chain.add(roundtrip(b2)); assertEquals(FIFTY_COINS, wallet.getBalance()); assertTrue(wallet.isConsistent()); assertEquals(2, wallet.getTransaction(t.getHash()).getAppearsInHashes().size()); // -> b2 -> b3 Block b3 = b2.createNextBlock(someOtherGuy); chain.add(b3); assertEquals(FIFTY_COINS, wallet.getBalance()); }