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.
251inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]252outputs = { self.nodes[0].getnewaddress() : 1.0 }253rawtx = self.nodes[2].createrawtransaction(inputs, outputs)254dec_tx = self.nodes[2].decoderawtransaction(rawtx)255assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])257rawtxfund = self.nodes[2].fundrawtransaction(rawtx, fee_rate=self.fee_rate_sats_per_vb)258fee = rawtxfund['fee']259self.test_no_change_fee = fee # Use the same fee for the next tx260dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])261totalOut = 0262for out in dec_tx['vout']:263totalOut += out['value']265assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee267def test_no_change(self):268self.log.info("Test fundrawtxn not having a change output")269utx = get_unspent(self.nodes[2].listunspent(), 5)271inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]272outputs = {self.nodes[0].getnewaddress(): Decimal(5.0) - self.test_no_change_fee - self.fee_tolerance}273rawtx = self.nodes[2].createrawtransaction(inputs, outputs)274dec_tx = self.nodes[2].decoderawtransaction(rawtx)275assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])277rawtxfund = self.nodes[2].fundrawtransaction(rawtx, fee_rate=self.fee_rate_sats_per_vb)278fee = rawtxfund['fee']279dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])280totalOut = 0281for out in dec_tx['vout']:282totalOut += out['value']284assert_equal(rawtxfund['changepos'], -1)285assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee287def test_invalid_option(self):288self.log.info("Test fundrawtxn with an invalid option")289utx = get_unspent(self.nodes[2].listunspent(), 5)291inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ]292outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) }293rawtx = self.nodes[2].createrawtransaction(inputs, outputs)294dec_tx = self.nodes[2].decoderawtransaction(rawtx)295assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])297assert_raises_rpc_error(-8, "Unknown named parameter foo", self.nodes[2].fundrawtransaction, rawtx, foo='bar')298assert_raises_rpc_error(-3, "JSON value of type bool is not of expected type object", self.nodes[2].fundrawtransaction, rawtx, True)300# reserveChangeKey was deprecated and is now removed301assert_raises_rpc_error(-8, "Unknown named parameter reserveChangeKey", lambda: self.nodes[2].fundrawtransaction(hexstring=rawtx, reserveChangeKey=True))303def test_invalid_change_address(self):304self.log.info("Test fundrawtxn with an invalid change address")305utx = get_unspent(self.nodes[2].listunspent(), 5)307inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ]308outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) }309rawtx = self.nodes[2].createrawtransaction(inputs, outputs)310dec_tx = self.nodes[2].decoderawtransaction(rawtx)311assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])313assert_raises_rpc_error(-5, "Change address must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, changeAddress='foobar')315def test_valid_change_address(self):316self.log.info("Test fundrawtxn with a provided change address")317utx = get_unspent(self.nodes[2].listunspent(), 5)319inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ]320outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) }321rawtx = self.nodes[2].createrawtransaction(inputs, outputs)322dec_tx = self.nodes[2].decoderawtransaction(rawtx)323assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])325change = self.nodes[2].getnewaddress()326assert_raises_rpc_error(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, changeAddress=change, changePosition=2)327rawtxfund = self.nodes[2].fundrawtransaction(rawtx, changeAddress=change, changePosition=0, fee_rate=self.fee_rate_sats_per_vb)328dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])329out = dec_tx['vout'][0]330assert_equal(change, out['scriptPubKey']['address'])332def test_change_type(self):333self.log.info("Test fundrawtxn with a provided change type")334utx = get_unspent(self.nodes[2].listunspent(), 5)336inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ]337outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) }338rawtx = self.nodes[2].createrawtransaction(inputs, outputs)339assert_raises_rpc_error(-3, "JSON value of type null is not of expected type string", self.nodes[2].fundrawtransaction, rawtx, change_type=None)340assert_raises_rpc_error(-5, "Unknown change type ''", self.nodes[2].fundrawtransaction, rawtx, change_type='')341rawtx = self.nodes[2].fundrawtransaction(rawtx, change_type='bech32', fee_rate=self.fee_rate_sats_per_vb)342dec_tx = self.nodes[2].decoderawtransaction(rawtx['hex'])343assert_equal('witness_v0_keyhash', dec_tx['vout'][rawtx['changepos']]['scriptPubKey']['type'])345def test_coin_selection(self):346self.log.info("Test fundrawtxn with a vin < required amount")347utx = get_unspent(self.nodes[2].listunspent(), 1)349inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]350outputs = { self.nodes[0].getnewaddress() : 1.0 }351rawtx = self.nodes[2].createrawtransaction(inputs, outputs)353# 4-byte version + 1-byte vin count + 36-byte prevout then script_len354rawtx = rawtx[:82] + "0100" + rawtx[84:]356dec_tx = self.nodes[2].decoderawtransaction(rawtx)357assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])358assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])360# Should fail without add_inputs:361assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, add_inputs=False)362# add_inputs is enabled by default363rawtxfund = self.nodes[2].fundrawtransaction(rawtx, fee_rate=self.fee_rate_sats_per_vb)365dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])366matchingOuts = 0367for i, out in enumerate(dec_tx['vout']):368if out['scriptPubKey']['address'] in outputs:369matchingOuts+=1370else:371assert_equal(i, rawtxfund['changepos'])373assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])374assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])376assert_equal(matchingOuts, 1)377assert_equal(len(dec_tx['vout']), 2)379def test_two_vin(self):380self.log.info("Test fundrawtxn with 2 vins")381utx = get_unspent(self.nodes[2].listunspent(), 1)382utx2 = get_unspent(self.nodes[2].listunspent(), 5)384inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ]385outputs = { self.nodes[0].getnewaddress() : 6.0 }386rawtx = self.nodes[2].createrawtransaction(inputs, outputs)387dec_tx = self.nodes[2].decoderawtransaction(rawtx)388assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])390# Should fail without add_inputs:391assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, add_inputs=False)392rawtxfund = self.nodes[2].fundrawtransaction(rawtx, add_inputs=True, fee_rate=self.fee_rate_sats_per_vb)393dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])394matchingOuts = 0395for out in dec_tx['vout']:396if out['scriptPubKey']['address'] in outputs:397matchingOuts+=1399assert_equal(matchingOuts, 1)400assert_equal(len(dec_tx['vout']), 2)402matchingIns = 0403for vinOut in dec_tx['vin']:404for vinIn in inputs:405if vinIn['txid'] == vinOut['txid']:406matchingIns+=1408assert_equal(matchingIns, 2) #we now must see two vins identical to vins given as params410def test_two_vin_two_vout(self):411self.log.info("Test fundrawtxn with 2 vins and 2 vouts")412utx = get_unspent(self.nodes[2].listunspent(), 1)413utx2 = get_unspent(self.nodes[2].listunspent(), 5)415inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ]416outputs = { self.nodes[0].getnewaddress() : 6.0, self.nodes[0].getnewaddress() : 1.0 }417rawtx = self.nodes[2].createrawtransaction(inputs, outputs)418dec_tx = self.nodes[2].decoderawtransaction(rawtx)419assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])421# Should fail without add_inputs:422assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, add_inputs=False)423rawtxfund = self.nodes[2].fundrawtransaction(rawtx, add_inputs=True, fee_rate=self.fee_rate_sats_per_vb)425dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])426matchingOuts = 0427for out in dec_tx['vout']:428if out['scriptPubKey']['address'] in outputs:429matchingOuts+=1431assert_equal(matchingOuts, 2)432assert_equal(len(dec_tx['vout']), 3)434def test_invalid_input(self):435self.log.info("Test fundrawtxn with an invalid vin")436txid = "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1"437vout = 0438inputs = [ {'txid' : txid, 'vout' : vout} ] #invalid vin!439outputs = { self.nodes[0].getnewaddress() : 1.0}440rawtx = self.nodes[2].createrawtransaction(inputs, outputs)441assert_raises_rpc_error(-4, "Unable to find UTXO for external input", self.nodes[2].fundrawtransaction, rawtx)443def test_fee_p2pkh(self):444"""Compare fee of a standard pubkeyhash transaction."""445self.log.info("Test fundrawtxn p2pkh fee")446self.lock_outputs_type(self.nodes[0], "p2pkh")447inputs = []448outputs = {self.nodes[1].getnewaddress():1.1}449rawtx = self.nodes[0].createrawtransaction(inputs, outputs)450fundedTx = self.nodes[0].fundrawtransaction(rawtx, fee_rate=self.fee_rate_sats_per_vb)452# Create same transaction over sendtoaddress.453txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1, fee_rate=self.fee_rate_sats_per_vb)454signedFee = self.nodes[0].getmempoolentry(txId)['fees']['base']456# Compare fee.457feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)458assert feeDelta >= 0 and feeDelta <= self.fee_tolerance460self.unlock_utxos(self.nodes[0])462def test_fee_p2pkh_multi_out(self):463"""Compare fee of a standard pubkeyhash transaction with multiple outputs."""464self.log.info("Test fundrawtxn p2pkh fee with multiple outputs")465self.lock_outputs_type(self.nodes[0], "p2pkh")466inputs = []467outputs = {468self.nodes[1].getnewaddress():1.1,469self.nodes[1].getnewaddress():1.2,470self.nodes[1].getnewaddress():0.1,471self.nodes[1].getnewaddress():1.3,472self.nodes[1].getnewaddress():0.2,473self.nodes[1].getnewaddress():0.3,474}475rawtx = self.nodes[0].createrawtransaction(inputs, outputs)476fundedTx = self.nodes[0].fundrawtransaction(rawtx, fee_rate=self.fee_rate_sats_per_vb)478# Create same transaction over sendtoaddress.479txId = self.nodes[0].sendmany("", outputs, fee_rate=self.fee_rate_sats_per_vb)480signedFee = self.nodes[0].getmempoolentry(txId)['fees']['base']482# Compare fee.483feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)484assert feeDelta >= 0 and feeDelta <= self.fee_tolerance486self.unlock_utxos(self.nodes[0])488def test_fee_p2sh(self):489"""Compare fee of a 2-of-2 multisig p2sh transaction."""490self.lock_outputs_type(self.nodes[0], "p2pkh")491# Create 2-of-2 addr.492addr1 = self.nodes[1].getnewaddress()493addr2 = self.nodes[1].getnewaddress()495addr1Obj = self.nodes[1].getaddressinfo(addr1)496addr2Obj = self.nodes[1].getaddressinfo(addr2)498mSigObj = self.nodes[3].createmultisig(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address']500inputs = []
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.