Browse Source

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>
ppa-0.6.1
Rusty Russell 7 years ago
committed by Christian Decker
parent
commit
7151c65535
  1. 67
      lightningd/bitcoind.c
  2. 24
      lightningd/bitcoind.h
  3. 86
      lightningd/chaintopology.c
  4. 11
      lightningd/chaintopology.h
  5. 28
      lightningd/peer_control.c

67
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)

24
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,

86
lightningd/chaintopology.c

@ -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;

11
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. */

28
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);

Loading…
Cancel
Save