From b70e83da4210e8098cbf3fc3b2289fc710828455 Mon Sep 17 00:00:00 2001 From: Ava Chow Date: Wed, 8 Jan 2025 16:47:55 -0500 Subject: [PATCH] rpc, psbt: Require sighashes match for descriptorprocesspsbt --- src/rpc/rawtransaction.cpp | 6 ++++-- test/functional/rpc_psbt.py | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 63b0ecd1e2b2e..9f349196a4412 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -235,8 +235,10 @@ PartiallySignedTransaction ProcessPSBT(const std::string& psbt_string, const std // Note that SignPSBTInput does a lot more than just constructing ECDSA signatures. // We only actually care about those if our signing provider doesn't hide private // information, as is the case with `descriptorprocesspsbt` - // As such, we ignore the return value as any errors just mean that we do not have enough information. - SignPSBTInput(provider, psbtx, /*index=*/i, &txdata, sighash_type, /*out_sigdata=*/nullptr, finalize); + // Only error for mismatching sighash types as it is critical that the sighash to sign with matches the PSBT's + if (SignPSBTInput(provider, psbtx, /*index=*/i, &txdata, sighash_type, /*out_sigdata=*/nullptr, finalize) == common::PSBTError::SIGHASH_MISMATCH) { + throw JSONRPCPSBTError(common::PSBTError::SIGHASH_MISMATCH); + } } // Update script/keypath information using descriptor data. diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 4ac1d5bdeb93f..4df9b785aec10 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -212,6 +212,12 @@ def test_sighash_mismatch(self): def_wallet.sendtoaddress(addr, 5) self.generate(self.nodes[0], 6) + # Retrieve the descriptors so we can do all of the tests with descriptorprocesspsbt as well + if self.options.descriptors: + descs = wallet.listdescriptors(True)["descriptors"] + else: + descs = [descsum_create(f"wpkh({wallet.dumpprivkey(addr)})")] + # Make a PSBT psbt = wallet.walletcreatefundedpsbt([], [{def_wallet.getnewaddress(): 1}])["psbt"] @@ -235,6 +241,22 @@ def test_sighash_mismatch(self): proc = wallet.walletprocesspsbt(psbt, True, "ALL|ANYONECANPAY") assert_equal(proc["complete"], True) + # Repeat with descriptorprocesspsbt + # Mismatching sighash type fails + assert_raises_rpc_error(-22, "Specified sighash value does not match value stored in PSBT", self.nodes[0].descriptorprocesspsbt, psbt, descs, "DEFAULT") + assert_raises_rpc_error(-22, "Specified sighash value does not match value stored in PSBT", self.nodes[0].descriptorprocesspsbt, psbt, descs, "ALL") + assert_raises_rpc_error(-22, "Specified sighash value does not match value stored in PSBT", self.nodes[0].descriptorprocesspsbt, psbt, descs, "NONE") + assert_raises_rpc_error(-22, "Specified sighash value does not match value stored in PSBT", self.nodes[0].descriptorprocesspsbt, psbt, descs, "SINGLE") + assert_raises_rpc_error(-22, "Specified sighash value does not match value stored in PSBT", self.nodes[0].descriptorprocesspsbt, psbt, descs, "NONE|ANYONECANPAY") + assert_raises_rpc_error(-22, "Specified sighash value does not match value stored in PSBT", self.nodes[0].descriptorprocesspsbt, psbt, descs, "SINGLE|ANYONECANPAY") + + # No sighash type specified fails + assert_raises_rpc_error(-22, "Specified sighash value does not match value stored in PSBT", self.nodes[0].descriptorprocesspsbt, psbt, descs) + + # Matching sighash type succeeds + proc = self.nodes[0].descriptorprocesspsbt(psbt, descs, "ALL|ANYONECANPAY") + assert_equal(proc["complete"], True) + wallet.unloadwallet() def test_sighash_adding(self):