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.
502assert_equal(decoded_tx["version"], 3)504assert confirmed_v3 in decoded_vin_txids505assert confirmed_v2 in decoded_vin_txids506assert unconfirmed_v3 in decoded_vin_txids507assert unconfirmed_v2 not in decoded_vin_txids509# Test that the only unconfirmed inputs this v2 tx spends are v2510tx_hex = self.alice.sendall([self.bob.getnewaddress()], version=2, add_to_wallet=False, minconf=0)["hex"]512decoded_tx = self.alice.decoderawtransaction(tx_hex)513decoded_vin_txids = [txin["txid"] for txin in decoded_tx["vin"]]515assert_equal(decoded_tx["version"], 2)517assert confirmed_v3 in decoded_vin_txids518assert confirmed_v2 in decoded_vin_txids519assert unconfirmed_v2 in decoded_vin_txids520assert unconfirmed_v3 not in decoded_vin_txids522@cleanup523def walletcreatefundedpsbt_v3(self):524self.log.info("Test setting version to 3 with walletcreatefundedpsbt")526outputs = {self.alice.getnewaddress() : 10}527psbt = self.charlie.walletcreatefundedpsbt(inputs=[], outputs=outputs, version=3)["psbt"]528assert_equal(self.charlie.decodepsbt(psbt)["tx_version"], 3)530@cleanup531def sendall_truc_weight_limit(self):532self.log.info("Test that sendall follows truc tx weight limit")533self.charlie.sendall([self.alice.getnewaddress() for _ in range(300)], add_to_wallet=False, version=2)535# check that error is only raised if version is 3536assert_raises_rpc_error(537-4,538"Transaction too large" ,539self.charlie.sendall,540[self.alice.getnewaddress() for _ in range(300)],541version=3542)544@cleanup545def sendall_truc_child_weight_limit(self):546self.log.info("Test that sendall follows spending unconfirmed truc tx weight limit")547outputs = {self.charlie.getnewaddress() : 2.0}548self.send_tx(self.charlie, [], outputs, 3)550self.charlie.sendall([self.alice.getnewaddress() for _ in range(50)], add_to_wallet=False)552assert_raises_rpc_error(553-4,554"Transaction too large" ,555self.charlie.sendall,556[self.alice.getnewaddress() for _ in range(50)],557version=3558)560@cleanup561def mix_non_truc_versions(self):562self.log.info("Test that we can mix non-truc versions when spending an unconfirmed output")564outputs = {self.bob.getnewaddress() : 2.0}565self.send_tx(self.charlie, [], outputs, 1)567assert_equal(self.bob.getbalances()["mine"]["trusted"], 0)568assert_greater_than(self.bob.getbalances()["mine"]["untrusted_pending"], 0)570outputs = {self.alice.getnewaddress() : 1.0}572raw_tx_v2 = self.bob.createrawtransaction(inputs=[], outputs=outputs, version=2)574# does not throw an error575self.bob.fundrawtransaction(raw_tx_v2, {'include_unsafe': True})["hex"]577@cleanup578def cant_spend_multiple_unconfirmed_truc_outputs(self):579self.log.info("Test that we can't spend multiple unconfirmed truc outputs")581outputs = {self.alice.getnewaddress(): 2.00001}582self.send_tx(self.charlie, [], outputs, 3)583self.send_tx(self.charlie, [], outputs, 3)585assert_equal(len(self.alice.listunspent(minconf=0)), 2)587outputs = {self.bob.getnewaddress() : 3.0}589raw_tx = self.alice.createrawtransaction(inputs=[], outputs=outputs, version=3)591assert_raises_rpc_error(592-4,593"Insufficient funds",594self.alice.fundrawtransaction,595raw_tx,596{'include_unsafe' : True}597)599@cleanup600def test_spend_third_generation(self):601self.log.info("Test that we can't spend an unconfirmed TRUC output that already has an unconfirmed parent")603# Generation 1: Consolidate all UTXOs into one output using sendall604self.charlie.sendall([self.charlie.getnewaddress()], version=3)605outputs1 = self.charlie.listunspent(minconf=0)606assert_equal(len(outputs1), 1)608# Generation 2: to ensure no change address is created, do another sendall609self.charlie.sendall([self.charlie.getnewaddress()], version=3)610outputs2 = self.charlie.listunspent(minconf=0)611assert_equal(len(outputs2), 1)612total_amount = sum([utxo['amount'] for utxo in outputs2])614# Generation 3: try to send half of total amount to Alice615outputs = {self.alice.getnewaddress(): total_amount / 2}616assert_raises_rpc_error(617-4,618"Insufficient funds",619self.charlie.send,620outputs,621version=3622)624# Also doesn't work with fundrawtransaction625raw_tx = self.charlie.createrawtransaction(inputs=[], outputs=outputs, version=3)626assert_raises_rpc_error(627-4,628"Insufficient funds",629self.charlie.fundrawtransaction,630raw_tx,631{'include_unsafe' : True}632)634# Also doesn't work with sendall635assert_raises_rpc_error(636-6,637"Total value of UTXO pool too low to pay for transaction",638self.charlie.sendall,639[self.alice.getnewaddress()],640version=3641)643@cleanup644def test_coins_availability_reorg(self):645self.log.info("Test coin availability after reorg with v2 parent and truc child")647# Prep fork blocks648fork_blocks = create_empty_fork(self.nodes[0])650# Send funds to alice so she can create transactions651outputs = {self.alice.getnewaddress(): 5.0}652self.send_tx(self.charlie, [], outputs, 2)653self.generate(self.nodes[0], 1)655# Alice creates a v2 transaction with 2 outputs656alice_unspent = self.alice.listunspent()[0]657v2_outputs = [658{self.alice.getnewaddress(): 2.5},659{self.alice.getnewaddress(): 2.4999},660]661v2_txid = self.send_tx(self.alice, [alice_unspent], v2_outputs, 2)663# Mine the v2 transaction in one block664self.generate(self.nodes[0], 1)666# Get the output from the v2 transaction for chaining667v2_utxo = self.alice.listunspent(minconf=1)[0]668assert_equal(v2_utxo["txid"], v2_txid)670# Alice creates a truc child chaining from the v2 utxo671truc_outputs = {self.alice.getnewaddress(): v2_utxo["amount"] - Decimal("0.0001")}672truc_txid = self.send_tx(self.alice, [v2_utxo], truc_outputs, 3)674# Mine the truc transaction in a second block675self.generate(self.nodes[0], 1)677# Verify both transactions are confirmed678wallet_tx_v2 = self.alice.gettransaction(v2_txid)679wallet_tx_truc = self.alice.gettransaction(truc_txid)681assert_equal(wallet_tx_v2["confirmations"], 2)682assert_equal(wallet_tx_truc["confirmations"], 1)684# Check that their versions are correct685assert_equal(self.alice.decoderawtransaction(wallet_tx_v2["hex"])["version"], 2)686assert_equal(self.alice.decoderawtransaction(wallet_tx_truc["hex"])["version"], 3)688# Check listunspent before reorg - should have the truc output689unspent_before = self.alice.listunspent()690truc_output_txids = [u["txid"] for u in unspent_before]691assert truc_txid in truc_output_txids693# Trigger the reorg694self.trigger_reorg(fork_blocks)695# The TRUC transaction is now in a cluster of size 3, which is only permitted in a reorg.696assert_equal(self.nodes[0].getmempoolcluster(truc_txid)["txcount"], 3)698# After reorg, both transactions should be back in mempool699mempool = self.nodes[0].getrawmempool()700assert v2_txid in mempool701assert truc_txid in mempool703# Check listunspent after reorg - the truc output should still appear704# as unconfirmed since the transaction is in the mempool705unspent_after = self.alice.listunspent(minconf=0)706unspent_txids_after = [u["txid"] for u in unspent_after]707assert truc_txid in unspent_txids_after709total_unconfirmed_amount = sum([u["amount"] for u in self.alice.listunspent(minconf=0)])710# We cannot create a transaction spending both outputs, regardless of version.711output_too_high = {self.bob.getnewaddress(): total_unconfirmed_amount - Decimal("1")}712for version in [2, 3]:713raw_output_too_high = self.alice.createrawtransaction(inputs=[], outputs=output_too_high, version=version)714assert_raises_rpc_error(715-4,716"Insufficient funds",717self.alice.fundrawtransaction,718raw_output_too_high,719{'include_unsafe' : True}720)722# Now try to create a v2 transaction - this triggers AvailableCoins with723# check_version_trucness=true. The v2 parent has truc_child_in_mempool set724# because the truc child is in mempool.725new_v2_outputs = {self.bob.getnewaddress(): 0.1}726raw_v2_child = self.alice.createrawtransaction(inputs=[], outputs=new_v2_outputs, version=2)727raw_v2_with_v3_sibling = self.alice.fundrawtransaction(raw_v2_child, {'include_unsafe': True})729# See that this transaction can be added to mempool730signed_raw_v2_with_v3_sibling = self.alice.signrawtransactionwithwallet(raw_v2_with_v3_sibling["hex"])731self.alice.sendrawtransaction(signed_raw_v2_with_v3_sibling["hex"])733# This TRUC transaction is in a cluster of size 4734assert_equal(self.nodes[0].getmempoolcluster(truc_txid)["txcount"], 4)738if __name__ == '__main__':739WalletV3Test(__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.