|
|
@ -849,17 +849,17 @@ UniValue estimaterawfee(const JSONRPCRequest& request) |
|
|
|
"confirmation within nblocks blocks if possible. Uses virtual transaction size as defined\n" |
|
|
|
"confirmation within nblocks blocks if possible. 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. 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 nblocks 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" |
|
|
|
" \"short\" : { (json object) estimate for short time horizon\n" |
|
|
|
" \"short\" : { (json object, optional) estimate for short time horizon\n" |
|
|
|
" \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n" |
|
|
|
" \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n" |
|
|
|
" \"decay\" : x.x, (numeric) exponential decay (per block) for historical moving average of confirmation data\n" |
|
|
|
" \"decay\" : x.x, (numeric) exponential decay (per block) for historical moving average of confirmation data\n" |
|
|
|
" \"scale\" : x, (numeric) The resolution of confirmation targets at this time horizon\n" |
|
|
|
" \"scale\" : x, (numeric) The resolution of confirmation targets at this time horizon\n" |
|
|
|
" \"pass\" : { (json object) information about the lowest range of feerates to succeed in meeting the threshold\n" |
|
|
|
" \"pass\" : { (json object, optional) information about the lowest range of feerates to succeed in meeting the threshold\n" |
|
|
|
" \"startrange\" : x.x, (numeric) start of feerate range\n" |
|
|
|
" \"startrange\" : x.x, (numeric) start of feerate range\n" |
|
|
|
" \"endrange\" : x.x, (numeric) end of feerate range\n" |
|
|
|
" \"endrange\" : x.x, (numeric) end of feerate range\n" |
|
|
|
" \"withintarget\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed within target\n" |
|
|
|
" \"withintarget\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed within target\n" |
|
|
@ -867,13 +867,14 @@ UniValue estimaterawfee(const JSONRPCRequest& request) |
|
|
|
" \"inmempool\" : x.x, (numeric) current number of txs in mempool in the feerate range unconfirmed for at least target blocks\n" |
|
|
|
" \"inmempool\" : x.x, (numeric) current number of txs in mempool in the feerate range unconfirmed for at least target blocks\n" |
|
|
|
" \"leftmempool\" : x.x, (numeric) number of txs over history horizon in the feerate range that left mempool unconfirmed after target\n" |
|
|
|
" \"leftmempool\" : x.x, (numeric) number of txs over history horizon in the feerate range that left mempool unconfirmed after target\n" |
|
|
|
" },\n" |
|
|
|
" },\n" |
|
|
|
" \"fail\" : { ... }, (json object) information about the highest range of feerates to fail to meet the threshold\n" |
|
|
|
" \"fail\" : { ... }, (json object, optional) information about the highest range of feerates to fail to meet the threshold\n" |
|
|
|
|
|
|
|
" \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n" |
|
|
|
" },\n" |
|
|
|
" },\n" |
|
|
|
" \"medium\" : { ... }, (json object) estimate for medium time horizon\n" |
|
|
|
" \"medium\" : { ... }, (json object, optional) estimate for medium time horizon\n" |
|
|
|
" \"long\" : { ... } (json object) estimate for long time horizon\n" |
|
|
|
" \"long\" : { ... } (json object) estimate for long time horizon\n" |
|
|
|
"}\n" |
|
|
|
"}\n" |
|
|
|
"\n" |
|
|
|
"\n" |
|
|
|
"A negative feerate is returned if no answer can be given.\n" |
|
|
|
"Results are returned for any horizon which tracks blocks up to the confirmation target.\n" |
|
|
|
"\nExample:\n" |
|
|
|
"\nExample:\n" |
|
|
|
+ HelpExampleCli("estimaterawfee", "6 0.9") |
|
|
|
+ HelpExampleCli("estimaterawfee", "6 0.9") |
|
|
|
); |
|
|
|
); |
|
|
@ -881,23 +882,29 @@ UniValue estimaterawfee(const JSONRPCRequest& request) |
|
|
|
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM, UniValue::VNUM}, true); |
|
|
|
RPCTypeCheck(request.params, {UniValue::VNUM, 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)) { |
|
|
|
|
|
|
|
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(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (threshold < 0 || threshold > 1) { |
|
|
|
|
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid threshold"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
UniValue result(UniValue::VOBJ); |
|
|
|
UniValue result(UniValue::VOBJ); |
|
|
|
|
|
|
|
|
|
|
|
for (FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) { |
|
|
|
for (FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) { |
|
|
|
CFeeRate feeRate; |
|
|
|
CFeeRate feeRate; |
|
|
|
EstimationResult buckets; |
|
|
|
EstimationResult buckets; |
|
|
|
feeRate = ::feeEstimator.estimateRawFee(nBlocks, threshold, horizon, &buckets); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Only output results for horizons which track the target
|
|
|
|
|
|
|
|
if ((unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(horizon)) continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
feeRate = ::feeEstimator.estimateRawFee(nBlocks, threshold, horizon, &buckets); |
|
|
|
UniValue horizon_result(UniValue::VOBJ); |
|
|
|
UniValue horizon_result(UniValue::VOBJ); |
|
|
|
horizon_result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK()))); |
|
|
|
UniValue errors(UniValue::VARR); |
|
|
|
if (!(feeRate == CFeeRate(0))) { |
|
|
|
|
|
|
|
horizon_result.push_back(Pair("decay", buckets.decay)); |
|
|
|
|
|
|
|
horizon_result.push_back(Pair("scale", (int)buckets.scale)); |
|
|
|
|
|
|
|
UniValue passbucket(UniValue::VOBJ); |
|
|
|
UniValue passbucket(UniValue::VOBJ); |
|
|
|
passbucket.push_back(Pair("startrange", round(buckets.pass.start))); |
|
|
|
passbucket.push_back(Pair("startrange", round(buckets.pass.start))); |
|
|
|
passbucket.push_back(Pair("endrange", round(buckets.pass.end))); |
|
|
|
passbucket.push_back(Pair("endrange", round(buckets.pass.end))); |
|
|
@ -905,7 +912,6 @@ UniValue estimaterawfee(const JSONRPCRequest& request) |
|
|
|
passbucket.push_back(Pair("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0)); |
|
|
|
passbucket.push_back(Pair("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0)); |
|
|
|
passbucket.push_back(Pair("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0)); |
|
|
|
passbucket.push_back(Pair("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0)); |
|
|
|
passbucket.push_back(Pair("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0)); |
|
|
|
passbucket.push_back(Pair("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0)); |
|
|
|
horizon_result.push_back(Pair("pass", passbucket)); |
|
|
|
|
|
|
|
UniValue failbucket(UniValue::VOBJ); |
|
|
|
UniValue failbucket(UniValue::VOBJ); |
|
|
|
failbucket.push_back(Pair("startrange", round(buckets.fail.start))); |
|
|
|
failbucket.push_back(Pair("startrange", round(buckets.fail.start))); |
|
|
|
failbucket.push_back(Pair("endrange", round(buckets.fail.end))); |
|
|
|
failbucket.push_back(Pair("endrange", round(buckets.fail.end))); |
|
|
@ -913,7 +919,22 @@ UniValue estimaterawfee(const JSONRPCRequest& request) |
|
|
|
failbucket.push_back(Pair("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0)); |
|
|
|
failbucket.push_back(Pair("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0)); |
|
|
|
failbucket.push_back(Pair("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0)); |
|
|
|
failbucket.push_back(Pair("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0)); |
|
|
|
failbucket.push_back(Pair("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0)); |
|
|
|
failbucket.push_back(Pair("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CFeeRate(0) is used to indicate error as a return value from estimateRawFee
|
|
|
|
|
|
|
|
if (feeRate != CFeeRate(0)) { |
|
|
|
|
|
|
|
horizon_result.push_back(Pair("feerate", ValueFromAmount(feeRate.GetFeePerK()))); |
|
|
|
|
|
|
|
horizon_result.push_back(Pair("decay", buckets.decay)); |
|
|
|
|
|
|
|
horizon_result.push_back(Pair("scale", (int)buckets.scale)); |
|
|
|
|
|
|
|
horizon_result.push_back(Pair("pass", passbucket)); |
|
|
|
|
|
|
|
// buckets.fail.start == -1 indicates that all buckets passed, there is no fail bucket to output
|
|
|
|
|
|
|
|
if (buckets.fail.start != -1) horizon_result.push_back(Pair("fail", failbucket)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Output only information that is still meaningful in the event of error
|
|
|
|
|
|
|
|
horizon_result.push_back(Pair("decay", buckets.decay)); |
|
|
|
|
|
|
|
horizon_result.push_back(Pair("scale", (int)buckets.scale)); |
|
|
|
horizon_result.push_back(Pair("fail", failbucket)); |
|
|
|
horizon_result.push_back(Pair("fail", failbucket)); |
|
|
|
|
|
|
|
errors.push_back("Insufficient data or no feerate found which meets threshold"); |
|
|
|
|
|
|
|
horizon_result.push_back(Pair("errors",errors)); |
|
|
|
} |
|
|
|
} |
|
|
|
result.push_back(Pair(StringForFeeEstimateHorizon(horizon), horizon_result)); |
|
|
|
result.push_back(Pair(StringForFeeEstimateHorizon(horizon), horizon_result)); |
|
|
|
} |
|
|
|
} |
|
|
|