Browse Source

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>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
e7b003b499
  1. 10
      daemon/Makefile
  2. 161
      daemon/db.c
  3. 4
      daemon/db.h
  4. 142
      daemon/feechange.c
  5. 50
      daemon/feechange.h
  6. 23
      daemon/feechange_state.h
  7. 10
      daemon/packets.c
  8. 1
      daemon/packets.h
  9. 130
      daemon/peer.c
  10. 4
      daemon/peer.h

10
daemon/Makefile

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

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

4
daemon/db.h

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

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

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

@ -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 */

10
daemon/packets.c

@ -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)
{

1
daemon/packets.h

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

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

4
daemon/peer.h

@ -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…
Cancel
Save