Skip to content

Commit 2452c6c

Browse files
committed
Merge #14978: Factor out PSBT utilities from RPCs for use in GUI code; related refactoring.
102faad Factor out combine / finalize / extract PSBT helpers (Glenn Willen) 78b9893 Remove op== on PSBTs; check compatibility in Merge (Glenn Willen) bd0dbe8 Switch away from exceptions in refactored tx code (Glenn Willen) c6c3d42 Move PSBT definitions and code to separate files (Glenn Willen) 81cd958 Factor BroadcastTransaction out of sendrawtransaction (Glenn Willen) c734aaa Split DecodePSBT into Base64 and Raw versions (Glenn Willen) 162ffef Add pf_invalid arg to std::string DecodeBase{32,64} (Glenn Willen) Pull request description: * Move most PSBT definitions into psbt.h. * Move most PSBT RPC utilities into psbt.{h,cpp}. * Move wallet-touching PSBT RPC utilities (FillPSBT) into wallet/psbtwallet.{h,cpp}. * Switch exceptions from JSONRPCError() to new PSBTException class. * Split DecodePSBT into DecodeBase64PSBT (old behavior) and DecodeRawPSBT. * Add one new version of DecodeBase64 utility in strencodings.h (and corresponding DecodeBase32 for completeness). * Factor BroadcastTransaction utility function out of sendrawtransaction RPC handler in rpc/rawtransaction.cpp Note: For those keeping score at home wondering why refactor, this is in anticipation of (and developed in parallel with) a change to actually introduce GUI use of all this stuff, which is already under development and working-ish. Tree-SHA512: 2197c448e657421f430943025357597e7b06c4c377d5d4b2622b9edea52a7193c48843dd731abb3a88ac4023a9c88d211991e0a9b740c22f2e1cbe72adefe390
2 parents 9c93f5d + 102faad commit 2452c6c

20 files changed

+1229
-929
lines changed

src/Makefile.am

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ BITCOIN_CORE_H = \
152152
netaddress.h \
153153
netbase.h \
154154
netmessagemaker.h \
155+
node/transaction.h \
155156
noui.h \
156157
optional.h \
157158
outputtype.h \
@@ -161,6 +162,7 @@ BITCOIN_CORE_H = \
161162
policy/rbf.h \
162163
pow.h \
163164
protocol.h \
165+
psbt.h \
164166
random.h \
165167
reverse_iterator.h \
166168
reverselock.h \
@@ -209,6 +211,7 @@ BITCOIN_CORE_H = \
209211
wallet/db.h \
210212
wallet/feebumper.h \
211213
wallet/fees.h \
214+
wallet/psbtwallet.h \
212215
wallet/rpcwallet.h \
213216
wallet/wallet.h \
214217
wallet/walletdb.h \
@@ -255,6 +258,7 @@ libbitcoin_server_a_SOURCES = \
255258
miner.cpp \
256259
net.cpp \
257260
net_processing.cpp \
261+
node/transaction.cpp \
258262
noui.cpp \
259263
outputtype.cpp \
260264
policy/fees.cpp \
@@ -308,6 +312,7 @@ libbitcoin_wallet_a_SOURCES = \
308312
wallet/feebumper.cpp \
309313
wallet/fees.cpp \
310314
wallet/init.cpp \
315+
wallet/psbtwallet.cpp \
311316
wallet/rpcdump.cpp \
312317
wallet/rpcwallet.cpp \
313318
wallet/wallet.cpp \
@@ -421,6 +426,7 @@ libbitcoin_common_a_SOURCES = \
421426
netaddress.cpp \
422427
netbase.cpp \
423428
policy/feerate.cpp \
429+
psbt.cpp \
424430
protocol.cpp \
425431
scheduler.cpp \
426432
script/descriptor.cpp \

src/core_io.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
3737
*/
3838
bool ParseHashStr(const std::string& strHex, uint256& result);
3939
std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
40-
NODISCARD bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error);
40+
41+
//! Decode a base64ed PSBT into a PartiallySignedTransaction
42+
NODISCARD bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
43+
//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction
44+
NODISCARD bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
4145
int ParseSighashString(const UniValue& sighash);
4246

4347
// core_write.cpp

src/core_read.cpp

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

55
#include <core_io.h>
66

7+
#include <psbt.h>
78
#include <primitives/block.h>
89
#include <primitives/transaction.h>
910
#include <script/script.h>
@@ -176,10 +177,20 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
176177
return true;
177178
}
178179

