From e8aac7e4a923a97cba73681697e7c3ffe7eddeb7 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 29 Apr 2025 09:54:33 +0930 Subject: [PATCH] lightningd: delete all trace of nonexistent channels. We're going to start loading them into memory for nicer responses if people try to reestablish closed channels, but we don't care about ones which were never actually opened. We could add a new state, but easier to simply remove them. Signed-off-by: Rusty Russell --- lightningd/channel.c | 14 ++++-- lightningd/channel.h | 3 +- lightningd/channel_control.c | 6 +-- lightningd/dual_open_control.c | 8 ++-- lightningd/onchain_control.c | 2 +- lightningd/peer_control.c | 4 +- lightningd/test/run-invoice-select-inchan.c | 2 +- wallet/test/run-db.c | 3 +- wallet/test/run-wallet.c | 8 ++-- wallet/wallet.c | 52 ++++++++++++++++++--- wallet/wallet.h | 5 ++ 11 files changed, 80 insertions(+), 27 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index b971ebe8e..90fede3cd 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -88,13 +88,17 @@ static void destroy_channel(struct channel *channel) list_del_from(&channel->peer->channels, &channel->list); } -void delete_channel(struct channel *channel STEALS) +void delete_channel(struct channel *channel STEALS, bool completely_eliminate) { const u8 *msg; struct peer *peer = channel->peer; - if (channel->dbid != 0) + if (channel->dbid != 0) { wallet_channel_close(channel->peer->ld->wallet, channel); + /* Never open at all, not ours. */ + if (completely_eliminate) + wallet_channel_delete(channel->peer->ld->wallet, channel); + } /* Tell the hsm to forget the channel, needs to be after it's * been forgotten here */ @@ -1035,7 +1039,7 @@ static void channel_fail_perm(struct channel *channel, drop_to_chain(ld, channel, false, spent_by); if (channel_state_open_uncommitted(channel->state)) - delete_channel(channel); + delete_channel(channel, false); } void channel_fail_permanent(struct channel *channel, @@ -1093,7 +1097,7 @@ void channel_fail_forget(struct channel *channel, const char *fmt, ...) channel->error = towire_errorfmt(channel, &channel->cid, "%s", why); - delete_channel(channel); + delete_channel(channel, false); tal_free(why); } @@ -1162,7 +1166,7 @@ void channel_internal_error(struct channel *channel, const char *fmt, ...) /* Nothing ventured, nothing lost! */ if (channel_state_uncommitted(channel->state)) { channel_set_owner(channel, NULL); - delete_channel(channel); + delete_channel(channel, false); return; } diff --git a/lightningd/channel.h b/lightningd/channel.h index 51b6353c3..5a802ce6b 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -479,7 +479,8 @@ channel_current_inflight(const struct channel *channel); /* What's the last feerate used for a funding tx on this channel? */ u32 channel_last_funding_feerate(const struct channel *channel); -void delete_channel(struct channel *channel STEALS); +/* Only set completely_eliminate for never-existed channels */ +void delete_channel(struct channel *channel STEALS, bool completely_eliminate); const char *channel_state_name(const struct channel *channel); const char *channel_state_str(enum channel_state state); diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index 64d52cc16..f1d3d6477 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -1321,7 +1321,7 @@ static void forget(struct channel *channel) channel->forgets = tal_arr(channel, struct command *, 0); /* Forget the channel. */ - delete_channel(channel); + delete_channel(channel, false); for (size_t i = 0; i < tal_count(forgets); i++) { assert(!forgets[i]->json_stream); @@ -2017,8 +2017,8 @@ void channel_notify_new_block(struct lightningd *ld, block_height - channel->first_blocknum, fmt_bitcoin_txid(tmpctx, &channel->funding.txid)); /* FIXME: Send an error packet for this case! */ - /* And forget it. */ - delete_channel(channel); + /* And forget it. COMPLETELY. */ + delete_channel(channel, true); } tal_free(to_forget); diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index c1863d2ee..925ab1fe1 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -67,7 +67,7 @@ void channel_unsaved_close_conn(struct channel *channel, const char *why) assert(channel->owner); channel_set_owner(channel, NULL); - delete_channel(channel); + delete_channel(channel, false); } static void channel_saved_err_broken_reconn(struct channel *channel, @@ -3959,13 +3959,13 @@ static void dualopen_errmsg(struct channel *channel, if (channel_state_uncommitted(channel->state)) { log_info(channel->log, "%s", "Unsaved peer failed." " Deleting channel."); - delete_channel(channel); + delete_channel(channel, false); return; } if ((warning || disconnect) && channel_state_open_uncommitted(channel->state)) { log_info(channel->log, "%s", "Commit ready peer failed." " Deleting channel."); - delete_channel(channel); + delete_channel(channel, false); return; } @@ -4009,7 +4009,7 @@ static void dualopen_errmsg(struct channel *channel, if (channel_state_open_uncommitted(channel->state)) { log_info(channel->log, "%s", "Commit ready peer can't reconnect." " Deleting channel."); - delete_channel(channel); + delete_channel(channel, false); return; } char *err = restart_dualopend(tmpctx, diff --git a/lightningd/onchain_control.c b/lightningd/onchain_control.c index cb09b1ee4..3ea834ee0 100644 --- a/lightningd/onchain_control.c +++ b/lightningd/onchain_control.c @@ -528,7 +528,7 @@ static void handle_irrevocably_resolved(struct channel *channel, const u8 *msg U log_info(channel->log, "onchaind complete, forgetting peer"); /* This will also free onchaind. */ - delete_channel(channel); + delete_channel(channel, false); } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 38fec6961..e9092d74a 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -519,7 +519,7 @@ void channel_errmsg(struct channel *channel, if (channel_state_uncommitted(channel->state)) { log_info(channel->log, "%s", "Unsaved peer failed." " Deleting channel."); - delete_channel(channel); + delete_channel(channel, false); return; } @@ -3432,7 +3432,7 @@ static void process_dev_forget_channel(struct bitcoind *bitcoind UNUSED, forget->channel->error = towire_errorfmt(forget->channel, &forget->channel->cid, "dev_forget_channel"); - delete_channel(forget->channel); + delete_channel(forget->channel, false); was_pending(command_success(forget->cmd, response)); } diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index ca8d78e48..188b6a5c4 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -243,7 +243,7 @@ struct anchor_details *create_anchor_details(const tal_t *ctx UNNEEDED, const struct bitcoin_tx *tx UNNEEDED) { fprintf(stderr, "create_anchor_details called!\n"); abort(); } /* Generated stub for delete_channel */ -void delete_channel(struct channel *channel STEALS UNNEEDED) +void delete_channel(struct channel *channel STEALS UNNEEDED, bool completely_eliminate UNNEEDED) { fprintf(stderr, "delete_channel called!\n"); abort(); } /* Generated stub for depthcb_update_scid */ bool depthcb_update_scid(struct channel *channel UNNEEDED, diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index c68a5f314..492527cdf 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -285,7 +285,8 @@ struct peer *new_peer(struct lightningd *ld UNNEEDED, u64 dbid UNNEEDED, bool connected_incoming UNNEEDED) { fprintf(stderr, "new_peer called!\n"); abort(); } /* Generated stub for notify_chain_mvt */ -void notify_chain_mvt(struct lightningd *ld UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED) +void notify_chain_mvt(struct lightningd *ld UNNEEDED, + const struct chain_coin_mvt *chain_mvt UNNEEDED) { fprintf(stderr, "notify_chain_mvt called!\n"); abort(); } /* Generated stub for notify_forward_event */ void notify_forward_event(struct lightningd *ld UNNEEDED, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index de5787ed3..590cb1956 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -701,10 +701,12 @@ struct uncommitted_channel *new_uncommitted_channel(struct peer *peer UNNEEDED) bool node_announcement_same(const u8 *nann1 UNNEEDED, const u8 *nann2 UNNEEDED) { fprintf(stderr, "node_announcement_same called!\n"); abort(); } /* Generated stub for notify_chain_mvt */ -void notify_chain_mvt(struct lightningd *ld UNNEEDED, const struct chain_coin_mvt *mvt UNNEEDED) +void notify_chain_mvt(struct lightningd *ld UNNEEDED, + const struct chain_coin_mvt *chain_mvt UNNEEDED) { fprintf(stderr, "notify_chain_mvt called!\n"); abort(); } /* Generated stub for notify_channel_mvt */ -void notify_channel_mvt(struct lightningd *ld UNNEEDED, const struct channel_coin_mvt *mvt UNNEEDED) +void notify_channel_mvt(struct lightningd *ld UNNEEDED, + const struct channel_coin_mvt *chan_mvt UNNEEDED) { fprintf(stderr, "notify_channel_mvt called!\n"); abort(); } /* Generated stub for notify_channel_open_failed */ void notify_channel_open_failed(struct lightningd *ld UNNEEDED, @@ -2116,7 +2118,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) /* do inflights get cleared when the channel is closed?*/ dbid = chan->dbid; - delete_channel(chan); /* Also clears up peer! */ + delete_channel(chan, false); /* Also clears up peer! */ CHECK_MSG(count_inflights(w, dbid) == 0, "inflights cleaned up"); db_commit_transaction(w->db); CHECK_MSG(!wallet_err, wallet_err); diff --git a/wallet/wallet.c b/wallet/wallet.c index 9b83dbdb5..b8b2f5d64 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -2814,12 +2814,8 @@ void wallet_channel_insert(struct wallet *w, struct channel *chan) void wallet_channel_close(struct wallet *w, const struct channel *chan) { - /* We keep a couple of dependent tables around as well, such as the - * channel_configs table, since that might help us debug some issues, - * and it is rather limited in size. Tables that can grow quite - * considerably and that are of limited use after channel closure will - * be pruned as well. */ - + /* We keep the entry in the channel_configs table, since that might + * help us debug some issues, and it is rather limited in size. */ struct db_stmt *stmt; /* Delete entries from `channel_htlcs` */ @@ -2861,6 +2857,24 @@ void wallet_channel_close(struct wallet *w, db_bind_u64(stmt, chan->dbid); db_exec_prepared_v2(take(stmt)); + /* Delete transaction annotations */ + stmt = db_prepare_v2(w->db, SQL("DELETE FROM transaction_annotations " + "WHERE channel=?")); + db_bind_u64(stmt, chan->dbid); + db_exec_prepared_v2(take(stmt)); + + /* Delete feerates */ + stmt = db_prepare_v2(w->db, SQL("DELETE FROM channel_feerates " + "WHERE channel_id=?")); + db_bind_u64(stmt, chan->dbid); + db_exec_prepared_v2(take(stmt)); + + /* Delete anchor information */ + stmt = db_prepare_v2(w->db, SQL("DELETE FROM local_anchors " + "WHERE channel_id=?")); + db_bind_u64(stmt, chan->dbid); + db_exec_prepared_v2(take(stmt)); + /* Set the channel to closed */ stmt = db_prepare_v2(w->db, SQL("UPDATE channels " "SET state=? " @@ -2870,6 +2884,32 @@ void wallet_channel_close(struct wallet *w, db_exec_prepared_v2(take(stmt)); } +/* Completely unused channels get wiped entirely (we've already closed it above) */ +void wallet_channel_delete(struct wallet *w, const struct channel *channel) +{ + struct db_stmt *stmt; + + /* Delete channel configuration for both sides */ + stmt = db_prepare_v2(w->db, SQL("DELETE FROM channel_configs" + " WHERE id=? OR id=?")); + db_bind_u64(stmt, channel->channel_info.their_config.id); + db_bind_u64(stmt, channel->our_config.id); + db_exec_prepared_v2(stmt); + + assert(db_count_changes(stmt) == 2); + tal_free(stmt); + + stmt = db_prepare_v2(w->db, SQL("DELETE FROM channels" + " WHERE state = ?" + " AND id=?")); + db_bind_u64(stmt, channel_state_in_db(CLOSED)); + db_bind_u64(stmt, channel->dbid); + db_exec_prepared_v2(stmt); + + assert(db_count_changes(stmt) == 1); + tal_free(stmt); +} + void wallet_channel_inflight_cleanup_incomplete(struct wallet *w, u64 wallet_id) { struct db_stmt *stmt; diff --git a/wallet/wallet.h b/wallet/wallet.h index ea0853528..b2e9430e0 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -699,6 +699,11 @@ void wallet_channel_clear_inflights(struct wallet *w, void wallet_channel_close(struct wallet *w, const struct channel *chan); +/** + * If it was never used, we can forget it entirely after wallet_channel_close. + */ +void wallet_channel_delete(struct wallet *w, const struct channel *channel); + /** * Adds a channel state change history entry into the database */