p2p_invalid_tx.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2015-present The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Test node responses to invalid transactions. 6 7 In this test we connect to one node over p2p, and test tx requests.""" 8 from test_framework.blocktools import create_block, create_coinbase 9 from test_framework.messages import ( 10 COIN, 11 COutPoint, 12 CTransaction, 13 CTxIn, 14 CTxOut, 15 ) 16 from test_framework.p2p import P2PDataStore 17 from test_framework.test_framework import BitcoinTestFramework 18 from test_framework.util import ( 19 assert_equal, 20 ) 21 from data import invalid_txs 22 23 24 class InvalidTxRequestTest(BitcoinTestFramework): 25 def set_test_params(self): 26 self.num_nodes = 1 27 self.extra_args = [[ 28 "-acceptnonstdtxn=1", 29 ]] 30 self.setup_clean_chain = True 31 32 def bootstrap_p2p(self, *, num_connections=1): 33 """Add a P2P connection to the node. 34 35 Helper to connect and wait for version handshake.""" 36 for _ in range(num_connections): 37 self.nodes[0].add_p2p_connection(P2PDataStore()) 38 39 def reconnect_p2p(self, **kwargs): 40 """Tear down and bootstrap the P2P connection to the node. 41 42 The node gets disconnected several times in this test. This helper 43 method reconnects the p2p and restarts the network thread.""" 44 self.nodes[0].disconnect_p2ps() 45 self.bootstrap_p2p(**kwargs) 46 47 def run_test(self): 48 node = self.nodes[0] # convenience reference to the node 49 50 self.bootstrap_p2p() # Add one p2p connection to the node 51 52 best_block = self.nodes[0].getbestblockhash() 53 tip = int(best_block, 16) 54 best_block_time = self.nodes[0].getblock(best_block)['time'] 55 block_time = best_block_time + 1 56 57 self.log.info("Create a new block with an anyone-can-spend coinbase.") 58 height = 1 59 block = create_block(tip, create_coinbase(height), block_time) 60 block.solve() 61 # Save the coinbase for later 62 block1 = block 63 node.p2ps[0].send_blocks_and_test([block], node, success=True) 64 65 self.log.info("Mature the block.") 66 self.generatetoaddress(self.nodes[0], 100, self.nodes[0].get_deterministic_priv_key().address) 67 68 # Iterate through a list of known invalid transaction types, ensuring each is 69 # rejected. Some are consensus invalid and some just violate policy. 70 for BadTxTemplate in invalid_txs.iter_all_templates(): 71 self.log.info("Testing invalid transaction: %s", BadTxTemplate.__name__) 72 template = BadTxTemplate(spend_block=block1) 73 tx = template.get_tx() 74 node.p2ps[0].send_txs_and_test( 75 [tx], node, success=False, 76 reject_reason=template.reject_reason, 77 ) 78 79 # Make two p2p connections to provide the node with orphans 80 # * p2ps[0] will send valid orphan txs (one with low fee) 81 # * p2ps[1] will send an invalid orphan tx (and is later disconnected for that) 82 self.reconnect_p2p(num_connections=2) 83 84 self.log.info('Test orphan transaction handling ... ') 85 # Create a root transaction that we withhold until all dependent transactions 86 # are sent out and in the orphan cache 87 SCRIPT_PUB_KEY_OP_TRUE = b'\x51\x75' * 15 + b'\x51' 88 tx_withhold = CTransaction() 89 tx_withhold.vin.append(CTxIn(outpoint=COutPoint(block1.vtx[0].txid_int, 0))) 90 tx_withhold.vout = [CTxOut(nValue=25 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)] * 2 91 92 # Our first orphan tx with some outputs to create further orphan txs 93 tx_orphan_1 = CTransaction() 94 tx_orphan_1.vin.append(CTxIn(outpoint=COutPoint(tx_withhold.txid_int, 0))) 95 tx_orphan_1.vout = [CTxOut(nValue=8 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)] * 3 96 97 # A valid transaction with low fee 98 tx_orphan_2_no_fee = CTransaction() 99 tx_orphan_2_no_fee.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.txid_int, 0))) 100 tx_orphan_2_no_fee.vout.append(CTxOut(nValue=8 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) 101 102 # A valid transaction with sufficient fee 103 tx_orphan_2_valid = CTransaction() 104 tx_orphan_2_valid.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.txid_int, 1))) 105 tx_orphan_2_valid.vout.append(CTxOut(nValue=8 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) 106 107 # An invalid transaction with negative fee 108 tx_orphan_2_invalid = CTransaction() 109 tx_orphan_2_invalid.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_1.txid_int, 2))) 110 tx_orphan_2_invalid.vout.append(CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) 111 112 self.log.info('Send the orphans ... ') 113 # Send valid orphan txs from p2ps[0] 114 node.p2ps[0].send_txs_and_test([tx_orphan_1, tx_orphan_2_no_fee, tx_orphan_2_valid], node, success=False) 115 # Send invalid tx from p2ps[1] 116 node.p2ps[1].send_txs_and_test([tx_orphan_2_invalid], node, success=False) 117 118 assert_equal(0, node.getmempoolinfo()['size']) # Mempool should be empty 119 assert_equal(2, len(node.getpeerinfo())) # p2ps[1] is still connected 120 121 self.log.info('Send the withhold tx ... ') 122 with node.assert_debug_log(expected_msgs=["bad-txns-in-belowout"]): 123 node.p2ps[0].send_txs_and_test([tx_withhold], node, success=True) 124 125 # Transactions that should end up in the mempool 126 expected_mempool = { 127 t.txid_hex 128 for t in [ 129 tx_withhold, # The transaction that is the root for all orphans 130 tx_orphan_1, # The orphan transaction that splits the coins 131 tx_orphan_2_valid, # The valid transaction (with sufficient fee) 132 ] 133 } 134 # Transactions that do not end up in the mempool: 135 # tx_orphan_2_no_fee, because it has too low fee (p2ps[0] is not disconnected for relaying that tx) 136 # tx_orphan_2_invalid, because it has negative fee (p2ps[1] is disconnected for relaying that tx) 137 138 assert_equal(expected_mempool, set(node.getrawmempool())) 139 140 self.log.info('Test orphanage can store more than 100 transactions') 141 orphan_tx_pool = [CTransaction() for _ in range(101)] 142 for i in range(len(orphan_tx_pool)): 143 orphan_tx_pool[i].vin.append(CTxIn(outpoint=COutPoint(i, 333))) 144 orphan_tx_pool[i].vout.append(CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) 145 146 node.p2ps[0].send_txs_and_test(orphan_tx_pool, node, success=False) 147 self.wait_until(lambda: len(node.getorphantxs()) >= 101) 148 149 self.log.info('Test orphan with rejected parents') 150 rejected_parent = CTransaction() 151 rejected_parent.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_2_invalid.txid_int, 0))) 152 rejected_parent.vout.append(CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) 153 with node.assert_debug_log(['not keeping orphan with rejected parents {}'.format(rejected_parent.txid_hex)]): 154 node.p2ps[0].send_txs_and_test([rejected_parent], node, success=False) 155 156 self.log.info('Test that a peer disconnection causes erase its transactions from the orphan pool') 157 self.reconnect_p2p(num_connections=1) 158 self.wait_until(lambda: len(node.getorphantxs()) == 0) 159 160 self.log.info('Test that a transaction in the orphan pool is included in a new tip block causes erase this transaction from the orphan pool') 161 tx_withhold_until_block_A = CTransaction() 162 tx_withhold_until_block_A.vin.append(CTxIn(outpoint=COutPoint(tx_withhold.txid_int, 1))) 163 tx_withhold_until_block_A.vout = [CTxOut(nValue=12 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)] * 2 164 165 tx_orphan_include_by_block_A = CTransaction() 166 tx_orphan_include_by_block_A.vin.append(CTxIn(outpoint=COutPoint(tx_withhold_until_block_A.txid_int, 0))) 167 tx_orphan_include_by_block_A.vout.append(CTxOut(nValue=12 * COIN - 12000, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) 168 169 self.log.info('Send the orphan ... ') 170 node.p2ps[0].send_txs_and_test([tx_orphan_include_by_block_A], node, success=False) 171 172 tip = int(node.getbestblockhash(), 16) 173 height = node.getblockcount() + 1 174 block_A = create_block(tip, create_coinbase(height)) 175 block_A.vtx.extend([tx_withhold, tx_withhold_until_block_A, tx_orphan_include_by_block_A]) 176 block_A.hashMerkleRoot = block_A.calc_merkle_root() 177 block_A.solve() 178 179 self.log.info('Send the block that includes the previous orphan ... ') 180 with node.assert_debug_log(["Erased 1 orphan transaction(s) included or conflicted by block"]): 181 node.p2ps[0].send_blocks_and_test([block_A], node, success=True) 182 node.syncwithvalidationinterfacequeue() 183 184 self.log.info('Test that a transaction in the orphan pool conflicts with a new tip block causes erase this transaction from the orphan pool') 185 tx_withhold_until_block_B = CTransaction() 186 tx_withhold_until_block_B.vin.append(CTxIn(outpoint=COutPoint(tx_withhold_until_block_A.txid_int, 1))) 187 tx_withhold_until_block_B.vout.append(CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) 188 189 tx_orphan_include_by_block_B = CTransaction() 190 tx_orphan_include_by_block_B.vin.append(CTxIn(outpoint=COutPoint(tx_withhold_until_block_B.txid_int, 0))) 191 tx_orphan_include_by_block_B.vout.append(CTxOut(nValue=10 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) 192 193 tx_orphan_conflict_by_block_B = CTransaction() 194 tx_orphan_conflict_by_block_B.vin.append(CTxIn(outpoint=COutPoint(tx_withhold_until_block_B.txid_int, 0))) 195 tx_orphan_conflict_by_block_B.vout.append(CTxOut(nValue=9 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) 196 self.log.info('Send the orphan ... ') 197 node.p2ps[0].send_txs_and_test([tx_orphan_conflict_by_block_B], node, success=False) 198 199 tip = int(node.getbestblockhash(), 16) 200 height = node.getblockcount() + 1 201 block_B = create_block(tip, create_coinbase(height)) 202 block_B.vtx.extend([tx_withhold_until_block_B, tx_orphan_include_by_block_B]) 203 block_B.hashMerkleRoot = block_B.calc_merkle_root() 204 block_B.solve() 205 206 self.log.info('Send the block that includes a transaction which conflicts with the previous orphan ... ') 207 with node.assert_debug_log(["Erased 1 orphan transaction(s) included or conflicted by block"]): 208 node.p2ps[0].send_blocks_and_test([block_B], node, success=True) 209 node.syncwithvalidationinterfacequeue() 210 211 212 if __name__ == '__main__': 213 InvalidTxRequestTest(__file__).main()