Skip to content

Commit c756042

Browse files
kiminuoluke-jr
authored andcommitted
Introduce fee histogram in getmempoolinfo RPC command
Co-authored-by: Jonas Schnelli <[email protected]> Co-authored-by: Jon Atack <[email protected]> Github-Pull: bitcoin#21422 Rebased-From: d242aa5
1 parent c6557a3 commit c756042

File tree

4 files changed

+108
-8
lines changed

4 files changed

+108
-8
lines changed

src/rest.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <validation.h>
3434

3535
#include <any>
36+
#include <optional>
3637
#include <vector>
3738

3839
#include <univalue.h>
@@ -686,7 +687,7 @@ static bool rest_mempool(const std::any& context, HTTPRequest* req, const std::s
686687
}
687688
str_json = MempoolToJSON(*mempool, verbose, mempool_sequence).write() + "\n";
688689
} else {
689-
str_json = MempoolInfoToJSON(*mempool).write() + "\n";
690+
str_json = MempoolInfoToJSON(*mempool, std::nullopt).write() + "\n";
690691
}
691692

692693
req->WriteHeader("Content-Type", "application/json");

src/rpc/client.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
250250
{ "getblockstats", 1, "stats" },
251251
{ "pruneblockchain", 0, "height" },
252252
{ "keypoolrefill", 0, "newsize" },
253+
{ "getmempoolinfo", 0, "fee_histogram" },
253254
{ "getrawmempool", 0, "verbose" },
254255
{ "getrawmempool", 1, "mempool_sequence" },
255256
{ "estimatesmartfee", 0, "conf_target" },

src/rpc/mempool.cpp

Lines changed: 97 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <policy/rbf.h>
1616
#include <policy/settings.h>
1717
#include <primitives/transaction.h>
18+
#include <rpc/mempool.h>
1819
#include <rpc/server.h>
1920
#include <rpc/server_util.h>
2021
#include <rpc/util.h>
@@ -25,6 +26,7 @@
2526
#include <util/strencodings.h>
2627
#include <util/time.h>
2728

29+
#include <optional>
2830
#include <utility>
2931

3032
using node::DumpMempool;
@@ -664,7 +666,7 @@ static RPCHelpMan gettxspendingprevout()
664666
};
665667
}
666668

667-
UniValue MempoolInfoToJSON(const CTxMemPool& pool)
669+
UniValue MempoolInfoToJSON(const CTxMemPool& pool, const std::optional<MempoolHistogramFeeRates>& histogram_floors)
668670
{
669671
// Make sure this call is atomic in the pool.
670672
LOCK(pool.cs);
@@ -680,14 +682,64 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool)
680682
ret.pushKV("incrementalrelayfee", ValueFromAmount(pool.m_opts.incremental_relay_feerate.GetFeePerK()));
681683
ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
682684
ret.pushKV("fullrbf", pool.m_opts.full_rbf);
685+
686+
if (histogram_floors) {
687+
const MempoolHistogramFeeRates& floors{histogram_floors.value()};
688+
689+
std::vector<uint64_t> sizes(floors.size(), 0);
690+
std::vector<uint64_t> count(floors.size(), 0);
691+
std::vector<CAmount> fees(floors.size(), 0);
692+
693+
for (const CTxMemPoolEntry& e : pool.mapTx) {
694+
const CAmount fee{e.GetFee()};
695+
const uint32_t size{uint32_t(e.GetTxSize())};
696+
const CAmount fee_rate{CFeeRate{fee, size}.GetFee(1)};
697+
698+
// Distribute fee rates
699+
for (size_t i = floors.size(); i-- > 0;) {
700+
if (fee_rate >= floors[i]) {
701+
sizes[i] += size;
702+
++count[i];
703+
fees[i] += fee;
704+
break;
705+
}
706+
}
707+
}
708+
709+
// Track total amount of available fees in fee rate groups
710+
CAmount total_fees = 0;
711+
UniValue groups(UniValue::VOBJ);
712+
for (size_t i = 0; i < floors.size(); ++i) {
713+
UniValue info_sub(UniValue::VOBJ);
714+
info_sub.pushKV("size", sizes.at(i));
715+
info_sub.pushKV("count", count.at(i));
716+
info_sub.pushKV("fees", fees.at(i));
717+
info_sub.pushKV("from", floors.at(i));
718+
719+
total_fees += fees.at(i);
720+
groups.pushKV(ToString(floors.at(i)), info_sub);
721+
}
722+
723+
UniValue info(UniValue::VOBJ);
724+
info.pushKV("fee_rate_groups", groups);
725+
info.pushKV("total_fees", total_fees);
726+
ret.pushKV("fee_histogram", info);
727+
}
728+
683729
return ret;
684730
}
685731

