Skip to content

Commit 02e62c6

Browse files
committed
common: Add PSBTError enum
Add separate PSBTError enum instead of reusing TransactionError enum for PSBT operations, and drop unused error codes. The error codes returned by PSBT operations and transaction broadcast functions mostly do not overlap, so using an unified enum makes it harder to call any of these functions and know which errors actually need to be handled. Define PSBTError in the common library because PSBT functionality is implemented in the common library and used by both the node (for rawtransaction RPCs) and the wallet.
1 parent 0d44c44 commit 02e62c6

25 files changed

+156
-97
lines changed

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ BITCOIN_CORE_H = \
137137
common/bloom.h \
138138
common/init.h \
139139
common/run_command.h \
140+
common/types.h \
140141
common/url.h \
141142
compat/assumptions.h \
142143
compat/byteswap.h \

src/common/types.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) 2010-2021 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
//! @file common/types.h is a home for simple enum and struct type definitions
6+
//! that can be used internally by functions in the libbitcoin_common library,
7+
//! but also used externally by node, wallet, and GUI code.
8+
//!
9+
//! This file is intended to define only simple types that do not have external
10+
//! dependencies. More complicated types should be defined in dedicated header
11+
//! files.
12+
13+
#ifndef BITCOIN_COMMON_TYPES_H
14+
#define BITCOIN_COMMON_TYPES_H
15+
16+
namespace common {
17+
enum class PSBTError {
18+
MISSING_INPUTS,
19+
SIGHASH_MISMATCH,
20+
EXTERNAL_SIGNER_NOT_FOUND,
21+
EXTERNAL_SIGNER_FAILED,
22+
UNSUPPORTED,
23+
};
24+
} // namespace common
25+
26+
#endif // BITCOIN_COMMON_TYPES_H

src/interfaces/wallet.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ class CFeeRate;
3030
class CKey;
3131
enum class FeeReason;
3232
enum class OutputType;
33-
enum class TransactionError;
3433
struct PartiallySignedTransaction;
3534
struct bilingual_str;
35+
namespace common {
36+
enum class PSBTError;
37+
} // namespace common
3638
namespace wallet {
3739
class CCoinControl;
3840
class CWallet;
@@ -202,7 +204,7 @@ class Wallet
202204
int& num_blocks) = 0;
203205

204206
//! Fill PSBT.
205-
virtual TransactionError fillPSBT(int sighash_type,
207+
virtual std::optional<common::PSBTError> fillPSBT(int sighash_type,
206208
bool sign,
207209
bool bip32derivs,
208210
size_t* n_signed,

src/node/types.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,10 @@ enum class TransactionError {
1717
OK, //!< No error
1818
MISSING_INPUTS,
1919
ALREADY_IN_CHAIN,
20-
P2P_DISABLED,
2120
MEMPOOL_REJECTED,
2221
MEMPOOL_ERROR,
23-
INVALID_PSBT,
24-
PSBT_MISMATCH,
25-
SIGHASH_MISMATCH,
2622
MAX_FEE_EXCEEDED,
2723
MAX_BURN_EXCEEDED,
28-
EXTERNAL_SIGNER_NOT_FOUND,
29-
EXTERNAL_SIGNER_FAILED,
3024
INVALID_PACKAGE,
3125
};
3226

src/psbt.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -508,17 +508,17 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
508508
return true;
509509
}
510510

511-
TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs)
511+
bool CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs)
512512
{
513513
out = psbtxs[0]; // Copy the first one
514514

515515
// Merge
516516
for (auto it = std::next(psbtxs.begin()); it != psbtxs.end(); ++it) {
517517
if (!out.Merge(*it)) {
518-
return TransactionError::PSBT_MISMATCH;
518+
return false;
519519
}
520520
}
521-
return TransactionError::OK;
521+
return true;
522522
}
523523

524524
std::string PSBTRoleName(PSBTRole role) {

src/psbt.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,9 +1263,9 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
12631263
*
12641264
* @param[out] out the combined PSBT, if successful
12651265
* @param[in] psbtxs the PSBTs to combine
1266-
* @return error (OK if we successfully combined the transactions, other error if they were not compatible)
1266+
* @return True if we successfully combined the transactions, false if they were not compatible
12671267
*/
1268-
[[nodiscard]] TransactionError CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs);
1268+
[[nodiscard]] bool CombinePSBTs(PartiallySignedTransaction& out, const std::vector<PartiallySignedTransaction>& psbtxs);
12691269

12701270
//! Decode a base64ed PSBT into a PartiallySignedTransaction
12711271
[[nodiscard]] bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);

src/qt/psbtoperationsdialog.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <qt/forms/ui_psbtoperationsdialog.h>
1414
#include <qt/guiutil.h>
1515
#include <qt/optionsmodel.h>
16+
#include <util/error.h>
1617
#include <util/fs.h>
1718
#include <util/strencodings.h>
1819

@@ -55,10 +56,10 @@ void PSBTOperationsDialog::openWithPSBT(PartiallySignedTransaction psbtx)
5556
bool complete = FinalizePSBT(psbtx); // Make sure all existing signatures are fully combined before checking for completeness.
5657
if (m_wallet_model) {
5758
size_t n_could_sign;
58-
TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, &n_could_sign, m_transaction_data, complete);
59-
if (err != TransactionError::OK) {
59+
const auto err{m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, &n_could_sign, m_transaction_data, complete)};
60+
if (err) {
6061
showStatus(tr("Failed to load transaction: %1")
61-
.arg(QString::fromStdString(TransactionErrorString(err).translated)),
62+
.arg(QString::fromStdString(PSBTErrorString(*err).translated)),
6263
StatusLevel::ERR);
6364
return;
6465
}
@@ -79,11 +80,11 @@ void PSBTOperationsDialog::signTransaction()
7980