179-
bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
180+
bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
180181
{
181-
std::vector<unsigned char> tx_data = DecodeBase64(base64_tx.c_str());
182-
CDataStream ss_data(tx_data, SER_NETWORK, PROTOCOL_VERSION);
182+
bool invalid;
183+
std::string tx_data = DecodeBase64(base64_tx, &invalid);
184+
if (invalid) {
185+
error = "invalid base64";
186+
return false;
187+
}
188+
return DecodeRawPSBT(psbt, tx_data, error);
189+
}
190+
191+
bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data, std::string& error)
192+
{
193+
CDataStream ss_data(tx_data.data(), tx_data.data() + tx_data.size(), SER_NETWORK, PROTOCOL_VERSION);
183194
try {
184195
ss_data >> psbt;
185196
if (!ss_data.empty()) {

src/node/transaction.cpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright (c) 2010 Satoshi Nakamoto
2+
// Copyright (c) 2009-2018 The Bitcoin Core developers
3+
// Distributed under the MIT software license, see the accompanying
4+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
6+
#include <consensus/validation.h>
7+
#include <net.h>
8+
#include <txmempool.h>
9+
#include <validation.h>
10+
#include <validationinterface.h>
11+
#include <node/transaction.h>
12+
13+
#include <future>
14+
15+
const char* TransactionErrorString(const TransactionError err)
16+
{
17+
switch (err) {
18+
case TransactionError::OK:
19+
return "No error";
20+
case TransactionError::MISSING_INPUTS:
21+
return "Missing inputs";
22+
case TransactionError::ALREADY_IN_CHAIN:
23+
return "Transaction already in block chain";
24+
case TransactionError::P2P_DISABLED:
25+
return "Peer-to-peer functionality missing or disabled";
26+
case TransactionError::MEMPOOL_REJECTED:
27+
return "Transaction rejected by AcceptToMemoryPool";
28+
case TransactionError::MEMPOOL_ERROR:
29+
return "AcceptToMemoryPool failed";
30+
case TransactionError::INVALID_PSBT:
31+
return "PSBT is not sane";
32+
case TransactionError::PSBT_MISMATCH:
33+
return "PSBTs not compatible (different transactions)";
34+
case TransactionError::SIGHASH_MISMATCH:
35+
return "Specified sighash value does not match existing value";
36+
37+
case TransactionError::UNKNOWN_ERROR:
38+
default: break;
39+
}
40+
return "Unknown error";
41+
}
42+
43+
bool BroadcastTransaction(const CTransactionRef tx, uint256& hashTx, TransactionError& error, std::string& err_string, const bool allowhighfees)
44+
{
45+
std::promise<void> promise;
46+
hashTx = tx->GetHash();
47+
48+
CAmount nMaxRawTxFee = maxTxFee;
49+
if (allowhighfees)
50+
nMaxRawTxFee = 0;
51+
52+
{ // cs_main scope
53+
LOCK(cs_main);
54+
CCoinsViewCache &view = *pcoinsTip;
55+
bool fHaveChain = false;
56+
for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
57+
const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
58+
fHaveChain = !existingCoin.IsSpent();
59+
}
60+
bool fHaveMempool = mempool.exists(hashTx);
61+
if (!fHaveMempool && !fHaveChain) {
62+
// push to local node and sync with wallets
63+
CValidationState state;
64+
bool fMissingInputs;
65+
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
66+
nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) {
67+
if (state.IsInvalid()) {
68+
err_string = FormatStateMessage(state);
69+
error = TransactionError::MEMPOOL_REJECTED;
70+
return false;
71+
} else {
72+
if (fMissingInputs) {
73+
error = TransactionError::MISSING_INPUTS;
74+
return false;
75+
}
76+
err_string = FormatStateMessage(state);
77+
error = TransactionError::MEMPOOL_ERROR;
78+
return false;
79+
}
80+
} else {
81+
// If wallet is enabled, ensure that the wallet has been made aware
82+
// of the new transaction prior to returning. This prevents a race
83+
// where a user might call sendrawtransaction with a transaction
84+
// to/from their wallet, immediately call some wallet RPC, and get
85+
// a stale result because callbacks have not yet been processed.
86+
CallFunctionInValidationInterfaceQueue([&promise] {
87+
promise.set_value();
88+
});
89+
}
90+
} else if (fHaveChain) {
91+
error = TransactionError::ALREADY_IN_CHAIN;
92+
return false;
93+
} else {
94+
// Make sure we don't block forever if re-sending
95+
// a transaction already in mempool.
96+
promise.set_value();
97+
}
98+
99+
} // cs_main
100+
101+
promise.get_future().wait();
102+
103+
if(!g_connman) {
104+
error = TransactionError::P2P_DISABLED;
105+
return false;
106+
}
107+
108+
CInv inv(MSG_TX, hashTx);
109+
g_connman->ForEachNode([&inv](CNode* pnode)
110+
{
111+
pnode->PushInventory(inv);
112+
});
113+
114+
return true;
115+
}

src/node/transaction.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2017-2018 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+
#ifndef BITCOIN_NODE_TRANSACTION_H
6+
#define BITCOIN_NODE_TRANSACTION_H
7+
8+
#include <primitives/transaction.h>
9+
#include <uint256.h>
10+
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(CTransactionRef tx, uint256& txid, TransactionError& error, std::string& err_string, bool allowhighfees = false);
42+
43+
#endif // BITCOIN_NODE_TRANSACTION_H

0 commit comments

Comments
 (0)