core-lightning/common/fee_states.c
Christian Decker 24ec17126c channeld: Adjust the feerate security margin profile
The feerate security margin is a multiplicative factor applied to the
feerate of some transactions in order to guarantee that the
transaction remains publishable and has a sufficient chance of being
confirmed, that we can base some of our decisions on that.

The multiplicative factor is >=1 and was so far a constant 2. This
might have been sensible in the low-fee environment, where the fees
are expected to oscillate, and almost guaranteeing that we will
eventually have rising feerates but in high-fee environments that is
no longer the case, and the 100% margin that the multiplicator 2
brings is excessive. We therefore opt to start out with 100%, then
linearly interpolate up to a given maxfeerate (which does not have to
be a real feerate ever reached, it just indicates the feerate after
which we apply the constant 10% margin.

Fixes #6974
Closes #6976
[Fixed up all the other changes required, including spendable calcualtion
 comments and unit test and pytest tests --RR]
2024-05-13 14:06:45 -05:00

198 lines
5.6 KiB
C

#include "config.h"
#include <ccan/array_size/array_size.h>
#include <ccan/cast/cast.h>
#include <ccan/tal/str/str.h>
#include <common/fee_states.h>
#include <wire/wire.h>
/* If we're the finder, it's like an HTLC we added, if they are, it's like
* a HTLC they added. */
enum htlc_state first_fee_state(enum side opener)
{
if (opener == LOCAL)
return SENT_ADD_HTLC;
else
return RCVD_ADD_HTLC;
}
enum htlc_state last_fee_state(enum side opener)
{
if (opener == LOCAL)
return SENT_ADD_ACK_REVOCATION;
else
return RCVD_ADD_ACK_REVOCATION;
}
struct fee_states *new_fee_states(const tal_t *ctx,
enum side opener,
const u32 *feerate_per_kw)
{
struct fee_states *fee_states = tal(ctx, struct fee_states);
/* Set to NULL except terminal value */
for (size_t i = 0; i < ARRAY_SIZE(fee_states->feerate); i++)
fee_states->feerate[i] = NULL;
if (feerate_per_kw)
fee_states->feerate[last_fee_state(opener)]
= tal_dup(fee_states, u32, feerate_per_kw);
return fee_states;
}
struct fee_states *dup_fee_states(const tal_t *ctx,
const struct fee_states *fee_states TAKES)
{
struct fee_states *n;
if (taken(fee_states))
return cast_const(struct fee_states *,
tal_steal(ctx, fee_states));
n = tal_dup(ctx, struct fee_states, fee_states);
for (size_t i = 0; i < ARRAY_SIZE(n->feerate); i++)
n->feerate[i] = tal_dup_or_null(n, u32, n->feerate[i]);
return n;
}
u32 get_feerate(const struct fee_states *fee_states,
enum side opener,
enum side side)
{
/* The first non-NULL feerate committed to this side is current */
for (enum htlc_state i = first_fee_state(opener);
i <= last_fee_state(opener);
i++) {
if (!fee_states->feerate[i])
continue;
if (!(htlc_state_flags(i) & HTLC_FLAG(side, HTLC_F_COMMITTED)))
continue;
return *fee_states->feerate[i];
}
/* Some feerate should always be set! */
abort();
}
/* Are feerates all agreed by both sides? */
bool feerate_changes_done(const struct fee_states *fee_states,
bool ignore_uncommitted)
{
size_t num_feerates = 0;
for (size_t i = 0; i < ARRAY_SIZE(fee_states->feerate); i++) {
if (ignore_uncommitted
&& (i == RCVD_ADD_HTLC || i == SENT_ADD_HTLC))
continue;
num_feerates += (fee_states->feerate[i] != NULL);
}
return num_feerates == 1;
}
void start_fee_update(struct fee_states *fee_states,
enum side opener,
u32 feerate_per_kw)
{
enum htlc_state start = first_fee_state(opener);
/* BOLT #2:
* Unlike an HTLC, `update_fee` is never closed but simply replaced.
*/
if (fee_states->feerate[start] == NULL)
fee_states->feerate[start] = tal(fee_states, u32);
*fee_states->feerate[start] = feerate_per_kw;
}
bool inc_fee_state(struct fee_states *fee_states, enum htlc_state hstate)
{
/* These only advance through ADDING states. */
assert(htlc_state_flags(hstate) & HTLC_ADDING);
if (!fee_states->feerate[hstate])
return false;
/* FIXME: We can never clash, except at final state unless someone
* has violated protocol (eg, send two revoke_and_ack back-to-back) */
tal_free(fee_states->feerate[hstate+1]);
fee_states->feerate[hstate+1] = fee_states->feerate[hstate];
fee_states->feerate[hstate] = NULL;
return true;
}
struct fee_states *fromwire_fee_states(const tal_t *ctx,
const u8 **cursor, size_t *max)
{
struct fee_states *fee_states = tal(ctx, struct fee_states);
for (enum htlc_state i = 0; i < ARRAY_SIZE(fee_states->feerate); i++) {
if (fromwire_bool(cursor, max)) {
fee_states->feerate[i] = tal(fee_states, u32);
*fee_states->feerate[i] = fromwire_u32(cursor, max);
} else {
fee_states->feerate[i] = NULL;
}
}
if (!*cursor)
return tal_free(fee_states);
return fee_states;
}
void towire_fee_states(u8 **pptr, const struct fee_states *fee_states)
{
for (enum htlc_state i = 0; i < ARRAY_SIZE(fee_states->feerate); i++) {
/* We don't send uncommitted feestates */
if (!(htlc_state_flags(i) & (HTLC_REMOTE_F_COMMITTED
| HTLC_LOCAL_F_COMMITTED))
|| fee_states->feerate[i] == NULL) {
towire_bool(pptr, false);
continue;
}
towire_bool(pptr, true);
towire_u32(pptr, *fee_states->feerate[i]);
}
}
/* FIXME: we don't know opener inside fromwire_fee_states, so can't do
* this there :( */
bool fee_states_valid(const struct fee_states *fee_states, enum side opener)
{
return fee_states->feerate[last_fee_state(opener)] != NULL;
}
/* The calculation starts with a 100% margin at very low fees, since
* they are likely to rise, and can do so quickly, whereas on the
* higher fee side, asking for a 100% margin is excessive, so ask for
* a 10% margin. In-between these two regions we interpolate
* linearly. Notice that minfeerate and maxfeerate are just the
* markers of the linear interpolation, they don't have to correspond
* to actual feerates seen in the network. */
u32 marginal_feerate(u32 current_feerate)
{
const u32 minfeerate = 253, maxfeerate = 45000;
#ifdef TEST_ALLOW_ZERO_FEERATE
/* The BOLT test for commitment transactions does this. */
if (current_feerate == 0)
return 0;
#endif
assert(current_feerate >= minfeerate);
if (current_feerate > maxfeerate)
return current_feerate * 1.1;
/* min gives 1, max gives 0.1 */
double proportion = 1.0 - ((double)current_feerate - minfeerate) / (maxfeerate - minfeerate) * 0.9;
return current_feerate + proportion * current_feerate;
}
char *fmt_fee_states(const tal_t *ctx,
const struct fee_states *fee_states)
{
char *ret = tal_strdup(ctx, "{");
for (enum htlc_state i = 0; i < ARRAY_SIZE(fee_states->feerate); i++) {
if (fee_states->feerate[i] != NULL)
tal_append_fmt(&ret, " %s:%u",
htlc_state_name(i),
*fee_states->feerate[i]);
}
tal_append_fmt(&ret, " }");
return ret;
}