From 334767a4fa151b1022b528fabb901bf1d9a464c4 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 19 Sep 2024 16:30:37 +0930 Subject: [PATCH 1/5] lightningd: move stats into struct channel. Like other fields, mirror them into the db. Signed-off-by: Rusty Russell --- lightningd/channel.c | 6 +++- lightningd/channel.h | 6 +++- lightningd/opening_control.c | 13 ++++++-- lightningd/peer_htlcs.c | 58 ++++++++++++++++++++++++++++-------- wallet/test/run-db.c | 3 +- wallet/test/run-wallet.c | 4 ++- wallet/wallet.c | 6 +++- 7 files changed, 77 insertions(+), 19 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index af5dae06ed9f..1ea3693cde31 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -310,6 +310,8 @@ struct channel *new_unsaved_channel(struct peer *peer, channel->ignore_fee_limits = ld->config.ignore_fee_limits; channel->last_stable_connection = 0; channel->stable_conn_timer = NULL; + /* Nothing happened yet */ + memset(&channel->stats, 0, sizeof(channel->stats)); /* No shachain yet */ channel->their_shachain.id = 0; @@ -445,7 +447,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, bool ignore_fee_limits, /* NULL or stolen */ struct peer_update *peer_update STEALS, - u64 last_stable_connection) + u64 last_stable_connection, + const struct channel_stats *stats) { struct channel *channel = tal(peer->ld, struct channel); struct amount_msat htlc_min, htlc_max; @@ -602,6 +605,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->ignore_fee_limits = ignore_fee_limits; channel->last_stable_connection = last_stable_connection; channel->stable_conn_timer = NULL; + channel->stats = *stats; /* Populate channel->channel_gossip */ channel_gossip_init(channel, take(peer_update)); diff --git a/lightningd/channel.h b/lightningd/channel.h index b04e68d84dc8..cdb6cc15f5b8 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -314,6 +314,9 @@ struct channel { /* Last time we had a stable connection, if any (0 = none) */ u64 last_stable_connection; struct oneshot *stable_conn_timer; + + /* Our stats */ + struct channel_stats stats; }; /* Is channel owned (and should be talking to peer) */ @@ -395,7 +398,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, bool ignore_fee_limits, /* NULL or stolen */ struct peer_update *peer_update STEALS, - u64 last_stable_connection); + u64 last_stable_connection, + const struct channel_stats *stats); /* new_inflight - Create a new channel_inflight for a channel */ struct channel_inflight *new_inflight(struct channel *channel, diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index a1066eb166e8..197316615661 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -109,6 +109,10 @@ wallet_commit_channel(struct lightningd *ld, u32 lease_start_blockheight = 0; /* No leases on v1 */ struct timeabs timestamp; bool any_active = peer_any_channel(uc->peer, channel_state_wants_peercomms, NULL); + struct channel_stats zero_channel_stats; + + /* We can't have any payments yet */ + memset(&zero_channel_stats, 0, sizeof(zero_channel_stats)); /* We cannot both be the fundee *and* have a `fundchannel_start` * command running! @@ -215,7 +219,8 @@ wallet_commit_channel(struct lightningd *ld, ld->config.htlc_maximum_msat, ld->config.ignore_fee_limits, NULL, - 0); + 0, + &zero_channel_stats); /* Now we finally put it in the database. */ wallet_channel_insert(ld->wallet, channel); @@ -1456,6 +1461,7 @@ static struct channel *stub_chan(struct command *cmd, struct short_channel_id *scid; u32 blockht; u32 feerate; + struct channel_stats zero_channel_stats; u8 *dummy_sig = tal_hexdata(cmd, "30450221009b2e0eef267b94c3899fb0dc73750" "12e2cee4c10348a068fe78d1b82b4b1403602207" @@ -1530,6 +1536,8 @@ static struct channel *stub_chan(struct command *cmd, if (!mk_short_channel_id(scid, 1, 1, 1)) fatal("Failed to make short channel 1x1x1!"); + memset(&zero_channel_stats, 0, sizeof(zero_channel_stats)); + /* Channel Shell with Dummy data(mostly) */ channel = new_channel(peer, id, NULL, /* No shachain yet */ @@ -1589,7 +1597,8 @@ static struct channel *stub_chan(struct command *cmd, ld->config.htlc_maximum_msat, false, NULL, - 0); + 0, + &zero_channel_stats); /* We don't want to gossip about this, ever. */ channel->channel_gossip = tal_free(channel->channel_gossip); diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 97bb11b035b1..a9af74260cae 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -93,6 +93,48 @@ static bool htlc_out_update_state(struct channel *channel, return true; } +static void cstat_accumulate(struct channel *c, + struct amount_msat *val, + struct amount_msat msat) +{ + if (!amount_msat_add(val, *val, msat)) + log_broken(c->log, "Adding %s to stat %s overflowed!", + fmt_amount_msat(tmpctx, *val), + fmt_amount_msat(tmpctx, msat)); +} + +static void channel_stats_incr_in_fulfilled(struct channel *c, + struct amount_msat msat) +{ + c->stats.in_payments_fulfilled++; + cstat_accumulate(c, &c->stats.in_msatoshi_fulfilled, msat); + wallet_channel_stats_incr_in_fulfilled(c->peer->ld->wallet, c->dbid, msat); +} + +static void channel_stats_incr_out_fulfilled(struct channel *c, + struct amount_msat msat) +{ + c->stats.out_payments_fulfilled++; + cstat_accumulate(c, &c->stats.out_msatoshi_fulfilled, msat); + wallet_channel_stats_incr_out_fulfilled(c->peer->ld->wallet, c->dbid, msat); +} + +static void channel_stats_incr_in_offered(struct channel *c, + struct amount_msat msat) +{ + c->stats.in_payments_offered++; + cstat_accumulate(c, &c->stats.in_msatoshi_offered, msat); + wallet_channel_stats_incr_in_offered(c->peer->ld->wallet, c->dbid, msat); +} + +static void channel_stats_incr_out_offered(struct channel *c, + struct amount_msat msat) +{ + c->stats.out_payments_offered++; + cstat_accumulate(c, &c->stats.out_msatoshi_offered, msat); + wallet_channel_stats_incr_out_offered(c->peer->ld->wallet, c->dbid, msat); +} + /* BOLT #4: * - if `blinding_point` is set in the incoming `update_add_htlc`: * - MUST return an `invalid_onion_blinding` error. @@ -332,7 +374,6 @@ void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage) { u8 *msg; struct channel *channel = hin->key.channel; - struct wallet *wallet = channel->peer->ld->wallet; if (hin->hstate != RCVD_ADD_ACK_REVOCATION) { log_debug(channel->log, @@ -349,9 +390,7 @@ void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage) htlc_in_check(hin, __func__); /* Update channel stats */ - wallet_channel_stats_incr_in_fulfilled(wallet, - channel->dbid, - hin->msat); + channel_stats_incr_in_fulfilled(channel, hin->msat); /* No owner? We'll either send to channeld in peer_htlcs, or * onchaind in onchaind_tell_fulfill. */ @@ -1417,9 +1456,7 @@ static void fulfill_our_htlc_out(struct channel *channel, struct htlc_out *hout, 0, hout->failonion, hout->failmsg, &we_filled); /* Update channel stats */ - wallet_channel_stats_incr_out_fulfilled(ld->wallet, - channel->dbid, - hout->msat); + channel_stats_incr_out_fulfilled(channel, hout->msat); if (hout->am_origin) payment_succeeded(ld, &hout->payment_hash, hout->partid, hout->groupid, preimage); @@ -1892,9 +1929,7 @@ static bool update_out_htlc(struct channel *channel, if (!hout->dbid) { wallet_htlc_save_out(ld->wallet, channel, hout); /* Update channel stats */ - wallet_channel_stats_incr_out_offered(ld->wallet, - channel->dbid, - hout->msat); + channel_stats_incr_out_offered(channel, hout->msat); if (hout->in) { struct short_channel_id scid; @@ -2131,8 +2166,7 @@ static bool channel_added_their_htlc(struct channel *channel, /* Save an incoming htlc to the wallet */ wallet_htlc_save_in(ld->wallet, channel, hin); /* Update channel stats */ - wallet_channel_stats_incr_in_offered(ld->wallet, channel->dbid, - added->amount); + channel_stats_incr_in_offered(channel, added->amount); log_debug(channel->log, "Adding their HTLC %"PRIu64, added->id); connect_htlc_in(channel->peer->ld->htlcs_in, hin); diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index fc73479c23ae..4af4988e7521 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -191,7 +191,8 @@ struct channel *new_channel(struct peer *peer UNNEEDED, u64 dbid UNNEEDED, bool ignore_fee_limits UNNEEDED, /* NULL or stolen */ struct peer_update *peer_update STEALS UNNEEDED, - u64 last_stable_connection UNNEEDED) + u64 last_stable_connection UNNEEDED, + const struct channel_stats *stats UNNEEDED) { fprintf(stderr, "new_channel called!\n"); abort(); } /* Generated stub for new_coin_wallet_deposit */ struct chain_coin_mvt *new_coin_wallet_deposit(const tal_t *ctx UNNEEDED, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index b6f0791a9231..68c961fc3480 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1918,6 +1918,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) secp256k1_ecdsa_signature *lease_commit_sig; u32 feerate, lease_blockheight_start; u64 dbid; + struct channel_stats *stats = talz(w, struct channel_stats); pubkey_from_der(tal_hexdata(w, "02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc", 66), 33, &pk); node_id_from_pubkey(&id, &pk); @@ -1995,7 +1996,8 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) AMOUNT_MSAT(-1ULL), false, NULL, - 0); + 0, + stats); db_begin_transaction(w->db); CHECK(!wallet_err); wallet_channel_insert(w, chan); diff --git a/wallet/wallet.c b/wallet/wallet.c index 6d0ee76a99b2..831ae4880098 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1536,6 +1536,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm u16 lease_chan_max_ppt; bool ignore_fee_limits; struct peer_update *remote_update; + struct channel_stats stats; peer_dbid = db_col_u64(stmt, "peer_id"); peer = find_peer_by_dbid(w->ld, peer_dbid); @@ -1718,6 +1719,8 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm db_col_ignore(stmt, "remote_htlc_maximum_msat"); } + wallet_channel_stats_load(w, db_col_u64(stmt, "id"), &stats); + chan = new_channel(peer, db_col_u64(stmt, "id"), &wshachain, channel_state_in_db(db_col_int(stmt, "state")), @@ -1779,7 +1782,8 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm htlc_maximum_msat, ignore_fee_limits, remote_update, - db_col_u64(stmt, "last_stable_connection")); + db_col_u64(stmt, "last_stable_connection"), + &stats); if (!wallet_channel_load_inflights(w, chan)) { tal_free(chan); From a9fc90f77a164cf5bd4f96fefe6e9d4929b28700 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 19 Sep 2024 16:30:39 +0930 Subject: [PATCH 2/5] listpeerchannels: use struct channel stats, don't fetch from db. This avoids a db lookup on every iteration of listpeerchannels, which can be slow on large nodes (Postgres, I assume). We can now simply add the fields we want to channel load, and remove wallet_channel_stats_load entirely. Signed-off-by: Rusty Russell --- lightningd/peer_control.c | 18 +++-- lightningd/test/run-invoice-select-inchan.c | 3 - wallet/wallet.c | 74 ++++++++------------- wallet/wallet.h | 9 --- 4 files changed, 36 insertions(+), 68 deletions(-) diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index aaf7897754e3..285a209ab6d0 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -818,7 +818,6 @@ static void NON_NULL_ARGS(1, 2, 4, 5) json_add_channel(struct command *cmd, const struct peer *peer) { struct lightningd *ld = cmd->ld; - struct channel_stats channel_stats; struct amount_msat funding_msat; struct amount_sat peer_funded_sats; struct state_change_entry *state_changes; @@ -1191,27 +1190,26 @@ static void NON_NULL_ARGS(1, 2, 4, 5) json_add_channel(struct command *cmd, json_array_end(response); /* Provide channel statistics */ - wallet_channel_stats_load(ld->wallet, channel->dbid, &channel_stats); json_add_u64(response, "in_payments_offered", - channel_stats.in_payments_offered); + channel->stats.in_payments_offered); json_add_amount_msat(response, "in_offered_msat", - channel_stats.in_msatoshi_offered); + channel->stats.in_msatoshi_offered); json_add_u64(response, "in_payments_fulfilled", - channel_stats.in_payments_fulfilled); + channel->stats.in_payments_fulfilled); json_add_amount_msat(response, "in_fulfilled_msat", - channel_stats.in_msatoshi_fulfilled); + channel->stats.in_msatoshi_fulfilled); json_add_u64(response, "out_payments_offered", - channel_stats.out_payments_offered); + channel->stats.out_payments_offered); json_add_amount_msat(response, "out_offered_msat", - channel_stats.out_msatoshi_offered); + channel->stats.out_msatoshi_offered); json_add_u64(response, "out_payments_fulfilled", - channel_stats.out_payments_fulfilled); + channel->stats.out_payments_fulfilled); json_add_amount_msat(response, "out_fulfilled_msat", - channel_stats.out_msatoshi_fulfilled); + channel->stats.out_msatoshi_fulfilled); json_add_htlcs(ld, response, channel); json_object_end(response); diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index 154684d3d10a..cc17b7947f51 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -1023,9 +1023,6 @@ const char *version(void) /* Generated stub for wallet_channel_save */ void wallet_channel_save(struct wallet *w UNNEEDED, struct channel *chan UNNEEDED) { fprintf(stderr, "wallet_channel_save called!\n"); abort(); } -/* Generated stub for wallet_channel_stats_load */ -void wallet_channel_stats_load(struct wallet *w UNNEEDED, u64 cdbid UNNEEDED, struct channel_stats *stats UNNEEDED) -{ fprintf(stderr, "wallet_channel_stats_load called!\n"); abort(); } /* Generated stub for wallet_channeltxs_add */ void wallet_channeltxs_add(struct wallet *w UNNEEDED, struct channel *chan UNNEEDED, const int type UNNEEDED, const struct bitcoin_txid *txid UNNEEDED, diff --git a/wallet/wallet.c b/wallet/wallet.c index 831ae4880098..5eeffd234654 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1719,7 +1719,26 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm db_col_ignore(stmt, "remote_htlc_maximum_msat"); } - wallet_channel_stats_load(w, db_col_u64(stmt, "id"), &stats); + stats.in_payments_offered + = db_col_int_or_default(stmt, "in_payments_offered", 0); + stats.in_payments_fulfilled + = db_col_int_or_default(stmt, "in_payments_fulfilled", 0); + db_col_amount_msat_or_default(stmt, "in_msatoshi_offered", + &stats.in_msatoshi_offered, + AMOUNT_MSAT(0)); + db_col_amount_msat_or_default(stmt, "in_msatoshi_fulfilled", + &stats.in_msatoshi_fulfilled, + AMOUNT_MSAT(0)); + stats.out_payments_offered + = db_col_int_or_default(stmt, "out_payments_offered", 0); + stats.out_payments_fulfilled + = db_col_int_or_default(stmt, "out_payments_fulfilled", 0); + db_col_amount_msat_or_default(stmt, "out_msatoshi_offered", + &stats.out_msatoshi_offered, + AMOUNT_MSAT(0)); + db_col_amount_msat_or_default(stmt, "out_msatoshi_fulfilled", + &stats.out_msatoshi_fulfilled, + AMOUNT_MSAT(0)); chan = new_channel(peer, db_col_u64(stmt, "id"), &wshachain, @@ -1977,6 +1996,14 @@ static bool wallet_channels_load_active(struct wallet *w) ", remote_htlc_minimum_msat" ", remote_htlc_maximum_msat" ", last_stable_connection" + ", in_payments_offered" + ", in_payments_fulfilled" + ", in_msatoshi_offered" + ", in_msatoshi_fulfilled" + ", out_payments_offered" + ", out_payments_fulfilled" + ", out_msatoshi_offered" + ", out_msatoshi_fulfilled" " FROM channels" " WHERE state != ?;")); //? 0 db_bind_int(stmt, CLOSED); @@ -2080,51 +2107,6 @@ void wallet_channel_stats_incr_out_fulfilled(struct wallet *w, u64 id, wallet_channel_stats_incr_x(w, "out", "fulfilled", id, m); } -void wallet_channel_stats_load(struct wallet *w, - u64 id, - struct channel_stats *stats) -{ - struct db_stmt *stmt; - int res; - stmt = db_prepare_v2(w->db, SQL( - "SELECT" - " in_payments_offered, in_payments_fulfilled" - ", in_msatoshi_offered, in_msatoshi_fulfilled" - ", out_payments_offered, out_payments_fulfilled" - ", out_msatoshi_offered, out_msatoshi_fulfilled" - " FROM channels" - " WHERE id = ?")); - db_bind_u64(stmt, id); - db_query_prepared(stmt); - - res = db_step(stmt); - - /* This must succeed, since we know the channel exists */ - assert(res); - - stats->in_payments_offered - = db_col_int_or_default(stmt, "in_payments_offered", 0); - stats->in_payments_fulfilled - = db_col_int_or_default(stmt, "in_payments_fulfilled", 0); - db_col_amount_msat_or_default(stmt, "in_msatoshi_offered", - &stats->in_msatoshi_offered, - AMOUNT_MSAT(0)); - db_col_amount_msat_or_default(stmt, "in_msatoshi_fulfilled", - &stats->in_msatoshi_fulfilled, - AMOUNT_MSAT(0)); - stats->out_payments_offered - = db_col_int_or_default(stmt, "out_payments_offered", 0); - stats->out_payments_fulfilled - = db_col_int_or_default(stmt, "out_payments_fulfilled", 0); - db_col_amount_msat_or_default(stmt, "out_msatoshi_offered", - &stats->out_msatoshi_offered, - AMOUNT_MSAT(0)); - db_col_amount_msat_or_default(stmt, "out_msatoshi_fulfilled", - &stats->out_msatoshi_fulfilled, - AMOUNT_MSAT(0)); - tal_free(stmt); -} - u32 wallet_blocks_maxheight(struct wallet *w) { u32 max = 0; diff --git a/wallet/wallet.h b/wallet/wallet.h index b26de521bc77..8fd3ca091f48 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -715,15 +715,6 @@ void wallet_channel_stats_incr_in_fulfilled(struct wallet *w, u64 cdbid, struct void wallet_channel_stats_incr_out_offered(struct wallet *w, u64 cdbid, struct amount_msat msatoshi); void wallet_channel_stats_incr_out_fulfilled(struct wallet *w, u64 cdbid, struct amount_msat msatoshi); -/** - * wallet_channel_stats_load - Load channel statistics - * - * @w: wallet containing the channel - * @cdbid: channel database id - * @stats: location to load statistics to - */ -void wallet_channel_stats_load(struct wallet *w, u64 cdbid, struct channel_stats *stats); - /** * Retrieve the blockheight of the last block processed by lightningd. * From 64a03ebb6c77181aa8019a34a576c55735d80994 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 19 Sep 2024 16:30:40 +0930 Subject: [PATCH 3/5] db: clean up channel_stats handling. Indirection via a string and an enum is just adding confusion here. And move the `struct channel_stats` into channel.h. Signed-off-by: Rusty Russell --- lightningd/channel.h | 8 ++++ wallet/wallet.c | 93 +++++++++++++------------------------------- wallet/wallet.h | 8 ---- 3 files changed, 34 insertions(+), 75 deletions(-) diff --git a/lightningd/channel.h b/lightningd/channel.h index cdb6cc15f5b8..9f1623ad9ab3 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -107,6 +107,14 @@ struct open_attempt { const u8 *open_msg; }; +/* Statistics for a channel */ +struct channel_stats { + u64 in_payments_offered, in_payments_fulfilled; + struct amount_msat in_msatoshi_offered, in_msatoshi_fulfilled; + u64 out_payments_offered, out_payments_fulfilled; + struct amount_msat out_msatoshi_offered, out_msatoshi_fulfilled; +}; + struct channel { /* Inside peer->channels. */ struct list_node list; diff --git a/wallet/wallet.c b/wallet/wallet.c index 5eeffd234654..fbab37d3dffa 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -37,21 +37,6 @@ /* 12 hours is usually enough reservation time */ #define RESERVATION_INC (6 * 12) -/* Possible channel state */ -enum channel_state_bucket { - IN_OFFERED = 0, - IN_FULLFILLED = 1, - OUT_OFFERED = 2, - OUT_FULLFILLED = 3, -}; - -/* channel state identifier */ -struct channel_state_param { - const char *dir_key; - const char *type_key; - const enum channel_state_bucket state; -}; - /* These go in db, so values cannot change (we can't put this into * lightningd/channel_state.h since it confuses cdump!) */ static enum state_change state_change_in_db(enum state_change s) @@ -2029,56 +2014,12 @@ bool wallet_init_channels(struct wallet *w) return wallet_channels_load_active(w); } -static enum channel_state_bucket get_state_channel_db(const char *dir, const char *typ) -{ - enum channel_state_bucket channel_state = IN_OFFERED; - if (streq(dir, "out")) - channel_state += 2; - if (streq(typ, "fulfilled")) - channel_state += 1; - return channel_state; -} - -static -void wallet_channel_stats_incr_x(struct wallet *w, - char const *dir, - char const *typ, - u64 cdbid, - struct amount_msat msat) +static void wallet_channel_stats_incr_x(struct wallet *w, + u64 cdbid, + struct amount_msat msat, + const char *query) { struct db_stmt *stmt; - const char *query = NULL; - - switch (get_state_channel_db(dir, typ)) { - case IN_OFFERED: - query = SQL("UPDATE channels" - " SET in_payments_offered = COALESCE(in_payments_offered, 0) + 1" - " , in_msatoshi_offered = COALESCE(in_msatoshi_offered, 0) + ?" - " WHERE id = ?;"); - break; - case IN_FULLFILLED: - query = SQL("UPDATE channels" - " SET in_payments_fulfilled = COALESCE(in_payments_fulfilled, 0) + 1" - " , in_msatoshi_fulfilled = COALESCE(in_msatoshi_fulfilled, 0) + ?" - " WHERE id = ?;"); - break; - case OUT_OFFERED: - query = SQL("UPDATE channels" - " SET out_payments_offered = COALESCE(out_payments_offered, 0) + 1" - " , out_msatoshi_offered = COALESCE(out_msatoshi_offered, 0) + ?" - " WHERE id = ?;"); - break; - case OUT_FULLFILLED: - query = SQL("UPDATE channels" - " SET out_payments_fulfilled = COALESCE(out_payments_fulfilled, 0) + 1" - " , out_msatoshi_fulfilled = COALESCE(out_msatoshi_fulfilled, 0) + ?" - " WHERE id = ?;"); - break; - } - - // Sanity check! - if (!query) - fatal("Unknown channel state key (direction %s, type %s)", dir, typ); stmt = db_prepare_v2(w->db, query); db_bind_amount_msat(stmt, &msat); @@ -2086,25 +2027,43 @@ void wallet_channel_stats_incr_x(struct wallet *w, db_exec_prepared_v2(take(stmt)); } + +/* I would use macros for these, but gettext needs string literals :( */ void wallet_channel_stats_incr_in_offered(struct wallet *w, u64 id, struct amount_msat m) { - wallet_channel_stats_incr_x(w, "in", "offered", id, m); + const char query[] = SQL("UPDATE channels" + " SET in_payments_offered = COALESCE(in_payments_offered, 0) + 1" + " , in_msatoshi_offered = COALESCE(in_msatoshi_offered, 0) + ?" + " WHERE id = ?;"); + wallet_channel_stats_incr_x(w, id, m, query); } void wallet_channel_stats_incr_in_fulfilled(struct wallet *w, u64 id, struct amount_msat m) { - wallet_channel_stats_incr_x(w, "in", "fulfilled", id, m); + const char query[] = SQL("UPDATE channels" + " SET in_payments_fulfilled = COALESCE(in_payments_fulfilled, 0) + 1" + " , in_msatoshi_fulfilled = COALESCE(in_msatoshi_fulfilled, 0) + ?" + " WHERE id = ?;"); + wallet_channel_stats_incr_x(w, id, m, query); } void wallet_channel_stats_incr_out_offered(struct wallet *w, u64 id, struct amount_msat m) { - wallet_channel_stats_incr_x(w, "out", "offered", id, m); + const char query[] = SQL("UPDATE channels" + " SET out_payments_offered = COALESCE(out_payments_offered, 0) + 1" + " , out_msatoshi_offered = COALESCE(out_msatoshi_offered, 0) + ?" + " WHERE id = ?;"); + wallet_channel_stats_incr_x(w, id, m, query); } void wallet_channel_stats_incr_out_fulfilled(struct wallet *w, u64 id, struct amount_msat m) { - wallet_channel_stats_incr_x(w, "out", "fulfilled", id, m); + const char query[] = SQL("UPDATE channels" + " SET out_payments_fulfilled = COALESCE(out_payments_fulfilled, 0) + 1" + " , out_msatoshi_fulfilled = COALESCE(out_msatoshi_fulfilled, 0) + ?" + " WHERE id = ?;"); + wallet_channel_stats_incr_x(w, id, m, query); } u32 wallet_blocks_maxheight(struct wallet *w) diff --git a/wallet/wallet.h b/wallet/wallet.h index 8fd3ca091f48..dce2475a4695 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -366,14 +366,6 @@ struct outpoint { u32 spendheight; }; -/* Statistics for a channel */ -struct channel_stats { - u64 in_payments_offered, in_payments_fulfilled; - struct amount_msat in_msatoshi_offered, in_msatoshi_fulfilled; - u64 out_payments_offered, out_payments_fulfilled; - struct amount_msat out_msatoshi_offered, out_msatoshi_fulfilled; -}; - struct channeltx { u32 channel_id; int type; From f94550dba58a28c60abf0d9deabac5ae3155a1d8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 19 Sep 2024 16:34:20 +0930 Subject: [PATCH 4/5] lightningd: move the state changes into `struct channel`. And instead of loading them in listpeerchannels, use them. This means listpeerchannels no longer touches the db. Signed-off-by: Rusty Russell Changelog-Fixed: JSONRPC: `listpeerchannels` (and thus, pay) sped up on very large nodes. --- lightningd/channel.c | 21 +++++++++++++++------ lightningd/channel.h | 6 +++++- lightningd/opening_control.c | 6 ++++-- lightningd/peer_control.c | 14 ++++++-------- wallet/test/run-db.c | 3 ++- wallet/test/run-wallet.c | 3 ++- wallet/wallet.c | 6 +++++- 7 files changed, 39 insertions(+), 20 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index 1ea3693cde31..646c4f2ed5cd 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -312,6 +312,7 @@ struct channel *new_unsaved_channel(struct peer *peer, channel->stable_conn_timer = NULL; /* Nothing happened yet */ memset(&channel->stats, 0, sizeof(channel->stats)); + channel->state_changes = tal_arr(channel, struct state_change_entry, 0); /* No shachain yet */ channel->their_shachain.id = 0; @@ -448,7 +449,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, /* NULL or stolen */ struct peer_update *peer_update STEALS, u64 last_stable_connection, - const struct channel_stats *stats) + const struct channel_stats *stats, + struct state_change_entry *state_changes STEALS) { struct channel *channel = tal(peer->ld, struct channel); struct amount_msat htlc_min, htlc_max; @@ -606,6 +608,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, channel->last_stable_connection = last_stable_connection; channel->stable_conn_timer = NULL; channel->stats = *stats; + channel->state_changes = tal_steal(channel, state_changes); + /* Populate channel->channel_gossip */ channel_gossip_init(channel, take(peer_update)); @@ -836,8 +840,6 @@ void channel_set_state(struct channel *channel, enum state_change reason, char *why) { - struct timeabs timestamp; - /* set closer, if known */ if (channel_state_closing(state) && channel->closer == NUM_SIDES) { if (reason == REASON_LOCAL) channel->closer = LOCAL; @@ -865,10 +867,17 @@ void channel_set_state(struct channel *channel, /* plugin notification channel_state_changed and DB entry */ if (state != old_state) { /* see issue #4029 */ - timestamp = time_now(); + struct state_change_entry change; + change.timestamp = time_now(); + change.old_state = old_state; + change.new_state = state; + change.cause = reason; + change.message = tal_strdup(channel->state_changes, why); + tal_arr_expand(&channel->state_changes, change); + wallet_state_change_add(channel->peer->ld->wallet, channel->dbid, - timestamp, + change.timestamp, old_state, state, reason, @@ -877,7 +886,7 @@ void channel_set_state(struct channel *channel, &channel->peer->id, &channel->cid, channel->scid, - timestamp, + change.timestamp, old_state, state, reason, diff --git a/lightningd/channel.h b/lightningd/channel.h index 9f1623ad9ab3..864854afa928 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -325,6 +325,9 @@ struct channel { /* Our stats */ struct channel_stats stats; + + /* Our change history. */ + struct state_change_entry *state_changes; }; /* Is channel owned (and should be talking to peer) */ @@ -407,7 +410,8 @@ struct channel *new_channel(struct peer *peer, u64 dbid, /* NULL or stolen */ struct peer_update *peer_update STEALS, u64 last_stable_connection, - const struct channel_stats *stats); + const struct channel_stats *stats, + struct state_change_entry *state_changes STEALS); /* new_inflight - Create a new channel_inflight for a channel */ struct channel_inflight *new_inflight(struct channel *channel, diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 197316615661..a52307323605 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -220,7 +220,8 @@ wallet_commit_channel(struct lightningd *ld, ld->config.ignore_fee_limits, NULL, 0, - &zero_channel_stats); + &zero_channel_stats, + tal_arr(NULL, struct state_change_entry, 0)); /* Now we finally put it in the database. */ wallet_channel_insert(ld->wallet, channel); @@ -1598,7 +1599,8 @@ static struct channel *stub_chan(struct command *cmd, false, NULL, 0, - &zero_channel_stats); + &zero_channel_stats, + tal_arr(NULL, struct state_change_entry, 0)); /* We don't want to gossip about this, ever. */ channel->channel_gossip = tal_free(channel->channel_gossip); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 285a209ab6d0..4bace9f47a96 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -820,7 +820,6 @@ static void NON_NULL_ARGS(1, 2, 4, 5) json_add_channel(struct command *cmd, struct lightningd *ld = cmd->ld; struct amount_msat funding_msat; struct amount_sat peer_funded_sats; - struct state_change_entry *state_changes; const struct peer_update *peer_update; u32 feerate; @@ -1161,19 +1160,18 @@ static void NON_NULL_ARGS(1, 2, 4, 5) json_add_channel(struct command *cmd, json_add_num(response, "max_accepted_htlcs", channel->our_config.max_accepted_htlcs); - state_changes = wallet_state_change_get(tmpctx, ld->wallet, channel->dbid); json_array_start(response, "state_changes"); - for (size_t i = 0; i < tal_count(state_changes); i++) { + for (size_t i = 0; i < tal_count(channel->state_changes); i++) { json_object_start(response, NULL); json_add_timeiso(response, "timestamp", - state_changes[i].timestamp); + channel->state_changes[i].timestamp); json_add_string(response, "old_state", - channel_state_str(state_changes[i].old_state)); + channel_state_str(channel->state_changes[i].old_state)); json_add_string(response, "new_state", - channel_state_str(state_changes[i].new_state)); + channel_state_str(channel->state_changes[i].new_state)); json_add_string(response, "cause", - channel_change_state_reason_str(state_changes[i].cause)); - json_add_string(response, "message", state_changes[i].message); + channel_change_state_reason_str(channel->state_changes[i].cause)); + json_add_string(response, "message", channel->state_changes[i].message); json_object_end(response); } json_array_end(response); diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index 4af4988e7521..445ef118c46b 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -192,7 +192,8 @@ struct channel *new_channel(struct peer *peer UNNEEDED, u64 dbid UNNEEDED, /* NULL or stolen */ struct peer_update *peer_update STEALS UNNEEDED, u64 last_stable_connection UNNEEDED, - const struct channel_stats *stats UNNEEDED) + const struct channel_stats *stats UNNEEDED, + struct state_change_entry *state_changes STEALS UNNEEDED) { fprintf(stderr, "new_channel called!\n"); abort(); } /* Generated stub for new_coin_wallet_deposit */ struct chain_coin_mvt *new_coin_wallet_deposit(const tal_t *ctx UNNEEDED, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 68c961fc3480..0d069701d667 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1997,7 +1997,8 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) false, NULL, 0, - stats); + stats, + tal_arr(NULL, struct state_change_entry, 0)); db_begin_transaction(w->db); CHECK(!wallet_err); wallet_channel_insert(w, chan); diff --git a/wallet/wallet.c b/wallet/wallet.c index fbab37d3dffa..c5b19ea42f6d 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1522,6 +1522,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm bool ignore_fee_limits; struct peer_update *remote_update; struct channel_stats stats; + struct state_change_entry *state_changes; peer_dbid = db_col_u64(stmt, "peer_id"); peer = find_peer_by_dbid(w->ld, peer_dbid); @@ -1725,6 +1726,8 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm &stats.out_msatoshi_fulfilled, AMOUNT_MSAT(0)); + /* Stolen by new_channel */ + state_changes = wallet_state_change_get(NULL, w, db_col_u64(stmt, "id")); chan = new_channel(peer, db_col_u64(stmt, "id"), &wshachain, channel_state_in_db(db_col_int(stmt, "state")), @@ -1787,7 +1790,8 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm ignore_fee_limits, remote_update, db_col_u64(stmt, "last_stable_connection"), - &stats); + &stats, + state_changes); if (!wallet_channel_load_inflights(w, chan)) { tal_free(chan); From 829fdab603b131f71128e83335ac15650ee2bc42 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 19 Sep 2024 16:34:33 +0930 Subject: [PATCH 5/5] lightningd: rename state_change_entry to channel_state_change, and use pointers. This name is clearer than the old one. And since the struct contains a string, it's more natural for the struct to be the tal parent of the string so it's a real object. This means we need an array of pointers, so each struct can be its own tal object. wallet_state_change_get is hoisted higher in the code and made static. Signed-off-by: Rusty Russell --- lightningd/channel.c | 38 ++++++++--- lightningd/channel.h | 20 +++++- lightningd/channel_state.h | 9 --- lightningd/opening_control.c | 4 +- lightningd/peer_control.c | 13 ++-- lightningd/test/run-invoice-select-inchan.c | 5 -- wallet/test/run-db.c | 10 ++- wallet/test/run-wallet.c | 2 +- wallet/wallet.c | 70 +++++++++++---------- wallet/wallet.h | 7 --- 10 files changed, 101 insertions(+), 77 deletions(-) diff --git a/lightningd/channel.c b/lightningd/channel.c index 646c4f2ed5cd..59c5be0a2d0e 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -312,7 +312,7 @@ struct channel *new_unsaved_channel(struct peer *peer, channel->stable_conn_timer = NULL; /* Nothing happened yet */ memset(&channel->stats, 0, sizeof(channel->stats)); - channel->state_changes = tal_arr(channel, struct state_change_entry, 0); + channel->state_changes = tal_arr(channel, struct channel_state_change *, 0); /* No shachain yet */ channel->their_shachain.id = 0; @@ -450,7 +450,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, struct peer_update *peer_update STEALS, u64 last_stable_connection, const struct channel_stats *stats, - struct state_change_entry *state_changes STEALS) + struct channel_state_change **state_changes STEALS) { struct channel *channel = tal(peer->ld, struct channel); struct amount_msat htlc_min, htlc_max; @@ -834,6 +834,22 @@ void channel_set_last_tx(struct channel *channel, channel->last_tx = tal_steal(channel, tx); } +struct channel_state_change *new_channel_state_change(const tal_t *ctx, + struct timeabs timestamp, + enum channel_state old_state, + enum channel_state new_state, + enum state_change cause, + const char *message TAKES) +{ + struct channel_state_change *c = tal(ctx, struct channel_state_change); + c->timestamp = timestamp; + c->old_state = old_state; + c->new_state = new_state; + c->cause = cause; + c->message = tal_strdup(c, message); + return c; +} + void channel_set_state(struct channel *channel, enum channel_state old_state, enum channel_state state, @@ -867,17 +883,19 @@ void channel_set_state(struct channel *channel, /* plugin notification channel_state_changed and DB entry */ if (state != old_state) { /* see issue #4029 */ - struct state_change_entry change; - change.timestamp = time_now(); - change.old_state = old_state; - change.new_state = state; - change.cause = reason; - change.message = tal_strdup(channel->state_changes, why); + struct channel_state_change *change; + + change = new_channel_state_change(channel->state_changes, + time_now(), + old_state, + state, + reason, + why); tal_arr_expand(&channel->state_changes, change); wallet_state_change_add(channel->peer->ld->wallet, channel->dbid, - change.timestamp, + change->timestamp, old_state, state, reason, @@ -886,7 +904,7 @@ void channel_set_state(struct channel *channel, &channel->peer->id, &channel->cid, channel->scid, - change.timestamp, + change->timestamp, old_state, state, reason, diff --git a/lightningd/channel.h b/lightningd/channel.h index 864854afa928..4b40356990c9 100644 --- a/lightningd/channel.h +++ b/lightningd/channel.h @@ -115,6 +115,15 @@ struct channel_stats { struct amount_msat out_msatoshi_offered, out_msatoshi_fulfilled; }; + +struct channel_state_change { + struct timeabs timestamp; + enum channel_state old_state; + enum channel_state new_state; + enum state_change cause; + const char *message; +}; + struct channel { /* Inside peer->channels. */ struct list_node list; @@ -327,7 +336,7 @@ struct channel { struct channel_stats stats; /* Our change history. */ - struct state_change_entry *state_changes; + struct channel_state_change **state_changes; }; /* Is channel owned (and should be talking to peer) */ @@ -411,7 +420,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid, struct peer_update *peer_update STEALS, u64 last_stable_connection, const struct channel_stats *stats, - struct state_change_entry *state_changes STEALS); + struct channel_state_change **state_changes STEALS); /* new_inflight - Create a new channel_inflight for a channel */ struct channel_inflight *new_inflight(struct channel *channel, @@ -431,6 +440,13 @@ struct channel_inflight *new_inflight(struct channel *channel, bool i_am_initiator, bool force_sign_first); +struct channel_state_change *new_channel_state_change(const tal_t *ctx, + struct timeabs timestamp, + enum channel_state old_state, + enum channel_state new_state, + enum state_change cause, + const char *message TAKES); + /* Add a last_tx and sig to an inflight */ void inflight_set_last_tx(struct channel_inflight *inflight, struct bitcoin_tx *last_tx STEALS, diff --git a/lightningd/channel_state.h b/lightningd/channel_state.h index 2c655bc8b0ef..8ef3da3bebe7 100644 --- a/lightningd/channel_state.h +++ b/lightningd/channel_state.h @@ -73,13 +73,4 @@ enum state_change { /* Note: This is very likely a conscious remote decision. */ REASON_ONCHAIN }; - -struct state_change_entry { - struct timeabs timestamp; - enum channel_state old_state; - enum channel_state new_state; - enum state_change cause; - char *message; -}; - #endif /* LIGHTNING_LIGHTNINGD_CHANNEL_STATE_H */ diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index a52307323605..d0a2c7e6eed6 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -221,7 +221,7 @@ wallet_commit_channel(struct lightningd *ld, NULL, 0, &zero_channel_stats, - tal_arr(NULL, struct state_change_entry, 0)); + tal_arr(NULL, struct channel_state_change *, 0)); /* Now we finally put it in the database. */ wallet_channel_insert(ld->wallet, channel); @@ -1600,7 +1600,7 @@ static struct channel *stub_chan(struct command *cmd, NULL, 0, &zero_channel_stats, - tal_arr(NULL, struct state_change_entry, 0)); + tal_arr(NULL, struct channel_state_change *, 0)); /* We don't want to gossip about this, ever. */ channel->channel_gossip = tal_free(channel->channel_gossip); diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 4bace9f47a96..d514f59364cb 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1162,16 +1162,17 @@ static void NON_NULL_ARGS(1, 2, 4, 5) json_add_channel(struct command *cmd, json_array_start(response, "state_changes"); for (size_t i = 0; i < tal_count(channel->state_changes); i++) { + const struct channel_state_change *change + = channel->state_changes[i]; json_object_start(response, NULL); - json_add_timeiso(response, "timestamp", - channel->state_changes[i].timestamp); + json_add_timeiso(response, "timestamp", change->timestamp); json_add_string(response, "old_state", - channel_state_str(channel->state_changes[i].old_state)); + channel_state_str(change->old_state)); json_add_string(response, "new_state", - channel_state_str(channel->state_changes[i].new_state)); + channel_state_str(change->new_state)); json_add_string(response, "cause", - channel_change_state_reason_str(channel->state_changes[i].cause)); - json_add_string(response, "message", channel->state_changes[i].message); + channel_change_state_reason_str(change->cause)); + json_add_string(response, "message", change->message); json_object_end(response); } json_array_end(response); diff --git a/lightningd/test/run-invoice-select-inchan.c b/lightningd/test/run-invoice-select-inchan.c index cc17b7947f51..54fe654ac139 100644 --- a/lightningd/test/run-invoice-select-inchan.c +++ b/lightningd/test/run-invoice-select-inchan.c @@ -1059,11 +1059,6 @@ char *wallet_offer_find(const tal_t *ctx UNNEEDED, enum offer_status *status) { fprintf(stderr, "wallet_offer_find called!\n"); abort(); } -/* Generated stub for wallet_state_change_get */ -struct state_change_entry *wallet_state_change_get(const tal_t *ctx UNNEEDED, - struct wallet *w UNNEEDED, - u64 channel_id UNNEEDED) -{ fprintf(stderr, "wallet_state_change_get called!\n"); abort(); } /* Generated stub for wallet_total_forward_fees */ struct amount_msat wallet_total_forward_fees(struct wallet *w UNNEEDED) { fprintf(stderr, "wallet_total_forward_fees called!\n"); abort(); } diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index 445ef118c46b..755b6318ee4c 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -193,8 +193,16 @@ struct channel *new_channel(struct peer *peer UNNEEDED, u64 dbid UNNEEDED, struct peer_update *peer_update STEALS UNNEEDED, u64 last_stable_connection UNNEEDED, const struct channel_stats *stats UNNEEDED, - struct state_change_entry *state_changes STEALS UNNEEDED) + struct channel_state_change **state_changes STEALS UNNEEDED) { fprintf(stderr, "new_channel called!\n"); abort(); } +/* Generated stub for new_channel_state_change */ +struct channel_state_change *new_channel_state_change(const tal_t *ctx UNNEEDED, + struct timeabs timestamp UNNEEDED, + enum channel_state old_state UNNEEDED, + enum channel_state new_state UNNEEDED, + enum state_change cause UNNEEDED, + const char *message TAKES UNNEEDED) +{ fprintf(stderr, "new_channel_state_change called!\n"); abort(); } /* Generated stub for new_coin_wallet_deposit */ struct chain_coin_mvt *new_coin_wallet_deposit(const tal_t *ctx UNNEEDED, const struct bitcoin_outpoint *outpoint UNNEEDED, diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 0d069701d667..31006b1f7a6d 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -1998,7 +1998,7 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx) NULL, 0, stats, - tal_arr(NULL, struct state_change_entry, 0)); + tal_arr(NULL, struct channel_state_change *, 0)); db_begin_transaction(w->db); CHECK(!wallet_err); wallet_channel_insert(w, chan); diff --git a/wallet/wallet.c b/wallet/wallet.c index c5b19ea42f6d..811944c27a18 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -1486,6 +1486,41 @@ static struct short_channel_id *db_col_optional_scid(const tal_t *ctx, return scid; } +static struct channel_state_change **wallet_state_change_get(const tal_t *ctx, + struct wallet *w, + u64 channel_id) +{ + struct db_stmt *stmt; + struct channel_state_change **res = tal_arr(ctx, + struct channel_state_change *, 0); + stmt = db_prepare_v2( + w->db, SQL("SELECT" + " timestamp," + " old_state," + " new_state," + " cause," + " message " + "FROM channel_state_changes " + "WHERE channel_id = ? " + "ORDER BY timestamp ASC;")); + db_bind_int(stmt, channel_id); + db_query_prepared(stmt); + + while (db_step(stmt)) { + struct channel_state_change *c; + + c = new_channel_state_change(res, + db_col_timeabs(stmt, "timestamp"), + db_col_int(stmt, "old_state"), + db_col_int(stmt, "new_state"), + state_change_in_db(db_col_int(stmt, "cause")), + take(db_col_strdup(NULL, stmt, "message"))); + tal_arr_expand(&res, c); + } + tal_free(stmt); + return res; +} + /** * wallet_stmt2channel - Helper to populate a wallet_channel from a `db_stmt` */ @@ -1522,7 +1557,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm bool ignore_fee_limits; struct peer_update *remote_update; struct channel_stats stats; - struct state_change_entry *state_changes; + struct channel_state_change **state_changes; peer_dbid = db_col_u64(stmt, "peer_id"); peer = find_peer_by_dbid(w->ld, peer_dbid); @@ -2464,39 +2499,6 @@ void wallet_state_change_add(struct wallet *w, db_exec_prepared_v2(take(stmt)); } -struct state_change_entry *wallet_state_change_get(const tal_t *ctx, - struct wallet *w, - u64 channel_id) -{ - struct db_stmt *stmt; - struct state_change_entry tmp; - struct state_change_entry *res = tal_arr(ctx, - struct state_change_entry, 0); - stmt = db_prepare_v2( - w->db, SQL("SELECT" - " timestamp," - " old_state," - " new_state," - " cause," - " message " - "FROM channel_state_changes " - "WHERE channel_id = ? " - "ORDER BY timestamp ASC;")); - db_bind_int(stmt, channel_id); - db_query_prepared(stmt); - - while (db_step(stmt)) { - tmp.timestamp = db_col_timeabs(stmt, "timestamp"); - tmp.old_state = db_col_int(stmt, "old_state"); - tmp.new_state = db_col_int(stmt, "new_state"); - tmp.cause = state_change_in_db(db_col_int(stmt, "cause")); - tmp.message = db_col_strdup(res, stmt, "message"); - tal_arr_expand(&res, tmp); - } - tal_free(stmt); - return res; -} - static void wallet_peer_save(struct wallet *w, struct peer *peer) { const char *addr = diff --git a/wallet/wallet.h b/wallet/wallet.h index dce2475a4695..9329e5a37750 100644 --- a/wallet/wallet.h +++ b/wallet/wallet.h @@ -662,13 +662,6 @@ void wallet_state_change_add(struct wallet *w, enum state_change cause, const char *message); -/** - * Gets all state change history entries for a channel from the database - */ -struct state_change_entry *wallet_state_change_get(const tal_t *ctx, - struct wallet *w, - u64 channel_id); - /** * wallet_delete_peer_if_unused -- After no more channels in peer, forget about it */