Skip to content

Commit 5e3b7b5

Browse files
committed
Improve error reporting for estimaterawfee
1 parent 1fafd70 commit 5e3b7b5

File tree

1 file changed

+46
-25
lines changed

1 file changed

+46
-25
lines changed

src/rpc/mining.cpp

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -849,71 +849,92 @@ UniValue estimaterawfee(const JSONRPCRequest& request)
849849
"confirmation within nblocks blocks if possible. Uses virtual transaction size as defined\n"
850850
"in BIP 141 (witness data is discounted).\n"
851851
"\nArguments:\n"
852-
"1. nblocks (numeric)\n"
852+
"1. nblocks (numeric) Confirmation target in blocks (1 - 1008)\n"
853853
"2. threshold (numeric, optional) The proportion of transactions in a given feerate range that must have been\n"
854854
" confirmed within nblocks in order to consider those feerates as high enough and proceed to check\n"
855855
" lower buckets. Default: 0.95\n"
856856
"\nResult:\n"
857857
"{\n"
858-
" \"short\" : { (json object) estimate for short time horizon\n"
859-
" \"feerate\" : x.x, (numeric) estimate fee-per-kilobyte (in BTC)\n"
858+
" \"short\" : { (json object, optional) estimate for short time horizon\n"
859+
" \"feerate\" : x.x, (numeric, optional) estimate fee-per-kilobyte (in BTC)\n"
860860
" \"decay\" : x.x, (numeric) exponential decay (per block) for historical moving average of confirmation data\n"
861861
" \"scale\" : x, (numeric) The resolution of confirmation targets at this time horizon\n"
862-
" \"pass\" : { (json object) information about the lowest range of feerates to succeed in meeting the threshold\n"
862+
" \"pass\" : { (json object, optional) information about the lowest range of feerates to succeed in meeting the threshold\n"
863863
" \"startrange\" : x.x, (numeric) start of feerate range\n"
864864
" \"endrange\" : x.x, (numeric) end of feerate range\n"
865865
" \"withintarget\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed within target\n"
866866
" \"totalconfirmed\" : x.x, (numeric) number of txs over history horizon in the feerate range that were confirmed at any point\n"
867867
" \"inmempool\" : x.x, (numeric) current number of txs in mempool in the feerate range unconfirmed for at least target blocks\n"
868868
" \"leftmempool\" : x.x, (numeric) number of txs over history horizon in the feerate range that left mempool unconfirmed after target\n"
869869
" },\n"
870-
" \"fail\" : { ... }, (json object) information about the highest range of feerates to fail to meet the threshold\n"
870+
" \"fail\" : { ... }, (json object, optional) information about the highest range of feerates to fail to meet the threshold\n"
871+
" \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
871872
" },\n"
872-
" \"medium\" : { ... }, (json object) estimate for medium time horizon\n"
873-
" \"long\" : { ... } (json object) estimate for long time horizon\n"
873+
" \"medium\" : { ... }, (json object, optional) estimate for medium time horizon\n"
874+
" \"long\" : { ... } (json object) estimate for long time horizon\n"
874875
"}\n"
875876
"\n"
876-
"A negative feerate is returned if no answer can be given.\n"
877+
"Results are returned for any horizon which tracks blocks up to the confirmation target.\n"
877878
"\nExample:\n"
878879
+ HelpExampleCli("estimaterawfee", "6 0.9")
879880
);
880881

881882
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM, UniValue::VNUM}, true);
882883
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
883884
int nBlocks = request.params[0].get_int();
885+
if (nBlocks < 1 || (unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE)) {
886+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid nblocks");
887+
}
884888
double threshold = 0.95;
885889
if (!request.params[1].isNull()) {
886890
threshold = request.params[1].get_real();
887891
}
892+
if (threshold < 0 || threshold > 1) {
893+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid threshold");
894+
}
888895

889896
UniValue result(UniValue::VOBJ);
890897

