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 simulaterawtransaction.6"""8from decimal import Decimal9from test_framework.blocktools import COINBASE_MATURITY10from test_framework.test_framework import BitcoinTestFramework11from test_framework.util import (12assert_approx,13assert_equal,14assert_raises_rpc_error,15)17class SimulateTxTest(BitcoinTestFramework):18def set_test_params(self):19self.setup_clean_chain = True20self.num_nodes = 122def skip_test_if_missing_module(self):23self.skip_if_no_wallet()25def setup_network(self, split=False):26self.setup_nodes()28def run_test(self):29node = self.nodes[0]31self.generate(node, 1, sync_fun=self.no_op) # Leave IBD33node.createwallet(wallet_name='w0')34node.createwallet(wallet_name='w1')35node.createwallet(wallet_name='w2', disable_private_keys=True)36w0 = node.get_wallet_rpc('w0')37w1 = node.get_wallet_rpc('w1')38w2 = node.get_wallet_rpc('w2')40self.generatetoaddress(node, COINBASE_MATURITY + 1, w0.getnewaddress())41assert_equal(w0.getbalance(), 50.0)42assert_equal(w1.getbalance(), 0.0)44address1 = w1.getnewaddress()45address2 = w1.getnewaddress()47# Add address1 as watch-only to w248import_res = w2.importdescriptors([{"desc": w1.getaddressinfo(address1)["desc"], "timestamp": "now"}])49assert_equal(import_res[0]["success"], True)51tx1 = node.createrawtransaction([], [{address1: 5.0}])52tx2 = node.createrawtransaction([], [{address2: 10.0}])54# w0 should be unaffected, w2 should see +5 for tx155assert_equal(w0.simulaterawtransaction([tx1])["balance_change"], 0.0)56assert_equal(w2.simulaterawtransaction([tx1])["balance_change"], 5.0)58# w1 should see +5 balance for tx159assert_equal(w1.simulaterawtransaction([tx1])["balance_change"], 5.0)61# w0 should be unaffected, w2 should see +5 for both transactions62assert_equal(w0.simulaterawtransaction([tx1, tx2])["balance_change"], 0.0)63assert_equal(w2.simulaterawtransaction([tx1, tx2])["balance_change"], 5.0)65# w1 should see +15 balance for both transactions66assert_equal(w1.simulaterawtransaction([tx1, tx2])["balance_change"], 15.0)68# w0 funds transaction; it should now see a decrease in (tx fee and payment), and w1 should see the same as above69funding = w0.fundrawtransaction(tx1)70tx1 = funding["hex"]71tx1changepos = funding["changepos"]72bitcoin_fee = Decimal(funding["fee"])74# w0 sees fee + 5 btc decrease, w2 sees + 5 btc75assert_approx(w0.simulaterawtransaction([tx1])["balance_change"], -(Decimal("5") + bitcoin_fee))76assert_approx(w2.simulaterawtransaction([tx1])["balance_change"], Decimal("5"))78# w1 sees same as before79assert_equal(w1.simulaterawtransaction([tx1])["balance_change"], 5.0)81# same inputs (tx) more than once should error82assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w0.simulaterawtransaction, [tx1,tx1])84tx1ob = node.decoderawtransaction(tx1)85tx1hex = tx1ob["txid"]86tx1vout = 1 - tx1changepos87# tx3 spends new w1 UTXO paying to w088tx3 = node.createrawtransaction([{"txid": tx1hex, "vout": tx1vout}], {w0.getnewaddress(): 4.9999})89# tx4 spends new w1 UTXO paying to w190tx4 = node.createrawtransaction([{"txid": tx1hex, "vout": tx1vout}], {w1.getnewaddress(): 4.9999})92# on their own, both should fail due to missing input(s)93assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w0.simulaterawtransaction, [tx3])94assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w1.simulaterawtransaction, [tx3])95assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w0.simulaterawtransaction, [tx4])96assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w1.simulaterawtransaction, [tx4])98# they should succeed when including tx1:99# wallet tx3 tx4100# w0 -5 - bitcoin_fee + 4.9999 -5 - bitcoin_fee101# w1 0 +4.9999102assert_approx(w0.simulaterawtransaction([tx1, tx3])["balance_change"], -Decimal("5") - bitcoin_fee + Decimal("4.9999"))103assert_approx(w1.simulaterawtransaction([tx1, tx3])["balance_change"], 0)104assert_approx(w0.simulaterawtransaction([tx1, tx4])["balance_change"], -Decimal("5") - bitcoin_fee)105assert_approx(w1.simulaterawtransaction([tx1, tx4])["balance_change"], Decimal("4.9999"))107# they should fail if attempting to include both tx3 and tx4108assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w0.simulaterawtransaction, [tx1, tx3, tx4])109assert_raises_rpc_error(-8, "Transaction(s) are spending the same output more than once", w1.simulaterawtransaction, [tx1, tx3, tx4])111# send tx1 to avoid reusing same UTXO below112node.sendrawtransaction(w0.signrawtransactionwithwallet(tx1)["hex"])113self.generate(node, 1, sync_fun=self.no_op) # Confirm tx to trigger error below114self.sync_all()116# w0 funds transaction 2; it should now see a decrease in (tx fee and payment), and w1 should see the same as above117funding = w0.fundrawtransaction(tx2)118tx2 = funding["hex"]119bitcoin_fee2 = Decimal(funding["fee"])120assert_approx(w0.simulaterawtransaction([tx2])["balance_change"], -(Decimal("10") + bitcoin_fee2))121assert_approx(w1.simulaterawtransaction([tx2])["balance_change"], +(Decimal("10")))122assert_approx(w2.simulaterawtransaction([tx2])["balance_change"], 0)124# w0-w2 error due to tx1 already being mined125assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w0.simulaterawtransaction, [tx1, tx2])126assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w1.simulaterawtransaction, [tx1, tx2])127assert_raises_rpc_error(-8, "One or more transaction inputs are missing or have been spent already", w2.simulaterawtransaction, [tx1, tx2])129if __name__ == '__main__':130SimulateTxTest(__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.