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:
Rusty Russell
2016-08-26 15:31:19 +09:30
parent 2c7256ac69
commit e7b003b499
10 changed files with 488 additions and 47 deletions

View File

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