mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-01 17:47:30 +01:00
common: add fee_states state machine for update_fee.
This uses the same state machine as HTLCs, but they're only ever added, not removed. Since we can only have one in each state, we use a simple array; mostly NULL. We could make this more space-efficient by folding everything into the first 5 states, but that would be more complex than just using the identical state machine. One subtlety: we don't send uncommitted fee_states over the wire. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
ec1505199e
commit
b9d6e8bbaa
6 changed files with 251 additions and 0 deletions
|
@ -46,6 +46,7 @@ CHANNELD_COMMON_OBJS := \
|
|||
common/derive_basepoints.o \
|
||||
common/dev_disconnect.o \
|
||||
common/features.o \
|
||||
common/fee_states.o \
|
||||
common/gen_status_wire.o \
|
||||
common/gen_peer_status_wire.o \
|
||||
common/gossip_rcvd_filter.o \
|
||||
|
|
|
@ -20,6 +20,7 @@ COMMON_SRC_NOGEN := \
|
|||
common/derive_basepoints.c \
|
||||
common/dev_disconnect.c \
|
||||
common/features.c \
|
||||
common/fee_states.c \
|
||||
common/funding_tx.c \
|
||||
common/gossip_rcvd_filter.c \
|
||||
common/gossip_store.c \
|
||||
|
|
158
common/fee_states.c
Normal file
158
common/fee_states.c
Normal file
|
@ -0,0 +1,158 @@
|
|||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/cast/cast.h>
|
||||
#include <common/fee_states.h>
|
||||
#include <common/type_to_string.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 funder)
|
||||
{
|
||||
if (funder == LOCAL)
|
||||
return SENT_ADD_HTLC;
|
||||
else
|
||||
return RCVD_ADD_HTLC;
|
||||
}
|
||||
|
||||
enum htlc_state last_fee_state(enum side funder)
|
||||
{
|
||||
if (funder == LOCAL)
|
||||
return SENT_ADD_ACK_REVOCATION;
|
||||
else
|
||||
return RCVD_ADD_ACK_REVOCATION;
|
||||
}
|
||||
|
||||
struct fee_states *new_fee_states(const tal_t *ctx,
|
||||
enum side funder,
|
||||
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(funder)]
|
||||
= 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++) {
|
||||
if (n->feerate[i])
|
||||
n->feerate[i] = tal_dup(n, u32, n->feerate[i]);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
u32 get_feerate(const struct fee_states *fee_states,
|
||||
enum side funder,
|
||||
enum side side)
|
||||
{
|
||||
/* The first non-NULL feerate committed to this side is current */
|
||||
for (enum htlc_state i = first_fee_state(funder);
|
||||
i <= last_fee_state(funder);
|
||||
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();
|
||||
}
|
||||
|
||||
void start_fee_update(struct fee_states *fee_states,
|
||||
enum side funder,
|
||||
u32 feerate_per_kw)
|
||||
{
|
||||
enum htlc_state start = first_fee_state(funder);
|
||||
|
||||
/* 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 funder inside fromwire_fee_states, so can't do
|
||||
* this there :( */
|
||||
bool fee_states_valid(const struct fee_states *fee_states, enum side funder)
|
||||
{
|
||||
return fee_states->feerate[last_fee_state(funder)] != NULL;
|
||||
}
|
||||
|
||||
static const 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;
|
||||
}
|
||||
REGISTER_TYPE_TO_STRING(fee_states, fmt_fee_states);
|
88
common/fee_states.h
Normal file
88
common/fee_states.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
#ifndef LIGHTNING_COMMON_FEE_STATES_H
|
||||
#define LIGHTNING_COMMON_FEE_STATES_H
|
||||
#include "config.h"
|
||||
#include <ccan/tal/tal.h>
|
||||
#include <common/htlc.h>
|
||||
|
||||
struct fee_states {
|
||||
/* Current feerate in satoshis per 1000 weight: goes through same
|
||||
* state machine as htlc addition, but can only have one rate at a
|
||||
* time in any state and are never removed.
|
||||
*
|
||||
* We need to know if there's an actual change pending though (even if
|
||||
* it's a "change" to an idential feerate!) so we use pointers.
|
||||
*/
|
||||
u32 *feerate[HTLC_STATE_INVALID];
|
||||
};
|
||||
|
||||
/**
|
||||
* new_fee_states: Initialize a fee_states structure as at open-of-channel.
|
||||
* @ctx: the tal ctx to allocate off
|
||||
* @funder: which side funded the channel (and thus, proposes fee updates).
|
||||
* @feerate_per_kw: the initial feerate (if any).
|
||||
*/
|
||||
struct fee_states *new_fee_states(const tal_t *ctx,
|
||||
enum side funder,
|
||||
const u32 *feerate_per_kw);
|
||||
|
||||
/**
|
||||
* dup_fee_states: copy a fee_states structure.
|
||||
* @ctx: the tal ctx to allocate off
|
||||
* @fee_states: the fee_states to copy.
|
||||
*/
|
||||
struct fee_states *dup_fee_states(const tal_t *ctx,
|
||||
const struct fee_states *fee_states TAKES);
|
||||
|
||||
/**
|
||||
* get_feerate: Get the current feerate
|
||||
* @fee_states: the fee state machine
|
||||
* @funder: which side funded the channel (and thus, proposes fee updates).
|
||||
* @side: which side to get the feerate for
|
||||
*/
|
||||
u32 get_feerate(const struct fee_states *fee_states,
|
||||
enum side funder,
|
||||
enum side side);
|
||||
|
||||
/**
|
||||
* first_fee_state: get the initial fee state.
|
||||
* @funder: which side funded the channel (and thus, proposes fee updates).
|
||||
*/
|
||||
enum htlc_state first_fee_state(enum side funder);
|
||||
|
||||
/**
|
||||
* last_fee_state: get the final fee state.
|
||||
* @funder: which side funded the channel (and thus, proposes fee updates).
|
||||
*/
|
||||
enum htlc_state last_fee_state(enum side funder);
|
||||
|
||||
/**
|
||||
* start_fee_update: feed a new fee update into state machine.
|
||||
* @fee_states: the fee state machine
|
||||
* @funder: which side funded the channel (and thus, proposes fee updates).
|
||||
* @feerate_per_kw: the new feerate.
|
||||
*/
|
||||
void start_fee_update(struct fee_states *fee_states,
|
||||
enum side funder,
|
||||
u32 feerate_per_kw);
|
||||
|
||||
/**
|
||||
* inc_fee_state: move this feerate to the next state.
|
||||
* @fee_states: the fee state machine
|
||||
* @hstate: state
|
||||
*
|
||||
* Moves fee_states[hstate] to fee_states[hstate+1], if not NULL.
|
||||
* Returns true if it wasn't NULL.
|
||||
*/
|
||||
bool inc_fee_state(struct fee_states *fee_states, enum htlc_state hstate);
|
||||
|
||||
/* Marshal and unmarshal */
|
||||
void towire_fee_states(u8 **pptr, const struct fee_states *fee_states);
|
||||
/* FIXME: You must check that fee_states_valid! */
|
||||
struct fee_states *fromwire_fee_states(const tal_t *ctx,
|
||||
const u8 **cursor, size_t *max);
|
||||
|
||||
/**
|
||||
* Is this fee_state struct valid for this funding side?
|
||||
*/
|
||||
bool fee_states_valid(const struct fee_states *fee_states, enum side funder);
|
||||
#endif /* LIGHTNING_COMMON_FEE_STATES_H */
|
|
@ -33,6 +33,7 @@ union printable_types {
|
|||
const struct channel *channel;
|
||||
const struct amount_msat *amount_msat;
|
||||
const struct amount_sat *amount_sat;
|
||||
const struct fee_states *fee_states;
|
||||
const char *charp_;
|
||||
};
|
||||
|
||||
|
|
|
@ -48,11 +48,13 @@ OPENINGD_COMMON_OBJS := \
|
|||
common/derive_basepoints.o \
|
||||
common/dev_disconnect.o \
|
||||
common/features.o \
|
||||
common/fee_states.o \
|
||||
common/funding_tx.o \
|
||||
common/gen_status_wire.o \
|
||||
common/gen_peer_status_wire.o \
|
||||
common/gossip_rcvd_filter.o \
|
||||
common/gossip_store.o \
|
||||
common/htlc_state.o \
|
||||
common/htlc_wire.o \
|
||||
common/initial_channel.o \
|
||||
common/initial_commit_tx.o \
|
||||
|
|
Loading…
Add table
Reference in a new issue