891898
for (FeeEstimateHorizon horizon : {FeeEstimateHorizon::SHORT_HALFLIFE, FeeEstimateHorizon::MED_HALFLIFE, FeeEstimateHorizon::LONG_HALFLIFE}) {
892899
CFeeRate feeRate;
893900
EstimationResult buckets;
894-
feeRate = ::feeEstimator.estimateRawFee(nBlocks, threshold, horizon, &buckets);
895901

902+
// Only output results for horizons which track the target
903+
if ((unsigned int)nBlocks > ::feeEstimator.HighestTargetTracked(horizon)) continue;
904+
905+
feeRate = ::feeEstimator.estimateRawFee(nBlocks, threshold, horizon, &buckets);
896906
UniValue horizon_result(UniValue::VOBJ);
897-
horizon_result.push_back(Pair("feerate", feeRate == CFeeRate(0) ? -1.0 : ValueFromAmount(feeRate.GetFeePerK())));
898-
if (!(feeRate == CFeeRate(0))) {
907+
UniValue errors(UniValue::VARR);
908+
UniValue passbucket(UniValue::VOBJ);
909+
passbucket.push_back(Pair("startrange", round(buckets.pass.start)));
910+
passbucket.push_back(Pair("endrange", round(buckets.pass.end)));
911+
passbucket.push_back(Pair("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0));
912+
passbucket.push_back(Pair("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0));
913+
passbucket.push_back(Pair("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0));
914+
passbucket.push_back(Pair("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0));
915+
UniValue failbucket(UniValue::VOBJ);
916+
failbucket.push_back(Pair("startrange", round(buckets.fail.start)));
917+
failbucket.push_back(Pair("endrange", round(buckets.fail.end)));
918+
failbucket.push_back(Pair("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0));
919+
failbucket.push_back(Pair("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0));
920+
failbucket.push_back(Pair("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0));
921+
failbucket.push_back(Pair("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0));
922+
923+
// CFeeRate(0) is used to indicate error as a return value from estimateRawFee
924+
if (feeRate != CFeeRate(0)) {
925+
horizon_result.push_back(Pair("feerate", ValueFromAmount(feeRate.GetFeePerK())));
899926
horizon_result.push_back(Pair("decay", buckets.decay));
900927
horizon_result.push_back(Pair("scale", (int)buckets.scale));
901-
UniValue passbucket(UniValue::VOBJ);
902-
passbucket.push_back(Pair("startrange", round(buckets.pass.start)));
903-
passbucket.push_back(Pair("endrange", round(buckets.pass.end)));
904-
passbucket.push_back(Pair("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0));
905-
passbucket.push_back(Pair("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0));
906-
passbucket.push_back(Pair("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0));
907-
passbucket.push_back(Pair("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0));
908928
horizon_result.push_back(Pair("pass", passbucket));
909-
UniValue failbucket(UniValue::VOBJ);
910-
failbucket.push_back(Pair("startrange", round(buckets.fail.start)));
911-
failbucket.push_back(Pair("endrange", round(buckets.fail.end)));
912-
failbucket.push_back(Pair("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0));
913-
failbucket.push_back(Pair("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0));
914-
failbucket.push_back(Pair("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0));
915-
failbucket.push_back(Pair("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0));
929+
// buckets.fail.start == -1 indicates that all buckets passed, there is no fail bucket to output
930+
if (buckets.fail.start != -1) horizon_result.push_back(Pair("fail", failbucket));
931+
} else {
932+
// Output only information that is still meaningful in the event of error
933+
horizon_result.push_back(Pair("decay", buckets.decay));
934+
horizon_result.push_back(Pair("scale", (int)buckets.scale));
916935
horizon_result.push_back(Pair("fail", failbucket));
936+
errors.push_back("Insufficient data or no feerate found which meets threshold");
937+
horizon_result.push_back(Pair("errors",errors));
917938
}
918939
result.push_back(Pair(StringForFeeEstimateHorizon(horizon), horizon_result));
919940
}

0 commit comments

Comments
 (0)