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.
251assert_equal(len(alice.getrawmempool()), 0)252assert_equal(len(bob.getrawmempool()), 3)254assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("49.99900000"))256# bob broadcasts tx_1 conflict257tx1_conflict_txid = bob.sendrawtransaction(tx1_conflict)258assert_equal(len(alice.getrawmempool()), 0)259assert_equal(len(bob.getrawmempool()), 2) # tx1_conflict kicks out both tx1, and its child tx3261assert tx2_txid in bob.getrawmempool()262assert tx1_conflict_txid in bob.getrawmempool()264assert_equal(bob.gettransaction(tx1_txid)["mempoolconflicts"], [tx1_conflict_txid])265assert_equal(bob.gettransaction(tx2_txid)["mempoolconflicts"], [])266assert_equal(bob.gettransaction(tx3_txid)["mempoolconflicts"], [tx1_conflict_txid])268# check that tx3 is now conflicted, so the output from tx2 can now be spent269assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("24.99990000"))271# we will be disconnecting this block in the future272alice.sendrawtransaction(tx2_conflict)273assert_equal(len(alice.getrawmempool()), 1) # currently alice's mempool is only aware of tx2_conflict274# 11 blocks are mined so that when they are invalidated, tx_2275# does not get put back into the mempool276blk = self.generate(self.nodes[0], 11, sync_fun=self.no_op)[0]277assert_equal(len(alice.getrawmempool()), 0) # tx2_conflict is now mined279self.connect_nodes(0, 1)280self.sync_blocks()281assert_equal(alice.getbestblockhash(), bob.getbestblockhash())283# now that tx2 has a block conflict, tx1_conflict should be the only tx in bob's mempool284assert tx1_conflict_txid in bob.getrawmempool()285assert_equal(len(bob.getrawmempool()), 1)287# tx3 should now also be block-conflicted by tx2_conflict288assert_equal(bob.gettransaction(tx3_txid)["confirmations"], -11)289# bob has no pending funds, since tx1, tx2, and tx3 are all conflicted290assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)291bob.invalidateblock(blk) # remove tx2_conflict292# bob should still have no pending funds because tx1 and tx3 are still conflicted, and tx2 has not been re-broadcast293assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)294assert_equal(len(bob.getrawmempool()), 1)295# check that tx3 is no longer block-conflicted296assert_equal(bob.gettransaction(tx3_txid)["confirmations"], 0)298bob.sendrawtransaction(raw_tx2)299assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("24.99990000"))301# create a conflict to previous tx (also spends unspents[2]), but don't broadcast, sends funds back to alice302raw_tx = alice.createrawtransaction(inputs=[unspents[2]], outputs=[{alice.getnewaddress() : 24.99}])303tx1_conflict_conflict = alice.signrawtransactionwithwallet(raw_tx)['hex']305bob.sendrawtransaction(tx1_conflict_conflict) # kick tx1_conflict out of the mempool306bob.sendrawtransaction(raw_tx1) #re-broadcast tx1 because it is no longer conflicted308# Now bob has pending funds because tx1 and tx2 are spent by tx3, which hasn't been re-broadcast yet309bob_bal = bob.getbalances()["mine"]310assert_equal(bob_bal["untrusted_pending"], -bob_bal["nonmempool"])312bob.sendrawtransaction(raw_tx3)313assert_equal(len(bob.getrawmempool()), 4) # The mempool contains: tx1, tx2, tx1_conflict_conflict, tx3314assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("49.99900000"))316# Clean up for next test317bob.reconsiderblock(blk)318assert_equal(alice.getbestblockhash(), bob.getbestblockhash())319self.sync_mempools()320self.generate(self.nodes[2], 1)322alice.unloadwallet()324def test_descendants_with_mempool_conflicts(self):325self.nodes[0].createwallet("alice_3")326alice = self.nodes[0].get_wallet_rpc("alice_3")328self.nodes[2].send(outputs=[{alice.getnewaddress() : 25} for _ in range(2)])329self.generate(self.nodes[2], 1)331self.nodes[1].createwallet("bob_1")332bob = self.nodes[1].get_wallet_rpc("bob_1")334self.nodes[2].createwallet("carol")335carol = self.nodes[2].get_wallet_rpc("carol")337self.log.info("Test a scenario where a transaction's parent has a mempool conflict")339unspents = alice.listunspent()340assert_equal(len(unspents), 2)341for tx in unspents:342assert_equal(tx["amount"], 25)344assert_equal(alice.getrawmempool(), [])346# Alice spends first utxo to bob in tx1347raw_tx = alice.createrawtransaction(inputs=[unspents[0]], outputs=[{bob.getnewaddress() : 24.9999}])348tx1 = alice.signrawtransactionwithwallet(raw_tx)['hex']349tx1_txid = alice.sendrawtransaction(tx1)351self.sync_mempools()353assert_equal(alice.getbalance(), 25)354assert_equal(bob.getbalances()["mine"]["untrusted_pending"], Decimal("24.99990000"))356assert_equal(bob.gettransaction(tx1_txid)["mempoolconflicts"], [])358raw_tx = bob.createrawtransaction(inputs=[bob.listunspent(minconf=0)[0]], outputs=[{carol.getnewaddress() : 24.999}])359# Bob creates a child to tx1360tx1_child = bob.signrawtransactionwithwallet(raw_tx)['hex']361tx1_child_txid = bob.sendrawtransaction(tx1_child)363self.sync_mempools()365# Currently neither tx1 nor tx1_child should have any conflicts366assert_equal(bob.gettransaction(tx1_txid)["mempoolconflicts"], [])367assert_equal(bob.gettransaction(tx1_child_txid)["mempoolconflicts"], [])368assert tx1_txid in bob.getrawmempool()369assert tx1_child_txid in bob.getrawmempool()370assert_equal(len(bob.getrawmempool()), 2)372assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)373assert_equal(carol.getbalances()["mine"]["untrusted_pending"], Decimal("24.99900000"))375# Alice spends first unspent again, conflicting with tx1376raw_tx = alice.createrawtransaction(inputs=[unspents[0], unspents[1]], outputs=[{carol.getnewaddress() : 49.99}])377tx1_conflict = alice.signrawtransactionwithwallet(raw_tx)['hex']378tx1_conflict_txid = alice.sendrawtransaction(tx1_conflict)380self.sync_mempools()382assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)383assert_equal(carol.getbalances()["mine"]["untrusted_pending"], Decimal("49.99000000"))385assert tx1_txid not in bob.getrawmempool()386assert tx1_child_txid not in bob.getrawmempool()387assert tx1_conflict_txid in bob.getrawmempool()388assert_equal(len(bob.getrawmempool()), 1)390# Now both tx1 and tx1_child are conflicted by tx1_conflict391assert_equal(bob.gettransaction(tx1_txid)["mempoolconflicts"], [tx1_conflict_txid])392assert_equal(bob.gettransaction(tx1_child_txid)["mempoolconflicts"], [tx1_conflict_txid])394# Now create a conflict to tx1_conflict, so that it gets kicked out of the mempool395raw_tx = alice.createrawtransaction(inputs=[unspents[1]], outputs=[{carol.getnewaddress() : 24.9895}])396tx1_conflict_conflict = alice.signrawtransactionwithwallet(raw_tx)['hex']397tx1_conflict_conflict_txid = alice.sendrawtransaction(tx1_conflict_conflict)399self.sync_mempools()401# Now that tx1_conflict has been removed, both tx1 and tx1_child402assert_equal(bob.gettransaction(tx1_txid)["mempoolconflicts"], [])403assert_equal(bob.gettransaction(tx1_child_txid)["mempoolconflicts"], [])405# Both tx1 and tx1_child are still not in the mempool because they have not be re-broadcasted406assert tx1_txid not in bob.getrawmempool()407assert tx1_child_txid not in bob.getrawmempool()408assert tx1_conflict_txid not in bob.getrawmempool()409assert tx1_conflict_conflict_txid in bob.getrawmempool()410assert_equal(len(bob.getrawmempool()), 1)412assert_equal(alice.getbalance(), 0)413assert_equal(bob.getbalances()["mine"]["untrusted_pending"], 0)414assert_equal(carol.getbalances()["mine"]["untrusted_pending"], Decimal("24.98950000"))416# Both tx1 and tx1_child can now be re-broadcasted417bob.sendrawtransaction(tx1)418bob.sendrawtransaction(tx1_child)419assert_equal(len(bob.getrawmempool()), 3)421alice.unloadwallet()422bob.unloadwallet()423carol.unloadwallet()425if __name__ == '__main__':426TxConflicts(__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.