Skip to content

Commit d6d472a

Browse files
kwvggades
authored andcommitted
merge bitcoin#14978: Factor out PSBT utilities from RPCs for use in GUI code; related refactoring
1 parent e85cafb commit d6d472a

File tree

18 files changed

+1016
-751
lines changed

18 files changed

+1016
-751
lines changed

src/Makefile.am

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ BITCOIN_CORE_H = \
231231
policy/policy.h \
232232
pow.h \
233233
protocol.h \
234+
psbt.h \
234235
random.h \
235236
reverse_iterator.h \
236237
rpc/blockchain.h \
@@ -293,6 +294,7 @@ BITCOIN_CORE_H = \
293294
wallet/crypter.h \
294295
wallet/db.h \
295296
wallet/fees.h \
297+
wallet/psbtwallet.h \
296298
wallet/rpcwallet.h \
297299
wallet/wallet.h \
298300
wallet/walletdb.h \
@@ -441,6 +443,7 @@ libcosanta_wallet_a_SOURCES = \
441443
wallet/db.cpp \
442444
wallet/fees.cpp \
443445
wallet/init.cpp \
446+
wallet/psbtwallet.cpp \
444447
wallet/rpcdump.cpp \
445448
wallet/rpcwallet.cpp \
446449
wallet/wallet.cpp \
@@ -602,6 +605,7 @@ libcosanta_common_a_SOURCES = \
602605
netbase.cpp \
603606
net_permissions.cpp \
604607
policy/feerate.cpp \
608+
psbt.cpp \
605609
protocol.cpp \
606610
saltedhasher.cpp \
607611
scheduler.cpp \

src/core_io.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
3939
*/
4040
bool ParseHashStr(const std::string& strHex, uint256& result);
4141
std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
42-
bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error);
4342
int ParseSighashString(const UniValue& sighash);
4443

44+
//! Decode a base64ed PSBT into a PartiallySignedTransaction
45+
[[nodiscard]] bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
46+
//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction
47+
[[nodiscard]] bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
48+
4549
// core_write.cpp
4650
UniValue ValueFromAmount(const CAmount& amount);
4751
std::string FormatScript(const CScript& script);

src/core_read.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <core_io.h>
77

8+
#include <psbt.h>
89
#include <primitives/block.h>
910
#include <primitives/transaction.h>
1011
#include <script/script.h>
@@ -140,10 +141,20 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
140141
return true;
141142
}
142143

