Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
751peer_late_announcer.send_and_ping(msg_inv([orphan_inv]))753# The orphan should have 2 announcers now754orphanage = node.getorphantxs(verbosity=2)755assert_equal(orphanage[0]["wtxid"], orphan_wtxid)756assert_equal(len(orphanage[0]["from"]), 2)758self.nodes[0].bumpmocktime(GETDATA_TX_INTERVAL)759peer_late_announcer.wait_for_parent_requests([parent_tx.txid_int])761@cleanup762def test_parents_change(self):763self.log.info("Test that, if a parent goes missing during orphan reso, it is requested")764node = self.nodes[0]765# Orphan will have 2 parents, 1 missing and 1 already in mempool when received.766# Create missing parent.767parent_missing = self.wallet.create_self_transfer()769# Create parent that will already be in mempool, but become missing during orphan resolution.770# Get 3 UTXOs for replacement-cycled parent, UTXOS A, B, C771coin_A = self.wallet.get_utxo(confirmed_only=True)772coin_B = self.wallet.get_utxo(confirmed_only=True)773coin_C = self.wallet.get_utxo(confirmed_only=True)774# parent_peekaboo_AB spends A and B. It is replaced by tx_replacer_BC (conflicting UTXO B),775# and then replaced by tx_replacer_C (conflicting UTXO C). This replacement cycle is used to776# ensure that parent_peekaboo_AB can be reintroduced without requiring package RBF.777FEE_INCREMENT = 2400778parent_peekaboo_AB = self.wallet.create_self_transfer_multi(779utxos_to_spend=[coin_A, coin_B],780num_outputs=1,781fee_per_output=FEE_INCREMENT782)783tx_replacer_BC = self.wallet.create_self_transfer_multi(784utxos_to_spend=[coin_B, coin_C],785num_outputs=1,786fee_per_output=2*FEE_INCREMENT787)788tx_replacer_C = self.wallet.create_self_transfer(789utxo_to_spend=coin_C,790fee_per_output=3*FEE_INCREMENT791)793# parent_peekaboo_AB starts out in the mempool794node.sendrawtransaction(parent_peekaboo_AB["hex"])796orphan = self.wallet.create_self_transfer_multi(utxos_to_spend=[parent_peekaboo_AB["new_utxos"][0], parent_missing["new_utxo"]])797orphan_wtxid = orphan["wtxid"]798orphan_inv = CInv(t=MSG_WTX, h=int(orphan_wtxid, 16))800# peer1 sends the orphan and gets a request for the missing parent801peer1 = node.add_p2p_connection(PeerTxRelayer())802peer1.send_and_ping(msg_inv([orphan_inv]))803node.bumpmocktime(TXREQUEST_TIME_SKIP)804peer1.wait_for_getdata([int(orphan_wtxid, 16)])805peer1.send_and_ping(msg_tx(orphan["tx"]))806self.wait_until(lambda: node.getorphantxs(verbosity=0) == [orphan["txid"]])807node.bumpmocktime(NONPREF_PEER_TX_DELAY + TXID_RELAY_DELAY)808peer1.wait_for_getdata([int(parent_missing["txid"], 16)])810# Replace parent_peekaboo_AB so that is a newly missing parent.811# Then, replace the replacement so that it can be resubmitted.812node.sendrawtransaction(tx_replacer_BC["hex"])813assert tx_replacer_BC["txid"] in node.getrawmempool()814node.sendrawtransaction(tx_replacer_C["hex"])815assert tx_replacer_BC["txid"] not in node.getrawmempool()816assert parent_peekaboo_AB["txid"] not in node.getrawmempool()817assert tx_replacer_C["txid"] in node.getrawmempool()819# Second peer is an additional announcer for this orphan, but its missing parents are different from when it was820# previously announced.821peer2 = node.add_p2p_connection(PeerTxRelayer())822peer2.send_and_ping(msg_inv([orphan_inv]))823assert_equal(len(node.getorphantxs(verbosity=2)[0]["from"]), 2)825# Disconnect peer1. peer2 should become the new candidate for orphan resolution.826peer1.peer_disconnect()827self.wait_until(lambda: node.num_test_p2p_connections() == 1)828peer2.sync_with_ping() # Sync with the 'net' thread which completes the disconnection fully829node.bumpmocktime(TXREQUEST_TIME_SKIP)830self.wait_until(lambda: len(node.getorphantxs(verbosity=2)[0]["from"]) == 1)831# Both parents should be requested, now that they are both missing.832peer2.wait_for_parent_requests([int(parent_peekaboo_AB["txid"], 16), int(parent_missing["txid"], 16)])833peer2.send_and_ping(msg_tx(parent_missing["tx"]))834peer2.send_and_ping(msg_tx(parent_peekaboo_AB["tx"]))836final_mempool = node.getrawmempool()837assert parent_missing["txid"] in final_mempool838assert parent_peekaboo_AB["txid"] in final_mempool839assert orphan["txid"] in final_mempool840assert tx_replacer_C["txid"] in final_mempool842def run_test(self):843self.nodes[0].setmocktime(int(time.time()))844self.wallet_nonsegwit = MiniWallet(self.nodes[0], mode=MiniWalletMode.RAW_P2PK)845self.generate(self.wallet_nonsegwit, 10)846self.wallet = MiniWallet(self.nodes[0])847self.generate(self.wallet, 160)849self.test_arrival_timing_orphan()850self.test_orphan_rejected_parents_exceptions()851self.test_orphan_multiple_parents()852self.test_orphans_overlapping_parents()853self.test_orphan_of_orphan()854self.test_orphan_parent_confirmed()855self.test_orphan_inherit_rejection()856self.test_same_txid_orphan()857self.test_same_txid_orphan_of_orphan()858self.test_orphan_txid_inv()859self.test_orphan_handling_prefer_outbound()860self.test_announcers_before_and_after()861self.test_parents_change()862self.test_maximal_package_protected()865if __name__ == '__main__':866OrphanHandlingTest(__file__).main()
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.