Merge 29016 via rpc_listmempooltxs-28+knots

This commit is contained in:
Luke Dashjr 2025-03-05 03:27:08 +00:00
commit 8bc551ae42
8 changed files with 160 additions and 1 deletions

View File

@ -268,6 +268,7 @@ BITCOIN_CORE_H = \
rpc/mempool.h \
rpc/mining.h \
rpc/protocol.h \
rpc/rawtransaction.h \
rpc/rawtransaction_util.h \
rpc/register.h \
rpc/request.h \

View File

@ -644,6 +644,45 @@ static bool rest_deploymentinfo(const std::any& context, HTTPRequest* req, const
}
static bool rest_mempool_transactions(const std::any& context, HTTPRequest* req, const std::string& str_uri_part)
{
if (!CheckWarmup(req))
return false;
std::string param;
const RESTResponseFormat rf = ParseDataFormat(param, str_uri_part);
if (param != "contents" && param != "info") {
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/mempool/transactions/<info|contents>.json");
}
const CTxMemPool* mempool = GetMemPool(context, req);
if (!mempool) return false;
switch (rf) {
case RESTResponseFormat::JSON: {
std::string str_json;
std::string raw_sequence_start;
const bool verbose = param == "contents";
try {
raw_sequence_start = req->GetQueryParameter("sequence_start").value_or("0");
} catch (const std::runtime_error& e) {
return RESTERR(req, HTTP_BAD_REQUEST, e.what());
}
const auto sequence_start{ToIntegral<uint64_t>(raw_sequence_start)};
str_json = MempoolTxsToJSON(*mempool, verbose, sequence_start.value()).write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, str_json);
return true;
}
default: {
return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
}
}
}
static bool rest_mempool(const std::any& context, HTTPRequest* req, const std::string& str_uri_part)
{
if (!CheckWarmup(req))
@ -1017,6 +1056,7 @@ static const struct {
{"/rest/blockfilterheaders/", rest_filter_header},
{"/rest/chaininfo", rest_chaininfo},
{"/rest/mempool/", rest_mempool},
{"/rest/mempool/transactions", rest_mempool_transactions},
{"/rest/headers/", rest_headers},
{"/rest/getutxos", rest_getutxos},
{"/rest/deploymentinfo/", rest_deploymentinfo},

View File

@ -333,6 +333,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "stop", 0, "wait" },
{ "addnode", 2, "v2transport" },
{ "addconnection", 2, "v2transport" },
{ "listmempooltransactions", 0, "start_sequence"},
{ "listmempooltransactions", 1, "verbose"},
};
// clang-format on

View File

