Skip to content

Commit 75b5643

Browse files
committed
Merge #10707: Better API for estimatesmartfee RPC
06bcdb8 Convert named argument from nblocks to conf_target (Alex Morcos) 439c4e8 Improve api to estimatesmartfee (Alex Morcos) Pull request description: Through 0.14 branch, the estimatesmartfee API was tagged "WARNING: This interface is unstable and may disappear or change!" and this warning is removed for 0.15, so any wanted API updates should happen now. The changes here are to make the additional parameter for conservative estimates a more general estimate_mode string , to omit the feerate and include an error string instead of returning -1 on error, and to do better parameter checking initially. ~It is only the last 2 commits, but it's built on #10706 and #10543~. See bitcoin/bitcoin#10707 (comment) for renaming of nblocks argument to conf_target. Will need to be included before string freeze. PR description edited for clarity Tree-SHA512: 6d8ebee8bb410e2950ffd59663eebfed8d1611d995dc935bb91e430d9da7e2f306796f45631458376027d26341c660f09e825e61748103d2f2736ec6dc3df3ae
2 parents fee0d80 + 06bcdb8 commit 75b5643

File tree

3 files changed

+52
-42
lines changed

3 files changed

+52
-42
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: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -806,42 +806,59 @@ 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 conf_target (\"estimate_mode\")\n"
810810
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
811-
"confirmation within nblocks blocks if possible and return the number of blocks\n"
811+
"confirmation within conf_target 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. conf_target (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-
834-
int nBlocks = request.params[0].get_int();
840+
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
841+
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
842+
unsigned int conf_target = ParseConfirmTarget(request.params[0]);
835843
bool conservative = true;
836844
if (request.params.size() > 1 && !request.params[1].isNull()) {
837-
RPCTypeCheckArgument(request.params[1], UniValue::VBOOL);
838-
conservative = request.params[1].get_bool();
845+
FeeEstimateMode fee_mode;
846+
if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
847+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
848+
}
849+
if (fee_mode == FeeEstimateMode::ECONOMICAL) conservative = false;
839850
}
840851

841852
UniValue result(UniValue::VOBJ);
853+
UniValue errors(UniValue::VARR);
842854
FeeCalculation feeCalc;
843-
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &feeCalc, conservative);
844-
result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
855+
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(conf_target, &feeCalc, conservative);
856+
if (feeRate != CFeeRate(0)) {
857+
result.push_back(Pair("feerate", ValueFromAmount(feeRate.GetFeePerK())));
858+
} else {
859+
errors.push_back("Insufficient data or no feerate found");
860+
result.push_back(Pair("errors", errors));
861+
}
845862
result.push_back(Pair("blocks", feeCalc.returnedTarget));
846863
return result;
847864
}
@@ -850,18 +867,18 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
850867
{
851868
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
852869
throw std::runtime_error(
853-
"estimaterawfee nblocks (threshold)\n"
870+
"estimaterawfee conf_target (threshold)\n"
854871
"\nWARNING: This interface is unstable and may disappear or change!\n"
855872
"\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
856873
" implementation of fee estimation. The parameters it can be called with\n"
857874
" and the results it returns will change if the internal implementation changes.\n"
858875
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
859-
"confirmation within nblocks blocks if possible. Uses virtual transaction size as defined\n"
860-
"in BIP 141 (witness data is discounted).\n"
876+
"confirmation within conf_target blocks if possible. Uses virtual transaction size as\n"
877+
"defined in BIP 141 (witness data is discounted).\n"
861878
"\nArguments:\n"
862-
"1. nblocks (numeric) Confirmation target in blocks (1 - 1008)\n"
879+
"1. conf_target (numeric) Confirmation target in blocks (1 - 1008)\n"
863880
"2. threshold (numeric, optional) The proportion of transactions in a given feerate range that must have been\n"
864-
" confirmed within nblocks in order to consider those feerates as high enough and proceed to check\n"
881+
" confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
865882
" lower buckets. Default: 0.95\n"
866883
"\nResult:\n"
867884
"{\n"
@@ -889,12 +906,9 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
889906
+ HelpExampleCli("estimaterawfee", "6 0.9")
890907
);
891908

892-
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM, UniValue::VNUM}, true);
909+
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
893910
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
894-
int nBlocks = request.params[0].get_int();
895-
if (nBlocks < 1 || (unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE)) {
896-
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid nblocks");
897-
}
911+
unsigned int conf_target = ParseConfirmTarget(request.params[0]);
898912
double threshold = 0.95;
899913
if (!request.params[1].isNull()) {
900914
threshold = request.params[1].get_real();
@@ -910,9 +924,9 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
910924
EstimationResult buckets;
911925

912926
// Only output results for horizons which track the target
913-
if ((unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(horizon)) continue;
927+
if (conf_target > ::feeEstimator.HighestTargetTracked(horizon)) continue;
914928

915-
feeRate = ::feeEstimator.estimateRawFee(nBlocks, threshold, horizon, &buckets);
929+
feeRate = ::feeEstimator.estimateRawFee(conf_target, threshold, horizon, &buckets);
916930
UniValue horizon_result(UniValue::VOBJ);
917931
UniValue errors(UniValue::VARR);
918932
UniValue passbucket(UniValue::VOBJ);
@@ -963,9 +977,9 @@ static const CRPCCommand commands[] =
963977
{ "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
964978

965979
{ "util", "estimatefee", &estimatefee, true, {"nblocks"} },
966-
{ "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks", "conservative"} },
980+
{ "util", "estimatesmartfee", &estimatesmartfee, true, {"conf_target", "estimate_mode"} },
967981

968-
{ "hidden", "estimaterawfee", &estimaterawfee, true, {"nblocks", "threshold"} },
982+
{ "hidden", "estimaterawfee", &estimaterawfee, true, {"conf_target", "threshold"} },
969983
};
970984

971985
void RegisterMiningRPCCommands(CRPCTable &t)

0 commit comments

Comments
 (0)