aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc')
-rw-r--r--src/rpc/rawtransaction.cpp120
-rw-r--r--src/rpc/util.cpp28
-rw-r--r--src/rpc/util.h4
3 files changed, 59 insertions, 93 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index c2f0c73851..7fe73e56da 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -13,10 +13,11 @@
#include <key_io.h>
#include <keystore.h>
#include <merkleblock.h>
-#include <net.h>
+#include <node/transaction.h>
#include <policy/policy.h>
#include <policy/rbf.h>
#include <primitives/transaction.h>
+#include <psbt.h>
#include <rpc/rawtransaction.h>
#include <rpc/server.h>
#include <rpc/util.h>
@@ -24,13 +25,11 @@
#include <script/script_error.h>
#include <script/sign.h>
#include <script/standard.h>
-#include <txmempool.h>
#include <uint256.h>
#include <util/strencodings.h>
#include <validation.h>
#include <validationinterface.h>
-#include <future>
#include <stdint.h>
#include <univalue.h>
@@ -1041,8 +1040,6 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
},
}.ToString());
- std::promise<void> promise;
-
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL});
// parse hex string from parameter
@@ -1050,67 +1047,17 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request)
if (!DecodeHexTx(mtx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
- const uint256& hashTx = tx->GetHash();
-
- CAmount nMaxRawTxFee = maxTxFee;
- if (!request.params[1].isNull() && request.params[1].get_bool())
- nMaxRawTxFee = 0;
- { // cs_main scope
- LOCK(cs_main);
- CCoinsViewCache &view = *pcoinsTip;
- bool fHaveChain = false;
- for (size_t o = 0; !fHaveChain && o < tx->vout.size(); o++) {
- const Coin& existingCoin = view.AccessCoin(COutPoint(hashTx, o));
- fHaveChain = !existingCoin.IsSpent();
+ bool allowhighfees = false;
+ if (!request.params[1].isNull()) allowhighfees = request.params[1].get_bool();
+ uint256 txid;
+ TransactionError err;
+ std::string err_string;
+ if (!BroadcastTransaction(tx, txid, err, err_string, allowhighfees)) {
+ throw JSONRPCTransactionError(err, err_string);
}
- bool fHaveMempool = mempool.exists(hashTx);
- if (!fHaveMempool && !fHaveChain) {
- // push to local node and sync with wallets
- CValidationState state;
- bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
- nullptr /* plTxnReplaced */, false /* bypass_limits */, nMaxRawTxFee)) {
- if (state.IsInvalid()) {
- throw JSONRPCError(RPC_TRANSACTION_REJECTED, FormatStateMessage(state));
- } else {
- if (fMissingInputs) {
- throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs");
- }
- throw JSONRPCError(RPC_TRANSACTION_ERROR, FormatStateMessage(state));
- }
- } else {
- // If wallet is enabled, ensure that the wallet has been made aware
- // of the new transaction prior to returning. This prevents a race
- // where a user might call sendrawtransaction with a transaction
- // to/from their wallet, immediately call some wallet RPC, and get
- // a stale result because callbacks have not yet been processed.
- CallFunctionInValidationInterfaceQueue([&promise] {
- promise.set_value();
- });
- }
- } else if (fHaveChain) {
- throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain");
- } else {
- // Make sure we don't block forever if re-sending
- // a transaction already in mempool.
- promise.set_value();
- }
-
- } // cs_main
-
- promise.get_future().wait();
-
- if(!g_connman)
- throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- CInv inv(MSG_TX, hashTx);
- g_connman->ForEachNode([&inv](CNode* pnode)
- {
- pnode->PushInventory(inv);
- });
-
- return hashTx.GetHex();
+ return txid.GetHex();
}
static UniValue testmempoolaccept(const JSONRPCRequest& request)
@@ -1323,7 +1270,7 @@ UniValue decodepsbt(const JSONRPCRequest& request)
// Unserialize the transactions
PartiallySignedTransaction psbtx;
std::string error;
- if (!DecodePSBT(psbtx, request.params[0].get_str(), error)) {
+ if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
@@ -1524,23 +1471,16 @@ UniValue combinepsbt(const JSONRPCRequest& request)
for (unsigned int i = 0; i < txs.size(); ++i) {
PartiallySignedTransaction psbtx;
std::string error;
- if (!DecodePSBT(psbtx, txs[i].get_str(), error)) {
+ if (!DecodeBase64PSBT(psbtx, txs[i].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
psbtxs.push_back(psbtx);
}
- PartiallySignedTransaction merged_psbt(psbtxs[0]); // Copy the first one
-
- // Merge
- for (auto it = std::next(psbtxs.begin()); it != psbtxs.end(); ++it) {
- if (*it != merged_psbt) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "PSBTs do not refer to the same transactions.");
- }
- merged_psbt.Merge(*it);
- }
- if (!merged_psbt.IsSane()) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Merged PSBT is inconsistent");
+ PartiallySignedTransaction merged_psbt;
+ TransactionError error;
+ if (!CombinePSBTs(merged_psbt, error, psbtxs)) {
+ throw JSONRPCTransactionError(error);
}
UniValue result(UniValue::VOBJ);
@@ -1581,33 +1521,27 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
// Unserialize the transactions
PartiallySignedTransaction psbtx;
std::string error;
- if (!DecodePSBT(psbtx, request.params[0].get_str(), error)) {
+ if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
}
- // Finalize input signatures -- in case we have partial signatures that add up to a complete
- // signature, but have not combined them yet (e.g. because the combiner that created this
- // PartiallySignedTransaction did not understand them), this will combine them into a final
- // script.
- bool complete = true;
- for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
- complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, SIGHASH_ALL);
- }
+ bool extract = request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool());
+
+ CMutableTransaction mtx;
+ bool complete = FinalizeAndExtractPSBT(psbtx, mtx);
UniValue result(UniValue::VOBJ);
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
- bool extract = request.params[1].isNull() || (!request.params[1].isNull() && request.params[1].get_bool());
+ std::string result_str;
+
if (complete && extract) {
- CMutableTransaction mtx(*psbtx.tx);
- for (unsigned int i = 0; i < mtx.vin.size(); ++i) {
- mtx.vin[i].scriptSig = psbtx.inputs[i].final_script_sig;
- mtx.vin[i].scriptWitness = psbtx.inputs[i].final_script_witness;
- }
ssTx << mtx;
- result.pushKV("hex", HexStr(ssTx.str()));
+ result_str = HexStr(ssTx.str());
+ result.pushKV("hex", result_str);
} else {
ssTx << psbtx;
- result.pushKV("psbt", EncodeBase64(ssTx.str()));
+ result_str = EncodeBase64(ssTx.str());
+ result.pushKV("psbt", result_str);
}
result.pushKV("complete", complete);
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index ee7f3ca0dc..023b4b6746 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -141,6 +141,34 @@ unsigned int ParseConfirmTarget(const UniValue& value)
return (unsigned int)target;
}
+RPCErrorCode RPCErrorFromTransactionError(TransactionError terr)
+{
+ switch (terr) {
+ case TransactionError::MEMPOOL_REJECTED:
+ return RPC_TRANSACTION_REJECTED;
+ case TransactionError::ALREADY_IN_CHAIN:
+ return RPC_TRANSACTION_ALREADY_IN_CHAIN;
+ case TransactionError::P2P_DISABLED:
+ return RPC_CLIENT_P2P_DISABLED;
+ case TransactionError::INVALID_PSBT:
+ case TransactionError::PSBT_MISMATCH:
+ return RPC_INVALID_PARAMETER;
+ case TransactionError::SIGHASH_MISMATCH:
+ return RPC_DESERIALIZATION_ERROR;
+ default: break;
+ }
+ return RPC_TRANSACTION_ERROR;
+}
+
+UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string)
+{
+ if (err_string.length() > 0) {
+ return JSONRPCError(RPCErrorFromTransactionError(terr), err_string);
+ } else {
+ return JSONRPCError(RPCErrorFromTransactionError(terr), TransactionErrorString(terr));
+ }
+}
+
struct Section {
Section(const std::string& left, const std::string& right)
: m_left{left}, m_right{right} {}
diff --git a/src/rpc/util.h b/src/rpc/util.h
index d895e99c7e..1c9ddcdf44 100644
--- a/src/rpc/util.h
+++ b/src/rpc/util.h
@@ -5,6 +5,7 @@
#ifndef BITCOIN_RPC_UTIL_H
#define BITCOIN_RPC_UTIL_H
+#include <node/transaction.h>
#include <pubkey.h>
#include <script/standard.h>
#include <univalue.h>
@@ -33,6 +34,9 @@ UniValue DescribeAddress(const CTxDestination& dest);
//! Parse a confirm target option and raise an RPC error if it is invalid.
unsigned int ParseConfirmTarget(const UniValue& value);
+RPCErrorCode RPCErrorFromTransactionError(TransactionError terr);
+UniValue JSONRPCTransactionError(TransactionError terr, const std::string& err_string = "");
+
struct RPCArg {
enum class Type {
OBJ,