mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 22:45:27 +01:00
bcli: adapt interface to the new fees estimation interface
We keep the same behaviour as lightningd before.
This commit is contained in:
parent
d4fe4073a4
commit
5e72b22e80
2 changed files with 130 additions and 31 deletions
148
plugins/bcli.c
148
plugins/bcli.c
|
@ -449,17 +449,36 @@ static struct command_result *process_getblockchaininfo(struct bitcoin_cli *bcli
|
||||||
return command_finished(bcli->cmd, response);
|
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, "opening");
|
||||||
|
json_add_null(response, "mutual_close");
|
||||||
|
json_add_null(response, "unilateral_close");
|
||||||
|
json_add_null(response, "delayed_to_us");
|
||||||
|
json_add_null(response, "htlc_resolution");
|
||||||
|
json_add_null(response, "penalty");
|
||||||
|
json_add_null(response, "min_acceptable");
|
||||||
|
json_add_null(response, "max_acceptable");
|
||||||
|
|
||||||
|
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;
|
const jsmntok_t *tokens, *feeratetok = NULL;
|
||||||
struct json_stream *response;
|
|
||||||
bool valid;
|
bool valid;
|
||||||
u64 feerate;
|
|
||||||
char *err;
|
char *err;
|
||||||
|
|
||||||
if (*bcli->exitstatus != 0)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
tokens = json_parse_input(bcli->output, bcli->output,
|
tokens = json_parse_input(bcli->output, bcli->output,
|
||||||
(int)bcli->output_bytes, &valid);
|
(int)bcli->output_bytes, &valid);
|
||||||
if (!tokens) {
|
if (!tokens) {
|
||||||
|
@ -478,23 +497,96 @@ static struct command_result *process_estimatefee(struct bitcoin_cli *bcli)
|
||||||
|
|
||||||
feeratetok = json_get_member(bcli->output, tokens, "feerate");
|
feeratetok = json_get_member(bcli->output, tokens, "feerate");
|
||||||
if (feeratetok &&
|
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)",
|
err = tal_fmt(bcli->cmd, "%s: bad 'feerate' field (%.*s)",
|
||||||
bcli_args(bcli), (int)bcli->output_bytes,
|
bcli_args(bcli), (int)bcli->output_bytes,
|
||||||
bcli->output);
|
bcli->output);
|
||||||
return command_done_err(bcli->cmd, BCLI_ERROR, err, NULL);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
/* 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;
|
||||||
|
|
||||||
response = jsonrpc_stream_success(bcli->cmd);
|
response = jsonrpc_stream_success(bcli->cmd);
|
||||||
if (feeratetok)
|
json_add_u64(response, "opening", stash->normal);
|
||||||
json_add_u64(response, "feerate", feerate);
|
json_add_u64(response, "mutual_close", stash->normal);
|
||||||
else
|
json_add_u64(response, "unilateral_close", stash->urgent);
|
||||||
json_add_null(response, "feerate");
|
json_add_u64(response, "delayed_to_us", stash->normal);
|
||||||
|
json_add_u64(response, "htlc_resolution", stash->normal);
|
||||||
|
json_add_u64(response, "penalty", stash->normal);
|
||||||
|
/* We divide the slow feerate for the minimum acceptable, lightningd
|
||||||
|
* will use floor if it's hit, though. */
|
||||||
|
json_add_u64(response, "min_acceptable", stash->slow / 2);
|
||||||
|
json_add_u64(response, "max_acceptable", stash->urgent);
|
||||||
|
|
||||||
return command_finished(bcli->cmd, response);
|
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)
|
static struct command_result *process_sendrawtransaction(struct bitcoin_cli *bcli)
|
||||||
{
|
{
|
||||||
struct json_stream *response;
|
struct json_stream *response;
|
||||||
|
@ -623,25 +715,28 @@ static struct command_result *getchaininfo(struct command *cmd,
|
||||||
return command_still_pending(cmd);
|
return command_still_pending(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get current feerate.
|
/* Get the current feerates. We use an urgent feerate for unilateral_close and max,
|
||||||
* Calls `estimatesmartfee` and returns the feerate as btc/k*VBYTE*.
|
* a slow feerate for min, and a normal for all others.
|
||||||
|
*
|
||||||
|
* Calls `estimatesmartfee` with targets 2/CONSERVATIVE (urgent),
|
||||||
|
* 4/ECONOMICAL (normal), and 100/ECONOMICAL (slow) then returns the
|
||||||
|
* feerates as sat/kVB.
|
||||||
*/
|
*/
|
||||||
static struct command_result *getfeerate(struct command *cmd,
|
static struct command_result *estimatefees(struct command *cmd,
|
||||||
const char *buf UNUSED,
|
const char *buf UNUSED,
|
||||||
const jsmntok_t *toks 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);
|
const char **params = tal_arr(cmd, const char *, 2);
|
||||||
|
|
||||||
if (!param(cmd, buf, toks,
|
if (!param(cmd, buf, toks, NULL))
|
||||||
p_req("blocks", param_number, &blocks),
|
|
||||||
p_req("mode", param_string, ¶ms[1]),
|
|
||||||
NULL))
|
|
||||||
return command_param_failed();
|
return command_param_failed();
|
||||||
|
|
||||||
params[0] = tal_fmt(params, "%u", *blocks);
|
/* First call to estimatesmartfee, for urgent estimation. */
|
||||||
start_bitcoin_cli(NULL, cmd, process_estimatefee, true,
|
params[0] = "2";
|
||||||
BITCOIND_LOW_PRIO, "estimatesmartfee", params, NULL);
|
params[1] = "CONSERVATIVE";
|
||||||
|
start_bitcoin_cli(NULL, cmd, estimatefees_second_step, true,
|
||||||
|
BITCOIND_LOW_PRIO, "estimatesmartfee", params, stash);
|
||||||
|
|
||||||
return command_still_pending(cmd);
|
return command_still_pending(cmd);
|
||||||
}
|
}
|
||||||
|
@ -773,11 +868,12 @@ static const struct plugin_command commands[] = {
|
||||||
getchaininfo
|
getchaininfo
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"getfeerate",
|
"estimatefees",
|
||||||
"bitcoin",
|
"bitcoin",
|
||||||
"Get the Bitcoin feerate in btc/kilo-vbyte.",
|
"Get the urgent, normal and slow Bitcoin feerates as"
|
||||||
|
" sat/kVB.",
|
||||||
"",
|
"",
|
||||||
getfeerate
|
estimatefees
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"sendrawtransaction",
|
"sendrawtransaction",
|
||||||
|
|
|
@ -1071,8 +1071,11 @@ def test_bcli(node_factory, bitcoind, chainparams):
|
||||||
l1.rpc.plugin_stop("bcli")
|
l1.rpc.plugin_stop("bcli")
|
||||||
|
|
||||||
# Failure case of feerate is tested in test_misc.py
|
# Failure case of feerate is tested in test_misc.py
|
||||||
assert "feerate" in l1.rpc.call("getfeerate", {"blocks": 3,
|
estimates = l1.rpc.call("estimatefees")
|
||||||
"mode": "CONSERVATIVE"})
|
for est in ["opening", "mutual_close", "unilateral_close", "delayed_to_us",
|
||||||
|
"htlc_resolution", "penalty", "min_acceptable",
|
||||||
|
"max_acceptable"]:
|
||||||
|
assert est in estimates
|
||||||
|
|
||||||
resp = l1.rpc.call("getchaininfo")
|
resp = l1.rpc.call("getchaininfo")
|
||||||
assert resp["chain"] == chainparams['name']
|
assert resp["chain"] == chainparams['name']
|
||||||
|
|
Loading…
Add table
Reference in a new issue