15
15
#include < policy/rbf.h>
16
16
#include < policy/settings.h>
17
17
#include < primitives/transaction.h>
18
+ #include < rpc/mempool.h>
18
19
#include < rpc/server.h>
19
20
#include < rpc/server_util.h>
20
21
#include < rpc/util.h>
25
26
#include < util/strencodings.h>
26
27
#include < util/time.h>
27
28
29
+ #include < optional>
28
30
#include < utility>
29
31
30
32
using node::DumpMempool;
@@ -664,7 +666,7 @@ static RPCHelpMan gettxspendingprevout()
664
666
};
665
667
}
666
668
667
- UniValue MempoolInfoToJSON (const CTxMemPool& pool)
669
+ UniValue MempoolInfoToJSON (const CTxMemPool& pool, const std::optional<MempoolHistogramFeeRates>& histogram_floors )
668
670
{
669
671
// Make sure this call is atomic in the pool.
670
672
LOCK (pool.cs );
@@ -680,14 +682,64 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool)
680
682
ret.pushKV (" incrementalrelayfee" , ValueFromAmount (pool.m_opts .incremental_relay_feerate .GetFeePerK ()));
681
683
ret.pushKV (" unbroadcastcount" , uint64_t {pool.GetUnbroadcastTxs ().size ()});
682
684
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
+
683
729
return ret;
684
730
}
685
731
686
732
static RPCHelpMan getmempoolinfo ()
687
733
{
688
734
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
+ },
691
743
RPCResult{
692
744
RPCResult::Type::OBJ, " " , " " ,
693
745
{
@@ -702,14 +754,53 @@ static RPCHelpMan getmempoolinfo()
702
754
{RPCResult::Type::NUM, " incrementalrelayfee" , " minimum fee rate increment for mempool limiting or replacement in " + CURRENCY_UNIT + " /kvB" },
703
755
{RPCResult::Type::NUM, " unbroadcastcount" , " Current number of transactions that haven't passed initial broadcast yet" },
704
756
{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
+ }},
705
770
}},
706
771
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])" )
709
776
},
710
777
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
711
778
{
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);
713
804
},
714
805
};
715
806
}
0 commit comments