Repository: bitcoin/bitcoin
File: src/rpc/fees.cpp (C++)

Code before:

static RPCHelpMan estimatesmartfee()
{
    return RPCHelpMan{"estimatesmartfee",
        "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
        "confirmation within conf_target blocks if possible and return the number of blocks\n"
        "for which the estimate is valid. Uses virtual transaction size as defined\n"
        "in BIP 141 (witness data is discounted).\n",
        {
            {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
            {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"economical"}, "The fee estimate mode.\n"
            "Whether to return a more conservative estimate which also satisfies\n"
            "a longer history. A conservative estimate potentially returns a\n"
            "higher feerate and is more likely to be sufficient for the desired\n"
            "target, but is not as responsive to short term drops in the\n"
            "prevailing fee market. Must be one of (case insensitive):\n"
             "\"" + FeeModes("\"\n\"") + "\""},
        },
        RPCResult{
            RPCResult::Type::OBJ, "", "",
            {
                {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB (only present if no errors were encountered)"},
                {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
                    {
                        {RPCResult::Type::STR, "", "error"},
                    }},
                {RPCResult::Type::NUM, "blocks", "block number where estimate was found\n"
                "The request target will be clamped between 2 and the highest target\n"
                "fee estimation is able to return based on how long it has been running.\n"
                "An error is returned if not enough transactions and blocks\n"
                "have been observed to make an estimate for any number of blocks."},
        }},
        RPCExamples{
            HelpExampleCli("estimatesmartfee", "6") +
            HelpExampleRpc("estimatesmartfee", "6")
        },
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
        {
            CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
            const NodeContext& node = EnsureAnyNodeContext(request.context);
            const CTxMemPool& mempool = EnsureMemPool(node);

            CHECK_NONFATAL(mempool.m_opts.signals)->SyncWithValidationInterfaceQueue();
            unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
            unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
            bool conservative = false;
            if (!request.params[1].isNull()) {
                FeeEstimateMode fee_mode;
                if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
                    throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage());
                }

Review comment (suggestion):
Might it make more sense to change this to something simpler:

```
The number of blocks from the current tip where the estimate was found.
```

And amend the doc on L38 about the confirmation target range from `1` to `2` to avoid having to explain it in `blocks`:

```
            {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (2 - 1008)"},
```

The error could be moved to the error description string:

```
                {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing. An error is returned if not enough transactions and blocks have been observed to make an estimate for any number of blocks."
```



Code after:

static RPCHelpMan estimatesmartfee()
{
    return RPCHelpMan{"estimatesmartfee",
        "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
        "confirmation within conf_target blocks if possible and return the number of blocks\n"
        "for which the estimate is valid. Uses virtual transaction size as defined\n"
        "in BIP 141 (witness data is discounted).\n",
        {
            {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
            {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"economical"}, "The fee estimate mode.\n"
              + FeeModesDetail(std::string("default mode will be used"))},
        },
        RPCResult{
            RPCResult::Type::OBJ, "", "",
            {
                {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB (only present if no errors were encountered)"},
                {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
                    {
                        {RPCResult::Type::STR, "", "error"},
                    }},
                {RPCResult::Type::NUM, "blocks", "block number where estimate was found\n"
                "The request target will be clamped between 2 and the highest target\n"
                "fee estimation is able to return based on how long it has been running.\n"
                "An error is returned if not enough transactions and blocks\n"
                "have been observed to make an estimate for any number of blocks."},
        }},
        RPCExamples{
            HelpExampleCli("estimatesmartfee", "6") +
            HelpExampleRpc("estimatesmartfee", "6")
        },
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
        {
            CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
            const NodeContext& node = EnsureAnyNodeContext(request.context);
            const CTxMemPool& mempool = EnsureMemPool(node);

            CHECK_NONFATAL(mempool.m_opts.signals)->SyncWithValidationInterfaceQueue();
            unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
            unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
            bool conservative = false;
            if (!request.params[1].isNull()) {
                FeeEstimateMode fee_mode;
                if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
                    throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage());
                }
                if (fee_mode == FeeEstimateMode::CONSERVATIVE) conservative = true;
            }

            UniValue result(UniValue::VOBJ);
            UniValue errors(UniValue::VARR);