8081
WalletModel::UnlockContext ctx(m_wallet_model->requestUnlock());
8182

82-
TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/true, /*bip32derivs=*/true, &n_signed, m_transaction_data, complete);
83+
const auto err{m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/true, /*bip32derivs=*/true, &n_signed, m_transaction_data, complete)};
8384

84-
if (err != TransactionError::OK) {
85+
if (err) {
8586
showStatus(tr("Failed to sign transaction: %1")
86-
.arg(QString::fromStdString(TransactionErrorString(err).translated)), StatusLevel::ERR);
87+
.arg(QString::fromStdString(PSBTErrorString(*err).translated)), StatusLevel::ERR);
8788
return;
8889
}
8990

@@ -247,9 +248,9 @@ size_t PSBTOperationsDialog::couldSignInputs(const PartiallySignedTransaction &p
247248

248249
size_t n_signed;
249250
bool complete;
250-
TransactionError err = m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/false, &n_signed, m_transaction_data, complete);
251+
const auto err{m_wallet_model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/false, &n_signed, m_transaction_data, complete)};
251252

252-
if (err != TransactionError::OK) {
253+
if (err) {
253254
return 0;
254255
}
255256
return n_signed;

src/qt/sendcoinsdialog.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <QSettings>
3838
#include <QTextDocument>
3939

40+
using common::PSBTError;
4041
using wallet::CCoinControl;
4142
using wallet::DEFAULT_PAY_TX_FEE;
4243

@@ -442,26 +443,26 @@ void SendCoinsDialog::presentPSBT(PartiallySignedTransaction& psbtx)
442443
}
443444

444445
bool SendCoinsDialog::signWithExternalSigner(PartiallySignedTransaction& psbtx, CMutableTransaction& mtx, bool& complete) {
445-
TransactionError err;
446+
std::optional<PSBTError> err;
446447
try {
447448
err = model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/true, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete);
448449
} catch (const std::runtime_error& e) {
449450
QMessageBox::critical(nullptr, tr("Sign failed"), e.what());
450451
return false;
451452
}
452-
if (err == TransactionError::EXTERNAL_SIGNER_NOT_FOUND) {
453+
if (err == PSBTError::EXTERNAL_SIGNER_NOT_FOUND) {
453454
//: "External signer" means using devices such as hardware wallets.
454455
const QString msg = tr("External signer not found");
455456
QMessageBox::critical(nullptr, msg, msg);
456457
return false;
457458
}
458-
if (err == TransactionError::EXTERNAL_SIGNER_FAILED) {
459+
if (err == PSBTError::EXTERNAL_SIGNER_FAILED) {
459460
//: "External signer" means using devices such as hardware wallets.
460461
const QString msg = tr("External signer failure");
461462
QMessageBox::critical(nullptr, msg, msg);
462463
return false;
463464
}
464-
if (err != TransactionError::OK) {
465+
if (err) {
465466
tfm::format(std::cerr, "Failed to sign PSBT");
466467
processSendCoinsReturn(WalletModel::TransactionCreationFailed);
467468
return false;
@@ -501,9 +502,9 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
501502
PartiallySignedTransaction psbtx(mtx);
502503
bool complete = false;
503504
// Fill without signing
504-
TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete);
505+
const auto err{model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete)};
505506
assert(!complete);
506-
assert(err == TransactionError::OK);
507+
assert(!err);
507508

508509
// Copy PSBT to clipboard and offer to save
509510
presentPSBT(psbtx);
@@ -517,9 +518,9 @@ void SendCoinsDialog::sendButtonClicked([[maybe_unused]] bool checked)
517518
bool complete = false;
518519
// Always fill without signing first. This prevents an external signer
519520
// from being called prematurely and is not expensive.
520-
TransactionError err = model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete);
521+
const auto err{model->wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, /*n_signed=*/nullptr, psbtx, complete)};
521522
assert(!complete);
522-
assert(err == TransactionError::OK);
523+
assert(!err);
523524
send_failure = !signWithExternalSigner(psbtx, mtx, complete);
524525
// Don't broadcast when user rejects it on the device or there's a failure:
525526
broadcast = complete && !send_failure;

src/qt/walletmodel.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,8 +534,8 @@ bool WalletModel::bumpFee(uint256 hash, uint256& new_hash)
534534
// "Create Unsigned" clicked
535535
PartiallySignedTransaction psbtx(mtx);
536536
bool complete = false;
537-
const TransactionError err = wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, nullptr, psbtx, complete);
538-
if (err != TransactionError::OK || complete) {
537+
const auto err{wallet().fillPSBT(SIGHASH_ALL, /*sign=*/false, /*bip32derivs=*/true, nullptr, psbtx, complete)};
538+
if (err || complete) {
539539
QMessageBox::critical(nullptr, tr("Fee bump error"), tr("Can't draft transaction."));
540540
return false;
541541
}

src/rpc/rawtransaction.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,9 +1485,8 @@ static RPCHelpMan combinepsbt()
14851485
}
14861486

14871487
PartiallySignedTransaction merged_psbt;
1488-
const TransactionError error = CombinePSBTs(merged_psbt, psbtxs);
1489-
if (error != TransactionError::OK) {
1490-
throw JSONRPCTransactionError(error);
1488+
if (!CombinePSBTs(merged_psbt, psbtxs)) {
1489+
throw JSONRPCError(RPC_INVALID_PARAMETER, "PSBTs not compatible (different transactions)");
14911490
}
14921491

14931492
DataStream ssTx{};

0 commit comments

Comments
 (0)