Skip to content

Commit

Permalink
rpc, psbt: Require sighashes match for descriptorprocesspsbt
Browse files Browse the repository at this point in the history
  • Loading branch information
achow101 committed Jan 9, 2025
1 parent 83641b0 commit b70e83d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
6 changes: 4 additions & 2 deletions src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
22 changes: 22 additions & 0 deletions test/functional/rpc_psbt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand All @@ -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):
Expand Down

0 comments on commit b70e83d

Please sign in to comment.