rpc_orphans.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2014-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 """Tests for orphan related RPCs.""" 6 7 from test_framework.mempool_util import ( 8 tx_in_orphanage, 9 ) 10 from test_framework.messages import ( 11 CInv, 12 msg_inv, 13 msg_tx, 14 MSG_WTX, 15 ) 16 from test_framework.p2p import P2PInterface 17 from test_framework.util import ( 18 assert_equal, 19 assert_not_equal, 20 assert_raises_rpc_error, 21 ) 22 from test_framework.test_framework import BitcoinTestFramework 23 from test_framework.wallet import MiniWallet 24 25 26 class OrphanRPCsTest(BitcoinTestFramework): 27 def set_test_params(self): 28 self.num_nodes = 1 29 30 def run_test(self): 31 self.wallet = MiniWallet(self.nodes[0]) 32 self.test_orphan_activity() 33 self.test_orphan_details() 34 self.test_misc() 35 36 def test_orphan_activity(self): 37 self.log.info("Check that orphaned transactions are returned with getorphantxs") 38 node = self.nodes[0] 39 40 self.log.info("Create two 1P1C packages, but only broadcast the children") 41 tx_parent_1 = self.wallet.create_self_transfer() 42 tx_child_1 = self.wallet.create_self_transfer(utxo_to_spend=tx_parent_1["new_utxo"]) 43 tx_parent_2 = self.wallet.create_self_transfer() 44 tx_child_2 = self.wallet.create_self_transfer(utxo_to_spend=tx_parent_2["new_utxo"]) 45 peer = node.add_p2p_connection(P2PInterface()) 46 peer.send_and_ping(msg_tx(tx_child_1["tx"])) 47 peer.send_and_ping(msg_tx(tx_child_2["tx"])) 48 49 self.log.info("Check that neither parent is in the mempool") 50 assert_equal(node.getmempoolinfo()["size"], 0) 51 52 orphanage = node.getorphantxs(verbosity=0) 53 self.log.info("Check the size of the orphanage") 54 assert_equal(len(orphanage), 2) 55 self.log.info("Check that undefined verbosity is disallowed") 56 assert_raises_rpc_error(-8, "Invalid verbosity value -1", node.getorphantxs, verbosity=-1) 57 assert_raises_rpc_error(-8, "Invalid verbosity value 3", node.getorphantxs, verbosity=3) 58 self.log.info("Check that both children are in the orphanage") 59 assert tx_in_orphanage(node, tx_child_1["tx"]) 60 assert tx_in_orphanage(node, tx_child_2["tx"]) 61 62 self.log.info("Broadcast parent 1") 63 peer.send_and_ping(msg_tx(tx_parent_1["tx"])) 64 self.log.info("Check that parent 1 and child 1 are in the mempool") 65 raw_mempool = node.getrawmempool() 66 assert_equal(len(raw_mempool), 2) 67 assert tx_parent_1["txid"] in raw_mempool 68 assert tx_child_1["txid"] in raw_mempool 69 70 self.log.info("Check that orphanage only contains child 2") 71 orphanage = node.getorphantxs() 72 assert_equal(len(orphanage), 1) 73 assert tx_in_orphanage(node, tx_child_2["tx"]) 74 75 peer.send_and_ping(msg_tx(tx_parent_2["tx"])) 76 self.log.info("Check that all parents and children are now in the mempool") 77 raw_mempool = node.getrawmempool() 78 assert_equal(len(raw_mempool), 4) 79 assert tx_parent_1["txid"] in raw_mempool 80 assert tx_child_1["txid"] in raw_mempool 81 assert tx_parent_2["txid"] in raw_mempool 82 assert tx_child_2["txid"] in raw_mempool 83 self.log.info("Check that the orphanage is empty") 84 assert_equal(len(node.getorphantxs()), 0) 85 86 self.log.info("Confirm the transactions (clears mempool)") 87 self.generate(node, 1) 88 assert_equal(node.getmempoolinfo()["size"], 0) 89 90 def test_orphan_details(self): 91 self.log.info("Check the transaction details returned from getorphantxs") 92 node = self.nodes[0] 93 94 self.log.info("Create two orphans, from different peers") 95 tx_parent_1 = self.wallet.create_self_transfer() 96 tx_child_1 = self.wallet.create_self_transfer(utxo_to_spend=tx_parent_1["new_utxo"]) 97 tx_parent_2 = self.wallet.create_self_transfer() 98 tx_child_2 = self.wallet.create_self_transfer(utxo_to_spend=tx_parent_2["new_utxo"]) 99 peer_1 = node.add_p2p_connection(P2PInterface()) 100 peer_2 = node.add_p2p_connection(P2PInterface()) 101 peer_1.send_and_ping(msg_tx(tx_child_1["tx"])) 102 peer_2.send_and_ping(msg_tx(tx_child_2["tx"])) 103 104 orphanage = node.getorphantxs(verbosity=2) 105 assert tx_in_orphanage(node, tx_child_1["tx"]) 106 assert tx_in_orphanage(node, tx_child_2["tx"]) 107 108 self.log.info("Check that orphan 1 and 2 were from different peers") 109 assert_not_equal(orphanage[0]["from"][0], orphanage[1]["from"][0]) 110 peer_ids = [orphanage[0]["from"][0], orphanage[1]["from"][0]] 111 112 self.log.info("Unorphan child 2") 113 peer_2.send_and_ping(msg_tx(tx_parent_2["tx"])) 114 assert not tx_in_orphanage(node, tx_child_2["tx"]) 115 116 self.log.info("Check that additional announcers are reflected in RPC result") 117 peer_2.send_and_ping(msg_inv([CInv(t=MSG_WTX, h=int(tx_child_1["wtxid"], 16))])) 118 119 orphanage = node.getorphantxs(verbosity=2) 120 assert_equal(set(orphanage[0]["from"]), set(peer_ids)) 121 122 self.log.info("Checking orphan details") 123 assert_equal(len(node.getorphantxs()), 1) 124 orphan_1 = orphanage[0] 125 self.orphan_details_match(orphan_1, tx_child_1, verbosity=1) 126 127 self.log.info("Checking orphan details (verbosity 2)") 128 orphanage = node.getorphantxs(verbosity=2) 129 orphan_1 = orphanage[0] 130 self.orphan_details_match(orphan_1, tx_child_1, verbosity=2) 131 132 def orphan_details_match(self, orphan, tx, verbosity): 133 self.log.info("Check txid/wtxid of orphan") 134 assert_equal(orphan["txid"], tx["txid"]) 135 assert_equal(orphan["wtxid"], tx["wtxid"]) 136 137 self.log.info("Check the sizes of orphan") 138 assert_equal(orphan["bytes"], len(tx["tx"].serialize())) 139 assert_equal(orphan["vsize"], tx["tx"].get_vsize()) 140 assert_equal(orphan["weight"], tx["tx"].get_weight()) 141 142 if verbosity == 2: 143 self.log.info("Check the transaction hex of orphan") 144 assert_equal(orphan["hex"], tx["hex"]) 145 146 def test_misc(self): 147 node = self.nodes[0] 148 assert_raises_rpc_error(-3, "Verbosity was boolean but only integer allowed", node.getorphantxs, verbosity=True) 149 assert_raises_rpc_error(-3, "Verbosity was boolean but only integer allowed", node.getorphantxs, verbosity=False) 150 help_output = node.help() 151 self.log.info("Check that getorphantxs is a hidden RPC") 152 assert "getorphantxs" not in help_output 153 assert "unknown command: getorphantxs" not in node.help("getorphantxs") 154 155 156 if __name__ == '__main__': 157 OrphanRPCsTest(__file__).main()