From 233628ad48ee588dd6a2d8f1eaa86e3616763110 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 19 Aug 2025 10:30:45 +0930 Subject: [PATCH] lightningd: speed mapping from coinmoves table to channel for listcoinmoves. Iterating through every peer and channel every time can be very slow for large nodes, when calling wallet_coinmoves_extract for listcoinmoves. Signed-off-by: Rusty Russell --- lightningd/channel.c | 30 ++++++++++++++++-------------- lightningd/channel.h | 21 +++++++++++++++++++++ lightningd/dual_open_control.c | 4 ++++ lightningd/lightningd.c | 4 ++++ lightningd/lightningd.h | 3 +++ wallet/test/run-wallet.c | 8 +++++++- 6 files changed, 55 insertions(+), 15 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index d69865b29..354249a4c 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -312,6 +312,20 @@ void channel_add_old_scid(struct channel *channel, chanmap_add(channel->peer->ld, channel, old_scid); } +static void remove_from_dbid_map(struct channel *channel) +{ + if (!channel_dbid_map_del(channel->peer->ld->channels_by_dbid, channel)) + abort(); +} + +void add_channel_to_dbid_map(struct lightningd *ld, + struct channel *channel) +{ + assert(channel->dbid != 0); + channel_dbid_map_add(ld->channels_by_dbid, channel); + tal_add_destructor(channel, remove_from_dbid_map); +} + struct channel *new_unsaved_channel(struct peer *peer, u32 feerate_base, u32 feerate_ppm) @@ -698,6 +712,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->rr_number = peer->ld->rr_counter++; tal_add_destructor(channel, destroy_channel); + add_channel_to_dbid_map(peer->ld, channel); list_head_init(&channel->inflights); channel->closer = closer; @@ -842,20 +857,7 @@ struct channel *any_channel_by_scid(struct lightningd *ld, struct channel *channel_by_dbid(struct lightningd *ld, const u64 dbid) { - struct peer *p; - struct channel *chan; - struct peer_node_id_map_iter it; - - /* FIXME: Support lookup by id directly! */ - for (p = peer_node_id_map_first(ld->peers, &it); - p; - p = peer_node_id_map_next(ld->peers, &it)) { - list_for_each(&p->channels, chan, list) { - if (chan->dbid == dbid) - return chan; - } - } - return NULL; + return channel_dbid_map_get(ld->channels_by_dbid, dbid); } struct channel *channel_by_cid(struct lightningd *ld, diff --git a/lightningd/channel.h b/lightningd/channel.h index 0e4959e83..af2f18a54 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -784,6 +784,27 @@ static inline bool channel_state_open_uncommitted(enum channel_state state) abort(); } +static inline size_t channel_dbid_hash(u64 dbid) +{ + return siphash24(siphash_seed(), &dbid, sizeof(dbid)); +} + +static u64 channel_dbid(const struct channel *channel) +{ + assert(channel->dbid); + return channel->dbid; +} + +static bool channel_dbid_eq(const struct channel *channel, u64 dbid) +{ + return channel->dbid == dbid; +} +/* Defines struct channel_dbid_map */ +HTABLE_DEFINE_NODUPS_TYPE(struct channel, + channel_dbid, channel_dbid_hash, channel_dbid_eq, + channel_dbid_map); + +void add_channel_to_dbid_map(struct lightningd *ld, struct channel *channel); void channel_set_owner(struct channel *channel, struct subd *owner); diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index fe995d3d4..3ad5cfb1d 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1446,6 +1446,7 @@ wallet_commit_channel(struct lightningd *ld, channel_info->old_remote_per_commit = channel_info->remote_per_commit; /* Promote the unsaved_dbid to the dbid */ + assert(channel->dbid == 0); assert(channel->unsaved_dbid != 0); channel->dbid = channel->unsaved_dbid; channel->unsaved_dbid = 0; @@ -1524,6 +1525,9 @@ wallet_commit_channel(struct lightningd *ld, /* Now we finally put it in the database. */ wallet_channel_insert(ld->wallet, channel); + /* So we can find it by the newly-assigned dbid */ + add_channel_to_dbid_map(ld, channel); + /* Open attempt to channel's inflights */ inflight = new_inflight(channel, NULL, diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index d76d5b605..452cee386 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -213,6 +213,10 @@ static struct lightningd *new_lightningd(const tal_t *ctx) ld->channels_by_scid = tal(ld, struct channel_scid_map); channel_scid_map_init(ld->channels_by_scid); + /*~ Coin movements in db are indexed by the channel dbid. */ + ld->channels_by_dbid = tal(ld, struct channel_dbid_map); + channel_dbid_map_init(ld->channels_by_dbid); + /*~ For multi-part payments, we need to keep some incoming payments * in limbo until we get all the parts, or we time them out. */ ld->htlc_sets = tal(ld, struct htlc_set_map); diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index 44a76e18d..306b8c29c 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -218,6 +218,9 @@ struct lightningd { /* Here are all our channels and their aliases */ struct channel_scid_map *channels_by_scid; + /* Open channels by dbid */ + struct channel_dbid_map *channels_by_dbid; + /* Outstanding connect commands. */ struct list_head connects; diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 13aa9461b..84ac059d9 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1358,6 +1358,8 @@ static struct wallet *create_test_wallet(struct lightningd *ld, const tal_t *ctx /* Create fresh channels map */ ld->channels_by_scid = tal(ld, struct channel_scid_map); channel_scid_map_init(ld->channels_by_scid); + ld->channels_by_dbid = tal(ld, struct channel_dbid_map); + channel_dbid_map_init(ld->channels_by_dbid); return w; } @@ -2088,8 +2090,10 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) /* do inflights get correctly added to the channel? */ wallet_inflight_add(w, inflight); - /* Hack to remove scids from htable so we don't clash! */ + /* Hack to remove scid & dbid from htables so we don't clash! */ chanmap_remove(ld, chan, *chan->alias[LOCAL]); + remove_from_dbid_map(chan); + tal_del_destructor(chan, remove_from_dbid_map); /* do inflights get correctly loaded from the database? */ CHECK_MSG(c2 = wallet_channel_load(w, chan->dbid), @@ -2385,6 +2389,8 @@ int main(int argc, const char *argv[]) list_head_init(&ld->wait_commands); ld->closed_channels = tal(ld, struct closed_channel_map); closed_channel_map_init(ld->closed_channels); + ld->channels_by_dbid = tal(ld, struct channel_dbid_map); + channel_dbid_map_init(ld->channels_by_dbid); /* We do a runtime test here, so we still check compile! */ if (HAVE_SQLITE3) {