mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 07:04:22 +01:00
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 <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
ef4d54df94
commit
7151c65535
@@ -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;
|
||||
|
||||
cb(bcli->bitcoind, satoshi_per_kw, bcli->cb_arg);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void bitcoind_estimate_fee_(struct bitcoind *bitcoind,
|
||||
void (*cb)(struct bitcoind *bitcoind,
|
||||
u64, void *),
|
||||
void *arg)
|
||||
static void do_one_estimatefee(struct bitcoind *bitcoind,
|
||||
struct estimatefee *efee)
|
||||
{
|
||||
start_bitcoin_cli(bitcoind, NULL, process_estimatefee, false, cb, arg,
|
||||
"estimatesmartfee", "2", "CONSERVATIVE", NULL);
|
||||
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_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)
|
||||
{
|
||||
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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "watch.h"
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/asort/asort.h>
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
feelimit = commit_tx_base_fee(peer->channel_info->feerate_per_kw, 0);
|
||||
|
||||
/* FIXME: Real fees! */
|
||||
minfee = maxfee / 2;
|
||||
startfee = (maxfee + minfee)/2;
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user