Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
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 <util/fees.h>
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/register.h> // IWYU pragma: associated
17#include <rpc/request.h>
18#include <rpc/server.h>
19#include <rpc/server_util.h>
20#include <rpc/util.h>
21#include <txmempool.h>
22#include <univalue.h>
23#include <util/check.h>
24#include <util/expected.h>
25#include <validationinterface.h>
26
27#include <algorithm>
28#include <array>
29#include <cmath>
30#include <map>
31#include <optional>
32#include <string>
33#include <string_view>
34#include <utility>
35#include <vector>
36
41
43{
44 return RPCMethod{
45 "estimatesmartfee",
46 "Estimates the approximate fee per kilobyte needed for a transaction to begin\n"
47 "confirmation within conf_target blocks if possible and return the number of blocks\n"
48 "for which the estimate is valid. Uses virtual transaction size as defined\n"
49 "in BIP 141 (witness data is discounted).\n",
50 {
51 {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
52 {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"economical"}, "The fee estimate mode.\n"
53 + FeeModesDetail(std::string("default mode will be used"))},
55 {
56 {"fee_rate_estimator", RPCArg::Type::STR, RPCArg::Default{"auto"},
57 "Selects which fee rate estimator to use.\n"
58 "\"auto\" (the default) combines both estimators, returning the lower of the block policy and\n"
59 "mempool fee rate estimates. If the mempool fee rate estimator cannot produce an estimate, the\n"
60 "block policy fee rate estimate is returned instead. An error is returned only if the block\n"
61 "policy fee rate estimate is unavailable.\n"
62 "\"block_policy\" uses only the block policy fee rate estimator.\n"
63 "\"mempool_policy\" uses only the mempool fee rate estimator."},
64 {"verbosity", RPCArg::Type::NUM, RPCArg::Default{1},
65 "1 returns feerate or errors. 2 also returns \"mempool_health_statistics\"."},
66 },
67 },
68 },
71 {
72 {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB (only present if no errors were encountered)"},
73 {RPCResult::Type::STR, "estimator", /*optional=*/true, "the fee estimator used to produce the result (only present for successful estimates when fee_rate_estimator is \"auto\")"},
74 {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
75 {
76 {RPCResult::Type::STR, "", "error"},
77 }},
78 {RPCResult::Type::NUM, "blocks", "the confirmation target in blocks for the returned fee rate estimate.\n"
79 "For the block policy fee rate estimator, this is the target the estimate was found at, clamped to at\n"
80 "least 2 and at most the estimator's maximum usable target. For the mempool fee rate\n"
81 "estimator, it is always 2."},
82 {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)",
83 {
84 {RPCResult::Type::OBJ, "", "",
85 {
86 {RPCResult::Type::NUM, "block_height", "Block height"},
87 {RPCResult::Type::NUM, "block_weight", "Total weight of non-coinbase transactions in the block"},
88 {RPCResult::Type::NUM, "mempool_txs_weight", "Total weight of transactions removed from the mempool for this block"},
89 }},
90 }},
91 }},
93 HelpExampleCli("estimatesmartfee", "6") +
94 HelpExampleRpc("estimatesmartfee", "6")
95 },
96 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
97 {
98 FeeRateEstimatorManager& fee_estimator_man = EnsureAnyFeeEstimatorMan(request.context);
99 const NodeContext& node = EnsureAnyNodeContext(request.context);
100 const CTxMemPool& mempool = EnsureMemPool(node);
101
102 CHECK_NONFATAL(mempool.m_opts.signals)->SyncWithValidationInterfaceQueue();
103 unsigned int max_target = fee_estimator_man.MaximumTarget();
104 unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
106 if (!FeeModeFromString(self.Arg<std::string_view>("estimate_mode"), fee_mode)) {
107 throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage());
108 }
109 const UniValue options{request.params[2].isNull() ? UniValue::VOBJ : request.params[2]};
110 RPCTypeCheckObj(options,
111 {
112 {"fee_rate_estimator", UniValueType(UniValue::VSTR)},
113 {"verbosity", UniValueType(UniValue::VNUM)},
114 }, /*fAllowNull=*/true, /*fStrict=*/true);
116 options["fee_rate_estimator"].isNull() ? "auto" : options["fee_rate_estimator"].get_str())};
118 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid fee_rate_estimator parameter, must be one of: \"auto\", \"block_policy\", \"mempool_policy\"");
119 }
122 int verbosity{ParseVerbosity(options["verbosity"], /*default_verbosity=*/1, /*allow_bool=*/false)};
123 UniValue result(UniValue::VOBJ);
126 if (estimate) {
127 const CFeeRate min_mempool_feerate{mempool.GetMinFee()};
128 const CFeeRate min_relay_feerate{mempool.m_opts.min_relay_feerate};
129 const auto fee_rate{std::max({CFeeRate(estimate->feerate), min_mempool_feerate, min_relay_feerate})};
130 result.pushKV("feerate", ValueFromAmount(fee_rate.GetFeePerK()));
131 } else {
132 errors.push_back(estimate.error().reason);
133 result.pushKV("errors", std::move(errors));
134 }
136 result.pushKV("estimator", FeeRateEstimatorTypeToString(estimate->feerate_estimator));
137 }
139 result.pushKV("blocks", estimation.returned_target);
140 if (verbosity >= 2) {
142 const auto blocks_data = fee_estimator_man.MempoolPolicyEstimatorBlocksStats();
143 for (auto it = blocks_data.rbegin(); it != blocks_data.rend(); ++it) {
145 entry.pushKV("block_height", it->m_height);
146 entry.pushKV("block_weight", it->m_block_weight);
147 entry.pushKV("mempool_txs_weight", it->m_removed_block_txs_weight);
148 mempool_health_stats.push_back(std::move(entry));
149 }
150 result.pushKV("mempool_health_statistics", std::move(mempool_health_stats));
151 }
152 return result;
153 },
154 };
155}
156
157static std::vector<RPCResult> FeeRateBucketDoc(bool elide = false)
158{
159 auto fields = std::vector<RPCResult>{
160 {RPCResult::Type::NUM, "startrange", "start of feerate range"},
161 {RPCResult::Type::NUM, "endrange", "end of feerate range"},
162 {RPCResult::Type::NUM, "withintarget", "number of txs over history horizon in the feerate range that were confirmed within target"},
163 {RPCResult::Type::NUM, "totalconfirmed", "number of txs over history horizon in the feerate range that were confirmed at any point"},
164 {RPCResult::Type::NUM, "inmempool", "current number of txs in mempool in the feerate range unconfirmed for at least target blocks"},
165 {RPCResult::Type::NUM, "leftmempool", "number of txs over history horizon in the feerate range that left mempool unconfirmed after target"},
166 };
167 return elide ? ElideGroup(std::move(fields)) : fields;
168}
169
170static std::vector<RPCResult> FeeEstimateHorizonDoc(bool elide = false)
171{
172 auto fields = std::vector<RPCResult>{
173 {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB"},
174 {RPCResult::Type::NUM, "decay", "exponential decay (per block) for historical moving average of confirmation data"},
175 {RPCResult::Type::NUM, "scale", "The resolution of confirmation targets at this time horizon"},
176 {RPCResult::Type::OBJ, "pass", /*optional=*/true, "information about the lowest range of feerates to succeed in meeting the threshold", FeeRateBucketDoc()},
177 {RPCResult::Type::OBJ, "fail", /*optional=*/true, "information about the highest range of feerates to fail to meet the threshold", FeeRateBucketDoc(/*elide=*/true)},
178 {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
179 {
180 {RPCResult::Type::STR, "", "error"},
181 }},
182 };
183 return elide ? ElideGroup(std::move(fields)) : fields;
184}
185
187{
188 return RPCMethod{
189 "estimaterawfee",
190 "WARNING: This interface is unstable and may disappear or change!\n"
191 "\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
192 "implementation of fee estimation. The parameters it can be called with\n"
193 "and the results it returns will change if the internal implementation changes.\n"
194 "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
195 "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n"
196 "defined in BIP 141 (witness data is discounted).\n",
197 {
198 {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
199 {"threshold", RPCArg::Type::NUM, RPCArg::Default{0.95}, "The proportion of transactions in a given feerate range that must have been\n"
200 "confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
201 "lower buckets."},
202 },
203 RPCResult{
204 RPCResult::Type::OBJ, "", "Results are returned for any horizon which tracks blocks up to the confirmation target",
205 {
206 {RPCResult::Type::OBJ, "short", /*optional=*/true, "estimate for short time horizon",
208 {RPCResult::Type::OBJ, "medium", /*optional=*/true, "estimate for medium time horizon",
209 FeeEstimateHorizonDoc(/*elide=*/true)},
210 {RPCResult::Type::OBJ, "long", /*optional=*/true, "estimate for long time horizon",
211 FeeEstimateHorizonDoc(/*elide=*/true)},
212 }},
214 HelpExampleCli("estimaterawfee", "6 0.9")
215 },
216 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
217 {
218 FeeRateEstimatorManager& fee_estimator_man = EnsureAnyFeeEstimatorMan(request.context);
219 const NodeContext& node = EnsureAnyNodeContext(request.context);
220
221 CHECK_NONFATAL(node.validation_signals)->SyncWithValidationInterfaceQueue();
222 unsigned int max_target = fee_estimator_man.MaximumTarget();
223 unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
224 const double threshold{self.Arg<double>("threshold")};
226 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid threshold");
227 }
228
229 UniValue result(UniValue::VOBJ);
230
233 EstimationResult buckets;
234
235 // Only output results for horizons which track the target
236 if (conf_target > fee_estimator_man.BlockPolicyHighestTargetTracked(horizon)) continue;
237
238 feeRate = fee_estimator_man.BlockPolicyEstimateRawFee(conf_target, threshold, horizon, &buckets);
242 passbucket.pushKV("startrange", round(buckets.pass.start));
243 passbucket.pushKV("endrange", round(buckets.pass.end));
244 passbucket.pushKV("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0);
245 passbucket.pushKV("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0);
246 passbucket.pushKV("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0);
247 passbucket.pushKV("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0);
249 failbucket.pushKV("startrange", round(buckets.fail.start));
250 failbucket.pushKV("endrange", round(buckets.fail.end));
251 failbucket.pushKV("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0);
252 failbucket.pushKV("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0);
253 failbucket.pushKV("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0);
254 failbucket.pushKV("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0);
255
256 // CFeeRate(0) is used to indicate error as a return value from estimateRawFee
257 if (feeRate != CFeeRate(0)) {
258 horizon_result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
259 horizon_result.pushKV("decay", buckets.decay);
260 horizon_result.pushKV("scale", buckets.scale);
261 horizon_result.pushKV("pass", std::move(passbucket));
262 // buckets.fail.start == -1 indicates that all buckets passed, there is no fail bucket to output
263 if (buckets.fail.start != -1) horizon_result.pushKV("fail", std::move(failbucket));
264 } else {
265 // Output only information that is still meaningful in the event of error
266 horizon_result.pushKV("decay", buckets.decay);
267 horizon_result.pushKV("scale", buckets.scale);
268 horizon_result.pushKV("fail", std::move(failbucket));
269 errors.push_back("Insufficient data or no feerate found which meets threshold");
270 horizon_result.pushKV("errors", std::move(errors));
271 }
273 }
274 return result;
275 },
276 };
277}
278
280{
281 static const CRPCCommand commands[]{
282 {"util", &estimatesmartfee},
283 {"hidden", &estimaterawfee},
284 };
285 for (const auto& c : commands) {
286 t.appendCommand(c.name, &c);
287 }
288}
constexpr auto ALL_FEE_ESTIMATE_HORIZONS
#define CHECK_NONFATAL(condition)
Identity function.
Definition check.h:115
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
Definition feerate.h:32
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:188
CFeeRate GetMinFee(size_t sizelimit) const
const Options m_opts
Definition txmempool.h:302
Manages fee rate estimators.
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 combined 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).
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
Home for simple string functions returning descriptive messages.
std::string FeeModesDetail(std::string default_info)
Definition messages.cpp:77
bool FeeModeFromString(std::string_view mode_string, FeeEstimateMode &fee_estimate_mode)
Definition messages.cpp:96
std::string InvalidEstimateModeErrorMessage()
Definition messages.cpp:91
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
UniValue JSONRPCError(int code, const std::string &message)
Definition request.cpp:75
static RPCMethod estimaterawfee()
Definition fees.cpp:186
static std::vector< RPCResult > FeeEstimateHorizonDoc(bool elide=false)
Definition fees.cpp:170
static std::vector< RPCResult > FeeRateBucketDoc(bool elide=false)
Definition fees.cpp:157
static RPCMethod estimatesmartfee()
Definition fees.cpp:42
void RegisterFeeRPCCommands(CRPCTable &t)
Definition fees.cpp:279
@ 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:189
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:1431
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition util.cpp:207
int ParseVerbosity(const UniValue &arg, int default_verbosity, bool allow_bool)
Parses verbosity from provided UniValue.
Definition util.cpp:89
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:375
void RPCTypeCheckObj(const UniValue &o, const std::map< std::string, UniValueType > &typesExpected, bool fAllowNull, bool fStrict)
Definition util.cpp:62
NodeContext & EnsureAnyNodeContext(const std::any &context)
CTxMemPool & EnsureMemPool(const NodeContext &node)
FeeRateEstimatorManager & EnsureAnyFeeEstimatorMan(const std::any &context)
A successful fee rate estimate returned by a fee rate estimator.
Definition fees.h:47
@ 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:57
std::string_view FeeRateEstimatorTypeToString(FeeRateEstimatorType feerate_estimator_type)
Definition fees.cpp:13
std::optional< FeeRateEstimatorType > FeeRateEstimatorTypeFromString(std::string_view feerate_estimator_type)
Definition fees.cpp:27
FeeRateEstimatorType
Identifier for fee rate estimator.
Definition fees.h:37
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:88
FeeEstimateMode
Definition fees.h:18
@ CONSERVATIVE
Force Fee rate estimator to return conservative estimates.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82