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) 2021-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"""Test logic for limiting mempool and package ancestors/descendants."""6from test_framework.blocktools import COINBASE_MATURITY7from test_framework.test_framework import BitcoinTestFramework8from test_framework.util import (9assert_equal,10)11from test_framework.wallet import MiniWallet13# Decorator to14# 1) check that mempool is empty at the start of a subtest15# 2) run the subtest, which may submit some transaction(s) to the mempool and16# create a list of hex transactions17# 3) testmempoolaccept the package hex and check that it fails with the error18# "too-large-cluster" for each tx19# 4) after mining a block, clearing the pre-submitted transactions from mempool,20# check that submitting the created package succeeds21def check_package_limits(func):22def func_wrapper(self, *args, **kwargs):23node = self.nodes[0]24assert_equal(0, node.getmempoolinfo()["size"])25package_hex = func(self, *args, **kwargs)26testres_error_expected = node.testmempoolaccept(rawtxs=package_hex)27assert_equal(len(testres_error_expected), len(package_hex))28for txres in testres_error_expected:29assert "too-large-cluster" in txres["package-error"]31# Clear mempool and check that the package passes now32self.generate(node, 1)33assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])35return func_wrapper38class MempoolPackageLimitsTest(BitcoinTestFramework):39def set_test_params(self):40self.num_nodes = 141self.setup_clean_chain = True42self.extra_args = [["-limitclustercount=25"]]44def run_test(self):45self.wallet = MiniWallet(self.nodes[0])46# Add enough mature utxos to the wallet so that all txs spend confirmed coins.47self.generate(self.wallet, COINBASE_MATURITY + 35)49self.test_chain_limits()50self.test_desc_count_limits()51self.test_desc_count_limits_2()52self.test_desc_size_limits()54@check_package_limits55def test_chain_limits_helper(self, mempool_count, package_count):56node = self.nodes[0]57chain_hex = []59chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=mempool_count)[-1]["new_utxo"]60# in-package transactions61for _ in range(package_count):62tx = self.wallet.create_self_transfer(utxo_to_spend=chaintip_utxo)63chaintip_utxo = tx["new_utxo"]64chain_hex.append(tx["hex"])65return chain_hex67def test_chain_limits(self):68"""Create chains from mempool and package transactions that are longer than 25,69but only if both in-mempool and in-package transactions are considered together.70This checks that both mempool and in-package transactions are taken into account when71calculating ancestors/descendant limits.72"""73self.log.info("Check that in-package ancestors count for mempool ancestor limits")75# 24 transactions in the mempool and 2 in the package. The parent in the package has76# 24 in-mempool ancestors and 1 in-package descendant. The child has 0 direct parents77# in the mempool, but 25 in-mempool and in-package ancestors in total.78self.test_chain_limits_helper(24, 2)79# 2 transactions in the mempool and 24 in the package.80self.test_chain_limits_helper(2, 24)81# 13 transactions in the mempool and 13 in the package.82self.test_chain_limits_helper(13, 13)84@check_package_limits85def test_desc_count_limits(self):86"""Create an 'A' shaped package with 24 transactions in the mempool and 2 in the package:87M188^ ^89M2a M2b90. .91. .92. .93M12a ^94^ M13b95^ ^96Pa Pb97The top ancestor in the package exceeds descendant limits but only if the in-mempool and in-package98descendants are all considered together (24 including in-mempool descendants and 26 including both99package transactions).100"""101node = self.nodes[0]102self.log.info("Check that in-mempool and in-package descendants are calculated properly in packages")103# Top parent in mempool, M1104m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos']106package_hex = []107# Chain A (M2a... M12a)108chain_a_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=11, utxo_to_spend=m1_utxos[0])[-1]["new_utxo"]109# Pa110pa_hex = self.wallet.create_self_transfer(utxo_to_spend=chain_a_tip_utxo)["hex"]111package_hex.append(pa_hex)113# Chain B (M2b... M13b)114chain_b_tip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=12, utxo_to_spend=m1_utxos[1])[-1]["new_utxo"]115# Pb116pb_hex = self.wallet.create_self_transfer(utxo_to_spend=chain_b_tip_utxo)["hex"]117package_hex.append(pb_hex)119assert_equal(24, node.getmempoolinfo()["size"])120assert_equal(2, len(package_hex))121return package_hex123@check_package_limits124def test_desc_count_limits_2(self):125"""Create a Package with 24 transaction in mempool and 2 transaction in package:126M1127^ ^128M2 ^129. ^130. ^131. ^132M24 ^133^134P1135^136P2137P1 has M1 as a mempool ancestor, P2 has no in-mempool ancestors, but when138combined P2 has M1 as an ancestor and M1 exceeds descendant_limits(23 in-mempool139descendants + 2 in-package descendants, a total of 26 including itself).140"""142node = self.nodes[0]143package_hex = []144# M1145m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos']147# Chain M2...M24148self.wallet.send_self_transfer_chain(from_node=node, chain_length=23, utxo_to_spend=m1_utxos[0])[-1]["new_utxo"]150# P1151p1_tx = self.wallet.create_self_transfer(utxo_to_spend=m1_utxos[1])152package_hex.append(p1_tx["hex"])154# P2155p2_tx = self.wallet.create_self_transfer(utxo_to_spend=p1_tx["new_utxo"])156package_hex.append(p2_tx["hex"])158assert_equal(24, node.getmempoolinfo()["size"])159assert_equal(2, len(package_hex))160return package_hex162@check_package_limits163def test_desc_size_limits(self):164"""Create 3 mempool transactions and 2 package transactions (21KvB each):165Ma166^ ^167Mb Mc168^ ^169Pd Pe170The top ancestor in the package exceeds descendant size limits but only if the in-mempool171and in-package descendants are all considered together.172"""173node = self.nodes[0]174target_vsize = 21_000175high_fee = 10 * target_vsize # 10 sats/vB176self.log.info("Check that in-mempool and in-package descendant sizes are calculated properly in packages")177# Top parent in mempool, Ma178ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=high_fee // 2, target_vsize=target_vsize)179self.wallet.sendrawtransaction(from_node=node, tx_hex=ma_tx["hex"])181package_hex = []182for j in range(2): # Two legs (left and right)183# Mempool transaction (Mb and Mc)184mempool_tx = self.wallet.create_self_transfer(utxo_to_spend=ma_tx["new_utxos"][j], target_vsize=target_vsize)185self.wallet.sendrawtransaction(from_node=node, tx_hex=mempool_tx["hex"])187# Package transaction (Pd and Pe)188package_tx = self.wallet.create_self_transfer(utxo_to_spend=mempool_tx["new_utxo"], target_vsize=target_vsize)189package_hex.append(package_tx["hex"])191assert_equal(3, node.getmempoolinfo()["size"])192assert_equal(2, len(package_hex))193return package_hex196if __name__ == "__main__":197MempoolPackageLimitsTest(__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.