From f2ffb6d03eb769b7327f322dcaad27c1a75221e2 Mon Sep 17 00:00:00 2001 From: SimonVrouwe <3152756+SimonVrouwe@users.noreply.github.com> Date: Sun, 15 Jul 2018 19:30:43 +0300 Subject: [PATCH] improves exponential smoothing of feerate estimates (#1699) - fixes problem with polling interval > 150 * 0.9 - fixes log message 'feerate hit floor' at every feerate change - smoothed fee now reaches 90% of (exp weighted) fee estimates polled in last 120s, independent of polling interval - only apply smoothing when effect > 10 percent so it doesn't correct forever - fix indentation --- lightningd/chaintopology.c | 37 ++++++++++++++++++++++--------------- lightningd/chaintopology.h | 1 + 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/lightningd/chaintopology.c b/lightningd/chaintopology.c index 83b2bf751..25352c352 100644 --- a/lightningd/chaintopology.c +++ b/lightningd/chaintopology.c @@ -237,8 +237,11 @@ static void update_feerates(struct bitcoind *bitcoind, { u32 old_feerates[NUM_FEERATES]; bool changed = false; - /* Rate of change of the fee smoothing, depending on the poll-interval */ - double change_rate = (double)topo->poll_seconds / 150 * 0.9; + /* Smoothing factor alpha for simple exponential smoothing. The goal is to + * have the feerate account for 90 percent of the values polled in the last + * 2 minutes. The following will do that in a polling interval + * independent manner. */ + double alpha = 1 - pow(0.1,(double)topo->poll_seconds / 120); for (size_t i = 0; i < NUM_FEERATES; i++) { u32 feerate = satoshi_per_kw[i]; @@ -250,24 +253,28 @@ static void update_feerates(struct bitcoind *bitcoind, if (!feerate) continue; - /* Smooth the feerate to avoid spikes. The goal is to have the - * fee consist of 0.9 * feerate + 0.1 * old_feerate after 300 - * seconds. The following will do that in a polling interval - * independent manner. */ - feerate = - feerate * (1 - change_rate) + old_feerates[i] * change_rate; - - if (feerate < feerate_floor()) - feerate = feerate_floor(); + /* Smooth the feerate to avoid spikes. */ + u32 feerate_smooth = feerate * alpha + old_feerates[i] * (1 - alpha); + /* But to avoid updating forever, only apply smoothing when its + * effect is more then 10 percent */ + if (abs(feerate - feerate_smooth) > (0.1 * feerate)) { + feerate = feerate_smooth; + log_debug(topo->log, + "...feerate %u smoothed to %u (alpha=%.2f)", + satoshi_per_kw[i], feerate, alpha); + } + + if (feerate < feerate_floor()) { + feerate = feerate_floor(); + log_debug(topo->log, + "...feerate %u hit floor %u", + satoshi_per_kw[i], feerate); + } if (feerate != topo->feerate[i]) { log_debug(topo->log, "%s feerate %u (was %u)", feerate_name(i), feerate, topo->feerate[i]); - if (feerate != satoshi_per_kw[i]) - log_debug(topo->log, - "...feerate %u hit floor %u", - satoshi_per_kw[i], feerate); } topo->feerate[i] = feerate; } diff --git a/lightningd/chaintopology.h b/lightningd/chaintopology.h index 55d45643d..124a7b7fa 100644 --- a/lightningd/chaintopology.h +++ b/lightningd/chaintopology.h @@ -9,6 +9,7 @@ #include #include #include +#include #include struct bitcoin_tx;