mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-08 12:19:07 +02:00
psbt: Return PSBTError from SignPSBTInput
SignPSBTInput will need to report the specific things that caused an error to callers, so change it to return a PSBTError. Additionally some callers will now check the return value and report an error to the user. Currently, this should not change any behavior as the things that SignPBSTInput will error on are all first checked by its callers.
This commit is contained in:
parent
2a721dcfae
commit
5332407ccb
@ -116,6 +116,10 @@ bilingual_str PSBTErrorString(PSBTError err)
|
||||
return Untranslated("External signer failed to sign");
|
||||
case PSBTError::UNSUPPORTED:
|
||||
return Untranslated("Signer does not support PSBT");
|
||||
case PSBTError::INCOMPLETE:
|
||||
return Untranslated("Input needs additional signatures or other data");
|
||||
case PSBTError::OK:
|
||||
return Untranslated("No errors");
|
||||
// no default case, so the compiler can warn about missing cases
|
||||
}
|
||||
assert(false);
|
||||
|
@ -20,6 +20,8 @@ enum class PSBTError {
|
||||
EXTERNAL_SIGNER_NOT_FOUND,
|
||||
EXTERNAL_SIGNER_FAILED,
|
||||
UNSUPPORTED,
|
||||
INCOMPLETE,
|
||||
OK,
|
||||
};
|
||||
} // namespace common
|
||||
|
||||
|
@ -64,7 +64,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
|
||||
|
||||
// Figure out what is missing
|
||||
SignatureData outdata;
|
||||
bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, 1, &outdata);
|
||||
bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, 1, &outdata) == PSBTError::OK;
|
||||
|
||||
// Things are missing
|
||||
if (!complete) {
|
||||
@ -124,7 +124,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
|
||||
PSBTInput& input = psbtx.inputs[i];
|
||||
Coin newcoin;
|
||||
|
||||
if (!SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, nullptr, 1) || !psbtx.GetInputUTXO(newcoin.out, i)) {
|
||||
if (SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, nullptr, 1) != PSBTError::OK || !psbtx.GetInputUTXO(newcoin.out, i)) {
|
||||
success = false;
|
||||
break;
|
||||
} else {
|
||||
|
19
src/psbt.cpp
19
src/psbt.cpp
@ -4,12 +4,15 @@
|
||||
|
||||
#include <psbt.h>
|
||||
|
||||
#include <common/types.h>
|
||||
#include <node/types.h>
|
||||
#include <policy/policy.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <util/check.h>
|
||||
#include <util/strencodings.h>
|
||||
|
||||
using common::PSBTError;
|
||||
|
||||
PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx)
|
||||
{
|
||||
inputs.resize(tx.vin.size());
|
||||
@ -372,13 +375,13 @@ PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction&
|
||||
return txdata;
|
||||
}
|
||||
|
||||
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata, bool finalize)
|
||||
PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata, bool finalize)
|
||||
{
|
||||
PSBTInput& input = psbt.inputs.at(index);
|
||||
const CMutableTransaction& tx = *psbt.tx;
|
||||
|
||||
if (PSBTInputSignedAndVerified(psbt, index, txdata)) {
|
||||
return true;
|
||||
return PSBTError::OK;
|
||||
}
|
||||
|
||||
// Fill SignatureData with input info
|
||||
@ -393,10 +396,10 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
|
||||
// If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
|
||||
COutPoint prevout = tx.vin[index].prevout;
|
||||
if (prevout.n >= input.non_witness_utxo->vout.size()) {
|
||||
return false;
|
||||
return PSBTError::MISSING_INPUTS;
|
||||
}
|
||||
if (input.non_witness_utxo->GetHash() != prevout.hash) {
|
||||
return false;
|
||||
return PSBTError::MISSING_INPUTS;
|
||||
}
|
||||
utxo = input.non_witness_utxo->vout[prevout.n];
|
||||
} else if (!input.witness_utxo.IsNull()) {
|
||||
@ -407,7 +410,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
|
||||
// a witness signature in this situation.
|
||||
require_witness_sig = true;
|
||||
} else {
|
||||
return false;
|
||||
return PSBTError::MISSING_INPUTS;
|
||||
}
|
||||
|
||||
sigdata.witness = false;
|
||||
@ -419,7 +422,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
|
||||
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 false;
|
||||
if (require_witness_sig && !sigdata.witness) return PSBTError::INCOMPLETE;
|
||||
|
||||
// If we are not finalizing, set sigdata.complete to false to not set the scriptWitness
|
||||
if (!finalize && sigdata.complete) sigdata.complete = false;
|
||||
@ -442,7 +445,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
|
||||
out_sigdata->missing_witness_script = sigdata.missing_witness_script;
|
||||
}
|
||||
|
||||
return sig_complete;
|
||||
return sig_complete ? PSBTError::OK : PSBTError::INCOMPLETE;
|
||||
}
|
||||
|
||||
void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx, const int& sighash_type)
|
||||
@ -486,7 +489,7 @@ bool FinalizePSBT(PartiallySignedTransaction& psbtx)
|
||||
bool complete = true;
|
||||
const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
|
||||
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
|
||||
complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL, nullptr, true);
|
||||
complete &= (SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL, nullptr, true) == PSBTError::OK);
|
||||
}
|
||||
|
||||
return complete;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef BITCOIN_PSBT_H
|
||||
#define BITCOIN_PSBT_H
|
||||
|
||||
#include <common/types.h>
|
||||
#include <node/transaction.h>
|
||||
#include <policy/feerate.h>
|
||||
#include <primitives/transaction.h>
|
||||
@ -21,6 +22,8 @@ namespace node {
|
||||
enum class TransactionError;
|
||||
} // namespace node
|
||||
|
||||
using common::PSBTError;
|
||||
|
||||
// Magic bytes
|
||||
static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff};
|
||||
|
||||
@ -1241,7 +1244,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.
|
||||
**/
|
||||
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool finalize = true);
|
||||
[[nodiscard]] PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool finalize = true);
|
||||
|
||||
/** 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, const int& sighash_type);
|
||||
|
@ -235,7 +235,8 @@ 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`
|
||||
SignPSBTInput(provider, psbtx, /*index=*/i, &txdata, sighash_type, /*out_sigdata=*/nullptr, finalize);
|
||||
// As such, we ignore the return value as any errors just mean that we do not have enough information.
|
||||
(void)SignPSBTInput(provider, psbtx, /*index=*/i, &txdata, sighash_type, /*out_sigdata=*/nullptr, finalize);
|
||||
}
|
||||
|
||||
// Update script/keypath information using descriptor data.
|
||||
|
@ -665,7 +665,10 @@ std::optional<PSBTError> LegacyScriptPubKeyMan::FillPSBT(PartiallySignedTransact
|
||||
// There's no UTXO so we can just skip this now
|
||||
continue;
|
||||
}
|
||||
SignPSBTInput(HidingSigningProvider(this, !sign, !bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
|
||||
PSBTError res = SignPSBTInput(HidingSigningProvider(this, !sign, !bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
|
||||
if (res != PSBTError::OK && res != PSBTError::INCOMPLETE) {
|
||||
return res;
|
||||
}
|
||||
|
||||
bool signed_one = PSBTInputSigned(input);
|
||||
if (n_signed && (signed_one || !sign)) {
|
||||
@ -2620,7 +2623,10 @@ std::optional<PSBTError> DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTran
|
||||
}
|
||||
}
|
||||
|
||||
SignPSBTInput(HidingSigningProvider(keys.get(), /*hide_secret=*/!sign, /*hide_origin=*/!bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
|
||||
PSBTError res = SignPSBTInput(HidingSigningProvider(keys.get(), /*hide_secret=*/!sign, /*hide_origin=*/!bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
|
||||
if (res != PSBTError::OK && res != PSBTError::INCOMPLETE) {
|
||||
return res;
|
||||
}
|
||||
|
||||
bool signed_one = PSBTInputSigned(input);
|
||||
if (n_signed && (signed_one || !sign)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user