From a5ecc95c42d03a052449efbdf0debd46025c22d7 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 17 Aug 2018 14:36:36 +0930 Subject: [PATCH] db: store claimed per_commitment_point from option_data_loss_protect. This means we don't try to unilaterally close after a restart, *and* we can tell onchaind to try to use the point to recover funds when the peer unilaterally closes. Signed-off-by: Rusty Russell --- lightningd/channel.c | 6 ++++-- lightningd/channel.h | 5 +++-- lightningd/channel_control.c | 4 +++- lightningd/opening_control.c | 3 ++- tests/test_connection.py | 5 +++++ wallet/db.c | 2 ++ wallet/wallet.c | 22 ++++++++++++++++++---- 7 files changed, 37 insertions(+), 10 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index a3861a35c..ff12e037d 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -170,7 +170,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, u32 max_possible_feerate, bool connected, const struct basepoints *local_basepoints, - const struct pubkey *local_funding_pubkey) + const struct pubkey *local_funding_pubkey, + const struct pubkey *future_per_commitment_point) { struct channel *channel = tal(peer->ld, struct channel); @@ -231,7 +232,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->connected = connected; channel->local_basepoints = *local_basepoints; channel->local_funding_pubkey = *local_funding_pubkey; - channel->future_per_commitment_point = NULL; + channel->future_per_commitment_point + = tal_steal(channel, future_per_commitment_point); list_add_tail(&peer->channels, &channel->list); tal_add_destructor(channel, destroy_channel); diff --git a/lightningd/channel.h b/lightningd/channel.h index 80e1709fe..9a9cbd4f1 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -108,7 +108,7 @@ struct channel { /* Do we have an "impossible" future per_commitment_point from * peer via option_data_loss_protect? */ - struct pubkey *future_per_commitment_point; + const struct pubkey *future_per_commitment_point; }; struct channel *new_channel(struct peer *peer, u64 dbid, @@ -152,7 +152,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, u32 max_possible_feerate, bool connected, const struct basepoints *local_basepoints, - const struct pubkey *local_funding_pubkey); + const struct pubkey *local_funding_pubkey, + const struct pubkey *future_per_commitment_point); void delete_channel(struct channel *channel); diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 7b11ed62b..b5c548ae4 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -114,10 +114,12 @@ static void channel_fail_fallen_behind(struct channel *channel, const u8 *msg) return; } - /* FIXME: Save in db! */ channel->future_per_commitment_point = tal_dup(channel, struct pubkey, &per_commitment_point); + /* TODO(cdecker) Selectively save updated fields to DB */ + wallet_channel_save(channel->peer->ld->wallet, channel); + /* We don't fail yet, since we want daemon to send them an error * to trigger rebroadcasting. But make sure we set error now in * case something else goes wrong! */ diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index ac6c8ba70..f643deed7 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -202,7 +202,8 @@ wallet_commit_channel(struct lightningd *ld, /* We are connected */ true, &uc->local_basepoints, - &uc->local_funding_pubkey); + &uc->local_funding_pubkey, + NULL); /* Now we finally put it in the database. */ wallet_channel_insert(ld->wallet, channel); diff --git a/tests/test_connection.py b/tests/test_connection.py index 22a120e68..38dfc5170 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -1219,6 +1219,11 @@ def test_dataloss_protection(node_factory, bitcoind): # l2 should still recover something! bitcoind.generate_block(1) + l2.daemon.wait_for_log("ERROR: Unknown commitment #2, recovering our funds!") + + # Restarting l2, and it should remember from db. + l2.restart() + l2.daemon.wait_for_log("ERROR: Unknown commitment #2, recovering our funds!") bitcoind.generate_block(100) l2.daemon.wait_for_log('WIRE_ONCHAIN_ALL_IRREVOCABLY_RESOLVED') diff --git a/wallet/db.c b/wallet/db.c index 39713cbce..0e50c8500 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -335,6 +335,8 @@ char *dbmigrations[] = { /* -- End of PR #1398 -- */ "ALTER TABLE invoices ADD description TEXT;", "ALTER TABLE payments ADD description TEXT;", + /* future_per_commitment_point if other side proves we're out of date -- */ + "ALTER TABLE channels ADD future_per_commitment_point BLOB;", NULL, }; diff --git a/wallet/wallet.c b/wallet/wallet.c index 449966a85..abef40eca 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -585,6 +585,7 @@ static struct channel *wallet_stmt2channel(const tal_t *ctx, struct wallet *w, s s64 final_key_idx; struct basepoints local_basepoints; struct pubkey local_funding_pubkey; + struct pubkey *future_per_commitment_point; peer_dbid = sqlite3_column_int64(stmt, 1); peer = find_peer_by_dbid(w->ld, peer_dbid); @@ -616,6 +617,13 @@ static struct channel *wallet_stmt2channel(const tal_t *ctx, struct wallet *w, s last_sent_commit = NULL; } + if (sqlite3_column_type(stmt, 40) != SQLITE_NULL) { + future_per_commitment_point = tal(tmpctx, struct pubkey); + ok &= sqlite3_column_pubkey(stmt, 40, + future_per_commitment_point); + } else + future_per_commitment_point = NULL; + ok &= wallet_channel_config_load(w, sqlite3_column_int64(stmt, 3), &our_config); ok &= sqlite3_column_sha256_double(stmt, 12, &funding_txid.shad); @@ -682,7 +690,8 @@ static struct channel *wallet_stmt2channel(const tal_t *ctx, struct wallet *w, s sqlite3_column_int(stmt, 37), /* Not connected */ false, - &local_basepoints, &local_funding_pubkey); + &local_basepoints, &local_funding_pubkey, + future_per_commitment_point); return chan; } @@ -706,7 +715,7 @@ static const char *channel_fields = /*30*/ "last_sent_commit_state, last_sent_commit_id, " /*32*/ "last_tx, last_sig, last_was_revoke, first_blocknum, " /*36*/ "min_possible_feerate, max_possible_feerate, " - /*38*/ "msatoshi_to_us_min, msatoshi_to_us_max "; + /*38*/ "msatoshi_to_us_min, msatoshi_to_us_max, future_per_commitment_point "; bool wallet_channels_load_active(const tal_t *ctx, struct wallet *w) { @@ -966,7 +975,8 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) " old_per_commit_remote=?," " local_feerate_per_kw=?," " remote_feerate_per_kw=?," - " channel_config_remote=?" + " channel_config_remote=?," + " future_per_commitment_point=?" " WHERE id=?"); sqlite3_bind_pubkey(stmt, 1, &chan->channel_info.remote_fundingkey); sqlite3_bind_pubkey(stmt, 2, &chan->channel_info.theirbase.revocation); @@ -978,7 +988,11 @@ void wallet_channel_save(struct wallet *w, struct channel *chan) sqlite3_bind_int(stmt, 8, chan->channel_info.feerate_per_kw[LOCAL]); sqlite3_bind_int(stmt, 9, chan->channel_info.feerate_per_kw[REMOTE]); sqlite3_bind_int64(stmt, 10, chan->channel_info.their_config.id); - sqlite3_bind_int64(stmt, 11, chan->dbid); + if (chan->future_per_commitment_point) + sqlite3_bind_pubkey(stmt, 11, chan->future_per_commitment_point); + else + sqlite3_bind_null(stmt, 11); + sqlite3_bind_int64(stmt, 12, chan->dbid); db_exec_prepared(w->db, stmt); /* If we have a last_sent_commit, store it */