From 7151c655358ced47b96f51b34ba87b4ea3b1fe20 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 21 Nov 2017 14:00:29 +1030 Subject: [PATCH] chaintopology: track three different feerates. Depending on what we're doing, we can want different ones. So use IMMEDIATE (estimatesmartfee 2 CONSERVATIVE), NORMAL (estimatesmartfee 4 ECONOMICAL) and SLOW (estimatesmartfee 100 ECONOMICAL). If one isn't available, we try making each one half the previous. Signed-off-by: Rusty Russell --- lightningd/bitcoind.c | 67 +++++++++++++++++++++++------ lightningd/bitcoind.h | 24 ++++++----- lightningd/chaintopology.c | 86 +++++++++++++++++++++++++++++++------- lightningd/chaintopology.h | 11 ++++- lightningd/peer_control.c | 28 ++++++++----- 5 files changed, 167 insertions(+), 49 deletions(-) diff --git a/lightningd/bitcoind.c b/lightningd/bitcoind.c index 3d4a9dd11..cf1fe54d3 100644 --- a/lightningd/bitcoind.c +++ b/lightningd/bitcoind.c @@ -259,30 +259,73 @@ static bool extract_feerate(struct bitcoin_cli *bcli, return json_tok_double(output, feeratetok, feerate); } +struct estimatefee { + size_t i; + const u32 *blocks; + const char **estmode; + + void (*cb)(struct bitcoind *bitcoind, const u64 satoshi_per_kw[], + void *); + void *arg; + u64 *satoshi_per_kw; +}; + +static void do_one_estimatefee(struct bitcoind *bitcoind, + struct estimatefee *efee); + static void process_estimatefee(struct bitcoin_cli *bcli) { double feerate; - u64 satoshi_per_kw; - void (*cb)(struct bitcoind *, u64, void *) = bcli->cb; + struct estimatefee *efee = bcli->cb_arg; /* FIXME: We could trawl recent blocks for median fee... */ if (!extract_feerate(bcli, bcli->output, bcli->output_bytes, &feerate)) { - log_unusual(bcli->bitcoind->log, "Unable to estimate fee"); - satoshi_per_kw = 0; + log_unusual(bcli->bitcoind->log, "Unable to estimate %s/%u fee", + efee->estmode[efee->i], efee->blocks[efee->i]); + efee->satoshi_per_kw[efee->i] = 0; } else /* Rate in satoshi per kw. */ - satoshi_per_kw = feerate * 100000000 / 4; + efee->satoshi_per_kw[efee->i] = feerate * 100000000 / 4; + + efee->i++; + if (efee->i == tal_count(efee->satoshi_per_kw)) { + efee->cb(bcli->bitcoind, efee->satoshi_per_kw, efee->arg); + tal_free(efee); + } else { + /* Next */ + do_one_estimatefee(bcli->bitcoind, efee); + } +} - cb(bcli->bitcoind, satoshi_per_kw, bcli->cb_arg); +static void do_one_estimatefee(struct bitcoind *bitcoind, + struct estimatefee *efee) +{ + char blockstr[STR_MAX_CHARS(u32)]; + + sprintf(blockstr, "%u", efee->blocks[efee->i]); + start_bitcoin_cli(bitcoind, NULL, process_estimatefee, false, NULL, efee, + "estimatesmartfee", blockstr, efee->estmode[efee->i], + NULL); } -void bitcoind_estimate_fee_(struct bitcoind *bitcoind, - void (*cb)(struct bitcoind *bitcoind, - u64, void *), - void *arg) +void bitcoind_estimate_fees_(struct bitcoind *bitcoind, + const u32 blocks[], const char *estmode[], + size_t num_estimates, + void (*cb)(struct bitcoind *bitcoind, + const u64 satoshi_per_kw[], void *), + void *arg) { - start_bitcoin_cli(bitcoind, NULL, process_estimatefee, false, cb, arg, - "estimatesmartfee", "2", "CONSERVATIVE", NULL); + struct estimatefee *efee = tal(bitcoind, struct estimatefee); + + efee->i = 0; + efee->blocks = tal_dup_arr(efee, u32, blocks, num_estimates, 0); + efee->estmode = tal_dup_arr(efee, const char *, estmode, num_estimates, + 0); + efee->cb = cb; + efee->arg = arg; + efee->satoshi_per_kw = tal_arr(efee, u64, num_estimates); + + do_one_estimatefee(bitcoind, efee); } static void process_sendrawtx(struct bitcoin_cli *bcli) diff --git a/lightningd/bitcoind.h b/lightningd/bitcoind.h index f83d2f34a..ceec233ff 100644 --- a/lightningd/bitcoind.h +++ b/lightningd/bitcoind.h @@ -55,18 +55,20 @@ struct bitcoind *new_bitcoind(const tal_t *ctx, void wait_for_bitcoind(struct bitcoind *bitcoind); -void bitcoind_estimate_fee_(struct bitcoind *bitcoind, - void (*cb)(struct bitcoind *bitcoind, - u64 satoshi_per_kw, void *), - void *arg); +void bitcoind_estimate_fees_(struct bitcoind *bitcoind, + const u32 blocks[], const char *estmode[], + size_t num_estimates, + void (*cb)(struct bitcoind *bitcoind, + const u64 satoshi_per_kw[], void *), + void *arg); -#define bitcoind_estimate_fee(bitcoind_, cb, arg) \ - bitcoind_estimate_fee_((bitcoind_), \ - typesafe_cb_preargs(void, void *, \ - (cb), (arg), \ - struct bitcoind *, \ - u64), \ - (arg)) +#define bitcoind_estimate_fees(bitcoind_, blocks, estmode, num, cb, arg) \ + bitcoind_estimate_fees_((bitcoind_), (blocks), (estmode), (num), \ + typesafe_cb_preargs(void, void *, \ + (cb), (arg), \ + struct bitcoind *, \ + const u64 *), \ + (arg)) void bitcoind_sendrawtx_(struct bitcoind *bitcoind, const char *hextx, diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 4624c5b0c..d96da955d 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -8,6 +8,7 @@ #include "watch.h" #include #include +#include #include #include #include @@ -291,12 +292,36 @@ static void free_blocks(struct chain_topology *topo, struct block *b) } } -static void update_fee(struct bitcoind *bitcoind, u64 satoshi_per_kw, - struct chain_topology *topo) +static const char *feerate_name(enum feerate feerate) { - log_debug(topo->log, "Feerate %"PRIu64" (was %"PRIu64")", - satoshi_per_kw, topo->feerate); - topo->feerate = satoshi_per_kw; + return feerate == FEERATE_IMMEDIATE ? "Immediate" + : feerate == FEERATE_NORMAL ? "Normal" : "Slow"; +} + +/* We sanitize feerates if necessary to put them in descending order. */ +static void update_feerates(struct bitcoind *bitcoind, + const u64 *satoshi_per_kw, + struct chain_topology *topo) +{ + for (size_t i = 0; i < NUM_FEERATES; i++) { + log_debug(topo->log, "%s feerate %"PRIu64" (was %"PRIu64")", + feerate_name(i), + satoshi_per_kw[i], topo->feerate[i]); + topo->feerate[i] = satoshi_per_kw[i]; + } + + for (size_t i = 0; i < NUM_FEERATES; i++) { + for (size_t j = 0; j < i; j++) { + if (topo->feerate[j] < topo->feerate[i]) { + log_unusual(topo->log, + "Feerate %s (%"PRIu64") above" + " %s (%"PRIu64")", + feerate_name(i), topo->feerate[i], + feerate_name(j), topo->feerate[j]); + topo->feerate[j] = topo->feerate[i]; + } + } + } } /* B is the new chain (linked by ->next); update topology */ @@ -304,6 +329,12 @@ static void topology_changed(struct chain_topology *topo, struct block *prev, struct block *b) { + /* FEERATE_IMMEDIATE, FEERATE_NORMAL, FEERATE_SLOW */ + const char *estmodes[] = { "CONSERVATIVE", "ECONOMICAL", "ECONOMICAL" }; + const u32 blocks[] = { 2, 4, 100 }; + + BUILD_ASSERT(ARRAY_SIZE(blocks) == NUM_FEERATES); + /* Eliminate any old chain. */ if (prev->next) free_blocks(topo, prev->next); @@ -321,8 +352,9 @@ static void topology_changed(struct chain_topology *topo, /* Maybe need to rebroadcast. */ rebroadcast_txs(topo, NULL); - /* Once per new block head, update fee estimate. */ - bitcoind_estimate_fee(topo->bitcoind, update_fee, topo); + /* Once per new block head, update fee estimates. */ + bitcoind_estimate_fees(topo->bitcoind, blocks, estmodes, NUM_FEERATES, + update_feerates, topo); } static struct block *new_block(struct chain_topology *topo, @@ -453,17 +485,43 @@ u32 get_block_height(const struct chain_topology *topo) return topo->tip->height; } -u64 get_feerate(const struct chain_topology *topo) +/* We may only have estimate for 2 blocks, for example. Extrapolate. */ +static u64 guess_feerate(const struct chain_topology *topo, enum feerate feerate) +{ + size_t i = 0; + u64 rate = 0; + + /* We assume each one is half the previous. */ + for (i = 0; i < feerate; i++) { + if (topo->feerate[i]) { + log_info(topo->log, + "No fee estimate for %s: basing on %s rate", + feerate_name(feerate), + feerate_name(i)); + rate = topo->feerate[i]; + } + rate /= 2; + } + + if (rate == 0) { + rate = topo->default_fee_rate >> feerate; + log_info(topo->log, + "No fee estimate for %s: basing on default fee rate", + feerate_name(feerate)); + } + + return rate; +} + +u64 get_feerate(const struct chain_topology *topo, enum feerate feerate) { if (topo->override_fee_rate) { log_debug(topo->log, "Forcing fee rate, ignoring estimate"); return topo->override_fee_rate; + } else if (topo->feerate[feerate] == 0) { + return guess_feerate(topo, feerate); } - else if (topo->feerate == 0) { - log_info(topo->log, "No fee estimate: using default fee rate"); - return topo->default_fee_rate; - } - return topo->feerate; + return topo->feerate[feerate]; } struct txlocator *locate_tx(const void *ctx, const struct chain_topology *topo, @@ -575,7 +633,7 @@ void setup_topology(struct chain_topology *topo, struct timerel poll_time, u32 first_peer_block) { topo->startup = true; - topo->feerate = 0; + memset(&topo->feerate, 0, sizeof(topo->feerate)); topo->timers = timers; topo->poll_time = poll_time; topo->first_blocknum = first_peer_block; diff --git a/lightningd/chaintopology.h b/lightningd/chaintopology.h index 04909a6d7..48f6fb185 100644 --- a/lightningd/chaintopology.h +++ b/lightningd/chaintopology.h @@ -19,6 +19,13 @@ struct peer; struct sha256_double; struct txwatch; +enum feerate { + FEERATE_IMMEDIATE, /* Aka: aim for next block. */ + FEERATE_NORMAL, /* Aka: next 4 blocks or so. */ + FEERATE_SLOW, /* Aka: next 100 blocks or so. */ +}; +#define NUM_FEERATES (FEERATE_SLOW+1) + /* Off topology->outgoing_txs */ struct outgoing_tx { struct list_node list; @@ -82,7 +89,7 @@ struct chain_topology { struct block *root; struct block *tip; struct block_map block_map; - u64 feerate; + u64 feerate[NUM_FEERATES]; bool startup; /* Where to log things. */ @@ -139,7 +146,7 @@ size_t get_tx_depth(const struct chain_topology *topo, u32 get_block_height(const struct chain_topology *topo); /* Get fee rate in satoshi per kiloweight. */ -u64 get_feerate(const struct chain_topology *topo); +u64 get_feerate(const struct chain_topology *topo, enum feerate feerate); /* Broadcast a single tx, and rebroadcast as reqd (copies tx). * If failed is non-NULL, call that and don't rebroadcast. */ diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 2baff219a..428f3faff 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1767,13 +1767,11 @@ static bool better_closing_fee(struct peer *peer, const struct bitcoin_tx *tx) /* Weight once we add in sigs. */ weight = measure_tx_cost(tx) + 74 * 2; - /* FIXME: Use estimatefee 24 or something? */ - min_fee = get_feerate(peer->ld->topology) / 5 * weight / 1000; + min_fee = get_feerate(peer->ld->topology, FEERATE_SLOW) * weight / 1000; if (fee < min_fee) return false; - /* FIXME: Use estimatefee 6 */ - ideal_fee = get_feerate(peer->ld->topology) / 2 * weight / 1000; + ideal_fee = get_feerate(peer->ld->topology, FEERATE_NORMAL) * weight / 1000; /* We prefer fee which is closest to our ideal. */ old_diff = imaxabs((s64)ideal_fee - (s64)last_fee); @@ -1850,7 +1848,7 @@ static void peer_start_closingd(struct peer *peer, { const tal_t *tmpctx = tal_tmpctx(peer); u8 *initmsg, *local_scriptpubkey; - u64 minfee, maxfee, startfee; + u64 minfee, maxfee, startfee, feelimit; u64 num_revocations; if (peer->local_shutdown_idx == -1 @@ -1894,11 +1892,21 @@ static void peer_start_closingd(struct peer *peer, * calculated in [BOLT * #3](03-transactions.md#fee-calculation). */ - maxfee = commit_tx_base_fee(peer->channel_info->feerate_per_kw, 0); - - /* FIXME: Real fees! */ - minfee = maxfee / 2; - startfee = (maxfee + minfee)/2; + feelimit = commit_tx_base_fee(peer->channel_info->feerate_per_kw, 0); + + maxfee = commit_tx_base_fee(get_feerate(peer->ld->topology, + FEERATE_IMMEDIATE), 0); + minfee = commit_tx_base_fee(get_feerate(peer->ld->topology, + FEERATE_SLOW), 0); + startfee = commit_tx_base_fee(get_feerate(peer->ld->topology, + FEERATE_NORMAL), 0); + + if (maxfee > feelimit) + maxfee = feelimit; + if (startfee > feelimit) + startfee = feelimit; + if (minfee > feelimit) + minfee = feelimit; num_revocations = revocations_received(&peer->their_shachain.chain);