@ -17,6 +17,8 @@
#include <policy/settings.h>
#include <primitives/transaction.h>
#include <rpc/mempool.h>
#include <rpc/rawtransaction.h>
#include <rpc/mempool.h>
#include <rpc/server.h>
#include <rpc/server_util.h>
#include <rpc/util.h>
@ -412,6 +414,100 @@ static RPCHelpMan maxmempool()
};
}
static RPCHelpMan listmempooltransactions()
{
return RPCHelpMan{"listmempooltransactions",
"\nReturns all transactions in the mempool. Can be filtered by mempool_sequence\n"
"\nAllows for syncing with current mempool entries via polling (not zmq).",
{
{"start_sequence", RPCArg::Type::NUM, RPCArg::Default{0}, "The mempool_sequence to start the results to. Defaults to 0 (zero, all transactions)."},
{"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
},
{
RPCResult{"for verbose = false",
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::NUM, "mempool_sequence", "The current max mempool sequence value."},
{RPCResult::Type::ARR, "txs", "",
{
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::NUM, "entry_sequence", "The mempool sequence value for this transaction entry."},
{RPCResult::Type::STR_HEX, "txid", "The transaction id"},
}},
}},
}},
RPCResult{"for verbose = true",
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::NUM, "mempool_sequence", "The current max mempool sequence value."},
{RPCResult::Type::ARR, "txs", "",
{
{RPCResult::Type::OBJ, "", "",
{
Cat<std::vector<RPCResult>>(
{
{RPCResult::Type::NUM, "entry_sequence", "The mempool sequence value for this transaction entry."},
},
DecodeTxDoc(/*txid_field_doc=*/"The transaction id of the mempool transaction")),
}},
}},
}},
},
RPCExamples{
HelpExampleCli("listmempooltransactions", "true")
+ HelpExampleRpc("listmempooltransactions", "true")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
uint64_t start_mempool_sequence = 0;
if (!request.params[0].isNull()) {
start_mempool_sequence = request.params[0].getInt<uint64_t>();
}
bool fVerbose = false;
if (!request.params[1].isNull())
fVerbose = request.params[1].get_bool();
return MempoolTxsToJSON(EnsureAnyMemPool(request.context), fVerbose, start_mempool_sequence);
},
};
}
UniValue MempoolTxsToJSON(const CTxMemPool& pool, bool verbose, uint64_t sequence_start)
{
uint64_t mempool_sequence;
LOCK(pool.cs);
mempool_sequence = pool.GetSequence();
UniValue o(UniValue::VOBJ);
o.pushKV("mempool_sequence", mempool_sequence);
UniValue a(UniValue::VARR);
for (const CTxMemPoolEntry& e : pool.mapTx) {
UniValue txentry(UniValue::VOBJ);
// We skip anything not requested.
if (e.GetSequence() < sequence_start)
continue;
txentry.pushKV("entry_sequence", e.GetSequence());
if (verbose) {
// We could also calculate fees etc for this transaction, but yolo.
TxToUniv(e.GetTx(), /*block_hash=*/uint256::ZERO, /*entry=*/txentry, /*include_hex=*/false);
} else {
txentry.pushKV("txid", e.GetTx().GetHash().ToString());
}
a.push_back(txentry);
}
o.pushKV("txs", a);
return o;
}
static RPCHelpMan getrawmempool()
{
return RPCHelpMan{"getrawmempool",
@ -1171,6 +1267,7 @@ void RegisterMempoolRPCCommands(CRPCTable& t)
{"blockchain", &savemempool},
{"blockchain", &maxmempool},
{"rawtransactions", &submitpackage},
{"rawtransactions", &listmempooltransactions},
};
for (const auto& c : commands) {
t.appendCommand(c.name, &c);

View File

@ -30,4 +30,7 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool, const std::optional<MempoolHi
/** Mempool to JSON */
UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose = false, bool include_mempool_sequence = false);
/** Mempool Txs to JSON */
UniValue MempoolTxsToJSON(const CTxMemPool& pool, bool verbose = false, uint64_t sequence_start = 0);
#endif // BITCOIN_RPC_MEMPOOL_H

View File

@ -24,6 +24,7 @@
#include <psbt.h>
#include <random.h>
#include <rpc/blockchain.h>
#include <rpc/rawtransaction.h>
#include <rpc/rawtransaction_util.h>
#include <rpc/server.h>
#include <rpc/server_util.h>
@ -99,7 +100,7 @@ static std::vector<RPCResult> ScriptPubKeyDoc() {
};
}
static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
{
return {
{RPCResult::Type::STR_HEX, "txid", txid_field_doc},

14
src/rpc/rawtransaction.h Normal file
View File

@ -0,0 +1,14 @@
// Copyright (c) 2017-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_RPC_RAWTRANSACTION_H
#define BITCOIN_RPC_RAWTRANSACTION_H
#include <string>
struct RPCResult;
std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc);
#endif // BITCOIN_RPC_RAWTRANSACTION_H

View File

@ -159,6 +159,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
"invalidateblock",
"joinpsbts",
"listbanned",
"listmempooltransactions",
"listprunelocks",
"logging",
"maxmempool",