Skip to content

Commit 439c4e8

Browse files
committed
Improve api to estimatesmartfee
Change parameter for conservative estimates to be an estimate_mode string. Change to never return a -1 for failure but to instead omit the feerate and return an error string. Throw JSONRPC error on invalid nblocks parameter.
1 parent 91edda8 commit 439c4e8

File tree

3 files changed

+43
-27
lines changed

3 files changed

+43
-27
lines changed

src/policy/fees.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -839,20 +839,20 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
839839
EstimationResult tempResult;
840840

841841
// Return failure if trying to analyze a target we're not tracking
842-
if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms())
843-
return CFeeRate(0);
842+
if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms()) {
843+
return CFeeRate(0); // error conditon
844+
}
844845

845846
// It's not possible to get reasonable estimates for confTarget of 1
846-
if (confTarget == 1)
847-
confTarget = 2;
847+
if (confTarget == 1) confTarget = 2;
848848

849849
unsigned int maxUsableEstimate = MaxUsableEstimate();
850-
if (maxUsableEstimate <= 1)
851-
return CFeeRate(0);
852-
853850
if ((unsigned int)confTarget > maxUsableEstimate) {
854851
confTarget = maxUsableEstimate;
855852
}
853+
if (feeCalc) feeCalc->returnedTarget = confTarget;
854+
855+
if (confTarget <= 1) return CFeeRate(0); // error conditon
856856

857857
assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
858858
/** true is passed to estimateCombined fee for target/2 and target so
@@ -899,10 +899,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
899899
}
900900
}
901901

902-
if (feeCalc) feeCalc->returnedTarget = confTarget;
903-
904-
if (median < 0)
905-
return CFeeRate(0);
902+
if (median < 0) return CFeeRate(0); // error conditon
906903

907904
return CFeeRate(median);
908905
}

src/rpc/client.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
114114
{ "getrawmempool", 0, "verbose" },
115115
{ "estimatefee", 0, "nblocks" },
116116
{ "estimatesmartfee", 0, "nblocks" },
117-
{ "estimatesmartfee", 1, "conservative" },
118117
{ "estimaterawfee", 0, "nblocks" },
119118
{ "estimaterawfee", 1, "threshold" },
120119
{ "prioritisetransaction", 1, "dummy" },

src/rpc/mining.cpp

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -806,42 +806,62 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
806806
{
807807
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
808808
throw std::runtime_error(
809-
"estimatesmartfee nblocks (conservative)\n"
809+
"estimatesmartfee nblocks (\"estimate_mode\")\n"
810810
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
811811
"confirmation within nblocks blocks if possible and return the number of blocks\n"
812812
"for which the estimate is valid. Uses virtual transaction size as defined\n"
813813
"in BIP 141 (witness data is discounted).\n"
814814
"\nArguments:\n"
815-
"1. nblocks (numeric)\n"
816-
"2. conservative (bool, optional, default=true) Whether to return a more conservative estimate which\n"
817-
" also satisfies a longer history. A conservative estimate potentially returns a higher\n"
818-
" feerate and is more likely to be sufficient for the desired target, but is not as\n"
819-
" responsive to short term drops in the prevailing fee market\n"
815+
"1. nblocks (numeric) Confirmation target in blocks (1 - 1008)\n"
816+
"2. \"estimate_mode\" (string, optional, default=CONSERVATIVE) The fee estimate mode.\n"
817+
" Whether to return a more conservative estimate which also satisfies\n"
818+
" a longer history. A conservative estimate potentially returns a\n"
819+
" higher feerate and is more likely to be sufficient for the desired\n"
820+
" target, but is not as responsive to short term drops in the\n"
821+
" prevailing fee market. Must be one of:\n"
822+
" \"UNSET\" (defaults to CONSERVATIVE)\n"
823+
" \"ECONOMICAL\"\n"
824+
" \"CONSERVATIVE\"\n"
820825
"\nResult:\n"
821826
"{\n"
822-
" \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n"
827+
" \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
828+
" \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
823829
" \"blocks\" : n (numeric) block number where estimate was found\n"
824830
"}\n"
825831
"\n"
826-
"A negative value is returned if not enough transactions and blocks\n"
832+
"The request target will be clamped between 2 and the highest target\n"
833+
"fee estimation is able to return based on how long it has been running.\n"
834+
"An error is returned if not enough transactions and blocks\n"
827835
"have been observed to make an estimate for any number of blocks.\n"
828836
"\nExample:\n"
829837
+ HelpExampleCli("estimatesmartfee", "6")
830838
);
831839

832-
RPCTypeCheck(request.params, {UniValue::VNUM});
833-
840+
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
841+
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
834842
int nBlocks = request.params[0].get_int();
843+
if (nBlocks < 1 || (unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE)) {
844+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid nblocks");
845+
}
835846
bool conservative = true;
836847
if (request.params.size() > 1 && !request.params[1].isNull()) {
837-
RPCTypeCheckArgument(request.params[1], UniValue::VBOOL);
838-
conservative = request.params[1].get_bool();
848+
FeeEstimateMode fee_mode;
849+
if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
850+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
851+
}
852+
if (fee_mode == FeeEstimateMode::ECONOMICAL) conservative = false;
839853
}
840854

841855
UniValue result(UniValue::VOBJ);
856+
UniValue errors(UniValue::VARR);
842857
FeeCalculation feeCalc;
843858
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &feeCalc, conservative);
844-
result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
859+
if (feeRate != CFeeRate(0)) {
860+
result.push_back(Pair("feerate", ValueFromAmount(feeRate.GetFeePerK())));
861+
} else {
862+
errors.push_back("Insufficient data or no feerate found");
863+
result.push_back(Pair("errors", errors));
864+
}
845865
result.push_back(Pair("blocks", feeCalc.returnedTarget));
846866
return result;
847867
}
@@ -889,7 +909,7 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
889909
+ HelpExampleCli("estimaterawfee", "6 0.9")
890910
);
891911

892-
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM, UniValue::VNUM}, true);
912+
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
893913
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
894914
int nBlocks = request.params[0].get_int();
895915
if (nBlocks < 1 || (unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE)) {
@@ -963,7 +983,7 @@ static const CRPCCommand commands[] =
963983
{ "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
964984

965985
{ "util", "estimatefee", &estimatefee, true, {"nblocks"} },
966-
{ "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks", "conservative"} },
986+
{ "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks", "estimate_mode"} },
967987

968988
{ "hidden", "estimaterawfee", &estimaterawfee, true, {"nblocks", "threshold"} },
969989
};

0 commit comments

Comments
 (0)