Bitcoin Core 32.99.0
P2P Digital Currency
fees.cpp
Go to the documentation of this file.
1// Copyright (c) 2010 Satoshi Nakamoto
2// Copyright (c) 2009-present The Bitcoin Core developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include <rpc/register.h> // IWYU pragma: associated
7
8#include <common/messages.h>
9#include <core_io.h>
10#include <node/context.h>
11#include <policy/feerate.h>
15#include <rpc/protocol.h>
16#include <rpc/request.h>
17#include <rpc/server.h>
18#include <rpc/server_util.h>
19#include <rpc/util.h>
20#include <txmempool.h>
21#include <univalue.h>
22#include <util/check.h>
23#include <util/expected.h>
24#include <util/fees.h>
25#include <validationinterface.h>
26
27#include <algorithm>
28#include <array>
29#include <cmath>
30#include <map>
31#include <string>
32#include <string_view>
33#include <utility>
34#include <vector>
35
40
42{
43 return RPCMethod{
44 "estimatesmartfee",
45 "Estimates the approximate fee per kilobyte needed for a transaction to begin\n"
46 "confirmation within conf_target blocks if possible and return the number of blocks\n"
47 "for which the estimate is valid. Uses virtual transaction size as defined\n"
48 "in BIP 141 (witness data is discounted).\n",
49 {
50 {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
51 {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"economical"}, "The fee estimate mode.\n"
52 + FeeModesDetail(std::string("default mode will be used"))},
54 {
55 {"fee_rate_estimator", RPCArg::Type::STR, RPCArg::Default{"none"},
56 "Selects which fee rate estimator to use.\n"
57 "\"none\" returns the lower of the block policy and mempool estimates. If the mempool\n"
58 "estimate is unavailable, it returns that error instead of falling back to the block\n"
59 "policy estimate; use \"block_policy\" in that case to get the block policy estimate.\n"
60 "\"block_policy\" uses only the block policy fee rate estimator.\n"
61 "\"mempool_policy\" uses only the mempool fee rate estimator.\n"
62 "Unknown values are treated as \"none\"."},
63 {"verbosity", RPCArg::Type::NUM, RPCArg::Default{1},
64 "1 returns feerate or errors. 2 also returns \"mempool_health_statistics\"."},
65 },
66 },
67 },
70 {
71 {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB (only present if no errors were encountered)"},
72 {RPCResult::Type::STR, "estimator", /*optional=*/true, "the fee estimator used to produce the result (only present for successful estimates when fee_rate_estimator is \"none\")"},
73 {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
74 {
75 {RPCResult::Type::STR, "", "error"},
76 }},
77 {RPCResult::Type::NUM, "blocks", "the confirmation target in blocks for the returned fee rate estimate.\n"
78 "For the block policy fee rate estimator, this is the target the estimate was found at, clamped to at\n"
79 "least 2 and at most the estimator's maximum usable target. For the mempool fee rate\n"
80 "estimator, it is always 2."},
81 {RPCResult::Type::ARR, "mempool_health_statistics", /*optional=*/true, "Health statistics for the most recently mined blocks tracked by the mempool fee rate estimator (only present when verbosity >= 2)",
82 {
83 {RPCResult::Type::OBJ, "", "",
84 {
85 {RPCResult::Type::NUM, "block_height", "Block height"},
86 {RPCResult::Type::NUM, "block_weight", "Total weight of non-coinbase transactions in the block"},
87 {RPCResult::Type::NUM, "mempool_txs_weight", "Total weight of transactions removed from the mempool for this block"},
88 }},
89 }},
90 }},
92 HelpExampleCli("estimatesmartfee", "6") +
93 HelpExampleRpc("estimatesmartfee", "6")
94 },
95 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
96 {
97 FeeRateEstimatorManager& fee_estimator_man = EnsureAnyFeeEstimatorMan(request.context);
98 const NodeContext& node = EnsureAnyNodeContext(request.context);
99 const CTxMemPool& mempool = EnsureMemPool(node);
100
101 CHECK_NONFATAL(mempool.m_opts.signals)->SyncWithValidationInterfaceQueue();
102 unsigned int max_target = fee_estimator_man.MaximumTarget();
103 unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
104 FeeEstimateMode fee_mode;
105 if (!FeeModeFromString(self.Arg<std::string_view>("estimate_mode"), fee_mode)) {
107 }
108 const UniValue options{request.params[2].isNull() ? UniValue::VOBJ : request.params[2]};
109 RPCTypeCheckObj(options,
110 {
111 {"fee_rate_estimator", UniValueType(UniValue::VSTR)},
112 {"verbosity", UniValueType(UniValue::VNUM)},
113 }, /*fAllowNull=*/true, /*fStrict=*/true);
114 const auto fee_rate_estimator{FeeRateEstimatorTypeFromString(
115 options["fee_rate_estimator"].isNull() ? "none" : options["fee_rate_estimator"].get_str())};
116 bool conservative{fee_mode == FeeEstimateMode::CONSERVATIVE};
117 int verbosity{ParseVerbosity(options["verbosity"], /*default_verbosity=*/1, /*allow_bool=*/false)};
118 UniValue result(UniValue::VOBJ);
119 UniValue errors(UniValue::VARR);
120 const auto estimate{fee_estimator_man.GetFeeRateEstimate(fee_rate_estimator, conf_target, conservative)};
121 if (estimate) {
122 const CFeeRate min_mempool_feerate{mempool.GetMinFee()};
123 const CFeeRate min_relay_feerate{mempool.m_opts.min_relay_feerate};
124 const auto fee_rate{std::max({CFeeRate(estimate->feerate), min_mempool_feerate, min_relay_feerate})};
125 result.pushKV("feerate", ValueFromAmount(fee_rate.GetFeePerK()));
126 } else {
127 errors.push_back(estimate.error().reason);
128 result.pushKV("errors", std::move(errors));
129 }
130 if (estimate && fee_rate_estimator == FeeRateEstimatorType::NONE) {
131 result.pushKV("estimator", FeeRateEstimatorTypeToString(estimate->feerate_estimator));
132 }
133 const FeeRateEstimation& estimation{FeeRateEstimationRef(estimate)};
134 result.pushKV("blocks", estimation.returned_target);
135 if (verbosity >= 2) {
136 UniValue mempool_health_stats(UniValue::VARR);
137 const auto blocks_data = fee_estimator_man.MempoolPolicyEstimatorBlocksStats();
138 for (auto it = blocks_data.rbegin(); it != blocks_data.rend(); ++it) {
140 entry.pushKV("block_height", it->m_height);
141 entry.pushKV("block_weight", it->m_block_weight);
142 entry.pushKV("mempool_txs_weight", it->m_removed_block_txs_weight);
143 mempool_health_stats.push_back(std::move(entry));
144 }
145 result.pushKV("mempool_health_statistics", std::move(mempool_health_stats));
146 }
147 return result;
148 },
149 };
150}
151
152static std::vector<RPCResult> FeeRateBucketDoc(bool elide = false)
153{
154 auto fields = std::vector<RPCResult>{
155 {RPCResult::Type::NUM, "startrange", "start of feerate range"},
156 {RPCResult::Type::NUM, "endrange", "end of feerate range"},
157 {RPCResult::Type::NUM, "withintarget", "number of txs over history horizon in the feerate range that were confirmed within target"},
158 {RPCResult::Type::NUM, "totalconfirmed", "number of txs over history horizon in the feerate range that were confirmed at any point"},
159 {RPCResult::Type::NUM, "inmempool", "current number of txs in mempool in the feerate range unconfirmed for at least target blocks"},
160 {RPCResult::Type::NUM, "leftmempool", "number of txs over history horizon in the feerate range that left mempool unconfirmed after target"},
161 };
162 return elide ? ElideGroup(std::move(fields)) : fields;
163}
164
165static std::vector<RPCResult> FeeEstimateHorizonDoc(bool elide = false)
166{
167 auto fields = std::vector<RPCResult>{
168 {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB"},
169 {RPCResult::Type::NUM, "decay", "exponential decay (per block) for historical moving average of confirmation data"},
170 {RPCResult::Type::NUM, "scale", "The resolution of confirmation targets at this time horizon"},
171 {RPCResult::Type::OBJ, "pass", /*optional=*/true, "information about the lowest range of feerates to succeed in meeting the threshold", FeeRateBucketDoc()},
172 {RPCResult::Type::OBJ, "fail", /*optional=*/true, "information about the highest range of feerates to fail to meet the threshold", FeeRateBucketDoc(/*elide=*/true)},
173 {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
174 {
175 {RPCResult::Type::STR, "", "error"},
176 }},
177 };
178 return elide ? ElideGroup(std::move(fields)) : fields;
179}
180
182{
183 return RPCMethod{
184 "estimaterawfee",
185 "WARNING: This interface is unstable and may disappear or change!\n"
186 "\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
187 "implementation of fee estimation. The parameters it can be called with\n"
188 "and the results it returns will change if the internal implementation changes.\n"
189 "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
190 "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n"
191 "defined in BIP 141 (witness data is discounted).\n",
192 {
193 {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
194 {"threshold", RPCArg::Type::NUM, RPCArg::Default{0.95}, "The proportion of transactions in a given feerate range that must have been\n"
195 "confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
196 "lower buckets."},
197 },
198 RPCResult{
199 RPCResult::Type::OBJ, "", "Results are returned for any horizon which tracks blocks up to the confirmation target",
200 {
201 {RPCResult::Type::OBJ, "short", /*optional=*/true, "estimate for short time horizon",
203 {RPCResult::Type::OBJ, "medium", /*optional=*/true, "estimate for medium time horizon",
204 FeeEstimateHorizonDoc(/*elide=*/true)},
205 {RPCResult::Type::OBJ, "long", /*optional=*/true, "estimate for long time horizon",
206 FeeEstimateHorizonDoc(/*elide=*/true)},
207 }},
209 HelpExampleCli("estimaterawfee", "6 0.9")
210 },
211 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
212 {
213 FeeRateEstimatorManager& fee_estimator_man = EnsureAnyFeeEstimatorMan(request.context);
214 const NodeContext& node = EnsureAnyNodeContext(request.context);
215
216 CHECK_NONFATAL(node.validation_signals)->SyncWithValidationInterfaceQueue();
217 unsigned int max_target = fee_estimator_man.MaximumTarget();
218 unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
219 double threshold = 0.95;
220 if (!request.params[1].isNull()) {
221 threshold = request.params[1].get_real();
222 }
223 if (threshold < 0 || threshold > 1) {
224 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid threshold");
225 }
226
227 UniValue result(UniValue::VOBJ);
228
229 for (const FeeEstimateHorizon horizon : ALL_FEE_ESTIMATE_HORIZONS) {
230 CFeeRate feeRate;
231 EstimationResult buckets;
232
233 // Only output results for horizons which track the target
234 if (conf_target > fee_estimator_man.BlockPolicyHighestTargetTracked(horizon)) continue;
235
236 feeRate = fee_estimator_man.BlockPolicyEstimateRawFee(conf_target, threshold, horizon, &buckets);
237 UniValue horizon_result(UniValue::VOBJ);
238 UniValue errors(UniValue::VARR);
239 UniValue passbucket(UniValue::VOBJ);
240 passbucket.pushKV("startrange", round(buckets.pass.start));
241 passbucket.pushKV("endrange", round(buckets.pass.end));
242 passbucket.pushKV("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0);
243 passbucket.pushKV("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0);
244 passbucket.pushKV("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0);
245 passbucket.pushKV("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0);
246 UniValue failbucket(UniValue::VOBJ);
247 failbucket.pushKV("startrange", round(buckets.fail.start));
248 failbucket.pushKV("endrange", round(buckets.fail.end));
249 failbucket.pushKV("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0);
250 failbucket.pushKV("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0);
251 failbucket.pushKV("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0);
252 failbucket.pushKV("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0);
253
254 // CFeeRate(0) is used to indicate error as a return value from estimateRawFee
255 if (feeRate != CFeeRate(0)) {
256 horizon_result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
257 horizon_result.pushKV("decay", buckets.decay);
258 horizon_result.pushKV("scale", buckets.scale);
259 horizon_result.pushKV("pass", std::move(passbucket));
260 // buckets.fail.start == -1 indicates that all buckets passed, there is no fail bucket to output
261 if (buckets.fail.start != -1) horizon_result.pushKV("fail", std::move(failbucket));
262 } else {
263 // Output only information that is still meaningful in the event of error
264 horizon_result.pushKV("decay", buckets.decay);
265 horizon_result.pushKV("scale", buckets.scale);
266 horizon_result.pushKV("fail", std::move(failbucket));
267 errors.push_back("Insufficient data or no feerate found which meets threshold");
268 horizon_result.pushKV("errors", std::move(errors));
269 }
270 result.pushKV(StringForFeeEstimateHorizon(horizon), std::move(horizon_result));
271 }
272 return result;
273 },
274 };
275}
276
278{
279 static const CRPCCommand commands[]{
280 {"util", &estimatesmartfee},
281 {"hidden", &estimaterawfee},
282 };
283 for (const auto& c : commands) {
284 t.appendCommand(c.name, &c);
285 }
286}
constexpr auto ALL_FEE_ESTIMATE_HORIZONS
FeeEstimateHorizon
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:112
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
Definition: feerate.h:32
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
Definition: feerate.h:71
RPC command dispatcher.
Definition: server.h:89
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:187
CFeeRate GetMinFee(size_t sizelimit) const
Definition: txmempool.cpp:877
const Options m_opts
Definition: txmempool.h:301
Manages fee rate estimators.
Definition: estimator_man.h:31
unsigned int BlockPolicyHighestTargetTracked(FeeEstimateHorizon horizon) const
Returns the maximum supported confirmation target of block policy estimator.
virtual util::Expected< FeeRateEstimation, FeeRateEstimationError > GetFeeRateEstimate(int target, bool conservative) const
Get a fee rate estimate from the available fee rate estimators.
std::vector< MinedBlockStats > MempoolPolicyEstimatorBlocksStats() const
Returns per-block weight statistics for the last MEMPOOL_HEALTH_WINDOW_BLOCKS mined blocks.
virtual unsigned int MaximumTarget() const
Returns the maximum supported confirmation target from all fee rate estimators.
CFeeRate BlockPolicyEstimateRawFee(unsigned int target, double threshold, FeeEstimateHorizon horizon, EstimationResult *buckets) const
Delegate to the block policy estimator's estimateRawFee (used by the estimaterawfee RPC).
auto Arg(std::string_view key) const
Helper to get a required or default-valued request argument.
Definition: util.h:470
void push_back(UniValue val)
Definition: univalue.cpp:103
@ VOBJ
Definition: univalue.h:24
@ VSTR
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
@ VNUM
Definition: univalue.h:24
bool isNull() const
Definition: univalue.h:81
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:125
UniValue ValueFromAmount(const CAmount amount)
Definition: core_io.cpp:283
const std::string CURRENCY_UNIT
Definition: feerate.h:19
is a home for simple string functions returning descriptive messages that are used in RPC and GUI int...
std::string FeeModesDetail(std::string default_info)
Definition: messages.cpp:66
bool FeeModeFromString(std::string_view mode_string, FeeEstimateMode &fee_estimate_mode)
Definition: messages.cpp:85
std::string InvalidEstimateModeErrorMessage()
Definition: messages.cpp:80
Definition: messages.h:21
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:75
static RPCMethod estimaterawfee()
Definition: fees.cpp:181
static std::vector< RPCResult > FeeEstimateHorizonDoc(bool elide=false)
Definition: fees.cpp:165
static std::vector< RPCResult > FeeRateBucketDoc(bool elide=false)
Definition: fees.cpp:152
static RPCMethod estimatesmartfee()
Definition: fees.cpp:41
void RegisterFeeRPCCommands(CRPCTable &t)
Definition: fees.cpp:277
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:69
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:188
std::vector< RPCResult > ElideGroup(std::vector< RPCResult > fields, std::string summary)
Stamp elision onto an entire vector of RPCResult fields at once.
Definition: util.cpp:1436
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:206
int ParseVerbosity(const UniValue &arg, int default_verbosity, bool allow_bool)
Parses verbosity from provided UniValue.
Definition: util.cpp:88
unsigned int ParseConfirmTarget(const UniValue &value, unsigned int max_target)
Parse a confirm target option and raise an RPC error if it is invalid.
Definition: util.cpp:374
void RPCTypeCheckObj(const UniValue &o, const std::map< std::string, UniValueType > &typesExpected, bool fAllowNull, bool fStrict)
Definition: util.cpp:61
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:28
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:37
FeeRateEstimatorManager & EnsureAnyFeeEstimatorMan(const std::any &context)
Definition: server_util.cpp:98
A successful fee rate estimate returned by a fee rate estimator.
Definition: fees.h:46
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
Wrapper for UniValue::VType, which includes typeAny: Used to denote don't care type.
Definition: util.h:79
ValidationSignals * signals
CFeeRate min_relay_feerate
A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation)
NodeContext struct containing references to chain state and connection state.
Definition: context.h:59
std::string_view FeeRateEstimatorTypeToString(FeeRateEstimatorType feerate_estimator_type)
Definition: fees.cpp:12
FeeRateEstimatorType FeeRateEstimatorTypeFromString(std::string_view feerate_estimator_type)
Definition: fees.cpp:26
const FeeRateEstimation & FeeRateEstimationRef(const util::Expected< FeeRateEstimation, FeeRateEstimationError > &result LIFETIMEBOUND)
Return the estimation carried by a fee rate estimate result: the successful estimation,...
Definition: fees.h:87
FeeEstimateMode
Definition: fees.h:17
@ CONSERVATIVE
Force Fee rate estimator to return conservative estimates.