Bitcoin Core  24.1.0
P2P Digital Currency
fees.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2021 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 <core_io.h>
7 #include <policy/feerate.h>
8 #include <policy/fees.h>
9 #include <rpc/protocol.h>
10 #include <rpc/request.h>
11 #include <rpc/server.h>
12 #include <rpc/server_util.h>
13 #include <rpc/util.h>
14 #include <txmempool.h>
15 #include <univalue.h>
16 #include <util/fees.h>
17 
18 #include <algorithm>
19 #include <array>
20 #include <cmath>
21 #include <string>
22 
23 namespace node {
24 struct NodeContext;
25 }
26 
27 using node::NodeContext;
28 
30 {
31  return RPCHelpMan{"estimatesmartfee",
32  "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
33  "confirmation within conf_target blocks if possible and return the number of blocks\n"
34  "for which the estimate is valid. Uses virtual transaction size as defined\n"
35  "in BIP 141 (witness data is discounted).\n",
36  {
37  {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
38  {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"conservative"}, "The fee estimate mode.\n"
39  "Whether to return a more conservative estimate which also satisfies\n"
40  "a longer history. A conservative estimate potentially returns a\n"
41  "higher feerate and is more likely to be sufficient for the desired\n"
42  "target, but is not as responsive to short term drops in the\n"
43  "prevailing fee market. Must be one of (case insensitive):\n"
44  "\"" + FeeModes("\"\n\"") + "\""},
45  },
46  RPCResult{
47  RPCResult::Type::OBJ, "", "",
48  {
49  {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB (only present if no errors were encountered)"},
50  {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
51  {
52  {RPCResult::Type::STR, "", "error"},
53  }},
54  {RPCResult::Type::NUM, "blocks", "block number where estimate was found\n"
55  "The request target will be clamped between 2 and the highest target\n"
56  "fee estimation is able to return based on how long it has been running.\n"
57  "An error is returned if not enough transactions and blocks\n"
58  "have been observed to make an estimate for any number of blocks."},
59  }},
61  HelpExampleCli("estimatesmartfee", "6") +
62  HelpExampleRpc("estimatesmartfee", "6")
63  },
64  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
65  {
66  RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
67  RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
68 
69  CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
70  const NodeContext& node = EnsureAnyNodeContext(request.context);
71  const CTxMemPool& mempool = EnsureMemPool(node);
72 
73  unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
74  unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
75  bool conservative = true;
76  if (!request.params[1].isNull()) {
77  FeeEstimateMode fee_mode;
78  if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
80  }
81  if (fee_mode == FeeEstimateMode::ECONOMICAL) conservative = false;
82  }
83 
84  UniValue result(UniValue::VOBJ);
85  UniValue errors(UniValue::VARR);
86  FeeCalculation feeCalc;
87  CFeeRate feeRate{fee_estimator.estimateSmartFee(conf_target, &feeCalc, conservative)};
88  if (feeRate != CFeeRate(0)) {
89  CFeeRate min_mempool_feerate{mempool.GetMinFee()};
90  CFeeRate min_relay_feerate{mempool.m_min_relay_feerate};
91  feeRate = std::max({feeRate, min_mempool_feerate, min_relay_feerate});
92  result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
93  } else {
94  errors.push_back("Insufficient data or no feerate found");
95  result.pushKV("errors", errors);
96  }
97  result.pushKV("blocks", feeCalc.returnedTarget);
98  return result;
99  },
100  };
101 }
102 
104 {
105  return RPCHelpMan{"estimaterawfee",
106  "\nWARNING: This interface is unstable and may disappear or change!\n"
107  "\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
108  "implementation of fee estimation. The parameters it can be called with\n"
109  "and the results it returns will change if the internal implementation changes.\n"
110  "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
111  "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n"
112  "defined in BIP 141 (witness data is discounted).\n",
113  {
114  {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
115  {"threshold", RPCArg::Type::NUM, RPCArg::Default{0.95}, "The proportion of transactions in a given feerate range that must have been\n"
116  "confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
117  "lower buckets."},
118  },
119  RPCResult{
120  RPCResult::Type::OBJ, "", "Results are returned for any horizon which tracks blocks up to the confirmation target",
121  {
122  {RPCResult::Type::OBJ, "short", /*optional=*/true, "estimate for short time horizon",
123  {
124  {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB"},
125  {RPCResult::Type::NUM, "decay", "exponential decay (per block) for historical moving average of confirmation data"},
126  {RPCResult::Type::NUM, "scale", "The resolution of confirmation targets at this time horizon"},
127  {RPCResult::Type::OBJ, "pass", /*optional=*/true, "information about the lowest range of feerates to succeed in meeting the threshold",
128  {
129  {RPCResult::Type::NUM, "startrange", "start of feerate range"},
130  {RPCResult::Type::NUM, "endrange", "end of feerate range"},
131  {RPCResult::Type::NUM, "withintarget", "number of txs over history horizon in the feerate range that were confirmed within target"},
132  {RPCResult::Type::NUM, "totalconfirmed", "number of txs over history horizon in the feerate range that were confirmed at any point"},
133  {RPCResult::Type::NUM, "inmempool", "current number of txs in mempool in the feerate range unconfirmed for at least target blocks"},
134  {RPCResult::Type::NUM, "leftmempool", "number of txs over history horizon in the feerate range that left mempool unconfirmed after target"},
135  }},
136  {RPCResult::Type::OBJ, "fail", /*optional=*/true, "information about the highest range of feerates to fail to meet the threshold",
137  {
138  {RPCResult::Type::ELISION, "", ""},
139  }},
140  {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
141  {
142  {RPCResult::Type::STR, "error", ""},
143  }},
144  }},
145  {RPCResult::Type::OBJ, "medium", /*optional=*/true, "estimate for medium time horizon",
146  {
147  {RPCResult::Type::ELISION, "", ""},
148  }},
149  {RPCResult::Type::OBJ, "long", /*optional=*/true, "estimate for long time horizon",
150  {
151  {RPCResult::Type::ELISION, "", ""},
152  }},
153  }},
154  RPCExamples{
155  HelpExampleCli("estimaterawfee", "6 0.9")
156  },
157  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
158  {
159  RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
160  RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
161 
162  CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
163 
164  unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
165  unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
166  double threshold = 0.95;
167  if (!request.params[1].isNull()) {
168  threshold = request.params[1].get_real();
169  }
170  if (threshold < 0 || threshold > 1) {
171  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid threshold");
172  }
173 
174  UniValue result(UniValue::VOBJ);
175 
176  for (const FeeEstimateHorizon horizon : ALL_FEE_ESTIMATE_HORIZONS) {
177  CFeeRate feeRate;
178  EstimationResult buckets;
179 
180  // Only output results for horizons which track the target
181  if (conf_target > fee_estimator.HighestTargetTracked(horizon)) continue;
182 
183  feeRate = fee_estimator.estimateRawFee(conf_target, threshold, horizon, &buckets);
184  UniValue horizon_result(UniValue::VOBJ);
185  UniValue errors(UniValue::VARR);
186  UniValue passbucket(UniValue::VOBJ);
187  passbucket.pushKV("startrange", round(buckets.pass.start));
188  passbucket.pushKV("endrange", round(buckets.pass.end));
189  passbucket.pushKV("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0);
190  passbucket.pushKV("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0);
191  passbucket.pushKV("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0);
192  passbucket.pushKV("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0);
193  UniValue failbucket(UniValue::VOBJ);
194  failbucket.pushKV("startrange", round(buckets.fail.start));
195  failbucket.pushKV("endrange", round(buckets.fail.end));
196  failbucket.pushKV("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0);
197  failbucket.pushKV("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0);
198  failbucket.pushKV("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0);
199  failbucket.pushKV("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0);
200 
201  // CFeeRate(0) is used to indicate error as a return value from estimateRawFee
202  if (feeRate != CFeeRate(0)) {
203  horizon_result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
204  horizon_result.pushKV("decay", buckets.decay);
205  horizon_result.pushKV("scale", (int)buckets.scale);
206  horizon_result.pushKV("pass", passbucket);
207  // buckets.fail.start == -1 indicates that all buckets passed, there is no fail bucket to output
208  if (buckets.fail.start != -1) horizon_result.pushKV("fail", failbucket);
209  } else {
210  // Output only information that is still meaningful in the event of error
211  horizon_result.pushKV("decay", buckets.decay);
212  horizon_result.pushKV("scale", (int)buckets.scale);
213  horizon_result.pushKV("fail", failbucket);
214  errors.push_back("Insufficient data or no feerate found which meets threshold");
215  horizon_result.pushKV("errors", errors);
216  }
217  result.pushKV(StringForFeeEstimateHorizon(horizon), horizon_result);
218  }
219  return result;
220  },
221  };
222 }
223 
225 {
226  static const CRPCCommand commands[]{
227  {"util", &estimatesmartfee},
228  {"hidden", &estimaterawfee},
229  };
230  for (const auto& c : commands) {
231  t.appendCommand(c.name, &c);
232  }
233 }
EstimatorBucket pass
Definition: fees.h:70
void push_back(UniValue val)
Definition: univalue.cpp:104
RPC command dispatcher.
Definition: server.h:125
int returnedTarget
Definition: fees.h:81
Required arg.
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:29
double start
Definition: fees.h:59
Force estimateSmartFee to use non-conservative estimates.
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
Definition: fees.cpp:36
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:340
double withinTarget
Definition: fees.h:61
Invalid, missing or duplicate parameter.
Definition: protocol.h:43
void RPCTypeCheckArgument(const UniValue &value, const UniValueType &typeExpected)
Type-check one argument; throws JSONRPCError if wrong type given.
Definition: util.cpp:50
NodeContext struct containing references to chain state and connection state.
Definition: context.h:43
void RegisterFeeRPCCommands(CRPCTable &t)
Definition: fees.cpp:224
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:184
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:56
static RPCHelpMan estimaterawfee()
Definition: fees.cpp:103
static constexpr auto ALL_FEE_ESTIMATE_HORIZONS
Definition: fees.h:35
double end
Definition: fees.h:60
EstimatorBucket fail
Definition: fees.h:71
The BlockPolicyEstimator is used for estimating the feerate needed for a transaction to be included i...
Definition: fees.h:132
CBlockPolicyEstimator & EnsureAnyFeeEstimator(const std::any &context)
Definition: server_util.cpp:76
FeeEstimateMode
Definition: feerate.h:21
double inMempool
Definition: fees.h:63
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.
Definition: fees.cpp:826
const CFeeRate m_min_relay_feerate
Definition: txmempool.h:572
const std::string CURRENCY_UNIT
Definition: feerate.h:17
const std::string InvalidEstimateModeErrorMessage()
Definition: fees.cpp:52
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:166
CFeeRate GetMinFee(size_t sizelimit) const
Definition: txmempool.cpp:1085
std::string FeeModes(const std::string &delimiter)
Definition: fees.cpp:47
Definition: init.h:25
FeeEstimateHorizon
Definition: fees.h:29
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:431
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
double leftMempool
Definition: fees.h:64
UniValue ValueFromAmount(const CAmount amount)
Definition: core_write.cpp:26
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
Definition: feerate.h:32
double totalConfirmed
Definition: fees.h:62
bool FeeModeFromString(const std::string &mode_string, FeeEstimateMode &fee_estimate_mode)
Definition: fees.cpp:57
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...
Definition: fees.cpp:682
unsigned int scale
Definition: fees.h:73
unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator)
Calculation of highest target that estimates are tracked for.
Definition: fees.cpp:718
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
Definition: feerate.h:65
static RPCHelpMan estimatesmartfee()
Definition: fees.cpp:29
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:20
Special type to denote elision (...)
void RPCTypeCheck(const UniValue &params, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
Definition: util.cpp:33
double decay
Definition: fees.h:72