Repository: bitcoin/bitcoin
File: test/functional/p2p_orphan_handling.py (Python)

Code before:
        with node.assert_debug_log(["stored orphan tx"]):
            honest_peer.send_and_ping(msg_tx(tx_child["tx"]))

        # 5. After first parent request times out, the node sends another one for the missing parent
        # of the real orphan child.
        node.bumpmocktime(GETDATA_TX_INTERVAL)
        honest_peer.wait_for_getdata([parent_txid_int])
        honest_peer.send_and_ping(msg_tx(tx_parent["tx"]))

        # 6. After parent is accepted, orphans should be reconsidered.
        # The real child should be accepted and the fake one rejected. This may happen in either
        # order since the message-processing is randomized. If tx_orphan_bad_wit is validated first,
        # its consensus error leads to disconnection of bad_peer. If tx_child is validated first,
        # tx_orphan_bad_wit is rejected for txn-same-nonwitness-data-in-mempool (no punishment).
        node_mempool = node.getrawmempool()
        assert tx_parent["txid"] in node_mempool
        assert tx_child["txid"] in node_mempool
        assert_equal(node.getmempoolentry(tx_child["txid"])["wtxid"], tx_child["wtxid"])

    @cleanup
    def test_orphan_reject_large_tx(self):
        self.log.info("Test that large transactions (>MAX_STANDARD_TX_WEIGHT) aren't put into orphanage")
        # we have to explicitly allow non-standard txs to reach this code path, as otherwise
        # the tx is already rejected earlier with "tx-size" (see `IsStandardTx` check)
        self.restart_node(0, extra_args=['-acceptnonstdtxn=1'])
        oversize_weight = MAX_STANDARD_TX_WEIGHT + 1
        large_tx = self.wallet.create_self_transfer(target_weight=oversize_weight)['tx']
        assert_greater_than_or_equal(large_tx.get_weight(), oversize_weight)
        oversize_weight = large_tx.get_weight()
        large_tx.vin[0].prevout.hash = 3133742  # overwrite prevout with fake txid to create orphan
        txid, wtxid = large_tx.rehash(), large_tx.getwtxid()
        large_orphan_logmsg = f"ignoring large orphan tx (size: {oversize_weight}, txid: {txid}, wtxid: {wtxid})"
        peer = self.nodes[0].add_p2p_connection(P2PInterface())
        with self.nodes[0].assert_debug_log(expected_msgs=[large_orphan_logmsg]):
            peer.send_message(msg_tx(large_tx))
        self.restart_node(0)  # the following tests should only accept standard txs again

    def run_test(self):
        self.nodes[0].setmocktime(int(time.time()))
        self.wallet_nonsegwit = MiniWallet(self.nodes[0], mode=MiniWalletMode.RAW_P2PK)
        self.generate(self.wallet_nonsegwit, 10)
        self.wallet = MiniWallet(self.nodes[0])
        self.generate(self.wallet, 160)
        self.test_orphan_reject_large_tx()
        self.test_arrival_timing_orphan()
        self.test_orphan_rejected_parents_exceptions()
        self.test_orphan_multiple_parents()
        self.test_orphans_overlapping_parents()
        self.test_orphan_of_orphan()
        self.test_orphan_inherit_rejection()
        self.test_same_txid_orphan()

Review comment (bug):
Locally modified this (to 1000) to see the `assert_debug_log` check fail (missing `larg_orphan_logmsg`).  The assert failed as expected.

Code after:

        # 5. After first parent request times out, the node sends another one for the missing parent
        # of the real orphan child.
        node.bumpmocktime(GETDATA_TX_INTERVAL)
        honest_peer.wait_for_getdata([parent_txid_int])
        honest_peer.send_and_ping(msg_tx(tx_parent["tx"]))

        # 6. After parent is accepted, orphans should be reconsidered.
        # The real child should be accepted and the fake one rejected. This may happen in either
        # order since the message-processing is randomized. If tx_orphan_bad_wit is validated first,
        # its consensus error leads to disconnection of bad_peer. If tx_child is validated first,
        # tx_orphan_bad_wit is rejected for txn-same-nonwitness-data-in-mempool (no punishment).
        node_mempool = node.getrawmempool()
        assert tx_parent["txid"] in node_mempool
        assert tx_child["txid"] in node_mempool
        assert_equal(node.getmempoolentry(tx_child["txid"])["wtxid"], tx_child["wtxid"])


    def run_test(self):
        self.nodes[0].setmocktime(int(time.time()))
        self.wallet_nonsegwit = MiniWallet(self.nodes[0], mode=MiniWalletMode.RAW_P2PK)
        self.generate(self.wallet_nonsegwit, 10)
        self.wallet = MiniWallet(self.nodes[0])
        self.generate(self.wallet, 160)
        self.test_arrival_timing_orphan()
        self.test_orphan_rejected_parents_exceptions()
        self.test_orphan_multiple_parents()
        self.test_orphans_overlapping_parents()
        self.test_orphan_of_orphan()
        self.test_orphan_inherit_rejection()
        self.test_same_txid_orphan()
        self.test_same_txid_orphan_of_orphan()
        self.test_orphan_txid_inv()


if __name__ == '__main__':
    OrphanHandlingTest(__file__).main()