Skip to content

Commit e58b680

Browse files
committed
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.
1 parent 2adfd81 commit e58b680

File tree

7 files changed

+29
-13
lines changed

7 files changed

+29
-13
lines changed

src/common/messages.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ bilingual_str PSBTErrorString(PSBTError err)
116116
return Untranslated("External signer failed to sign");
117117
case PSBTError::UNSUPPORTED:
118118
return Untranslated("Signer does not support PSBT");
119+
case PSBTError::INCOMPLETE:
120+
return Untranslated("Input needs additional signatures or other data");
121+
case PSBTError::OK:
122+
return Untranslated("No errors");
119123
// no default case, so the compiler can warn about missing cases
120124
}
121125
assert(false);

src/common/types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ enum class PSBTError {
2020
EXTERNAL_SIGNER_NOT_FOUND,
2121
EXTERNAL_SIGNER_FAILED,
2222
UNSUPPORTED,
23+
INCOMPLETE,
24+
OK,
2325
};
2426
} // namespace common
2527

src/node/psbt.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
6464

6565
// Figure out what is missing
6666
SignatureData outdata;
67-
bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, 1, &outdata);
67+
bool complete = SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, 1, &outdata) == PSBTError::OK;
6868

6969
// Things are missing
7070
if (!complete) {
@@ -124,7 +124,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
124124
PSBTInput& input = psbtx.inputs[i];
125125
Coin newcoin;
126126

127-
if (!SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, nullptr, 1) || !psbtx.GetInputUTXO(newcoin.out, i)) {
127+
if (SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, nullptr, 1) != PSBTError::OK || !psbtx.GetInputUTXO(newcoin.out, i)) {
128128
success = false;
129129
break;
130130
} else {

src/psbt.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44

55
#include <psbt.h>
66

7+
#include <common/types.h>
78
#include <node/types.h>
89
#include <policy/policy.h>
910
#include <script/signingprovider.h>
1011
#include <util/check.h>
1112
#include <util/strencodings.h>
1213

14+
using common::PSBTError;
15+
1316
PartiallySignedTransaction::PartiallySignedTransaction(const CMutableTransaction& tx) : tx(tx)
1417
{
1518
inputs.resize(tx.vin.size());
@@ -372,13 +375,13 @@ PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction&
372375
return txdata;
373376
}
374377

375-
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata, bool finalize)
378+
PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata, bool finalize)
376379
{
377380
PSBTInput& input = psbt.inputs.at(index);
378381
const CMutableTransaction& tx = *psbt.tx;
379382

380383
if (PSBTInputSignedAndVerified(psbt, index, txdata)) {
381-
return true;
384+
return PSBTError::OK;
382385
}
383386

384387
// Fill SignatureData with input info
@@ -393,10 +396,10 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
393396
// If we're taking our information from a non-witness UTXO, verify that it matches the prevout.
394397
COutPoint prevout = tx.vin[index].prevout;
395398
if (prevout.n >= input.non_witness_utxo->vout.size()) {
396-
return false;
399+
return PSBTError::MISSING_INPUTS;
397400
}
398401
if (input.non_witness_utxo->GetHash() != prevout.hash) {
399-
return false;
402+
return PSBTError::MISSING_INPUTS;
400403
}
401404
utxo = input.non_witness_utxo->vout[prevout.n];
402405
} else if (!input.witness_utxo.IsNull()) {
@@ -407,7 +410,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
407410
// a witness signature in this situation.
408411
require_witness_sig = true;
409412
} else {
410-
return false;
413+
return PSBTError::MISSING_INPUTS;
411414
}
412415

413416
sigdata.witness = false;
@@ -419,7 +422,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
419422
sig_complete = ProduceSignature(provider, creator, utxo.scriptPubKey, sigdata);
420423
}
421424
// Verify that a witness signature was produced in case one was required.
422-
if (require_witness_sig && !sigdata.witness) return false;
425+
if (require_witness_sig && !sigdata.witness) return PSBTError::INCOMPLETE;
423426

424427
// If we are not finalizing, set sigdata.complete to false to not set the scriptWitness
425428
if (!finalize && sigdata.complete) sigdata.complete = false;
@@ -442,7 +445,7 @@ bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction&
442445
out_sigdata->missing_witness_script = sigdata.missing_witness_script;
443446
}
444447

445-
return sig_complete;
448+
return sig_complete ? PSBTError::OK : PSBTError::INCOMPLETE;
446449
}
447450

448451
void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx, const int& sighash_type)
@@ -486,7 +489,7 @@ bool FinalizePSBT(PartiallySignedTransaction& psbtx)
486489
bool complete = true;
487490
const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
488491
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
489-
complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL, nullptr, true);
492+
complete &= (SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL, nullptr, true) == PSBTError::OK);
490493
}
491494

492495
return complete;

src/psbt.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef BITCOIN_PSBT_H
66
#define BITCOIN_PSBT_H
77

8+
#include <common/types.h>
89
#include <node/transaction.h>
910
#include <policy/feerate.h>
1011
#include <primitives/transaction.h>
@@ -21,6 +22,8 @@ namespace node {
2122
enum class TransactionError;
2223
} // namespace node
2324

25+
using common::PSBTError;
26+
2427
// Magic bytes
2528
static constexpr uint8_t PSBT_MAGIC_BYTES[5] = {'p', 's', 'b', 't', 0xff};
2629

@@ -1401,7 +1404,7 @@ bool PSBTInputSignedAndVerified(const PartiallySignedTransaction psbt, unsigned
14011404
* txdata should be the output of PrecomputePSBTData (which can be shared across
14021405
* multiple SignPSBTInput calls). If it is nullptr, a dummy signature will be created.
14031406
**/
1404-
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool finalize = true);
1407+
[[nodiscard]] PSBTError SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool finalize = true);
14051408

14061409
/** 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. */
14071410
void RemoveUnnecessaryTransactions(PartiallySignedTransaction& psbtx, const int& sighash_type);

src/rpc/rawtransaction.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,8 @@ PartiallySignedTransaction ProcessPSBT(const std::string& psbt_string, const std
235235
// Note that SignPSBTInput does a lot more than just constructing ECDSA signatures.
236236
// We only actually care about those if our signing provider doesn't hide private
237237
// information, as is the case with `descriptorprocesspsbt`
238-
SignPSBTInput(provider, psbtx, /*index=*/i, &txdata, sighash_type, /*out_sigdata=*/nullptr, finalize);
238+
// As such, we ignore the return value as any errors just mean that we do not have enough information.
239+
(void)SignPSBTInput(provider, psbtx, /*index=*/i, &txdata, sighash_type, /*out_sigdata=*/nullptr, finalize);
239240
}
240241

241242
// Update script/keypath information using descriptor data.

src/wallet/scriptpubkeyman.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1386,7 +1386,10 @@ std::optional<PSBTError> DescriptorScriptPubKeyMan::FillPSBT(PartiallySignedTran
13861386
}
13871387
}
13881388

1389-
SignPSBTInput(HidingSigningProvider(keys.get(), /*hide_secret=*/!sign, /*hide_origin=*/!bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
1389+
PSBTError res = SignPSBTInput(HidingSigningProvider(keys.get(), /*hide_secret=*/!sign, /*hide_origin=*/!bip32derivs), psbtx, i, &txdata, sighash_type, nullptr, finalize);
1390+
if (res != PSBTError::OK && res != PSBTError::INCOMPLETE) {
1391+
return res;
1392+
}
13901393

13911394
bool signed_one = PSBTInputSigned(input);
13921395
if (n_signed && (signed_one || !sign)) {

0 commit comments

Comments
 (0)