Merge bitcoin/bitcoin#32958: wallet/refactor: Update SignPSBTInput to return util::Expected<void, PSBTError> and remove PSBTError:Ok

6cca38e2b9 refactor: remove unused PSBTError::Ok (kevkevinpal)
3660678b95 refactor: SignPSBTInput now uses util:Expected (kevkevinpal)

Pull request description:

  ### Description
  This is a follow-up to https://github.com/bitcoin/bitcoin/pull/31622#discussion_r2092030045 and https://github.com/bitcoin/bitcoin/pull/31622#discussion_r2092035407

  ### What this changes
  - Updates `SignPSBTInput` to return `util::Expected<void, PSBTError>`
  - Removes `PSBTError:Ok` from the `PSBTError` Enum

ACKs for top commit:
  achow101:
    ACK 6cca38e2b9
  rkrux:
    lgtm ACK 6cca38e2b9
  jeanpablojp:
    tACK 6cca38e2b9

Tree-SHA512: c83b2e7e440aff01becc788e36a732756085f507d447eaa16dd1276d0d0b54070d0d8a51727d553d214043935072586111a175f34338a8d1886a6d5b251de7e4
This commit is contained in:
Ava Chow
2026-08-20 14:13:21 -07:00
7 changed files with 28 additions and 25 deletions

View File

@@ -636,17 +636,17 @@ std::optional<PrecomputedTransactionData> PrecomputePSBTData(const PartiallySign
return txdata;
}
PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, const common::PSBTFillOptions& options, SignatureData* out_sigdata)
util::Expected<void, PSBTError> SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, const common::PSBTFillOptions& options, SignatureData* out_sigdata)
{
PSBTInput& input = psbt.inputs.at(index);
std::optional<CMutableTransaction> unsigned_tx = psbt.GetUnsignedTx();
if (!unsigned_tx) {
return PSBTError::INVALID_TX;
return util::Unexpected{PSBTError::INVALID_TX};
}
const CMutableTransaction& tx = *unsigned_tx;
if (PSBTInputSignedAndVerified(psbt, index, txdata)) {
return PSBTError::OK;
return {};
}
// Fill SignatureData with input info
@@ -661,10 +661,10 @@ PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransact
// If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
COutPoint prevout = input.GetOutPoint();
if (prevout.n >= input.non_witness_utxo->vout.size()) {
return PSBTError::MISSING_INPUTS;
return util::Unexpected{PSBTError::MISSING_INPUTS};
}
if (input.non_witness_utxo->GetHash() != prevout.hash) {
return PSBTError::MISSING_INPUTS;
return util::Unexpected{PSBTError::MISSING_INPUTS};
}
utxo = input.non_witness_utxo->vout[prevout.n];
} else if (!input.witness_utxo.IsNull()) {
@@ -675,7 +675,7 @@ PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransact
// a witness signature in this situation.
require_witness_sig = true;
} else {
return PSBTError::MISSING_INPUTS;
return util::Unexpected{PSBTError::MISSING_INPUTS};
}
// Get the sighash type
@@ -687,7 +687,7 @@ PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransact
// For user safety, the desired sighash must be provided if the PSBT wants something other than the default set in the previous line.
if (input.sighash_type && input.sighash_type != sighash) {
return PSBTError::SIGHASH_MISMATCH;
return util::Unexpected{PSBTError::SIGHASH_MISMATCH};
}
// Set the PSBT sighash field when sighash is not DEFAULT or ALL
// DEFAULT is allowed for non-taproot inputs since DEFAULT may be passed for them (e.g. the psbt being signed also has taproot inputs)
@@ -700,20 +700,20 @@ PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransact
// Check all existing signatures use the sighash type
if (sighash == SIGHASH_DEFAULT) {
if (!input.m_tap_key_sig.empty() && input.m_tap_key_sig.size() != 64) {
return PSBTError::SIGHASH_MISMATCH;
return util::Unexpected{PSBTError::SIGHASH_MISMATCH};
}
for (const auto& [_, sig] : input.m_tap_script_sigs) {
if (sig.size() != 64) return PSBTError::SIGHASH_MISMATCH;
if (sig.size() != 64) return util::Unexpected{PSBTError::SIGHASH_MISMATCH};
}
} else {
if (!input.m_tap_key_sig.empty() && (input.m_tap_key_sig.size() != 65 || input.m_tap_key_sig.back() != sighash)) {
return PSBTError::SIGHASH_MISMATCH;
return util::Unexpected{PSBTError::SIGHASH_MISMATCH};
}
for (const auto& [_, sig] : input.m_tap_script_sigs) {
if (sig.size() != 65 || sig.back() != sighash) return PSBTError::SIGHASH_MISMATCH;
if (sig.size() != 65 || sig.back() != sighash) return util::Unexpected{PSBTError::SIGHASH_MISMATCH};
}
for (const auto& [_, sig] : input.partial_sigs) {
if (sig.second.back() != sighash) return PSBTError::SIGHASH_MISMATCH;
if (sig.second.back() != sighash) return util::Unexpected{PSBTError::SIGHASH_MISMATCH};
}
}
@@ -726,7 +726,7 @@ PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransact
sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata);
}
// Verify that a witness signature was produced in case one was required.
if (require_witness_sig && !sigdata.witness) return PSBTError::INCOMPLETE;
if (require_witness_sig && !sigdata.witness) return util::Unexpected{PSBTError::INCOMPLETE};
// If we are not finalizing, set sigdata.complete to false to not set the scriptWitness
if (!options.finalize && sigdata.complete) sigdata.complete = false;
@@ -749,7 +749,8 @@ PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransact
out_sigdata->missing_witness_script = sigdata.missing_witness_script;
}
return sig_complete ? PSBTError::OK : PSBTError::INCOMPLETE;
if (!sig_complete) return util::Unexpected{PSBTError::INCOMPLETE};
return {};
}
void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx)
@@ -803,7 +804,8 @@ bool FinalizePSBT(PartiallySignedTransaction& psbtx)
const PrecomputedTransactionData& txdata = *txdata_res;
for (unsigned int i = 0; i < psbtx.inputs.size(); ++i) {
PSBTInput& input = psbtx.inputs.at(i);
complete &= (SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, {.sighash_type = input.sighash_type, .finalize = true}, /*out_sigdata=*/nullptr) == PSBTError::OK);
const auto sign_result = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, {.sighash_type = input.sighash_type, .finalize = true}, /*out_sigdata=*/nullptr);
complete &= sign_result.has_value();
}
return complete;