From 506703c766958527979663d93467a6fbff232fad Mon Sep 17 00:00:00 2001 From: darosior Date: Thu, 5 Mar 2020 12:00:57 +0100 Subject: [PATCH] bcli: adapt interface to the new estimatefees As did lightningd before, we use 2/CONSERVATIVE for urgent fees, 4/ECONOMICAL for normal fees, and 100/ECONOMICAL for slow fees. --- plugins/bcli.c | 141 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 112 insertions(+), 29 deletions(-) diff --git a/plugins/bcli.c b/plugins/bcli.c index e0133eee5a76..f260d9691e31 100644 --- a/plugins/bcli.c +++ b/plugins/bcli.c @@ -449,17 +449,31 @@ static struct command_result *process_getblockchaininfo(struct bitcoin_cli *bcli return command_finished(bcli->cmd, response); } -static struct command_result *process_estimatefee(struct bitcoin_cli *bcli) + +struct estimatefees_stash { + /* FIXME: We use u64 but lightningd will store them as u32. */ + u64 urgent, normal, slow; +}; + +static struct command_result * +estimatefees_null_response(struct bitcoin_cli *bcli) +{ + struct json_stream *response = jsonrpc_stream_success(bcli->cmd); + + json_add_null(response, "urgent"); + json_add_null(response, "normal"); + json_add_null(response, "slow"); + + return command_finished(bcli->cmd, response); +} + +static struct command_result * +estimatefees_parse_feerate(struct bitcoin_cli *bcli, u64 *feerate) { const jsmntok_t *tokens, *feeratetok = NULL; - struct json_stream *response; bool valid; - u64 feerate; char *err; - if (*bcli->exitstatus != 0) - goto end; - tokens = json_parse_input(bcli->output, bcli->output, (int)bcli->output_bytes, &valid); if (!tokens) { @@ -478,23 +492,89 @@ static struct command_result *process_estimatefee(struct bitcoin_cli *bcli) feeratetok = json_get_member(bcli->output, tokens, "feerate"); if (feeratetok && - !json_to_bitcoin_amount(bcli->output, feeratetok, &feerate)) { + !json_to_bitcoin_amount(bcli->output, feeratetok, feerate)) { err = tal_fmt(bcli->cmd, "%s: bad 'feerate' field (%.*s)", bcli_args(bcli), (int)bcli->output_bytes, bcli->output); return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL); - } + } else if (!feeratetok) + /* We return null if estimation failed, and bitcoin-cli will + * exit with 0 but no feerate field on failure. */ + return estimatefees_null_response(bcli); + + return NULL; +} + +/* We got all the feerates, give them to lightningd. */ +static struct command_result *estimatefees_final_step(struct bitcoin_cli *bcli) +{ + struct command_result *err; + struct json_stream *response; + struct estimatefees_stash *stash = bcli->stash; + + /* bitcoind could theoretically fail to estimate for a higher target. */ + if (*bcli->exitstatus != 0) + return estimatefees_null_response(bcli); + + err = estimatefees_parse_feerate(bcli, &stash->slow); + if (err) + return err; -end: response = jsonrpc_stream_success(bcli->cmd); - if (feeratetok) - json_add_u64(response, "feerate", feerate); - else - json_add_null(response, "feerate"); + json_add_u64(response, "urgent", stash->urgent); + json_add_u64(response, "normal", stash->normal); + json_add_u64(response, "slow", stash->slow); return command_finished(bcli->cmd, response); } +/* We got the response for the normal feerate, now treat the slow one. */ +static struct command_result *estimatefees_third_step(struct bitcoin_cli *bcli) +{ + struct command_result *err; + struct estimatefees_stash *stash = bcli->stash; + const char **params = tal_arr(bcli->cmd, const char *, 2); + + /* bitcoind could theoretically fail to estimate for a higher target. */ + if (*bcli->exitstatus != 0) + return estimatefees_null_response(bcli); + + err = estimatefees_parse_feerate(bcli, &stash->normal); + if (err) + return err; + + params[0] = "100"; + params[1] = "ECONOMICAL"; + start_bitcoin_cli(NULL, bcli->cmd, estimatefees_final_step, true, + BITCOIND_LOW_PRIO, "estimatesmartfee", params, stash); + + return command_still_pending(bcli->cmd); +} + +/* We got the response for the urgent feerate, now treat the normal one. */ +static struct command_result *estimatefees_second_step(struct bitcoin_cli *bcli) +{ + struct command_result *err; + struct estimatefees_stash *stash = bcli->stash; + const char **params = tal_arr(bcli->cmd, const char *, 2); + + /* If we cannot estimatefees, no need to continue bothering bitcoind. */ + if (*bcli->exitstatus != 0) + return estimatefees_null_response(bcli); + + err = estimatefees_parse_feerate(bcli, &stash->urgent); + if (err) + return err; + + params[0] = "4"; + params[1] = "ECONOMICAL"; + start_bitcoin_cli(NULL, bcli->cmd, estimatefees_third_step, true, + BITCOIND_LOW_PRIO, "estimatesmartfee", params, stash); + + return command_still_pending(bcli->cmd); +} + + static struct command_result *process_sendrawtransaction(struct bitcoin_cli *bcli) { struct json_stream *response; @@ -623,25 +703,27 @@ static struct command_result *getchaininfo(struct command *cmd, return command_still_pending(cmd); } -/* Get current feerate. - * Calls `estimatesmartfee` and returns the feerate as btc/k*VBYTE*. +/* Get the current urgent, normal, and slow feerates. + * + * Calls `estimatesmartfee` with targets 2/CONSERVATIVE (urgent), + * 4/ECONOMICAL (normal), and 100/ECONOMICAL (slow) then returns the + * feerates as btc/k*VBYTE*. */ -static struct command_result *getfeerate(struct command *cmd, - const char *buf UNUSED, - const jsmntok_t *toks UNUSED) +static struct command_result *estimatefees(struct command *cmd, + const char *buf UNUSED, + const jsmntok_t *toks UNUSED) { - u32 *blocks; + struct estimatefees_stash *stash = tal(cmd, struct estimatefees_stash); const char **params = tal_arr(cmd, const char *, 2); - if (!param(cmd, buf, toks, - p_req("blocks", param_number, &blocks), - p_req("mode", param_string, ¶ms[1]), - NULL)) + if (!param(cmd, buf, toks, NULL)) return command_param_failed(); - params[0] = tal_fmt(params, "%u", *blocks); - start_bitcoin_cli(NULL, cmd, process_estimatefee, true, - BITCOIND_LOW_PRIO, "estimatesmartfee", params, NULL); + /* First call to estimatesmartfee, for urgent estimation. */ + params[0] = "2"; + params[1] = "CONSERVATIVE"; + start_bitcoin_cli(NULL, cmd, estimatefees_second_step, true, + BITCOIND_LOW_PRIO, "estimatesmartfee", params, stash); return command_still_pending(cmd); } @@ -775,11 +857,12 @@ static const struct plugin_command commands[] = { getchaininfo }, { - "getfeerate", + "estimatefees", "bitcoin", - "Get the Bitcoin feerate in btc/kilo-vbyte.", + "Get the urgent, normal and slow Bitcoin feerates in" + " btc/kilo-vbyte.", "", - getfeerate + estimatefees }, { "sendrawtransaction",