diff options
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/client.cpp | 2 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 82 |
2 files changed, 84 insertions, 0 deletions
diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index e12685da65..01f932dbb4 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -103,6 +103,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "signrawtransactionwithkey", 2, "prevtxs" }, { "signrawtransactionwithwallet", 1, "prevtxs" }, { "sendrawtransaction", 1, "allowhighfees" }, + { "testmempoolaccept", 0, "rawtxs" }, + { "testmempoolaccept", 1, "allowhighfees" }, { "combinerawtransaction", 0, "txs" }, { "fundrawtransaction", 1, "options" }, { "fundrawtransaction", 2, "iswitness" }, diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 20bfd3f355..3247c61242 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1134,6 +1134,87 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) return hashTx.GetHex(); } +UniValue testmempoolaccept(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { + throw std::runtime_error( + // clang-format off + "testmempoolaccept [\"rawtxs\"] ( allowhighfees )\n" + "\nReturns if raw transaction (serialized, hex-encoded) would be accepted by mempool.\n" + "\nThis checks if the transaction violates the consensus or policy rules.\n" + "\nSee sendrawtransaction call.\n" + "\nArguments:\n" + "1. [\"rawtxs\"] (array, required) An array of hex strings of raw transactions.\n" + " Length must be one for now.\n" + "2. allowhighfees (boolean, optional, default=false) Allow high fees\n" + "\nResult:\n" + "[ (array) The result of the mempool acceptance test for each raw transaction in the input array.\n" + " Length is exactly one for now.\n" + " {\n" + " \"txid\" (string) The transaction hash in hex\n" + " \"allowed\" (boolean) If the mempool allows this tx to be inserted\n" + " \"reject-reason\" (string) Rejection string (only present when 'allowed' is false)\n" + " }\n" + "]\n" + "\nExamples:\n" + "\nCreate a transaction\n" + + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + + "Sign the transaction, and get back the hex\n" + + HelpExampleCli("signrawtransaction", "\"myhex\"") + + "\nTest acceptance of the transaction (signed hex)\n" + + HelpExampleCli("testmempoolaccept", "\"signedhex\"") + + "\nAs a json rpc call\n" + + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]") + // clang-format on + ); + } + + ObserveSafeMode(); + + RPCTypeCheck(request.params, {UniValue::VARR, UniValue::VBOOL}); + if (request.params[0].get_array().size() != 1) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Array must contain exactly one raw transaction for now"); + } + + CMutableTransaction mtx; + if (!DecodeHexTx(mtx, request.params[0].get_array()[0].get_str())) { + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + } + CTransactionRef tx(MakeTransactionRef(std::move(mtx))); + const uint256& tx_hash = tx->GetHash(); + + CAmount max_raw_tx_fee = ::maxTxFee; + if (!request.params[1].isNull() && request.params[1].get_bool()) { + max_raw_tx_fee = 0; + } + + UniValue result(UniValue::VARR); + UniValue result_0(UniValue::VOBJ); + result_0.pushKV("txid", tx_hash.GetHex()); + + CValidationState state; + bool missing_inputs; + bool test_accept_res; + { + LOCK(cs_main); + test_accept_res = AcceptToMemoryPool(mempool, state, std::move(tx), &missing_inputs, + nullptr /* plTxnReplaced */, false /* bypass_limits */, max_raw_tx_fee, /* test_accpet */ true); + } + result_0.pushKV("allowed", test_accept_res); + if (!test_accept_res) { + if (state.IsInvalid()) { + result_0.pushKV("reject-reason", strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); + } else if (missing_inputs) { + result_0.pushKV("reject-reason", "missing-inputs"); + } else { + result_0.pushKV("reject-reason", state.GetRejectReason()); + } + } + + result.push_back(std::move(result_0)); + return result; +} + static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- @@ -1145,6 +1226,7 @@ static const CRPCCommand commands[] = { "rawtransactions", "combinerawtransaction", &combinerawtransaction, {"txs"} }, { "rawtransactions", "signrawtransaction", &signrawtransaction, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ { "rawtransactions", "signrawtransactionwithkey", &signrawtransactionwithkey, {"hexstring","privkeys","prevtxs","sighashtype"} }, + { "rawtransactions", "testmempoolaccept", &testmempoolaccept, {"rawtxs","allowhighfees"} }, { "blockchain", "gettxoutproof", &gettxoutproof, {"txids", "blockhash"} }, { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} }, |