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.
252package_hex1, package_txns1 = self.create_simple_package(coin, DEFAULT_FEE, DEFAULT_CHILD_FEE)253node.submitpackage(package_hex1)254self.assert_mempool_contents(expected=package_txns1)256# Double-spends the original package257self.ctr += 1258parent_result1 = self.wallet.create_self_transfer(259fee=DEFAULT_FEE,260utxo_to_spend=coin,261sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr,262)264coin2 = self.coins.pop()266# Added to make package too large for package RBF;267# it will enter mempool individually268self.ctr += 1269parent_result2 = self.wallet.create_self_transfer(270fee=DEFAULT_FEE,271utxo_to_spend=coin2,272sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr,273)275# Child that spends both, violating cluster size rule due276# to in-mempool ancestry277self.ctr += 1278child_result = self.wallet.create_self_transfer_multi(279fee_per_output=int(DEFAULT_CHILD_FEE * COIN),280utxos_to_spend=[parent_result1["new_utxo"], parent_result2["new_utxo"]],281sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr,282)284package_hex2 = [parent_result1["hex"], parent_result2["hex"], child_result["hex"]]285package_txns2_succeed = [parent_result2["tx"]]287pkg_result = node.submitpackage(package_hex2)288assert_equal(pkg_result["package_msg"], 'package RBF failed: new transaction cannot have mempool ancestors')289self.assert_mempool_contents(expected=package_txns1 + package_txns2_succeed)290self.generate(node, 1)292def test_package_rbf_with_wrong_pkg_size(self):293self.log.info("Test that package RBF doesn't work with packages larger than 2 due to pkg size")294node = self.nodes[0]295coin1 = self.coins.pop()296coin2 = self.coins.pop()298# Two packages to require multiple direct conflicts, easier to set up illicit pkg size299package_hex1, package_txns1 = self.create_simple_package(coin1, DEFAULT_FEE, DEFAULT_CHILD_FEE)300package_hex2, package_txns2 = self.create_simple_package(coin2, DEFAULT_FEE, DEFAULT_CHILD_FEE)302node.submitpackage(package_hex1)303node.submitpackage(package_hex2)305self.assert_mempool_contents(expected=package_txns1 + package_txns2)306assert_equal(len(node.getrawmempool()), 4)308# Double-spends the first package309self.ctr += 1310parent_result1 = self.wallet.create_self_transfer(311fee=DEFAULT_FEE,312utxo_to_spend=coin1,313sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr,314)316# Double-spends the second package317self.ctr += 1318parent_result2 = self.wallet.create_self_transfer(319fee=DEFAULT_FEE,320utxo_to_spend=coin2,321sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr,322)324# Child that spends both, violating cluster size rule due325# to pkg size326self.ctr += 1327child_result = self.wallet.create_self_transfer_multi(328fee_per_output=int(DEFAULT_CHILD_FEE * COIN),329utxos_to_spend=[parent_result1["new_utxo"], parent_result2["new_utxo"]],330sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr,331)333package_hex3 = [parent_result1["hex"], parent_result2["hex"], child_result["hex"]]335pkg_result = node.submitpackage(package_hex3)336assert_equal(pkg_result["package_msg"], 'package RBF failed: package must be 1-parent-1-child')337self.assert_mempool_contents(expected=package_txns1 + package_txns2)338self.generate(node, 1)340def test_insufficient_feerate(self):341self.log.info("Check Package RBF must beat feerate of direct conflict")342node = self.nodes[0]343coin = self.coins.pop()345# Non-cpfp structure346package_hex1, package_txns1 = self.create_simple_package(coin, parent_fee=DEFAULT_CHILD_FEE, child_fee=DEFAULT_FEE)347node.submitpackage(package_hex1)348self.assert_mempool_contents(expected=package_txns1)350# Package 2 feerate is below the feerate of directly conflicted parent, so it fails even though351# total fees are higher than the original package352package_hex2, _package_txns2 = self.create_simple_package(coin, parent_fee=DEFAULT_CHILD_FEE - Decimal("0.00000001"), child_fee=DEFAULT_CHILD_FEE)353pkg_results2 = node.submitpackage(package_hex2)354assert_equal(pkg_results2["package_msg"], 'package RBF failed: insufficient feerate: does not improve feerate diagram')355self.assert_mempool_contents(expected=package_txns1)356self.generate(node, 1)358def test_0fee_package_rbf(self):359self.log.info("Test package RBF: TRUC 0-fee parent + high-fee child replaces parent's conflicts")360node = self.nodes[0]361# Reuse the same coins so that the transactions conflict with one another.362self.wallet.rescan_utxos()363parent_coin = self.wallet.get_utxo(confirmed_only=True)365# package1 pays default fee on both transactions366parent1 = self.wallet.create_self_transfer(utxo_to_spend=parent_coin, version=3)367child1 = self.wallet.create_self_transfer(utxo_to_spend=parent1["new_utxo"], version=3)368package_hex1 = [parent1["hex"], child1["hex"]]369fees_package1 = parent1["fee"] + child1["fee"]370submitres1 = node.submitpackage(package_hex1)371assert_equal(submitres1["package_msg"], "success")372self.assert_mempool_contents([parent1["tx"], child1["tx"]])374# package2 has a 0-fee parent (conflicting with package1) and very high fee child375parent2 = self.wallet.create_self_transfer(utxo_to_spend=parent_coin, fee=0, fee_rate=0, version=3)376child2 = self.wallet.create_self_transfer(utxo_to_spend=parent2["new_utxo"], fee=fees_package1*10, version=3)377package_hex2 = [parent2["hex"], child2["hex"]]379submitres2 = node.submitpackage(package_hex2)380assert_equal(submitres2["package_msg"], "success")381assert_equal(set(submitres2["replaced-transactions"]), set([parent1["txid"], child1["txid"]]))382self.assert_mempool_contents([parent2["tx"], child2["tx"]])384self.generate(node, 1)386def test_child_conflicts_parent_mempool_ancestor(self):387fill_mempool(self, self.nodes[0], tx_sync_fun=self.no_op)388# Reset coins since we filled the mempool with current coins389self.coins = self.wallet.get_utxos(mark_as_spent=False, confirmed_only=True)391self.log.info("Test that package RBF doesn't have issues with mempool<->package conflicts via inconsistency")392node = self.nodes[0]393coin = self.coins.pop()395self.ctr += 1396grandparent_result = self.wallet.create_self_transfer(397fee=DEFAULT_FEE,398utxo_to_spend=coin,399sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr,400)402node.sendrawtransaction(grandparent_result["hex"])403minrelayfeerate = node.getnetworkinfo()["relayfee"]405# Now make package of two descendants that looks406# like a cpfp where the parent can't get in on its own407self.ctr += 1408parent_result = self.wallet.create_self_transfer(409fee_rate=minrelayfeerate,410utxo_to_spend=grandparent_result["new_utxo"],411sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr,412)413# Last tx double-spends grandparent's coin,414# which is not inside the current package415self.ctr += 1416child_result = self.wallet.create_self_transfer_multi(417fee_per_output=int(DEFAULT_CHILD_FEE * COIN),418utxos_to_spend=[parent_result["new_utxo"], coin],419sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr,420)422pkg_result = node.submitpackage([parent_result["hex"], child_result["hex"]])423assert_equal(pkg_result["package_msg"], 'package RBF failed: new transaction cannot have mempool ancestors')424mempool_info = node.getrawmempool()425assert grandparent_result["txid"] in mempool_info426assert parent_result["txid"] not in mempool_info427assert child_result["txid"] not in mempool_info429if __name__ == "__main__":430PackageRBFTest(__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.