diff options
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/rawtransaction.cpp | 120 | ||||
-rw-r--r-- | src/rpc/util.cpp | 28 | ||||
-rw-r--r-- | src/rpc/util.h | 4 |
3 files changed, 59 insertions, 93 deletions
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 1126fa3d2c..6ec05565e9 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> @@ -1052,8 +1051,6 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) }, }.ToString()); - std::promise<void> promise; - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}); // parse hex string from parameter @@ -1061,67 +1058,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) @@ -1334,7 +1281,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)); } @@ -1535,23 +1482,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); @@ -1592,33 +1532,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, |