Skip to content

Commit

Permalink
rpc: create an rpc estimatesfeewithmempool
Browse files Browse the repository at this point in the history
Given a confirmation target, we use the mempool fee estimator
to  get the fee rate that a transaction will confirm in that target.

Co-authored-by: willcl-ark <[email protected]>
  • Loading branch information
ismaelsadeeq and willcl-ark committed Feb 21, 2024
1 parent 994b332 commit 994e1ed
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "estimatesmartfee", 0, "conf_target" },
{ "estimaterawfee", 0, "conf_target" },
{ "estimaterawfee", 1, "threshold" },
{ "estimatefeewithmempool", 0, "conf_target" },
{ "estimatefeewithmempool", 1, "force" },
{ "prioritisetransaction", 1, "dummy" },
{ "prioritisetransaction", 2, "fee_delta" },
{ "setban", 2, "bantime" },
Expand Down
55 changes: 55 additions & 0 deletions src/rpc/fees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <core_io.h>
#include <policy/feerate.h>
#include <policy/fees.h>
#include <policy/mempool_fees.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <rpc/server.h>
Expand All @@ -14,6 +15,7 @@
#include <txmempool.h>
#include <univalue.h>
#include <util/fees.h>
#include <validation.h>
#include <validationinterface.h>

#include <algorithm>
Expand Down Expand Up @@ -99,6 +101,58 @@ static RPCHelpMan estimatesmartfee()
};
}

static RPCHelpMan estimatefeewithmempool()
{
return RPCHelpMan{
"estimatefeewithmempool",
"\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"},
{"force", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Force run block-building algorithm, bypassing any cached values."},
},
RPCResult{
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::NUM, "feerate", /*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("estimatesfeewithmempool", "2") + HelpExampleRpc("estimatesfeewithmempool", "2")},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
MemPoolPolicyEstimator& fee_estimator = EnsureAnyMemPoolFeeEstimator(request.context);
const NodeContext& node = EnsureAnyNodeContext(request.context);
CTxMemPool& mempool = EnsureMemPool(node);
ChainstateManager& chainman = EnsureChainman(node);
Chainstate& chainstate = chainman.ActiveChainstate();
const unsigned int conf_target = request.params[0].getInt<unsigned int>();
bool force{false};
if (!request.params[1].isNull()) force = request.params[1].get_bool();
CFeeRate feeRate;
std::string err_message;
{
LOCK2(cs_main, mempool.cs);
feeRate = fee_estimator.EstimateFeeWithMemPool(chainstate, mempool, conf_target, force, err_message);
}
UniValue result(UniValue::VOBJ);
UniValue errors(UniValue::VARR);
if (feeRate != CFeeRate(0)) {
CFeeRate min_mempool_feerate{mempool.GetMinFee()};
CFeeRate min_relay_feerate{mempool.m_min_relay_feerate};
feeRate = std::max({feeRate, min_mempool_feerate, min_relay_feerate});
result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
} else {
errors.push_back(err_message.c_str());
result.pushKV("errors", errors);
}
return result;
},
};
}

static RPCHelpMan estimaterawfee()
{
return RPCHelpMan{"estimaterawfee",
Expand Down Expand Up @@ -222,6 +276,7 @@ void RegisterFeeRPCCommands(CRPCTable& t)
{
static const CRPCCommand commands[]{
{"util", &estimatesmartfee},
{"util", &estimatefeewithmempool},
{"hidden", &estimaterawfee},
};
for (const auto& c : commands) {
Expand Down
13 changes: 13 additions & 0 deletions src/rpc/server_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,19 @@ CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context)
return EnsureFeeEstimator(EnsureAnyNodeContext(context));
}

MemPoolPolicyEstimator& EnsureMemPoolFeeEstimator(const NodeContext& node)
{
if (!node.mempool_fee_estimator) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "MemPool based Fee estimation disabled");
}
return *node.mempool_fee_estimator;
}

MemPoolPolicyEstimator& EnsureAnyMemPoolFeeEstimator(const std::any& context)
{
return EnsureMemPoolFeeEstimator(EnsureAnyNodeContext(context));
}

CConnman& EnsureConnman(const NodeContext& node)
{
if (!node.connman) {
Expand Down
3 changes: 3 additions & 0 deletions src/rpc/server_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class AddrMan;
class ArgsManager;
class CBlockPolicyEstimator;
class CConnman;
class MemPoolPolicyEstimator;
class CTxMemPool;
class ChainstateManager;
class PeerManager;
Expand All @@ -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);
MemPoolPolicyEstimator& EnsureMemPoolFeeEstimator(const node::NodeContext& node);
MemPoolPolicyEstimator& EnsureAnyMemPoolFeeEstimator(const std::any& context);
CConnman& EnsureConnman(const node::NodeContext& node);
PeerManager& EnsurePeerman(const node::NodeContext& node);
AddrMan& EnsureAddrman(const node::NodeContext& node);
Expand Down

0 comments on commit 994e1ed

Please sign in to comment.