| 30 | using node::NodeContext; |
| 31 | |
| 32 | static RPCMethod estimatesmartfee() |
| 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 | }, |
| 45 | RPCResult{ |
| 46 | RPCResult::Type::OBJ, "", "", |
| 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 | }}, |
| 59 | RPCExamples{ |
| 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)) { |
| 74 | throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage()); |
| 75 | } |
| 76 | |
| 77 | UniValue result(UniValue::VOBJ); |
| 78 | UniValue errors(UniValue::VARR); |
| 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)); |
nothing calls this directly
no test coverage detected