Bitcoin Core 31.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 <common/messages.h>
7#include <core_io.h>
8#include <node/context.h>
9#include <policy/feerate.h>
11#include <rpc/protocol.h>
12#include <rpc/request.h>
13#include <rpc/server.h>
14#include <rpc/server_util.h>
15#include <rpc/util.h>
16#include <txmempool.h>
17#include <univalue.h>
18#include <util/fees.h>
19#include <validationinterface.h>
20
21#include <algorithm>
22#include <array>
23#include <cmath>
24#include <string>
25#include <string_view>
26
31
33{
34 return RPCMethod{
35 "estimatesmartfee",
36 "Estimates the approximate fee per kilobyte needed for a transaction to begin\n"
37 "confirmation within conf_target blocks if possible and return the number of blocks\n"
38 "for which the estimate is valid. Uses virtual transaction size as defined\n"
39 "in BIP 141 (witness data is discounted).\n",
40 {
41 {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
42 {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"economical"}, "The fee estimate mode.\n"
43 + FeeModesDetail(std::string("default mode will be used"))},
44 },
47 {
48 {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB (only present if no errors were encountered)"},
49 {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
50 {
51 {RPCResult::Type::STR, "", "error"},
52 }},
53 {RPCResult::Type::NUM, "blocks", "block number where estimate was found\n"
54 "The request target will be clamped between 2 and the highest target\n"
55 "fee estimation is able to return based on how long it has been running.\n"
56 "An error is returned if not enough transactions and blocks\n"
57 "have been observed to make an estimate for any number of blocks."},
58 }},
60 HelpExampleCli("estimatesmartfee", "6") +
61 HelpExampleRpc("estimatesmartfee", "6")
62 },
63 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
64 {
65 CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
66 const NodeContext& node = EnsureAnyNodeContext(request.context);
67 const CTxMemPool& mempool = EnsureMemPool(node);
68
69 CHECK_NONFATAL(mempool.m_opts.signals)->SyncWithValidationInterfaceQueue();
70 unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
71 unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
72 FeeEstimateMode fee_mode;
73 if (!FeeModeFromString(self.Arg<std::string_view>("estimate_mode"), fee_mode)) {
75 }
76
79 FeeCalculation feeCalc;
80 bool conservative{fee_mode == FeeEstimateMode::CONSERVATIVE};
81 CFeeRate feeRate{fee_estimator.estimateSmartFee(conf_target, &feeCalc, conservative)};
82 if (feeRate != CFeeRate(0)) {
83 CFeeRate min_mempool_feerate{mempool.GetMinFee()};
84 CFeeRate min_relay_feerate{mempool.m_opts.min_relay_feerate};
85 feeRate = std::max({feeRate, min_mempool_feerate, min_relay_feerate});
86 result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
87 } else {
88 errors.push_back("Insufficient data or no feerate found");
89 result.pushKV("errors", std::move(errors));
90 }
91 result.pushKV("blocks", feeCalc.returnedTarget);
92 return result;
93 },
94 };
95}
96
97static std::vector<RPCResult> FeeRateBucketDoc(bool elide = false)
98{
99 auto fields = std::vector<RPCResult>{
100 {RPCResult::Type::NUM, "startrange", "start of feerate range"},
101 {RPCResult::Type::NUM, "endrange", "end of feerate range"},
102 {RPCResult::Type::NUM, "withintarget", "number of txs over history horizon in the feerate range that were confirmed within target"},
103 {RPCResult::Type::NUM, "totalconfirmed", "number of txs over history horizon in the feerate range that were confirmed at any point"},
104 {RPCResult::Type::NUM, "inmempool", "current number of txs in mempool in the feerate range unconfirmed for at least target blocks"},
105 {RPCResult::Type::NUM, "leftmempool", "number of txs over history horizon in the feerate range that left mempool unconfirmed after target"},
106 };
107 return elide ? ElideGroup(std::move(fields)) : fields;
108}
109
110static std::vector<RPCResult> FeeEstimateHorizonDoc(bool elide = false)
111{
112 auto fields = std::vector<RPCResult>{
113 {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB"},
114 {RPCResult::Type::NUM, "decay", "exponential decay (per block) for historical moving average of confirmation data"},
115 {RPCResult::Type::NUM, "scale", "The resolution of confirmation targets at this time horizon"},
116 {RPCResult::Type::OBJ, "pass", /*optional=*/true, "information about the lowest range of feerates to succeed in meeting the threshold", FeeRateBucketDoc()},
117 {RPCResult::Type::OBJ, "fail", /*optional=*/true, "information about the highest range of feerates to fail to meet the threshold", FeeRateBucketDoc(/*elide=*/true)},
118 {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
119 {
120 {RPCResult::Type::STR, "error", ""},
121 }},
122 };
123 return elide ? ElideGroup(std::move(fields)) : fields;
124}
125
127{
128 return RPCMethod{
129 "estimaterawfee",
130 "WARNING: This interface is unstable and may disappear or change!\n"
131 "\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
132 "implementation of fee estimation. The parameters it can be called with\n"
133 "and the results it returns will change if the internal implementation changes.\n"
134 "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
135 "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n"
136 "defined in BIP 141 (witness data is discounted).\n",
137 {
138 {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
139 {"threshold", RPCArg::Type::NUM, RPCArg::Default{0.95}, "The proportion of transactions in a given feerate range that must have been\n"
140 "confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
141 "lower buckets."},
142 },
143 RPCResult{
144 RPCResult::Type::OBJ, "", "Results are returned for any horizon which tracks blocks up to the confirmation target",
145 {
146 {RPCResult::Type::OBJ, "short", /*optional=*/true, "estimate for short time horizon",
148 {RPCResult::Type::OBJ, "medium", /*optional=*/true, "estimate for medium time horizon",
149 FeeEstimateHorizonDoc(/*elide=*/true)},
150 {RPCResult::Type::OBJ, "long", /*optional=*/true, "estimate for long time horizon",
151 FeeEstimateHorizonDoc(/*elide=*/true)},
152 }},
154 HelpExampleCli("estimaterawfee", "6 0.9")
155 },
156 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
157 {
158 CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
159 const NodeContext& node = EnsureAnyNodeContext(request.context);
160
161 CHECK_NONFATAL(node.validation_signals)->SyncWithValidationInterfaceQueue();
162 unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
163 unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
164 double threshold = 0.95;
165 if (!request.params[1].isNull()) {
166 threshold = request.params[1].get_real();
167 }
168 if (threshold < 0 || threshold > 1) {
169 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid threshold");
170 }
171
172 UniValue result(UniValue::VOBJ);
173
174 for (const FeeEstimateHorizon horizon : ALL_FEE_ESTIMATE_HORIZONS) {
175 CFeeRate feeRate;
176 EstimationResult buckets;
177
178 // Only output results for horizons which track the target
179 if (conf_target > fee_estimator.HighestTargetTracked(horizon)) continue;
180
181 feeRate = fee_estimator.estimateRawFee(conf_target, threshold, horizon, &buckets);
182 UniValue horizon_result(UniValue::VOBJ);
183 UniValue errors(UniValue::VARR);
184 UniValue passbucket(UniValue::VOBJ);
185 passbucket.pushKV("startrange", round(buckets.pass.start));
186 passbucket.pushKV("endrange", round(buckets.pass.end));
187 passbucket.pushKV("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0);
188 passbucket.pushKV("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0);
189 passbucket.pushKV("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0);
190 passbucket.pushKV("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0);
191 UniValue failbucket(UniValue::VOBJ);
192 failbucket.pushKV("startrange", round(buckets.fail.start));
193 failbucket.pushKV("endrange", round(buckets.fail.end));
194 failbucket.pushKV("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0);
195 failbucket.pushKV("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0);
196 failbucket.pushKV("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0);
197 failbucket.pushKV("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0);
198
199 // CFeeRate(0) is used to indicate error as a return value from estimateRawFee
200 if (feeRate != CFeeRate(0)) {
201 horizon_result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
202 horizon_result.pushKV("decay", buckets.decay);
203 horizon_result.pushKV("scale", buckets.scale);
204 horizon_result.pushKV("pass", std::move(passbucket));
205 // buckets.fail.start == -1 indicates that all buckets passed, there is no fail bucket to output
206 if (buckets.fail.start != -1) horizon_result.pushKV("fail", std::move(failbucket));
207 } else {
208 // Output only information that is still meaningful in the event of error
209 horizon_result.pushKV("decay", buckets.decay);
210 horizon_result.pushKV("scale", buckets.scale);
211 horizon_result.pushKV("fail", std::move(failbucket));
212 errors.push_back("Insufficient data or no feerate found which meets threshold");
213 horizon_result.pushKV("errors", std::move(errors));
214 }
215 result.pushKV(StringForFeeEstimateHorizon(horizon), std::move(horizon_result));
216 }
217 return result;
218 },
219 };
220}
221
223{
224 static const CRPCCommand commands[]{
225 {"util", &estimatesmartfee},
226 {"hidden", &estimaterawfee},
227 };
228 for (const auto& c : commands) {
229 t.appendCommand(c.name, &c);
230 }
231}
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
static constexpr auto ALL_FEE_ESTIMATE_HORIZONS
FeeEstimateHorizon
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:112
The BlockPolicyEstimator is used for estimating the feerate needed for a transaction to be included i...
virtual CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Estimate feerate needed to get be included in a block within confTarget blocks.
virtual unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Calculation of highest target that estimates are tracked for.
CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult *result=nullptr) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Return a specific fee estimate calculation with a given success threshold and time horizon,...
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:62
RPC command dispatcher.
Definition: server.h:87
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:838
const Options m_opts
Definition: txmempool.h:301
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
@ VARR
Definition: univalue.h:24
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:73
bool FeeModeFromString(std::string_view mode_string, FeeEstimateMode &fee_estimate_mode)
Definition: messages.cpp:92
std::string InvalidEstimateModeErrorMessage()
Definition: messages.cpp:87
Definition: messages.h:21
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:70
static RPCMethod estimaterawfee()
Definition: fees.cpp:126
static std::vector< RPCResult > FeeEstimateHorizonDoc(bool elide=false)
Definition: fees.cpp:110
static std::vector< RPCResult > FeeRateBucketDoc(bool elide=false)
Definition: fees.cpp:97
static RPCMethod estimatesmartfee()
Definition: fees.cpp:32
void RegisterFeeRPCCommands(CRPCTable &t)
Definition: fees.cpp:222
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:67
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:183
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:1419
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:201
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:369
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:25
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:34
CBlockPolicyEstimator & EnsureAnyFeeEstimator(const std::any &context)
Definition: server_util.cpp:95
@ NO
Required arg.
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
FeeEstimateMode
Definition: fees.h:9
@ CONSERVATIVE
Force estimateSmartFee to use conservative estimates.