psbt: Add sighash types to PSBT when not DEFAULT or ALL

When an atypical sighash type is specified by the user, add it to the
PSBT so that further signing can enforce sighash type matching.
This commit is contained in:
Ava Chow
2025-01-08 19:58:08 -05:00
parent 15ce1bd73f
commit 28781b5f06
2 changed files with 57 additions and 1 deletions

View File

@@ -301,6 +301,53 @@ class PSBTTest(BitcoinTestFramework):
wallet.unloadwallet()
def test_sighash_adding(self):
self.log.info("Test adding of sighash type field")
self.nodes[0].createwallet("sighash_adding")
wallet = self.nodes[0].get_wallet_rpc("sighash_adding")
def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
outputs = [{wallet.getnewaddress(address_type="bech32"): 1}]
outputs.append({wallet.getnewaddress(address_type="bech32m"): 1})
descs = wallet.listdescriptors(True)["descriptors"]
def_wallet.send(outputs)
self.generate(self.nodes[0], 6)
utxos = wallet.listunspent()
# Make a PSBT
psbt = wallet.walletcreatefundedpsbt(utxos, [{def_wallet.getnewaddress(): 0.5}])["psbt"]
# Process the PSBT with the wallet
wallet_psbt = wallet.walletprocesspsbt(psbt=psbt, sighashtype="ALL|ANYONECANPAY", finalize=False)["psbt"]
# Separately process the PSBT with descriptors
desc_psbt = self.nodes[0].descriptorprocesspsbt(psbt=psbt, descriptors=descs, sighashtype="ALL|ANYONECANPAY", finalize=False)["psbt"]
for psbt in [wallet_psbt, desc_psbt]:
# Check that the PSBT has a sighash field on all inputs
dec_psbt = self.nodes[0].decodepsbt(psbt)
for input in dec_psbt["inputs"]:
assert_equal(input["sighash"], "ALL|ANYONECANPAY")
# Make sure we can still finalize the transaction
fin_res = self.nodes[0].finalizepsbt(psbt)
assert_equal(fin_res["complete"], True)
fin_hex = fin_res["hex"]
assert_equal(self.nodes[0].testmempoolaccept([fin_hex])[0]["allowed"], True)
# Change the sighash field to a different value and make sure we can no longer finalize
mod_psbt = PSBT.from_base64(psbt)
mod_psbt.i[0].map[PSBT_IN_SIGHASH_TYPE] = (SIGHASH_ALL).to_bytes(4, byteorder="little")
mod_psbt.i[1].map[PSBT_IN_SIGHASH_TYPE] = (SIGHASH_ALL).to_bytes(4, byteorder="little")
psbt = mod_psbt.to_base64()
fin_res = self.nodes[0].finalizepsbt(psbt)
assert_equal(fin_res["complete"], False)
self.nodes[0].sendrawtransaction(fin_hex)
self.generate(self.nodes[0], 1)
wallet.unloadwallet()
def assert_change_type(self, psbtx, expected_type):
"""Assert that the given PSBT has a change output with the given type."""
@@ -1139,6 +1186,7 @@ class PSBTTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "'all' is not a valid sighash parameter.", self.nodes[2].descriptorprocesspsbt, psbt, [descriptor], sighashtype="all")
self.test_sighash_mismatch()
self.test_sighash_adding()
if __name__ == '__main__':
PSBTTest(__file__).main()