Browse Source

Merge #10707: Better API for estimatesmartfee RPC

06bcdb8da Convert named argument from nblocks to conf_target (Alex Morcos)
439c4e8ad 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 https://github.com/bitcoin/bitcoin/pull/10707#issuecomment-314869251 for renaming of nblocks argument to conf_target.  Will need to be included before string freeze.

  PR description edited for clarity

Tree-SHA512: 6d8ebee8bb410e2950ffd59663eebfed8d1611d995dc935bb91e430d9da7e2f306796f45631458376027d26341c660f09e825e61748103d2f2736ec6dc3df3ae
0.15
Pieter Wuille 7 years ago
parent
commit
75b5643c47
No known key found for this signature in database
GPG Key ID: A636E97631F767E0
  1. 19
      src/policy/fees.cpp
  2. 1
      src/rpc/client.cpp
  3. 74
      src/rpc/mining.cpp

19
src/policy/fees.cpp

@ -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);
} }

1
src/rpc/client.cpp

@ -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" },

74
src/rpc/mining.cpp

@ -806,42 +806,59 @@ 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 conf_target (\"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 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" "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. conf_target (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(); unsigned int conf_target = ParseConfirmTarget(request.params[0]);
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(conf_target, &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;
} }
@ -850,18 +867,18 @@ UniValue estimaterawfee(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(
"estimaterawfee nblocks (threshold)\n" "estimaterawfee conf_target (threshold)\n"
"\nWARNING: This interface is unstable and may disappear or change!\n" "\nWARNING: This interface is unstable and may disappear or change!\n"
"\nWARNING: This is an advanced API call that is tightly coupled to the specific\n" "\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
" implementation of fee estimation. The parameters it can be called with\n" " implementation of fee estimation. The parameters it can be called with\n"
" and the results it returns will change if the internal implementation changes.\n" " and the results it returns will change if the internal implementation changes.\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. Uses virtual transaction size as defined\n" "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n"
"in BIP 141 (witness data is discounted).\n" "defined in BIP 141 (witness data is discounted).\n"
"\nArguments:\n" "\nArguments:\n"
"1. nblocks (numeric) Confirmation target in blocks (1 - 1008)\n" "1. conf_target (numeric) Confirmation target in blocks (1 - 1008)\n"
"2. threshold (numeric, optional) The proportion of transactions in a given feerate range that must have been\n" "2. threshold (numeric, optional) The proportion of transactions in a given feerate range that must have been\n"
" confirmed within nblocks in order to consider those feerates as high enough and proceed to check\n" " confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
" lower buckets. Default: 0.95\n" " lower buckets. Default: 0.95\n"
"\nResult:\n" "\nResult:\n"
"{\n" "{\n"
@ -889,12 +906,9 @@ 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(); unsigned int conf_target = ParseConfirmTarget(request.params[0]);
if (nBlocks < 1 || (unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid nblocks");
}
double threshold = 0.95; double threshold = 0.95;
if (!request.params[1].isNull()) { if (!request.params[1].isNull()) {
threshold = request.params[1].get_real(); threshold = request.params[1].get_real();
@ -910,9 +924,9 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
EstimationResult buckets; EstimationResult buckets;
// Only output results for horizons which track the target // Only output results for horizons which track the target
if ((unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(horizon)) continue; if (conf_target > ::feeEstimator.HighestTargetTracked(horizon)) continue;
feeRate = ::feeEstimator.estimateRawFee(nBlocks, threshold, horizon, &buckets); feeRate = ::feeEstimator.estimateRawFee(conf_target, threshold, horizon, &buckets);
UniValue horizon_result(UniValue::VOBJ); UniValue horizon_result(UniValue::VOBJ);
UniValue errors(UniValue::VARR); UniValue errors(UniValue::VARR);
UniValue passbucket(UniValue::VOBJ); UniValue passbucket(UniValue::VOBJ);
@ -963,9 +977,9 @@ 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, {"conf_target", "estimate_mode"} },
{ "hidden", "estimaterawfee", &estimaterawfee, true, {"nblocks", "threshold"} }, { "hidden", "estimaterawfee", &estimaterawfee, true, {"conf_target", "threshold"} },
}; };
void RegisterMiningRPCCommands(CRPCTable &t) void RegisterMiningRPCCommands(CRPCTable &t)

Loading…
Cancel
Save