686732
static RPCHelpMan getmempoolinfo()
687733
{
688734
return RPCHelpMan{"getmempoolinfo",
689-
"Returns details on the active state of the TX memory pool.",
690-
{},
735+
"Returns details on the active state of the TX memory pool.\n",
736+
{
737+
{"fee_histogram", RPCArg::Type::ARR, RPCArg::Optional::OMITTED, "Fee statistics grouped by fee rate ranges",
738+
{
739+
{"fee_rate", RPCArg::Type::NUM, RPCArg::Optional::NO, "Fee rate (in " + CURRENCY_ATOM + "/vB) to group the fees by"},
740+
},
741+
},
742+
},
691743
RPCResult{
692744
RPCResult::Type::OBJ, "", "",
693745
{
@@ -702,14 +754,53 @@ static RPCHelpMan getmempoolinfo()
702754
{RPCResult::Type::NUM, "incrementalrelayfee", "minimum fee rate increment for mempool limiting or replacement in " + CURRENCY_UNIT + "/kvB"},
703755
{RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"},
704756
{RPCResult::Type::BOOL, "fullrbf", "True if the mempool accepts RBF without replaceability signaling inspection"},
757+
{RPCResult::Type::OBJ, "fee_histogram", /*optional=*/true, "",
758+
{
759+
{RPCResult::Type::OBJ_DYN, "fee_rate_groups", "",
760+
{
761+
{RPCResult::Type::OBJ, "<fee_rate_group>", "Fee rate group named by its lower bound (in " + CURRENCY_ATOM + "/vB), identical to the \"from\" field below",
762+
{
763+
{RPCResult::Type::NUM, "size", "Cumulative size of all transactions in the fee rate group (in vBytes)"},
764+
{RPCResult::Type::NUM, "count", "Number of transactions in the fee rate group"},
765+
{RPCResult::Type::NUM, "fees", "Cumulative fees of all transactions in the fee rate group (in " + CURRENCY_ATOM + ")"},
766+
{RPCResult::Type::NUM, "from", "Group contains transactions with fee rates equal or greater than this value (in " + CURRENCY_ATOM + "/vB)"},
767+
}}}},
768+
{RPCResult::Type::NUM, "total_fees", "Total available fees in mempool (in " + CURRENCY_ATOM + ")"},
769+
}},
705770
}},
706771
RPCExamples{
707-
HelpExampleCli("getmempoolinfo", "")
708-
+ HelpExampleRpc("getmempoolinfo", "")
772+
HelpExampleCli("getmempoolinfo", "") +
773+
HelpExampleCli("getmempoolinfo", R"("[0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 17, 20, 25, 30, 40, 50, 60, 70, 80, 100, 120, 140, 170, 200]")") +
774+
HelpExampleRpc("getmempoolinfo", "") +
775+
HelpExampleRpc("getmempoolinfo", R"([0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 17, 20, 25, 30, 40, 50, 60, 70, 80, 100, 120, 140, 170, 200])")
709776
},
710777
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
711778
{
712-
return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
779+
MempoolHistogramFeeRates histogram_floors;
780+
std::optional<MempoolHistogramFeeRates> histogram_floors_opt = std::nullopt;
781+
782+
if (!request.params[0].isNull()) {
783+
const UniValue histogram_floors_univalue = request.params[0].get_array();
784+
785+
if (histogram_floors_univalue.empty()) {
786+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid number of parameters");
787+
}
788+
789+
for (size_t i = 0; i < histogram_floors_univalue.size(); ++i) {
790+
int64_t value = histogram_floors_univalue[i].getInt<int64_t>();
791+
792+
if (value < 0) {
793+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Non-negative values are expected");
794+
} else if (i > 0 && histogram_floors.back() >= value) {
795+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Strictly increasing values are expected");
796+
}
797+
798+
histogram_floors.push_back(value);
799+
}
800+
histogram_floors_opt = std::optional<MempoolHistogramFeeRates>(std::move(histogram_floors));
801+
}
802+
803+
return MempoolInfoToJSON(EnsureAnyMemPool(request.context), histogram_floors_opt);
713804
},
714805
};
715806
}

src/rpc/mempool.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,18 @@
55
#ifndef BITCOIN_RPC_MEMPOOL_H
66
#define BITCOIN_RPC_MEMPOOL_H
77

8+
#include <consensus/amount.h>
9+
10+
#include <optional>
11+
#include <vector>
12+
813
class CTxMemPool;
914
class UniValue;
1015

16+
typedef std::vector<CAmount> MempoolHistogramFeeRates;
17+
1118
/** Mempool information to JSON */
12-
UniValue MempoolInfoToJSON(const CTxMemPool& pool);
19+
UniValue MempoolInfoToJSON(const CTxMemPool& pool, const std::optional<MempoolHistogramFeeRates>& histogram_floors);
1320

1421
/** Mempool to JSON */
1522
UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose = false, bool include_mempool_sequence = false);

0 commit comments

Comments
 (0)