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.
1502psbt = watchonly.sendall([wallet.getnewaddress(), addr])["psbt"]1503processed_psbt = self.nodes[0].walletprocesspsbt(psbt)1504txid = self.nodes[0].sendrawtransaction(processed_psbt["hex"])1505vout = find_vout_for_address(self.nodes[0], txid, addr)1507# Make sure tap tree is in psbt1508parsed_psbt = PSBT.from_base64(psbt)1509assert_greater_than(len(parsed_psbt.o[vout].map[PSBT_OUT_TAP_TREE]), 0)1510assert "taproot_tree" in self.nodes[0].decodepsbt(psbt)["outputs"][vout]1511parsed_psbt.make_blank()1512comb_psbt = self.nodes[0].combinepsbt([psbt, parsed_psbt.to_base64()])1513assert_equal(comb_psbt, psbt)1515self.log.info("Test that walletprocesspsbt both updates and signs a non-updated psbt containing Taproot inputs")1516addr = self.nodes[0].getnewaddress("", "bech32m")1517utxo = self.create_outpoints(self.nodes[0], outputs=[{addr: 1}])[0]1518psbt = self.nodes[0].createpsbt([utxo], [{self.nodes[0].getnewaddress(): 0.9999}])1519signed = self.nodes[0].walletprocesspsbt(psbt)1520rawtx = signed["hex"]1521self.nodes[0].sendrawtransaction(rawtx)1522self.generate(self.nodes[0], 1)1524# Make sure tap tree is not in psbt1525parsed_psbt = PSBT.from_base64(psbt)1526assert PSBT_OUT_TAP_TREE not in parsed_psbt.o[0].map1527assert "taproot_tree" not in self.nodes[0].decodepsbt(psbt)["outputs"][0]1528parsed_psbt.make_blank()1529comb_psbt = self.nodes[0].combinepsbt([psbt, parsed_psbt.to_base64()])1530assert_equal(comb_psbt, psbt)1532self.log.info("Test walletprocesspsbt raises if an invalid sighashtype is passed")1533assert_raises_rpc_error(-8, "'all' is not a valid sighash parameter.", self.nodes[0].walletprocesspsbt, psbt=psbt, sighashtype="all")1535self.log.info("Test decoding PSBT with per-input preimage types")1536# note that the decodepsbt RPC doesn't check whether preimages and hashes match1537hash_ripemd160, preimage_ripemd160 = randbytes(20), randbytes(50)1538hash_sha256, preimage_sha256 = randbytes(32), randbytes(50)1539hash_hash160, preimage_hash160 = randbytes(20), randbytes(50)1540hash_hash256, preimage_hash256 = randbytes(32), randbytes(50)1542tx = CTransaction()1543tx.vin = [CTxIn(outpoint=COutPoint(hash=int('aa' * 32, 16), n=0), scriptSig=b""),1544CTxIn(outpoint=COutPoint(hash=int('bb' * 32, 16), n=0), scriptSig=b""),1545CTxIn(outpoint=COutPoint(hash=int('cc' * 32, 16), n=0), scriptSig=b""),1546CTxIn(outpoint=COutPoint(hash=int('dd' * 32, 16), n=0), scriptSig=b"")]1547tx.vout = [CTxOut(nValue=0, scriptPubKey=b"")]1548psbt = PSBT()1549psbt.g = PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()})1550psbt.i = [PSBTMap({bytes([PSBT_IN_RIPEMD160]) + hash_ripemd160: preimage_ripemd160}),1551PSBTMap({bytes([PSBT_IN_SHA256]) + hash_sha256: preimage_sha256}),1552PSBTMap({bytes([PSBT_IN_HASH160]) + hash_hash160: preimage_hash160}),1553PSBTMap({bytes([PSBT_IN_HASH256]) + hash_hash256: preimage_hash256})]1554psbt.o = [PSBTMap()]1555res_inputs = self.nodes[0].decodepsbt(psbt.to_base64())["inputs"]1556assert_equal(len(res_inputs), 4)1557preimage_keys = ["ripemd160_preimages", "sha256_preimages", "hash160_preimages", "hash256_preimages"]1558expected_hashes = [hash_ripemd160, hash_sha256, hash_hash160, hash_hash256]1559expected_preimages = [preimage_ripemd160, preimage_sha256, preimage_hash160, preimage_hash256]1560for res_input, preimage_key, hash, preimage in zip(res_inputs, preimage_keys, expected_hashes, expected_preimages):1561assert preimage_key in res_input1562assert_equal(len(res_input[preimage_key]), 1)1563assert hash.hex() in res_input[preimage_key]1564assert_equal(res_input[preimage_key][hash.hex()], preimage.hex())1566self.test_decodepsbt_musig2_input_output_types()1568self.test_combinepsbt_preserves_proprietary_fields()1569self.test_combinepsbt_global_xpub_origin_conflict()1570self.test_combinepsbt_tap_leaf_script_conflict()1572self.log.info("Test that combining PSBTs with different transactions fails")1573tx = CTransaction()1574tx.vin = [CTxIn(outpoint=COutPoint(hash=int('aa' * 32, 16), n=0), scriptSig=b"")]1575tx.vout = [CTxOut(nValue=0, scriptPubKey=b"")]1576psbt1 = PSBT(g=PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()}), i=[PSBTMap()], o=[PSBTMap()]).to_base64()1577tx.vout[0].nValue += 1 # slightly modify tx1578psbt2 = PSBT(g=PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()}), i=[PSBTMap()], o=[PSBTMap()]).to_base64()1579assert_raises_rpc_error(-8, "PSBTs not compatible (different transactions)", self.nodes[0].combinepsbt, [psbt1, psbt2])1580assert_equal(self.nodes[0].combinepsbt([psbt1, psbt1]), psbt1)1582self.log.info("Test that PSBT inputs are being checked via script execution")1583acs_prevout = CTxOut(nValue=0, scriptPubKey=CScript([OP_TRUE]))1584tx = CTransaction()1585tx.vin = [CTxIn(outpoint=COutPoint(hash=int('dd' * 32, 16), n=0), scriptSig=b"")]1586tx.vout = [CTxOut(nValue=0, scriptPubKey=b"")]1587psbt = PSBT()1588psbt.g = PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()})1589psbt.i = [PSBTMap({bytes([PSBT_IN_WITNESS_UTXO]) : acs_prevout.serialize()})]1590psbt.o = [PSBTMap()]1591assert_equal(self.nodes[0].finalizepsbt(psbt.to_base64()),1592{'hex': '0200000001dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd0000000000000000000100000000000000000000000000', 'complete': True})1594self.log.info("Test we don't crash when making a 0-value funded transaction at 0 fee without forcing an input selection")1595assert_raises_rpc_error(-4, "Transaction requires one destination of non-zero value, a non-zero feerate, or a pre-selected input", self.nodes[0].walletcreatefundedpsbt, [], [{"data": "deadbeef"}], 0, {"fee_rate": "0"})1597self.log.info("Test descriptorprocesspsbt updates and signs a psbt with descriptors")1599self.generate(self.nodes[2], 1)1601# Disable the wallet for node 2 since `descriptorprocesspsbt` does not use the wallet1602self.restart_node(2, extra_args=["-disablewallet"])1603self.connect_nodes(0, 2)1604self.connect_nodes(1, 2)1606key_info = get_generate_key()1607key = key_info.privkey1608address = key_info.p2wpkh_addr1610descriptor = descsum_create(f"wpkh({key})")1612utxo = self.create_outpoints(self.nodes[0], outputs=[{address: 1}])[0]1613self.sync_all()1615self.log.info("Test descriptorprocesspsbt updates PSBT outputs")1616for has_input in [False, True]:1617output_psbt = self.nodes[2].createpsbt([utxo] if has_input else [], {address: 1})1618processed = self.nodes[2].descriptorprocesspsbt(psbt=output_psbt, descriptors=[descriptor], finalize=False)1619decoded = self.nodes[2].decodepsbt(processed["psbt"])1620assert_equal(len(decoded["inputs"]), int(has_input))1621assert_equal(len(decoded["outputs"][0]["bip32_derivs"]), 1)1623psbt = self.nodes[2].createpsbt([utxo], {self.nodes[0].getnewaddress(): 0.99999})1624decoded = self.nodes[2].decodepsbt(psbt)1625test_psbt_input_keys(decoded['inputs'][0], [])1627# Test that even if the wrong descriptor is given, `witness_utxo` and `non_witness_utxo`1628# are still added to the psbt1629alt_descriptor = descsum_create(f"wpkh({get_generate_key().privkey})")1630alt_psbt = self.nodes[2].descriptorprocesspsbt(psbt=psbt, descriptors=[alt_descriptor], sighashtype="ALL")["psbt"]1631decoded = self.nodes[2].decodepsbt(alt_psbt)1632test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo', 'non_witness_utxo'])1634# Test that the psbt is not finalized and does not have bip32_derivs unless specified1635processed_psbt = self.nodes[2].descriptorprocesspsbt(psbt=psbt, descriptors=[descriptor], sighashtype="ALL", bip32derivs=True, finalize=False)1636decoded = self.nodes[2].decodepsbt(processed_psbt['psbt'])1637test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo', 'non_witness_utxo', 'partial_signatures', 'bip32_derivs'])1639# If psbt not finalized, test that result does not have hex1640assert "hex" not in processed_psbt1642processed_psbt = self.nodes[2].descriptorprocesspsbt(psbt=psbt, descriptors=[descriptor], sighashtype="ALL", bip32derivs=False, finalize=True)1643decoded = self.nodes[2].decodepsbt(processed_psbt['psbt'])1644test_psbt_input_keys(decoded['inputs'][0], ['witness_utxo', 'non_witness_utxo', 'final_scriptwitness'])1646# Test psbt is complete1647assert_equal(processed_psbt['complete'], True)1649# Broadcast transaction1650self.nodes[2].sendrawtransaction(processed_psbt['hex'])1652self.log.info("Test descriptorprocesspsbt raises if an invalid sighashtype is passed")1653assert_raises_rpc_error(-8, "'all' is not a valid sighash parameter.", self.nodes[2].descriptorprocesspsbt, psbt=psbt, descriptors=[descriptor], sighashtype="all")1655if not self.options.usecli:1656self.test_sighash_mismatch()1657self.test_sighash_adding()1658self.test_decodepsbt_long_sighash_type()1659self.test_combinepsbt_sighash_type()1660self.test_psbt_named_parameter_handling()1661self.test_psbt_roundtrip()1662self.test_psbt_version()1663self.test_psbt_with_invalid_signature()1664self.test_musig2_untrusted_derivation()1666if __name__ == '__main__':1667PSBTTest(__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.