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.
1#!/usr/bin/env python32# Copyright (c) 2024-present The Bitcoin Core developers3# Distributed under the MIT software license, see the accompanying4# file COPYING or http://www.opensource.org/licenses/mit-license.php.5"""6Test that 1p1c package submission allows a 1p1c package to propagate in a "network" of nodes. Send7various packages from different nodes on a network in which some nodes have already received some of8the transactions (and submitted them to mempool, kept them as orphans or rejected them as9too-low-feerate transactions). The packages should be received and accepted by all nodes.10"""12from decimal import Decimal14from test_framework.mempool_util import (15DEFAULT_MIN_RELAY_TX_FEE,16)17from test_framework.messages import (18COIN,19msg_tx,20)21from test_framework.p2p import (22P2PInterface,23)24from test_framework.test_framework import BitcoinTestFramework25from test_framework.util import (26assert_equal,27)28from test_framework.wallet import (29MiniWallet,30MiniWalletMode,31)33class PackageRelayTest(BitcoinTestFramework):34def set_test_params(self):35self.setup_clean_chain = True36self.num_nodes = 437# hugely speeds up the test, as it involves multiple hops of tx relay.38self.noban_tx_relay = True40def create_basic_1p1c(self, wallet):41low_fee_parent = wallet.create_self_transfer(fee_rate=0, confirmed_only=True)42high_fee_child = wallet.create_self_transfer(utxo_to_spend=low_fee_parent["new_utxo"], fee_rate=999*Decimal(DEFAULT_MIN_RELAY_TX_FEE)/ COIN)43package_hex_basic = [low_fee_parent["hex"], high_fee_child["hex"]]44return package_hex_basic, low_fee_parent["tx"], high_fee_child["tx"]46def create_package_2outs(self, wallet):47# First create a tester tx to see the vsize, and then adjust the fees48utxo_for_2outs = wallet.get_utxo(confirmed_only=True)50low_fee_parent_2outs = wallet.create_self_transfer_multi(51utxos_to_spend=[utxo_for_2outs],52num_outputs=2,53fee_per_output=0,54)56# Now create the child57high_fee_child_2outs = wallet.create_self_transfer_multi(58utxos_to_spend=low_fee_parent_2outs["new_utxos"][::-1],59fee_per_output=10_000,60)61return [low_fee_parent_2outs["hex"], high_fee_child_2outs["hex"]], low_fee_parent_2outs["tx"], high_fee_child_2outs["tx"]63def create_package_2p1c(self, wallet):64parent1 = wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN * 10, confirmed_only=True)65parent2 = wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN * 20, confirmed_only=True)66child = wallet.create_self_transfer_multi(67utxos_to_spend=[parent1["new_utxo"], parent2["new_utxo"]],68fee_per_output=999*parent1["tx"].get_vsize(),69)70return [parent1["hex"], parent2["hex"], child["hex"]], parent1["tx"], parent2["tx"], child["tx"]72def create_packages(self):73# 1: Basic 1-parent-1-child package, parent 0sat/vB, child 999sat/vB74package_hex_1, parent_1, child_1 = self.create_basic_1p1c(self.wallet)76# 2: same as 1, parent's txid is the same as its wtxid.77package_hex_2, parent_2, child_2 = self.create_basic_1p1c(self.wallet_nonsegwit)79# 3: 2-parent-1-child package. Both parents are above mempool min feerate. No package submission happens.80# We require packages to be child-with-parents and only allow 1-parent-1-child packages.81package_hex_3, parent_31, _parent_32, child_3 = self.create_package_2p1c(self.wallet)83# 4: parent + child package where the child spends 2 different outputs from the parent.84package_hex_4, parent_4, child_4 = self.create_package_2outs(self.wallet)86# Assemble return results87packages_to_submit = [package_hex_1, package_hex_2, package_hex_3, package_hex_4]88# node0: sender89# node1: pre-received the children (orphans, will be dropped on peer disconnect)90# node3: pre-received the parents (too low fee)91# All nodes receive parent_31 ahead of time.92txns_to_send = [93[],94[child_1, child_2, parent_31, child_3, child_4],95[parent_31],96[parent_1, parent_2, parent_31, parent_4]97]99return packages_to_submit, txns_to_send101def run_test(self):102self.wallet = MiniWallet(self.nodes[1])103self.wallet_nonsegwit = MiniWallet(self.nodes[2], mode=MiniWalletMode.RAW_P2PK)104self.generate(self.wallet_nonsegwit, 10)105self.generate(self.wallet, 120)107# Create the transactions.108self.wallet.rescan_utxos(include_mempool=True)109packages_to_submit, transactions_to_presend = self.create_packages()111self.peers = [self.nodes[i].add_p2p_connection(P2PInterface()) for i in range(self.num_nodes)]113self.log.info("Pre-send some transactions to nodes")114for (i, peer) in enumerate(self.peers):115for tx in transactions_to_presend[i]:116peer.send_and_ping(msg_tx(tx))118# The fee-having parent should be the only thing in mempools119self.sync_mempools()120sufficient_parent = transactions_to_presend[2][0].txid_hex121for i, node in enumerate(self.nodes):122# node1 has non-empty orphanage as well123if i == 1:124assert_equal(len(self.nodes[i].getorphantxs()), 4)125else:126assert_equal(self.nodes[i].getorphantxs(), [])128assert_equal(node.getrawmempool(), [sufficient_parent])130# Disconnect python peers to clear outstanding orphan requests with them, avoiding timeouts.131# We are only interested in the syncing behavior between real nodes.132for i in range(self.num_nodes):133self.nodes[i].disconnect_p2ps()134self.wait_until(lambda: len(self.nodes[i].getorphantxs()) == 0)136self.log.info("Submit full packages to node0")137for package_hex in packages_to_submit:138submitpackage_result = self.nodes[0].submitpackage(package_hex)139assert_equal(submitpackage_result["package_msg"], "success")141self.log.info("Wait for mempools to sync")142self.wait_until(lambda: len(self.nodes[0].getrawmempool()) == 9)143self.sync_mempools()146if __name__ == '__main__':147PackageRelayTest(__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.