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.
251resulting_ancestry_fee_rate = self.calc_set_fee_rate([gp_tx, p_tx, ancestor_aware_tx])252assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)253assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)255wallet.unloadwallet()257# Test fee calculation when bumping while using subtract fee from output (SFFO)258def test_target_feerate_unconfirmed_low_sffo(self):259self.log.info("Start test feerate with low feerate unconfirmed input, while subtracting from output")260wallet = self.setup_and_fund_wallet("unconfirmed_low_wallet_sffo")262parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)263parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)265self.assert_undershoots_target(parent_tx)267ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate, subtractfeefromamount=True)268ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)270self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])272self.assert_beats_target(ancestor_aware_tx)273resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])274assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)275assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)277wallet.unloadwallet()279# Test that parents of preset unconfirmed inputs get cpfp'ed280def test_preset_input_cpfp(self):281self.log.info("Start test with preset input from low feerate unconfirmed transaction")282wallet = self.setup_and_fund_wallet("preset_input")284parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)285parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)287self.assert_undershoots_target(parent_tx)289number_outputs = len(parent_tx["decoded"]["vout"])290assert_equal(number_outputs, 2)292# we don't care which of the two outputs we spent, they're both ours293ancestor_aware_txid = wallet.send(outputs=[{self.def_wallet.getnewaddress(): 0.5}], fee_rate=self.target_fee_rate, options={"add_inputs": True, "inputs": [{"txid": parent_txid, "vout": 0}]})["txid"]294ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)296self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])298self.assert_beats_target(ancestor_aware_tx)299resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])300assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)301assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)303wallet.unloadwallet()305# Test that RBFing a transaction with unconfirmed input gets the right feerate306def test_rbf_bumping(self):307self.log.info("Start test to rbf a transaction unconfirmed input to bump it")308wallet = self.setup_and_fund_wallet("bump")310parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)311parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)313self.assert_undershoots_target(parent_tx)315to_be_rbfed_ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate)316ancestor_aware_tx = wallet.gettransaction(txid=to_be_rbfed_ancestor_aware_txid, verbose=True)318self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])320self.assert_beats_target(ancestor_aware_tx)321resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])322assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)323assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)325bumped_ancestor_aware_txid = wallet.bumpfee(txid=to_be_rbfed_ancestor_aware_txid, options={"fee_rate": self.target_fee_rate * 2} )["txid"]326bumped_ancestor_aware_tx = wallet.gettransaction(txid=bumped_ancestor_aware_txid, verbose=True)327self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])329resulting_bumped_fee_rate = self.calc_fee_rate(bumped_ancestor_aware_tx)330assert_greater_than_or_equal(resulting_bumped_fee_rate, 2*self.target_fee_rate)331resulting_bumped_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, bumped_ancestor_aware_tx])332assert_greater_than_or_equal(resulting_bumped_ancestry_fee_rate, 2*self.target_fee_rate)333assert_greater_than_or_equal(2*self.target_fee_rate*1.01, resulting_bumped_ancestry_fee_rate)335wallet.unloadwallet()337# Test that transaction spending two UTXOs with overlapping ancestry does not bump shared ancestors twice338def test_target_feerate_unconfirmed_low_overlapping_ancestry(self):339self.log.info("Start test where two UTXOs have overlapping ancestry")340wallet = self.setup_and_fund_wallet("overlapping_ancestry_wallet")342parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)343two_output_parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)345self.assert_undershoots_target(two_output_parent_tx)347# spend both outputs from parent transaction348ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=1.5, fee_rate=self.target_fee_rate)349ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)350self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid, parent_txid])352self.assert_beats_target(ancestor_aware_tx)353resulting_ancestry_fee_rate = self.calc_set_fee_rate([two_output_parent_tx, ancestor_aware_tx])354assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)355assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)357wallet.unloadwallet()359# Test that new transaction ignores sibling transaction with low feerate360def test_sibling_tx_gets_ignored(self):361self.log.info("Start test where a low-fee sibling tx gets created and check that bumping ignores it")362wallet = self.setup_and_fund_wallet("ignore-sibling")364parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=2)365parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)367self.assert_undershoots_target(parent_tx)369# create sibling tx370sibling_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.9, fee_rate=1)371sibling_tx = wallet.gettransaction(txid=sibling_txid, verbose=True)372self.assert_undershoots_target(sibling_tx)374# spend both outputs from parent transaction375ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate)376ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)378self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])380self.assert_beats_target(ancestor_aware_tx)381resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])382assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)383assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)385wallet.unloadwallet()387# Test that new transaction only pays for itself when high feerate sibling pays for parent388def test_sibling_tx_bumps_parent(self):389self.log.info("Start test where a high-fee sibling tx bumps the parent")390wallet = self.setup_and_fund_wallet("generous-sibling")392parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=1)393parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)394self.assert_undershoots_target(parent_tx)396# create sibling tx397sibling_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.9, fee_rate=3*self.target_fee_rate)398sibling_tx = wallet.gettransaction(txid=sibling_txid, verbose=True)399self.assert_beats_target(sibling_tx)401# spend both outputs from parent transaction402ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=0.5, fee_rate=self.target_fee_rate)403ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)405self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])407self.assert_beats_target(ancestor_aware_tx)408# Child is only paying for itself…409resulting_fee_rate = self.calc_fee_rate(ancestor_aware_tx)410assert_greater_than_or_equal(1.05 * self.target_fee_rate, resulting_fee_rate)411# …because sibling bumped to parent to ~50 s/vB, while our target is 30 s/vB412resulting_ancestry_fee_rate_sibling = self.calc_set_fee_rate([parent_tx, sibling_tx])413assert_greater_than_or_equal(resulting_ancestry_fee_rate_sibling, self.target_fee_rate)414# and our resulting "ancestry feerate" is therefore BELOW target feerate415resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])416assert_greater_than_or_equal(self.target_fee_rate, resulting_ancestry_fee_rate)418wallet.unloadwallet()420# Spend a confirmed and an unconfirmed input at the same time421def test_confirmed_and_unconfirmed_parent(self):422self.log.info("Start test with one unconfirmed and one confirmed input")423wallet = self.setup_and_fund_wallet("confirmed_and_unconfirmed_wallet")424confirmed_parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=1, fee_rate=self.target_fee_rate)425self.generate(self.nodes[0], 1) # Wallet has two confirmed UTXOs of ~1BTC each426unconfirmed_parent_txid = wallet.sendtoaddress(address=wallet.getnewaddress(), amount=0.5, fee_rate=0.5*self.target_fee_rate)428# wallet has one confirmed UTXO of 1BTC and two unconfirmed UTXOs of ~0.5BTC each429ancestor_aware_txid = wallet.sendtoaddress(address=self.def_wallet.getnewaddress(), amount=1.4, fee_rate=self.target_fee_rate)430ancestor_aware_tx = wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)431self.assert_spends_only_parents(ancestor_aware_tx, [confirmed_parent_txid, unconfirmed_parent_txid])432resulting_fee_rate = self.calc_fee_rate(ancestor_aware_tx)433assert_greater_than_or_equal(resulting_fee_rate, self.target_fee_rate)435wallet.unloadwallet()437def test_external_input_unconfirmed_low(self):438self.log.info("Send funds to an external wallet then build tx that bumps parent by spending external input")439wallet = self.setup_and_fund_wallet("test_external_wallet")441external_address = self.def_wallet.getnewaddress()442address_info = self.def_wallet.getaddressinfo(external_address)443external_descriptor = address_info["desc"]444parent_txid = wallet.sendtoaddress(address=external_address, amount=1, fee_rate=1)445parent_tx = wallet.gettransaction(txid=parent_txid, verbose=True)447self.assert_undershoots_target(parent_tx)449spend_res = wallet.send(outputs=[{self.def_wallet.getnewaddress(): 0.5}], fee_rate=self.target_fee_rate, options={"inputs":[{"txid":parent_txid, "vout":find_vout_for_address(self.nodes[0], parent_txid, external_address)}], "solving_data":{"descriptors":[external_descriptor]}})450signed_psbt = self.def_wallet.walletprocesspsbt(spend_res["psbt"])451external_tx = self.def_wallet.finalizepsbt(signed_psbt["psbt"])452ancestor_aware_txid = self.def_wallet.sendrawtransaction(external_tx["hex"])454ancestor_aware_tx = self.def_wallet.gettransaction(txid=ancestor_aware_txid, verbose=True)456self.assert_spends_only_parents(ancestor_aware_tx, [parent_txid])458self.assert_beats_target(ancestor_aware_tx)459resulting_ancestry_fee_rate = self.calc_set_fee_rate([parent_tx, ancestor_aware_tx])460assert_greater_than_or_equal(resulting_ancestry_fee_rate, self.target_fee_rate)461assert_greater_than_or_equal(self.target_fee_rate*1.01, resulting_ancestry_fee_rate)463wallet.unloadwallet()466def run_test(self):467self.log.info("Starting UnconfirmedInputTest!")468self.target_fee_rate = 30469self.def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)470self.generate(self.nodes[0], 110)472self.test_target_feerate_confirmed()474self.test_target_feerate_unconfirmed_high()476self.test_target_feerate_unconfirmed_low()478self.test_chain_of_unconfirmed_low()480self.test_two_low_feerate_unconfirmed_parents()482self.test_mixed_feerate_unconfirmed_parents()484self.test_chain_of_high_low()486self.test_chain_of_high_low_below_target_feerate()488self.test_target_feerate_unconfirmed_low_sffo()490self.test_preset_input_cpfp()492self.test_rbf_bumping()494self.test_target_feerate_unconfirmed_low_overlapping_ancestry()496self.test_sibling_tx_gets_ignored()498self.test_sibling_tx_bumps_parent()500self.test_confirmed_and_unconfirmed_parent()
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.