From 7b6956e4f9af5e4281dd988458ccb6662107263a Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 19 Jul 2022 17:04:36 +0930 Subject: [PATCH] bkpr: annotate an account with the block at which it's been resolved Due to the way that onchain channel closes work, there is often a delay between when the funding output is spent and the channel is considered 'closed'. Once *every* downstream utxo of a channel has landed on chain, we annotate the account with the resolving blockheight. This gives us some insight into whether or not the chain fees etc of a channel are going to update further and allows for a natural marker to prune data (at a later date) --- plugins/bkpr/bookkeeper.c | 14 +++++++++---- plugins/bkpr/recorder.c | 44 +++++++++++++++++++++++++++++++++++++-- plugins/bkpr/recorder.h | 7 +++++++ 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/plugins/bkpr/bookkeeper.c b/plugins/bkpr/bookkeeper.c index 3da169e41..1e5fa6962 100644 --- a/plugins/bkpr/bookkeeper.c +++ b/plugins/bkpr/bookkeeper.c @@ -756,7 +756,11 @@ listpeers_done(struct command *cmd, const char *buf, "Unable to find account %s in listpeers", info->acct->name); - /* FIXME: maybe mark channel as 'onchain_resolved' */ + /* Maybe mark acct as onchain resolved */ + db_begin_transaction(db); + if (info->acct->closed_event_db_id) + maybe_mark_account_onchain(db, info->acct); + db_commit_transaction(db); return notification_handled(cmd); } @@ -1078,9 +1082,11 @@ parse_and_log_chain_move(struct command *cmd, return command_still_pending(cmd); } - /* FIXME: maybe mark channel as 'onchain_resolved' */ - if (err) - plugin_err(cmd->plugin, err); + /* Maybe mark acct as onchain resolved */ + db_begin_transaction(db); + if (acct->closed_event_db_id) + maybe_mark_account_onchain(db, acct); + db_commit_transaction(db); return notification_handled(cmd);; } diff --git a/plugins/bkpr/recorder.c b/plugins/bkpr/recorder.c index c03e4824a..dab6d477a 100644 --- a/plugins/bkpr/recorder.c +++ b/plugins/bkpr/recorder.c @@ -334,7 +334,8 @@ bool find_txo_chain(const tal_t *ctx, open_ev = find_chain_event_by_id(ctx, db, *acct->open_event_db_id); - *sets = tal_arr(ctx, struct txo_set *, 0); + if (sets) + *sets = tal_arr(ctx, struct txo_set *, 0); txids = tal_arr(ctx, struct bitcoin_txid *, 0); tal_arr_expand(&txids, &open_ev->outpoint.txid); @@ -379,12 +380,51 @@ bool find_txo_chain(const tal_t *ctx, } } - tal_arr_expand(sets, set); + if (sets) + tal_arr_expand(sets, set); } return is_complete; } +void maybe_mark_account_onchain(struct db *db, struct account *acct) +{ + const u8 *ctx = tal(NULL, u8); + if (find_txo_chain(ctx, db, acct, NULL)) { + /* Ok now we find the max block height of the + * spending chain_events for this channel */ + bool ok; + + struct db_stmt *stmt = db_prepare_v2(db, + SQL("SELECT" + " blockheight" + " FROM chain_events" + " WHERE account_id = ?" + " AND spending_txid IS NOT NULL" + " ORDER BY blockheight DESC" + " LIMIT 1")); + + db_bind_u64(stmt, 0, acct->db_id); + db_query_prepared(stmt); + ok = db_step(stmt); + assert(ok); + + acct->onchain_resolved_block = db_col_int(stmt, "blockheight"); + tal_free(stmt); + + /* Ok, now we update the account with this blockheight */ + stmt = db_prepare_v2(db, SQL("UPDATE accounts SET" + " onchain_resolved_block = ?" + " WHERE" + " id = ?")); + db_bind_int(stmt, 0, acct->onchain_resolved_block); + db_bind_u64(stmt, 1, acct->db_id); + db_exec_prepared_v2(take(stmt)); + } + + tal_free(ctx); +} + struct chain_event *find_chain_event_by_id(const tal_t *ctx, struct db *db, u64 event_db_id) diff --git a/plugins/bkpr/recorder.h b/plugins/bkpr/recorder.h index e1468c76f..0375ae6d7 100644 --- a/plugins/bkpr/recorder.h +++ b/plugins/bkpr/recorder.h @@ -117,6 +117,13 @@ char *maybe_update_onchain_fees(const tal_t *ctx, struct db *db, struct bitcoin_txid *txid); +/* Have all the outputs for this account's close tx + * been resolved onchain? If so, update the account with the + * highest blockheight that has a resolving tx in it. + * + * The point of this is to allow us to prune data, eventually */ +void maybe_mark_account_onchain(struct db *db, struct account *acct); + /* Log a channel event */ void log_channel_event(struct db *db, const struct account *acct,