From a99e7edab22654b658589a1464b6828536ff33a7 Mon Sep 17 00:00:00 2001 From: ismaelsadeeq Date: Fri, 18 Aug 2023 09:00:37 +0100 Subject: [PATCH] rpc: create an rpc `estimatefeewithforecasters` Given a confirmation target, we use fee estimator module that call all available fee estimator forcasters and return the fee rate with highest confidence level that if a transaction use will likely confirm in a given confirmation target. Co-authored-by: willcl-ark --- src/rpc/client.cpp | 1 + src/rpc/fees.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/rpc/server_util.cpp | 13 +++++++++++++ src/rpc/server_util.h | 3 +++ 4 files changed, 57 insertions(+) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index b8dc148eaea2d0..a31c77d1174ad8 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -252,6 +252,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "estimatesmartfee", 0, "conf_target" }, { "estimaterawfee", 0, "conf_target" }, { "estimaterawfee", 1, "threshold" }, + { "estimatefeewithforecasters", 0, "conf_target" }, { "prioritisetransaction", 1, "dummy" }, { "prioritisetransaction", 2, "fee_delta" }, { "setban", 2, "bantime" }, diff --git a/src/rpc/fees.cpp b/src/rpc/fees.cpp index f3345b4f1ca288..d0425526ba5787 100644 --- a/src/rpc/fees.cpp +++ b/src/rpc/fees.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include @@ -96,6 +98,43 @@ static RPCHelpMan estimatesmartfee() }; } +static RPCHelpMan estimatefeewithforecasters() +{ + return RPCHelpMan{ + "estimatefeewithforecasters", + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within conf_target blocks if possible Uses virtual transaction size as defined\n" + "in BIP 141 (witness data is discounted). By default caches values for 30 seconds to avoid\n" + "repeatedly running expensive block-building algorithm.\n", + { + {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks"}, + }, + RPCResult{ + RPCResult::Type::OBJ, "", "", + { + {RPCResult::Type::NUM, "Fee rate estimate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB (only present if no errors were encountered)"}, + {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)", + {{RPCResult::Type::STR, "", "error"},} + }, + }}, + RPCExamples{HelpExampleCli("estimatefeewithforecasters", "2") + HelpExampleRpc("estimatefeewithforecasters", "2")}, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + FeeEstimator& fee_estimator = EnsureAnyFeeForecasters(request.context); + const unsigned int conf_target = request.params[0].getInt(); + CFeeRate fee_estimate = fee_estimator.getFeeEstimateForecast(conf_target); + UniValue result(UniValue::VOBJ); + UniValue errors(UniValue::VARR); + if (fee_estimate != CFeeRate(0)) { + result.pushKV("Fee rate estimate", ValueFromAmount(fee_estimate.GetFeePerK())); + } else { + errors.push_back("Failed to get estimate from forecasters"); + result.pushKV("errors", errors); + } + return result; + }, + }; +} + static RPCHelpMan estimaterawfee() { return RPCHelpMan{"estimaterawfee", @@ -220,6 +259,7 @@ void RegisterFeeRPCCommands(CRPCTable& t) { static const CRPCCommand commands[]{ {"util", &estimatesmartfee}, + {"util", &estimatefeewithforecasters}, {"hidden", &estimaterawfee}, }; for (const auto& c : commands) { diff --git a/src/rpc/server_util.cpp b/src/rpc/server_util.cpp index 136b95cd5528cf..b3a4758072f3b9 100644 --- a/src/rpc/server_util.cpp +++ b/src/rpc/server_util.cpp @@ -94,6 +94,19 @@ CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context) return EnsureFeeEstimator(EnsureAnyNodeContext(context)); } +FeeEstimator& EnsureFeeForecasters(const NodeContext& node) +{ + if (!node.fee_estimator) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee estimation disabled"); + } + return *node.fee_estimator; +} + +FeeEstimator& EnsureAnyFeeForecasters(const std::any& context) +{ + return EnsureFeeForecasters(EnsureAnyNodeContext(context)); +} + CConnman& EnsureConnman(const NodeContext& node) { if (!node.connman) { diff --git a/src/rpc/server_util.h b/src/rpc/server_util.h index a4a53166b4b61f..dea5b2ab8c9630 100644 --- a/src/rpc/server_util.h +++ b/src/rpc/server_util.h @@ -11,6 +11,7 @@ class AddrMan; class ArgsManager; class CBlockPolicyEstimator; class CConnman; +class FeeEstimator; class CTxMemPool; class ChainstateManager; class PeerManager; @@ -30,6 +31,8 @@ ChainstateManager& EnsureChainman(const node::NodeContext& node); ChainstateManager& EnsureAnyChainman(const std::any& context); CBlockPolicyEstimator& EnsureFeeEstimator(const node::NodeContext& node); CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context); +FeeEstimator& EnsureFeeForecasters(const node::NodeContext& node); +FeeEstimator& EnsureAnyFeeForecasters(const std::any& context); CConnman& EnsureConnman(const node::NodeContext& node); PeerManager& EnsurePeerman(const node::NodeContext& node); AddrMan& EnsureAddrman(const node::NodeContext& node);