diff --git a/src/common/messages.cpp b/src/common/messages.cpp index e558442f427..8e4c0c7df25 100644 --- a/src/common/messages.cpp +++ b/src/common/messages.cpp @@ -119,8 +119,6 @@ bilingual_str PSBTErrorString(PSBTError err) return Untranslated("Input needs additional signatures or other data"); case PSBTError::INVALID_TX: return Untranslated("The transaction cannot be valid"); - case PSBTError::OK: - return Untranslated("No errors"); } // no default case, so the compiler can warn about missing cases assert(false); } diff --git a/src/common/types.h b/src/common/types.h index b9ebca15e84..1ffcd392d60 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -24,7 +24,6 @@ enum class PSBTError { UNSUPPORTED, INCOMPLETE, INVALID_TX, - OK, }; /** * Instructions for how a PSBT should be signed or filled with information. diff --git a/src/node/psbt.cpp b/src/node/psbt.cpp index 699d1d5f7ce..b0988d86828 100644 --- a/src/node/psbt.cpp +++ b/src/node/psbt.cpp @@ -72,7 +72,8 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx) // Figure out what is missing SignatureData outdata; - bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, /*options=*/{}, &outdata) == PSBTError::OK; + const auto sign_result = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, /*options*/{}, &outdata); + bool complete = sign_result.has_value(); // Things are missing if (!complete) { @@ -130,7 +131,8 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx) PSBTInput& input = psbtx.inputs[i]; Coin newcoin; - if (SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, nullptr, /*options=*/{}) != PSBTError::OK || !input.GetUTXO(newcoin.out)) { + const auto sign_result = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, nullptr, /*options=*/{}); + if (!sign_result.has_value() || !input.GetUTXO(newcoin.out)) { success = false; break; } else { diff --git a/src/psbt.cpp b/src/psbt.cpp index 9c595abc450..586fded2a29 100644 --- a/src/psbt.cpp +++ b/src/psbt.cpp @@ -636,17 +636,17 @@ std::optional 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 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 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; diff --git a/src/psbt.h b/src/psbt.h index a6f189d0151..fc627494490 100644 --- a/src/psbt.h +++ b/src/psbt.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1642,7 +1643,7 @@ bool PSBTInputSignedAndVerified(const PartiallySignedTransaction& psbt, unsigned * txdata should be the output of PrecomputePSBTData (which can be shared across * multiple SignPSBTInput calls). If it is nullptr, a dummy signature will be created. **/ -[[nodiscard]] PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, const common::PSBTFillOptions& options, SignatureData* out_sigdata = nullptr); +[[nodiscard]] util::Expected SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, const common::PSBTFillOptions& options, SignatureData* out_sigdata = nullptr); /** Reduces the size of the PSBT by dropping unnecessary `non_witness_utxos` (i.e. complete previous transactions) from a psbt when all inputs are segwit v1. */ void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 388a7fd9167..97b22c11e08 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -195,7 +195,8 @@ PartiallySignedTransaction ProcessPSBT(const std::string& psbt_string, const std // We only actually care about those if our signing provider doesn't hide private // information, as is the case with `descriptorprocesspsbt` // 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 = sighash_type, .finalize = finalize}, /*out_sigdata=*/nullptr) == common::PSBTError::SIGHASH_MISMATCH) { + const auto sign_result = SignPSBTInput(provider, psbtx, /*index=*/i, &txdata, {.sighash_type = sighash_type, .finalize = finalize}, /*out_sigdata=*/nullptr); + if (!sign_result.has_value() && sign_result.error() == common::PSBTError::SIGHASH_MISMATCH) { throw JSONRPCPSBTError(common::PSBTError::SIGHASH_MISMATCH); } } diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index c3db3816eb0..cd708a42dfb 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1425,9 +1425,9 @@ std::optional DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTran } } - PSBTError res = SignPSBTInput(HidingSigningProvider(keys.get(), /*hide_secret=*/!options.sign, /*hide_origin=*/!options.bip32_derivs), psbtx, i, &txdata, options, /*out_sigdata=*/nullptr); - if (res != PSBTError::OK && res != PSBTError::INCOMPLETE) { - return res; + const auto sign_result = SignPSBTInput(HidingSigningProvider(keys.get(), /*hide_secret=*/!options.sign, /*hide_origin=*/!options.bip32_derivs), psbtx, i, &txdata, options, /*out_sigdata=*/nullptr); + if (!sign_result.has_value() && sign_result.error() != PSBTError::INCOMPLETE) { + return sign_result.error(); } bool signed_one = PSBTInputSigned(input);