mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 21:35:11 +01:00
daemon: handle feechange requests.
I originally overloaded struct htlc for this, as they go through the same states, but separating them turned out to be clearer. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
2c7256ac69
commit
e7b003b499
@ -22,6 +22,7 @@ DAEMON_SRC := \
|
||||
daemon/cryptopkt.c \
|
||||
daemon/db.c \
|
||||
daemon/dns.c \
|
||||
daemon/feechange.c \
|
||||
daemon/htlc.c \
|
||||
daemon/jsonrpc.c \
|
||||
daemon/lightningd.c \
|
||||
@ -49,7 +50,9 @@ DAEMON_CLI_OBJS := $(DAEMON_CLI_SRC:.c=.o)
|
||||
DAEMON_JSMN_OBJS := daemon/jsmn.o
|
||||
DAEMON_JSMN_HEADERS := daemon/jsmn/jsmn.h
|
||||
|
||||
DAEMON_GEN_HEADERS := daemon/gen_htlc_state_names.h
|
||||
DAEMON_GEN_HEADERS := \
|
||||
daemon/gen_feechange_state_names.h \
|
||||
daemon/gen_htlc_state_names.h
|
||||
|
||||
DAEMON_HEADERS := \
|
||||
daemon/bitcoind.h \
|
||||
@ -61,6 +64,8 @@ DAEMON_HEADERS := \
|
||||
daemon/cryptopkt.h \
|
||||
daemon/db.h \
|
||||
daemon/dns.h \
|
||||
daemon/feechange.h \
|
||||
daemon/feechange_state.h \
|
||||
daemon/htlc.h \
|
||||
daemon/htlc_state.h \
|
||||
daemon/json.h \
|
||||
@ -85,6 +90,9 @@ DAEMON_HEADERS := \
|
||||
daemon/gen_htlc_state_names.h: daemon/htlc_state.h ccan/ccan/cdump/tools/cdump-enumstr
|
||||
ccan/ccan/cdump/tools/cdump-enumstr daemon/htlc_state.h > $@
|
||||
|
||||
daemon/gen_feechange_state_names.h: daemon/feechange_state.h ccan/ccan/cdump/tools/cdump-enumstr
|
||||
ccan/ccan/cdump/tools/cdump-enumstr daemon/feechange_state.h > $@
|
||||
|
||||
$(DAEMON_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_CLI_OBJS): $(DAEMON_HEADERS) $(DAEMON_JSMN_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(GEN_HEADERS) $(DAEMON_GEN_HEADERS) $(CCAN_HEADERS)
|
||||
$(DAEMON_JSMN_OBJS): $(DAEMON_JSMN_HEADERS)
|
||||
|
||||
|
161
daemon/db.c
161
daemon/db.c
@ -1,6 +1,7 @@
|
||||
#include "bitcoin/pullpush.h"
|
||||
#include "commit_tx.h"
|
||||
#include "db.h"
|
||||
#include "feechange.h"
|
||||
#include "htlc.h"
|
||||
#include "lightningd.h"
|
||||
#include "log.h"
|
||||
@ -434,21 +435,48 @@ static void load_peer_commit_info(struct peer *peer)
|
||||
fatal("load_peer_commit_info:no remote commit info found");
|
||||
}
|
||||
|
||||
/* This htlc no longer committed; either resolved or failed. */
|
||||
static void htlc_resolved(struct channel_state *cstate, const struct htlc *htlc)
|
||||
static void apply_htlc(struct channel_state *cstate, const struct htlc *htlc,
|
||||
enum htlc_side side)
|
||||
{
|
||||
if (htlc->r)
|
||||
cstate_fulfill_htlc(cstate, htlc);
|
||||
else
|
||||
cstate_fail_htlc(cstate, htlc);
|
||||
const char *sidestr = (side == LOCAL ? "LOCAL" : "REMOTE");
|
||||
|
||||
if (!htlc_has(htlc, HTLC_FLAG(side,HTLC_F_WAS_COMMITTED)))
|
||||
return;
|
||||
|
||||
log_debug(htlc->peer->log, " %s committed", sidestr);
|
||||
if (!cstate_add_htlc(cstate, htlc))
|
||||
fatal("load_peer_htlcs:can't add %s HTLC", sidestr);
|
||||
|
||||
if (!htlc_has(htlc, HTLC_FLAG(side, HTLC_F_COMMITTED))) {
|
||||
log_debug(htlc->peer->log, " %s %s",
|
||||
sidestr, htlc->r ? "resolved" : "failed");
|
||||
if (htlc->r)
|
||||
cstate_fulfill_htlc(cstate, htlc);
|
||||
else
|
||||
cstate_fail_htlc(cstate, htlc);
|
||||
}
|
||||
}
|
||||
|
||||
static void apply_feechange(struct channel_state *cstate,
|
||||
const struct feechange *f,
|
||||
enum htlc_side side)
|
||||
{
|
||||
/* We only ever apply feechanges to the owner. */
|
||||
if (feechange_side(f->state) != side)
|
||||
return;
|
||||
|
||||
if (!feechange_has(f, HTLC_FLAG(side,HTLC_F_WAS_COMMITTED)))
|
||||
return;
|
||||
|
||||
adjust_fee(cstate, f->fee_rate);
|
||||
}
|
||||
|
||||
/* As we load the HTLCs, we apply them to get the final channel_state.
|
||||
* We also get the last used htlc id.
|
||||
* This is slow, but sure. */
|
||||
static void load_peer_htlcs(struct peer *peer)
|
||||
{
|
||||
int err;
|
||||
int err, i;
|
||||
sqlite3_stmt *stmt;
|
||||
sqlite3 *sql = peer->dstate->db->sql;
|
||||
char *ctx = tal(peer, char);
|
||||
@ -482,6 +510,7 @@ static void load_peer_htlcs(struct peer *peer)
|
||||
struct htlc *htlc;
|
||||
struct sha256 rhash;
|
||||
enum htlc_state hstate;
|
||||
u64 id;
|
||||
|
||||
if (err != SQLITE_ROW)
|
||||
fatal("load_peer_htlcs:step gave %s:%s",
|
||||
@ -521,28 +550,8 @@ static void load_peer_htlcs(struct peer *peer)
|
||||
peer->htlc_id_counter = htlc->id + 1;
|
||||
|
||||
/* Update cstate with this HTLC. */
|
||||
if (htlc_has(htlc, HTLC_LOCAL_F_WAS_COMMITTED)) {
|
||||
log_debug(peer->log, " Local committed");
|
||||
if (!cstate_add_htlc(peer->local.commit->cstate, htlc))
|
||||
fatal("load_peer_htlcs:can't add local HTLC");
|
||||
|
||||
if (!htlc_has(htlc, HTLC_LOCAL_F_COMMITTED)) {
|
||||
log_debug(peer->log, " Local %s",
|
||||
htlc->r ? "resolved" : "failed");
|
||||
htlc_resolved(peer->local.commit->cstate, htlc);
|
||||
}
|
||||
}
|
||||
|
||||
if (htlc_has(htlc, HTLC_REMOTE_F_WAS_COMMITTED)) {
|
||||
log_debug(peer->log, " Remote committed");
|
||||
if (!cstate_add_htlc(peer->remote.commit->cstate, htlc))
|
||||
fatal("load_peer_htlcs:can't add remote HTLC");
|
||||
if (!htlc_has(htlc, HTLC_REMOTE_F_COMMITTED)) {
|
||||
log_debug(peer->log, " Remote %s",
|
||||
htlc->r ? "resolved" : "failed");
|
||||
htlc_resolved(peer->remote.commit->cstate, htlc);
|
||||
}
|
||||
}
|
||||
apply_htlc(peer->local.commit->cstate, htlc, LOCAL);
|
||||
apply_htlc(peer->remote.commit->cstate, htlc, REMOTE);
|
||||
}
|
||||
|
||||
err = sqlite3_finalize(stmt);
|
||||
@ -550,6 +559,55 @@ static void load_peer_htlcs(struct peer *peer)
|
||||
fatal("load_peer_htlcs:finalize gave %s:%s",
|
||||
sqlite3_errstr(err), sqlite3_errmsg(sql));
|
||||
|
||||
/* Now set any in-progress fee changes. */
|
||||
select = tal_fmt(ctx,
|
||||
"SELECT * FROM feechanges WHERE peer = x'%s';",
|
||||
pubkey_to_hexstr(ctx, peer->dstate->secpctx, peer->id));
|
||||
|
||||
err = sqlite3_prepare_v2(sql, select, -1, &stmt, NULL);
|
||||
if (err != SQLITE_OK)
|
||||
fatal("load_peer_htlcs:prepare gave %s:%s",
|
||||
sqlite3_errstr(err), sqlite3_errmsg(sql));
|
||||
|
||||
while ((err = sqlite3_step(stmt)) != SQLITE_DONE) {
|
||||
enum feechange_state feechange_state;
|
||||
|
||||
if (err != SQLITE_ROW)
|
||||
fatal("load_peer_htlcs:step gave %s:%s",
|
||||
sqlite3_errstr(err), sqlite3_errmsg(sql));
|
||||
|
||||
if (sqlite3_column_count(stmt) != 3)
|
||||
fatal("load_peer_htlcs:step gave %i cols, not 3",
|
||||
sqlite3_column_count(stmt));
|
||||
|
||||
feechange_state
|
||||
= feechange_state_from_name(sqlite3_column_str(stmt, 1));
|
||||
if (feechange_state == FEECHANGE_STATE_INVALID)
|
||||
fatal("load_peer_htlcs:invalid feechange state %s",
|
||||
sqlite3_column_str(stmt, 1));
|
||||
if (peer->feechanges[feechange_state])
|
||||
fatal("load_peer_htlcs: second feechange in state %s",
|
||||
sqlite3_column_str(stmt, 1));
|
||||
peer->feechanges[feechange_state]
|
||||
= new_feechange(peer, sqlite3_column_int64(stmt, 2),
|
||||
feechange_state);
|
||||
}
|
||||
err = sqlite3_finalize(stmt);
|
||||
if (err != SQLITE_OK)
|
||||
fatal("load_peer_htlcs:finalize gave %s:%s",
|
||||
sqlite3_errstr(err), sqlite3_errmsg(sql));
|
||||
|
||||
/* Apply feechanges from oldest to newest (newest counts). */
|
||||
for (i = FEECHANGE_STATE_INVALID - 1; i >= SENT_FEECHANGE; i--) {
|
||||
if (!peer->feechanges[i])
|
||||
continue;
|
||||
|
||||
apply_feechange(peer->local.commit->cstate,
|
||||
peer->feechanges[i], LOCAL);
|
||||
apply_feechange(peer->remote.commit->cstate,
|
||||
peer->feechanges[i], REMOTE);
|
||||
}
|
||||
|
||||
/* Update commit->tx and commit->map */
|
||||
peer->local.commit->tx = create_commit_tx(peer->local.commit,
|
||||
peer,
|
||||
@ -985,6 +1043,7 @@ void db_init(struct lightningd_state *dstate)
|
||||
"CREATE TABLE wallet (privkey "SQL_PRIVKEY");"
|
||||
"CREATE TABLE anchors (peer "SQL_PUBKEY", txid "SQL_TXID", idx INT, amount INT, ok_depth INT, min_depth INT, bool ours, PRIMARY KEY(peer));"
|
||||
"CREATE TABLE htlcs (peer "SQL_PUBKEY", id INT, state TEXT, msatoshis INT, expiry INT, rhash "SQL_RHASH", r "SQL_R", routing "SQL_ROUTING", src_peer "SQL_PUBKEY", src_id INT, PRIMARY KEY(peer, id));"
|
||||
"CREATE TABLE feechanges (peer "SQL_PUBKEY", state TEXT, fee_rate INT, PRIMARY KEY(peer,state));"
|
||||
"CREATE TABLE commit_info (peer "SQL_PUBKEY", side TEXT, commit_num INT, revocation_hash "SQL_SHA256", xmit_order INT, sig "SQL_SIGNATURE", prev_revocation_hash "SQL_SHA256", PRIMARY KEY(peer, side));"
|
||||
"CREATE TABLE shachain (peer "SQL_PUBKEY", shachain BINARY(%zu), PRIMARY KEY(peer));"
|
||||
"CREATE TABLE their_visible_state (peer "SQL_PUBKEY", offered_anchor BOOLEAN, commitkey "SQL_PUBKEY", finalkey "SQL_PUBKEY", locktime INT, mindepth INT, commit_fee_rate INT, next_revocation_hash "SQL_SHA256", PRIMARY KEY(peer));"
|
||||
@ -1242,6 +1301,28 @@ bool db_new_htlc(struct peer *peer, const struct htlc *htlc)
|
||||
return !errmsg;
|
||||
}
|
||||
|
||||
bool db_new_feechange(struct peer *peer, const struct feechange *feechange)
|
||||
{
|
||||
const char *errmsg, *ctx = tal(peer, char);
|
||||
const char *peerid = pubkey_to_hexstr(ctx, peer->dstate->secpctx, peer->id);
|
||||
|
||||
log_debug(peer->log, "%s(%s)", __func__, peerid);
|
||||
assert(peer->dstate->db->in_transaction);
|
||||
|
||||
/* "CREATE TABLE feechanges (peer "SQL_PUBKEY", state TEXT, fee_rate INT, PRIMARY KEY(peer,state));" */
|
||||
errmsg = db_exec(ctx, peer->dstate,
|
||||
"INSERT INTO feechanges VALUES"
|
||||
" (x'%s', '%s', %"PRIu64");",
|
||||
peerid,
|
||||
feechange_state_name(feechange->state),
|
||||
feechange->fee_rate);
|
||||
|
||||
if (errmsg)
|
||||
log_broken(peer->log, "%s:%s", __func__, errmsg);
|
||||
tal_free(ctx);
|
||||
return !errmsg;
|
||||
}
|
||||
|
||||
bool db_update_htlc_state(struct peer *peer, const struct htlc *htlc,
|
||||
enum htlc_state oldstate)
|
||||
{
|
||||
@ -1263,6 +1344,28 @@ bool db_update_htlc_state(struct peer *peer, const struct htlc *htlc,
|
||||
return !errmsg;
|
||||
}
|
||||
|
||||
bool db_update_feechange_state(struct peer *peer,
|
||||
const struct feechange *f,
|
||||
enum htlc_state oldstate)
|
||||
{
|
||||
const char *errmsg, *ctx = tal(peer, char);
|
||||
const char *peerid = pubkey_to_hexstr(ctx, peer->dstate->secpctx, peer->id);
|
||||
|
||||
log_debug(peer->log, "%s(%s): %s->%s", __func__, peerid,
|
||||
feechange_state_name(oldstate),
|
||||
feechange_state_name(f->state));
|
||||
assert(peer->dstate->db->in_transaction);
|
||||
errmsg = db_exec(ctx, peer->dstate,
|
||||
"UPDATE feechanges SET state='%s' WHERE peer=x'%s' AND state='%s';",
|
||||
feechange_state_name(f->state), peerid,
|
||||
feechange_state_name(oldstate));
|
||||
|
||||
if (errmsg)
|
||||
log_broken(peer->log, "%s:%s", __func__, errmsg);
|
||||
tal_free(ctx);
|
||||
return !errmsg;
|
||||
}
|
||||
|
||||
bool db_update_state(struct peer *peer)
|
||||
{
|
||||
const char *errmsg, *ctx = tal(peer, char);
|
||||
|
@ -32,8 +32,12 @@ bool db_update_their_closing(struct peer *peer);
|
||||
|
||||
/* Must be inside transaction. */
|
||||
bool db_new_htlc(struct peer *peer, const struct htlc *htlc);
|
||||
bool db_new_feechange(struct peer *peer, const struct feechange *feechange);
|
||||
bool db_update_htlc_state(struct peer *peer, const struct htlc *htlc,
|
||||
enum htlc_state oldstate);
|
||||
bool db_update_feechange_state(struct peer *peer,
|
||||
const struct feechange *f,
|
||||
enum htlc_state oldstate);
|
||||
bool db_new_commit_info(struct peer *peer, enum channel_side side,
|
||||
const struct sha256 *prev_rhash);
|
||||
bool db_remove_their_prev_revocation_hash(struct peer *peer);
|
||||
|
142
daemon/feechange.c
Normal file
142
daemon/feechange.c
Normal file
@ -0,0 +1,142 @@
|
||||
#include "db.h"
|
||||
#include "feechange.h"
|
||||
#include "log.h"
|
||||
#include "peer.h"
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <inttypes.h>
|
||||
#include "gen_feechange_state_names.h"
|
||||
|
||||
/* This is the HTLC-like flags for each state. */
|
||||
static const int per_state_bits[] = {
|
||||
[SENT_FEECHANGE] = HTLC_ADDING + HTLC_LOCAL_F_OWNER
|
||||
+ HTLC_REMOTE_F_PENDING,
|
||||
|
||||
[SENT_FEECHANGE_COMMIT] = HTLC_ADDING + HTLC_LOCAL_F_OWNER
|
||||
+ HTLC_REMOTE_F_COMMITTED
|
||||
+ HTLC_REMOTE_F_WAS_COMMITTED,
|
||||
|
||||
[RCVD_FEECHANGE_REVOCATION] = HTLC_ADDING + HTLC_LOCAL_F_OWNER
|
||||
+ HTLC_REMOTE_F_COMMITTED
|
||||
+ HTLC_REMOTE_F_REVOKED
|
||||
+ HTLC_LOCAL_F_PENDING
|
||||
+ HTLC_REMOTE_F_WAS_COMMITTED,
|
||||
|
||||
[RCVD_FEECHANGE_ACK_COMMIT] = HTLC_ADDING + HTLC_LOCAL_F_OWNER
|
||||
+ HTLC_REMOTE_F_COMMITTED
|
||||
+ HTLC_REMOTE_F_REVOKED
|
||||
+ HTLC_LOCAL_F_COMMITTED
|
||||
+ HTLC_LOCAL_F_WAS_COMMITTED
|
||||
+ HTLC_REMOTE_F_WAS_COMMITTED,
|
||||
|
||||
[SENT_FEECHANGE_ACK_REVOCATION] = HTLC_LOCAL_F_OWNER
|
||||
+ HTLC_REMOTE_F_COMMITTED
|
||||
+ HTLC_REMOTE_F_REVOKED
|
||||
+ HTLC_LOCAL_F_COMMITTED
|
||||
+ HTLC_LOCAL_F_REVOKED
|
||||
+ HTLC_LOCAL_F_WAS_COMMITTED
|
||||
+ HTLC_REMOTE_F_WAS_COMMITTED,
|
||||
|
||||
[RCVD_FEECHANGE] = HTLC_ADDING + HTLC_REMOTE_F_OWNER
|
||||
+ HTLC_LOCAL_F_PENDING,
|
||||
|
||||
[RCVD_FEECHANGE_COMMIT] = HTLC_ADDING + HTLC_REMOTE_F_OWNER
|
||||
+ HTLC_LOCAL_F_COMMITTED
|
||||
+ HTLC_LOCAL_F_WAS_COMMITTED,
|
||||
|
||||
[SENT_FEECHANGE_REVOCATION] = HTLC_ADDING + HTLC_REMOTE_F_OWNER
|
||||
+ HTLC_LOCAL_F_COMMITTED
|
||||
+ HTLC_LOCAL_F_REVOKED
|
||||
+ HTLC_REMOTE_F_PENDING
|
||||
+ HTLC_LOCAL_F_WAS_COMMITTED,
|
||||
|
||||
[SENT_FEECHANGE_ACK_COMMIT] = HTLC_ADDING + HTLC_REMOTE_F_OWNER
|
||||
+ HTLC_LOCAL_F_COMMITTED
|
||||
+ HTLC_LOCAL_F_REVOKED
|
||||
+ HTLC_REMOTE_F_COMMITTED
|
||||
+ HTLC_LOCAL_F_WAS_COMMITTED
|
||||
+ HTLC_REMOTE_F_WAS_COMMITTED,
|
||||
|
||||
[RCVD_FEECHANGE_ACK_REVOCATION] = HTLC_REMOTE_F_OWNER
|
||||
+ HTLC_LOCAL_F_COMMITTED
|
||||
+ HTLC_LOCAL_F_REVOKED
|
||||
+ HTLC_REMOTE_F_COMMITTED
|
||||
+ HTLC_REMOTE_F_REVOKED
|
||||
+ HTLC_LOCAL_F_WAS_COMMITTED
|
||||
+ HTLC_REMOTE_F_WAS_COMMITTED,
|
||||
};
|
||||
|
||||
int feechange_state_flags(enum feechange_state state)
|
||||
{
|
||||
assert(state < ARRAY_SIZE(per_state_bits));
|
||||
assert(per_state_bits[state]);
|
||||
return per_state_bits[state];
|
||||
}
|
||||
|
||||
const char *feechange_state_name(enum feechange_state s)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; enum_feechange_state_names[i].name; i++)
|
||||
if (enum_feechange_state_names[i].v == s)
|
||||
return enum_feechange_state_names[i].name;
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
enum feechange_state feechange_state_from_name(const char *name)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; enum_feechange_state_names[i].name; i++)
|
||||
if (streq(enum_feechange_state_names[i].name, name))
|
||||
return enum_feechange_state_names[i].v;
|
||||
return FEECHANGE_STATE_INVALID;
|
||||
}
|
||||
|
||||
struct feechange *new_feechange(struct peer *peer,
|
||||
u64 fee_rate,
|
||||
enum feechange_state state)
|
||||
{
|
||||
struct feechange *f = tal(peer, struct feechange);
|
||||
f->state = state;
|
||||
f->fee_rate = fee_rate;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
bool feechange_changestate(struct peer *peer,
|
||||
struct feechange *f,
|
||||
enum feechange_state oldstate,
|
||||
enum feechange_state newstate,
|
||||
bool db_commit)
|
||||
{
|
||||
log_debug(peer->log, "feechange: %s->%s",
|
||||
feechange_state_name(f->state),
|
||||
feechange_state_name(newstate));
|
||||
assert(f->state == oldstate);
|
||||
assert(peer->feechanges[f->state] == f);
|
||||
|
||||
/* You can only go to consecutive states. */
|
||||
assert(newstate == f->state + 1);
|
||||
|
||||
/* You can't change sides. */
|
||||
assert(feechange_side(f->state) == feechange_side(newstate));
|
||||
|
||||
f->state = newstate;
|
||||
|
||||
/* We can have multiple dead feestates, but only one in any other */
|
||||
if (!feechange_is_dead(f))
|
||||
assert(!peer->feechanges[f->state]);
|
||||
|
||||
peer->feechanges[oldstate] = NULL;
|
||||
peer->feechanges[newstate] = f;
|
||||
|
||||
if (db_commit) {
|
||||
if (newstate == RCVD_FEECHANGE_COMMIT
|
||||
|| newstate == SENT_FEECHANGE_COMMIT)
|
||||
return db_new_feechange(peer, f);
|
||||
|
||||
return db_update_feechange_state(peer, f, oldstate);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
50
daemon/feechange.h
Normal file
50
daemon/feechange.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef LIGHTNING_DAEMON_FEECHANGE_H
|
||||
#define LIGHTNING_DAEMON_FEECHANGE_H
|
||||
#include "config.h"
|
||||
#include "feechange_state.h"
|
||||
#include "htlc.h"
|
||||
|
||||
struct feechange {
|
||||
/* What's the status */
|
||||
enum feechange_state state;
|
||||
/* The rate. */
|
||||
u64 fee_rate;
|
||||
};
|
||||
|
||||
static inline enum htlc_side feechange_side(enum feechange_state state)
|
||||
{
|
||||
if (state <= SENT_FEECHANGE_ACK_REVOCATION) {
|
||||
return LOCAL;
|
||||
} else {
|
||||
assert(state < FEECHANGE_STATE_INVALID);
|
||||
return REMOTE;
|
||||
}
|
||||
}
|
||||
|
||||
bool feechange_changestate(struct peer *peer,
|
||||
struct feechange *feechange,
|
||||
enum feechange_state oldstate,
|
||||
enum feechange_state newstate,
|
||||
bool db_commit);
|
||||
|
||||
struct feechange *new_feechange(struct peer *peer,
|
||||
u64 fee_rate,
|
||||
enum feechange_state state);
|
||||
|
||||
const char *feechange_state_name(enum feechange_state s);
|
||||
enum feechange_state feechange_state_from_name(const char *name);
|
||||
|
||||
/* HTLC-add-style bitflags for each feechange state */
|
||||
int feechange_state_flags(enum feechange_state state);
|
||||
|
||||
static inline bool feechange_has(const struct feechange *f, int flag)
|
||||
{
|
||||
return feechange_state_flags(f->state) & flag;
|
||||
}
|
||||
|
||||
static inline bool feechange_is_dead(const struct feechange *feechange)
|
||||
{
|
||||
return feechange->state == SENT_FEECHANGE_ACK_REVOCATION
|
||||
|| feechange->state == RCVD_FEECHANGE_ACK_REVOCATION;
|
||||
}
|
||||
#endif /* LIGHTNING_DAEMON_FEECHANGE_H */
|
23
daemon/feechange_state.h
Normal file
23
daemon/feechange_state.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef LIGHTNING_DAEMON_FEECHANGE_STATE_H
|
||||
#define LIGHTNING_DAEMON_FEECHANGE_STATE_H
|
||||
#include "config.h"
|
||||
|
||||
/* Like HTLCs, but only adding; we never "remove" a feechange. */
|
||||
enum feechange_state {
|
||||
/* When we add a new feechange, it goes in this order. */
|
||||
SENT_FEECHANGE,
|
||||
SENT_FEECHANGE_COMMIT,
|
||||
RCVD_FEECHANGE_REVOCATION,
|
||||
RCVD_FEECHANGE_ACK_COMMIT,
|
||||
SENT_FEECHANGE_ACK_REVOCATION,
|
||||
|
||||
/* When they add a new feechange, it goes in this order. */
|
||||
RCVD_FEECHANGE,
|
||||
RCVD_FEECHANGE_COMMIT,
|
||||
SENT_FEECHANGE_REVOCATION,
|
||||
SENT_FEECHANGE_ACK_COMMIT,
|
||||
RCVD_FEECHANGE_ACK_REVOCATION,
|
||||
|
||||
FEECHANGE_STATE_INVALID
|
||||
};
|
||||
#endif /* LIGHTNING_DAEMON_FEECHANGE_STATE_H */
|
@ -178,6 +178,16 @@ void queue_pkt_htlc_fail(struct peer *peer, struct htlc *htlc)
|
||||
queue_pkt(peer, PKT__PKT_UPDATE_FAIL_HTLC, f);
|
||||
}
|
||||
|
||||
void queue_pkt_feechange(struct peer *peer, u64 feerate)
|
||||
{
|
||||
UpdateFee *f = tal(peer, UpdateFee);
|
||||
|
||||
update_fee__init(f);
|
||||
f->fee_rate = feerate;
|
||||
|
||||
queue_pkt(peer, PKT__PKT_UPDATE_FEE, f);
|
||||
}
|
||||
|
||||
/* OK, we're sending a signature for their pending changes. */
|
||||
void queue_pkt_commit(struct peer *peer, const struct bitcoin_signature *sig)
|
||||
{
|
||||
|
@ -17,6 +17,7 @@ void queue_pkt_open_complete(struct peer *peer);
|
||||
void queue_pkt_htlc_add(struct peer *peer, struct htlc *htlc);
|
||||
void queue_pkt_htlc_fulfill(struct peer *peer, struct htlc *htlc);
|
||||
void queue_pkt_htlc_fail(struct peer *peer, struct htlc *htlc);
|
||||
void queue_pkt_feechange(struct peer *peer, u64 feerate);
|
||||
void queue_pkt_commit(struct peer *peer, const struct bitcoin_signature *sig);
|
||||
void queue_pkt_revocation(struct peer *peer,
|
||||
const struct sha256 *preimage,
|
||||
|
130
daemon/peer.c
130
daemon/peer.c
@ -242,6 +242,7 @@ static bool peer_uncommitted_changes(const struct peer *peer)
|
||||
{
|
||||
struct htlc_map_iter it;
|
||||
struct htlc *h;
|
||||
enum feechange_state i;
|
||||
|
||||
for (h = htlc_map_first(&peer->htlcs, &it);
|
||||
h;
|
||||
@ -249,6 +250,13 @@ static bool peer_uncommitted_changes(const struct peer *peer)
|
||||
if (htlc_has(h, HTLC_REMOTE_F_PENDING))
|
||||
return true;
|
||||
}
|
||||
/* Pending feechange we sent, or pending ack of theirs. */
|
||||
for (i = 0; i < ARRAY_SIZE(peer->feechanges); i++) {
|
||||
if (!peer->feechanges[i])
|
||||
continue;
|
||||
if (feechange_state_flags(i) & HTLC_REMOTE_F_PENDING)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -632,6 +640,34 @@ static void adjust_cstates(struct peer *peer, struct htlc *h,
|
||||
adjust_cstate_side(peer->local.staging_cstate, h, old, new, LOCAL);
|
||||
}
|
||||
|
||||
static void adjust_cstate_fee_side(struct channel_state *cstate,
|
||||
const struct feechange *f,
|
||||
enum feechange_state old,
|
||||
enum feechange_state new,
|
||||
enum htlc_side side)
|
||||
{
|
||||
/* We applied changes to staging_cstate when we first received
|
||||
* feechange packet, so we could make sure it was valid. Don't
|
||||
* do that again. */
|
||||
if (old == SENT_FEECHANGE || old == RCVD_FEECHANGE)
|
||||
return;
|
||||
|
||||
/* Feechanges only ever get applied to the side which created them:
|
||||
* ours gets applied when they ack, theirs gets applied when we ack. */
|
||||
if (side == LOCAL && new == RCVD_FEECHANGE_REVOCATION)
|
||||
adjust_fee(cstate, f->fee_rate);
|
||||
else if (side == REMOTE && new == SENT_FEECHANGE_REVOCATION)
|
||||
adjust_fee(cstate, f->fee_rate);
|
||||
}
|
||||
|
||||
static void adjust_cstates_fee(struct peer *peer, const struct feechange *f,
|
||||
enum feechange_state old,
|
||||
enum feechange_state new)
|
||||
{
|
||||
adjust_cstate_fee_side(peer->remote.staging_cstate, f, old, new, REMOTE);
|
||||
adjust_cstate_fee_side(peer->local.staging_cstate, f, old, new, LOCAL);
|
||||
}
|
||||
|
||||
static void check_both_committed(struct peer *peer, struct htlc *h)
|
||||
{
|
||||
if (!htlc_has(h, HTLC_ADDING) && !htlc_has(h, HTLC_REMOVING))
|
||||
@ -657,22 +693,29 @@ static void check_both_committed(struct peer *peer, struct htlc *h)
|
||||
}
|
||||
}
|
||||
|
||||
struct state_table {
|
||||
struct htlcs_table {
|
||||
enum htlc_state from, to;
|
||||
};
|
||||
|
||||
static const char *htlcs_changestate(struct peer *peer,
|
||||
const struct state_table *table, size_t n,
|
||||
bool db_commit)
|
||||
struct feechanges_table {
|
||||
enum feechange_state from, to;
|
||||
};
|
||||
|
||||
static const char *changestates(struct peer *peer,
|
||||
const struct htlcs_table *table,
|
||||
size_t n,
|
||||
const struct feechanges_table *ftable,
|
||||
size_t n_ftable,
|
||||
bool db_commit)
|
||||
{
|
||||
struct htlc_map_iter it;
|
||||
struct htlc *h;
|
||||
bool changed = false;
|
||||
size_t i;
|
||||
|
||||
for (h = htlc_map_first(&peer->htlcs, &it);
|
||||
h;
|
||||
h = htlc_map_next(&peer->htlcs, &it)) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; i++) {
|
||||
if (h->state == table[i].from) {
|
||||
adjust_cstates(peer, h,
|
||||
@ -685,6 +728,19 @@ static const char *htlcs_changestate(struct peer *peer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n_ftable; i++) {
|
||||
struct feechange *f = peer->feechanges[ftable[i].from];
|
||||
if (!f)
|
||||
continue;
|
||||
adjust_cstates_fee(peer, f, ftable[i].from, ftable[i].to);
|
||||
if (!feechange_changestate(peer, f,
|
||||
ftable[i].from, ftable[i].to,
|
||||
db_commit))
|
||||
return "database error";
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT send an `update_commit` message which does
|
||||
@ -827,18 +883,26 @@ static Pkt *handle_pkt_commit(struct peer *peer, const Pkt *pkt)
|
||||
struct commit_info *ci;
|
||||
bool to_them_only;
|
||||
/* FIXME: We can actually merge these two... */
|
||||
static const struct state_table commit_changes[] = {
|
||||
static const struct htlcs_table commit_changes[] = {
|
||||
{ RCVD_ADD_REVOCATION, RCVD_ADD_ACK_COMMIT },
|
||||
{ RCVD_REMOVE_HTLC, RCVD_REMOVE_COMMIT },
|
||||
{ RCVD_ADD_HTLC, RCVD_ADD_COMMIT },
|
||||
{ RCVD_REMOVE_REVOCATION, RCVD_REMOVE_ACK_COMMIT }
|
||||
};
|
||||
static const struct state_table revocation_changes[] = {
|
||||
static const struct feechanges_table commit_feechanges[] = {
|
||||
{ RCVD_FEECHANGE_REVOCATION, RCVD_FEECHANGE_ACK_COMMIT },
|
||||
{ RCVD_FEECHANGE, RCVD_FEECHANGE_COMMIT }
|
||||
};
|
||||
static const struct htlcs_table revocation_changes[] = {
|
||||
{ RCVD_ADD_ACK_COMMIT, SENT_ADD_ACK_REVOCATION },
|
||||
{ RCVD_REMOVE_COMMIT, SENT_REMOVE_REVOCATION },
|
||||
{ RCVD_ADD_COMMIT, SENT_ADD_REVOCATION },
|
||||
{ RCVD_REMOVE_ACK_COMMIT, SENT_REMOVE_ACK_REVOCATION }
|
||||
};
|
||||
static const struct feechanges_table revocation_feechanges[] = {
|
||||
{ RCVD_FEECHANGE_ACK_COMMIT, SENT_FEECHANGE_ACK_REVOCATION },
|
||||
{ RCVD_FEECHANGE_COMMIT, SENT_FEECHANGE_REVOCATION }
|
||||
};
|
||||
|
||||
ci = new_commit_info(peer, peer->local.commit->commit_num + 1);
|
||||
|
||||
@ -850,9 +914,10 @@ static Pkt *handle_pkt_commit(struct peer *peer, const Pkt *pkt)
|
||||
* A node MUST NOT send an `update_commit` message which does
|
||||
* not include any updates.
|
||||
*/
|
||||
errmsg = htlcs_changestate(peer,
|
||||
commit_changes, ARRAY_SIZE(commit_changes),
|
||||
true);
|
||||
errmsg = changestates(peer,
|
||||
commit_changes, ARRAY_SIZE(commit_changes),
|
||||
commit_feechanges, ARRAY_SIZE(commit_feechanges),
|
||||
true);
|
||||
if (errmsg) {
|
||||
db_abort_transaction(peer);
|
||||
return pkt_err(peer, "%s", errmsg);
|
||||
@ -930,8 +995,11 @@ static Pkt *handle_pkt_commit(struct peer *peer, const Pkt *pkt)
|
||||
assert(to_them_only || peer->local.commit->sig);
|
||||
assert(peer->local.commit->commit_num > 0);
|
||||
|
||||
errmsg = htlcs_changestate(peer, revocation_changes,
|
||||
ARRAY_SIZE(revocation_changes), true);
|
||||
errmsg = changestates(peer,
|
||||
revocation_changes, ARRAY_SIZE(revocation_changes),
|
||||
revocation_feechanges,
|
||||
ARRAY_SIZE(revocation_feechanges),
|
||||
true);
|
||||
if (errmsg) {
|
||||
log_broken(peer->log, "queue_pkt_revocation: %s", errmsg);
|
||||
/* FIXME: Return error. */
|
||||
@ -1028,12 +1096,16 @@ static Pkt *handle_pkt_revocation(struct peer *peer, const Pkt *pkt,
|
||||
{
|
||||
Pkt *err;
|
||||
const char *errmsg;
|
||||
static const struct state_table changes[] = {
|
||||
static const struct htlcs_table changes[] = {
|
||||
{ SENT_ADD_COMMIT, RCVD_ADD_REVOCATION },
|
||||
{ SENT_REMOVE_ACK_COMMIT, RCVD_REMOVE_ACK_REVOCATION },
|
||||
{ SENT_ADD_ACK_COMMIT, RCVD_ADD_ACK_REVOCATION },
|
||||
{ SENT_REMOVE_COMMIT, RCVD_REMOVE_REVOCATION }
|
||||
};
|
||||
static const struct feechanges_table feechanges[] = {
|
||||
{ SENT_FEECHANGE_COMMIT, RCVD_FEECHANGE_REVOCATION },
|
||||
{ SENT_FEECHANGE_ACK_COMMIT, RCVD_FEECHANGE_ACK_REVOCATION }
|
||||
};
|
||||
|
||||
err = accept_pkt_revocation(peer, pkt);
|
||||
if (err)
|
||||
@ -1046,7 +1118,8 @@ static Pkt *handle_pkt_revocation(struct peer *peer, const Pkt *pkt,
|
||||
*/
|
||||
if (!db_start_transaction(peer))
|
||||
return pkt_err(peer, "database error");
|
||||
errmsg = htlcs_changestate(peer, changes, ARRAY_SIZE(changes), true);
|
||||
errmsg = changestates(peer, changes, ARRAY_SIZE(changes),
|
||||
feechanges, ARRAY_SIZE(feechanges), true);
|
||||
if (errmsg) {
|
||||
log_broken(peer->log, "accept_pkt_revocation: %s", errmsg);
|
||||
db_abort_transaction(peer);
|
||||
@ -1705,6 +1778,17 @@ static void retransmit_updates(struct peer *peer)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* This feechange may not be appropriate any more, but that's no
|
||||
* different from when we sent it last time. And this avoids us
|
||||
* creating different commit txids on retransmission */
|
||||
if (peer->feechanges[SENT_FEECHANGE_COMMIT]) {
|
||||
u64 feerate = peer->feechanges[SENT_FEECHANGE_COMMIT]->fee_rate;
|
||||
log_debug(peer->log,
|
||||
"Retransmitting feechange %"PRIu64, feerate);
|
||||
queue_pkt_feechange(peer, feerate);
|
||||
}
|
||||
assert(!peer->feechanges[SENT_FEECHANGE]);
|
||||
}
|
||||
|
||||
/* FIXME: Maybe it would be neater to remember all pay commands, and simply
|
||||
@ -1802,7 +1886,7 @@ again:
|
||||
if (!cstate_add_htlc(peer->remote.staging_cstate, h))
|
||||
fatal("Could not add HTLC?");
|
||||
break;
|
||||
}
|
||||
} /* Fall thru */
|
||||
case RCVD_ADD_HTLC:
|
||||
log_debug(peer->log, "Forgetting %s %"PRIu64,
|
||||
htlc_state_name(h->state), h->id);
|
||||
@ -1839,6 +1923,12 @@ again:
|
||||
}
|
||||
if (retry)
|
||||
goto again;
|
||||
|
||||
/* Forget uncommitted feechanges */
|
||||
peer->feechanges[SENT_FEECHANGE]
|
||||
= tal_free(peer->feechanges[SENT_FEECHANGE]);
|
||||
peer->feechanges[RCVD_FEECHANGE]
|
||||
= tal_free(peer->feechanges[RCVD_FEECHANGE]);
|
||||
}
|
||||
|
||||
static void retransmit_pkts(struct peer *peer, s64 ack)
|
||||
@ -1979,12 +2069,16 @@ static void do_commit(struct peer *peer, struct command *jsoncmd)
|
||||
{
|
||||
struct commit_info *ci;
|
||||
const char *errmsg;
|
||||
static const struct state_table changes[] = {
|
||||
static const struct htlcs_table changes[] = {
|
||||
{ SENT_ADD_HTLC, SENT_ADD_COMMIT },
|
||||
{ SENT_REMOVE_REVOCATION, SENT_REMOVE_ACK_COMMIT },
|
||||
{ SENT_ADD_REVOCATION, SENT_ADD_ACK_COMMIT},
|
||||
{ SENT_REMOVE_HTLC, SENT_REMOVE_COMMIT}
|
||||
};
|
||||
static const struct feechanges_table feechanges[] = {
|
||||
{ SENT_FEECHANGE, SENT_FEECHANGE_COMMIT },
|
||||
{ SENT_FEECHANGE_REVOCATION, SENT_FEECHANGE_ACK_COMMIT}
|
||||
};
|
||||
bool to_us_only;
|
||||
|
||||
/* We can have changes we suggested, or changes they suggested. */
|
||||
@ -2014,7 +2108,8 @@ static void do_commit(struct peer *peer, struct command *jsoncmd)
|
||||
fatal("queue_pkt_commit: db fail");
|
||||
}
|
||||
|
||||
errmsg = htlcs_changestate(peer, changes, ARRAY_SIZE(changes), true);
|
||||
errmsg = changestates(peer, changes, ARRAY_SIZE(changes),
|
||||
feechanges, ARRAY_SIZE(feechanges), true);
|
||||
if (errmsg) {
|
||||
log_broken(peer->log, "queue_pkt_commit: %s", errmsg);
|
||||
/* FIXME: Return error. */
|
||||
@ -2185,6 +2280,7 @@ struct peer *new_peer(struct lightningd_state *dstate,
|
||||
log_prefix(peer->dstate->base_log), peer);
|
||||
|
||||
htlc_map_init(&peer->htlcs);
|
||||
memset(peer->feechanges, 0, sizeof(peer->feechanges));
|
||||
shachain_init(&peer->their_preimages);
|
||||
|
||||
list_add(&dstate->peers, &peer->list);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "bitcoin/script.h"
|
||||
#include "bitcoin/shadouble.h"
|
||||
#include "channel.h"
|
||||
#include "feechange.h"
|
||||
#include "htlc.h"
|
||||
#include "lightning.pb-c.h"
|
||||
#include "netaddr.h"
|
||||
@ -190,6 +191,9 @@ struct peer {
|
||||
/* All HTLCs. */
|
||||
struct htlc_map htlcs;
|
||||
|
||||
/* We only track one feechange per state: last one counts. */
|
||||
struct feechange *feechanges[FEECHANGE_STATE_INVALID];
|
||||
|
||||
/* Current ongoing packetflow */
|
||||
struct io_data *io_data;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user