143-
bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
144+
bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
144145
{
145-
std::vector<unsigned char> tx_data = DecodeBase64(base64_tx.c_str());
146-
CDataStream ss_data(tx_data, SER_NETWORK, PROTOCOL_VERSION);
146+
bool invalid;
147+
std::string tx_data = DecodeBase64(base64_tx, &invalid);
148+
if (invalid) {
149+
error = "invalid base64";
150+
return false;
151+
}
152+
return DecodeRawPSBT(psbt, tx_data, error);
153+
}
154+
155+
bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data, std::string& error)
156+
{
157+
CDataStream ss_data(tx_data.data(), tx_data.data() + tx_data.size(), SER_NETWORK, PROTOCOL_VERSION);
147158
try {
148159
ss_data >> psbt;
149160
if (!ss_data.empty()) {

src/node/transaction.cpp

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
#include <consensus/validation.h>
77
#include <net.h>
8-
#include <rpc/server.h>
98
#include <txmempool.h>
109
#include <validation.h>
1110
#include <validationinterface.h>
@@ -14,9 +13,38 @@
1413

1514
#include <future>
1615

17-
uint256 BroadcastTransaction(const CTransactionRef tx, const bool allowhighfees) {
16+
const char* TransactionErrorString(const TransactionError err)
17+
{
18+
switch (err) {
19+
case TransactionError::OK:
20+
return "No error";
21+
case TransactionError::MISSING_INPUTS:
22+
return "Missing inputs";
23+
case TransactionError::ALREADY_IN_CHAIN:
24+
return "Transaction already in block chain";
25+
case TransactionError::P2P_DISABLED:
26+
return "Peer-to-peer functionality missing or disabled";
27+
case TransactionError::MEMPOOL_REJECTED:
28+
return "Transaction rejected by AcceptToMemoryPool";
29+
case TransactionError::MEMPOOL_ERROR:
30+
return "AcceptToMemoryPool failed";
31+
case TransactionError::INVALID_PSBT:
32+
return "PSBT is not sane";
33+
case TransactionError::PSBT_MISMATCH:
34+
return "PSBTs not compatible (different transactions)";
35+
case TransactionError::SIGHASH_MISMATCH:
36+
return "Specified sighash value does not match existing value";
37+
38+
case TransactionError::UNKNOWN_ERROR:
39+
default: break;
40+
}
41+
return "Unknown error";
42+
}
43+
44+
bool BroadcastTransaction(const CTransactionRef tx, uint256& hashTx, TransactionError& error, std::string& err_string, const bool allowhighfees, const bool bypass_limits)
45+
{
1846
std::promise<void> promise;
19-
const uint256& hashTx = tx->GetHash();
47+
hashTx = tx->GetHash();
2048

2149
CAmount nMaxRawTxFee = maxTxFee;
2250
if (allowhighfees)
@@ -36,14 +64,19 @@ uint256 BroadcastTransaction(const CTransactionRef tx, const bool allowhighfees)
3664
CValidationState state;
3765
bool fMissingInputs;
3866
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
39-
false /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) {
67+
bypass_limits, nMaxRawTxFee)) {
4068
if (state.IsInvalid()) {
41-
throw JSONRPCError(RPC_TRANSACTION_REJECTED, FormatStateMessage(state));
69+
err_string = FormatStateMessage(state);
70+
error = TransactionError::MEMPOOL_REJECTED;
71+
return false;
4272
} else {
4373
if (fMissingInputs) {
44-
throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
74+
error = TransactionError::MISSING_INPUTS;
75+
return false;
4576
}
46-
throw JSONRPCError(RPC_TRANSACTION_ERROR, FormatStateMessage(state));
77+
err_string = FormatStateMessage(state);
78+
error = TransactionError::MEMPOOL_ERROR;
79+
return false;
4780
}
4881
} else {
4982
// If wallet is enabled, ensure that the wallet has been made aware
@@ -56,7 +89,8 @@ uint256 BroadcastTransaction(const CTransactionRef tx, const bool allowhighfees)
5689
});
5790
}
5891
} else if (fHaveChain) {
59-
throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
92+
error = TransactionError::ALREADY_IN_CHAIN;
93+
return false;
6094
} else {
6195
// Make sure we don't block forever if re-sending
6296
// a transaction already in mempool.
@@ -67,10 +101,12 @@ uint256 BroadcastTransaction(const CTransactionRef tx, const bool allowhighfees)
67101

68102
promise.get_future().wait();
69103

70-
if(!g_connman)
71-
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
104+
if(!g_connman) {
105+
error = TransactionError::P2P_DISABLED;
106+
return false;
107+
}
72108

73109
g_connman->RelayTransaction(*tx);
74110

75-
return hashTx;
76-
}
111+
return true;
112+
}

src/node/transaction.h

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,36 @@
88
#include <primitives/transaction.h>
99
#include <uint256.h>
1010

11-
/** Broadcast a transaction */
12-
uint256 BroadcastTransaction(CTransactionRef tx, bool allowhighfees = false);
11+
enum class TransactionError {
12+
OK = 0,
13+
UNKNOWN_ERROR,
14+
15+
MISSING_INPUTS,
16+
ALREADY_IN_CHAIN,
17+
P2P_DISABLED,
18+
MEMPOOL_REJECTED,
19+
MEMPOOL_ERROR,
20+
INVALID_PSBT,
21+
PSBT_MISMATCH,
22+
SIGHASH_MISMATCH,
23+
24+
ERROR_COUNT
25+
};
26+
27+
#define TRANSACTION_ERR_LAST TransactionError::ERROR_COUNT
28+
29+
const char* TransactionErrorString(const TransactionError error);
30+
31+
/**
32+
* Broadcast a transaction
33+
*
34+
* @param[in] tx the transaction to broadcast
35+
* @param[out] &txid the txid of the transaction, if successfully broadcast
36+
* @param[out] &error reference to UniValue to fill with error info on failure
37+
* @param[out] &err_string reference to std::string to fill with error string if available
38+
* @param[in] allowhighfees whether to allow fees exceeding maxTxFee
39+
* return true on success, false on error (and fills in `error`)
40+
*/
41+
bool BroadcastTransaction(const CTransactionRef tx, uint256& txid, TransactionError& error, std::string& err_string, const bool allowhighfees = false, const bool bypass_limits = false);
1342

1443
#endif // BITCOIN_NODE_TRANSACTION_H

0 commit comments

Comments
 (0)