mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-11 22:50:59 +01:00
Merge #11742: rpc: Add testmempoolaccept
b55555d rpc: Add testmempoolaccept (MarcoFalke)
Pull request description:
To check if a single raw transaction makes it into the current transaction pool, one had to call `sendrawtransaction`. However, on success, this adds the transaction to the mempool with no easy way to undo.
The call `testmempoolaccept` is introduced to provide a way to solely check the result without changing the mempool state.
Tree-SHA512: 5afd9311190135cee8fc1f229c7d39bf893f1028f29e28d34f70df820198ff97b4bf86b41cbbd6e6c36a5c30073cefa92d541c74a4939c7a2a6fa283dfd41b63
This commit is contained in:
@@ -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"} },
|
||||
|
||||
Reference in New Issue
Block a user