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.
This commit is contained in:
Alex Morcos 2017-06-29 13:57:33 -04:00
parent 91edda8f3c
commit 439c4e8ad5
3 changed files with 43 additions and 27 deletions

View File

@ -839,20 +839,20 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
EstimationResult tempResult; EstimationResult tempResult;
// Return failure if trying to analyze a target we're not tracking // Return failure if trying to analyze a target we're not tracking
if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms()) if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms()) {
return CFeeRate(0); return CFeeRate(0); // error conditon
}
// It's not possible to get reasonable estimates for confTarget of 1 // It's not possible to get reasonable estimates for confTarget of 1
if (confTarget == 1) if (confTarget == 1) confTarget = 2;
confTarget = 2;
unsigned int maxUsableEstimate = MaxUsableEstimate(); unsigned int maxUsableEstimate = MaxUsableEstimate();
if (maxUsableEstimate <= 1)
return CFeeRate(0);
if ((unsigned int)confTarget > maxUsableEstimate) { if ((unsigned int)confTarget > maxUsableEstimate) {
confTarget = maxUsableEstimate; confTarget = maxUsableEstimate;
} }
if (feeCalc) feeCalc->returnedTarget = confTarget;
if (confTarget <= 1) return CFeeRate(0); // error conditon
assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
/** true is passed to estimateCombined fee for target/2 and target so /** true is passed to estimateCombined fee for target/2 and target so
@ -899,10 +899,7 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
} }
} }
if (feeCalc) feeCalc->returnedTarget = confTarget; if (median < 0) return CFeeRate(0); // error conditon
if (median < 0)
return CFeeRate(0);
return CFeeRate(median); return CFeeRate(median);
} }

View File

@ -114,7 +114,6 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getrawmempool", 0, "verbose" }, { "getrawmempool", 0, "verbose" },
{ "estimatefee", 0, "nblocks" }, { "estimatefee", 0, "nblocks" },
{ "estimatesmartfee", 0, "nblocks" }, { "estimatesmartfee", 0, "nblocks" },
{ "estimatesmartfee", 1, "conservative" },
{ "estimaterawfee", 0, "nblocks" }, { "estimaterawfee", 0, "nblocks" },
{ "estimaterawfee", 1, "threshold" }, { "estimaterawfee", 1, "threshold" },
{ "prioritisetransaction", 1, "dummy" }, { "prioritisetransaction", 1, "dummy" },

View File

@ -806,42 +806,62 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
{ {
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error( throw std::runtime_error(
"estimatesmartfee nblocks (conservative)\n" "estimatesmartfee nblocks (\"estimate_mode\")\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
"confirmation within nblocks blocks if possible and return the number of blocks\n" "confirmation within nblocks blocks if possible and return the number of blocks\n"
"for which the estimate is valid. Uses virtual transaction size as defined\n" "for which the estimate is valid. Uses virtual transaction size as defined\n"
"in BIP 141 (witness data is discounted).\n" "in BIP 141 (witness data is discounted).\n"
"\nArguments:\n" "\nArguments:\n"
"1. nblocks (numeric)\n" "1. nblocks (numeric) Confirmation target in blocks (1 - 1008)\n"
"2. conservative (bool, optional, default=true) Whether to return a more conservative estimate which\n" "2. \"estimate_mode\" (string, optional, default=CONSERVATIVE) The fee estimate mode.\n"
" also satisfies a longer history. A conservative estimate potentially returns a higher\n" " Whether to return a more conservative estimate which also satisfies\n"
" feerate and is more likely to be sufficient for the desired target, but is not as\n" " a longer history. A conservative estimate potentially returns a\n"
" responsive to short term drops in the prevailing fee market\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:\n"
" \"UNSET\" (defaults to CONSERVATIVE)\n"
" \"ECONOMICAL\"\n"
" \"CONSERVATIVE\"\n"
"\nResult:\n" "\nResult:\n"
"{\n" "{\n"
" \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n" " \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
" \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
" \"blocks\" : n (numeric) block number where estimate was found\n" " \"blocks\" : n (numeric) block number where estimate was found\n"
"}\n" "}\n"
"\n" "\n"
"A negative value is returned if not enough transactions and blocks\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.\n" "have been observed to make an estimate for any number of blocks.\n"
"\nExample:\n" "\nExample:\n"
+ HelpExampleCli("estimatesmartfee", "6") + HelpExampleCli("estimatesmartfee", "6")
); );
RPCTypeCheck(request.params, {UniValue::VNUM}); RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
int nBlocks = request.params[0].get_int(); int nBlocks = request.params[0].get_int();
if (nBlocks < 1 || (unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid nblocks");
}
bool conservative = true; bool conservative = true;
if (request.params.size() > 1 && !request.params[1].isNull()) { if (request.params.size() > 1 && !request.params[1].isNull()) {
RPCTypeCheckArgument(request.params[1], UniValue::VBOOL); FeeEstimateMode fee_mode;
conservative = request.params[1].get_bool(); if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
}
if (fee_mode == FeeEstimateMode::ECONOMICAL) conservative = false;
} }
UniValue result(UniValue::VOBJ); UniValue result(UniValue::VOBJ);
UniValue errors(UniValue::VARR);
FeeCalculation feeCalc; FeeCalculation feeCalc;
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &feeCalc, conservative); CFeeRate feeRate = ::feeEstimator.estimateSmartFee(nBlocks, &feeCalc, conservative);
result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK()))); if (feeRate != CFeeRate(0)) {
result.push_back(Pair("feerate", ValueFromAmount(feeRate.GetFeePerK())));
} else {
errors.push_back("Insufficient data or no feerate found");
result.push_back(Pair("errors", errors));
}
result.push_back(Pair("blocks", feeCalc.returnedTarget)); result.push_back(Pair("blocks", feeCalc.returnedTarget));
return result; return result;
} }
@ -889,7 +909,7 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
+ HelpExampleCli("estimaterawfee", "6 0.9") + HelpExampleCli("estimaterawfee", "6 0.9")
); );
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM, UniValue::VNUM}, true); RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
RPCTypeCheckArgument(request.params[0], UniValue::VNUM); RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
int nBlocks = request.params[0].get_int(); int nBlocks = request.params[0].get_int();
if (nBlocks < 1 || (unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE)) { if (nBlocks < 1 || (unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE)) {
@ -963,7 +983,7 @@ static const CRPCCommand commands[] =
{ "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} }, { "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
{ "util", "estimatefee", &estimatefee, true, {"nblocks"} }, { "util", "estimatefee", &estimatefee, true, {"nblocks"} },
{ "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks", "conservative"} }, { "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks", "estimate_mode"} },
{ "hidden", "estimaterawfee", &estimaterawfee, true, {"nblocks", "threshold"} }, { "hidden", "estimaterawfee", &estimaterawfee, true, {"nblocks", "threshold"} },
}; };