@@ -7723,3 +7723,84 @@ void migrate_setup_coinmoves(struct lightningd *ld, struct db *db)
77237723 tal_free (stmt );
77247724}
77257725
7726+ /* When we imported from accounts.db, we always used a reference into
7727+ * the move_accounts table (via account_nonchannel_id). But (on
7728+ * replay) if a channel was live, we used the reference into the
7729+ * channels table (via account_channel_id) and our duplicate detection
7730+ * didn't trigger. Now we need to get rid of such duplicates.
7731+ *
7732+ * Note that if the channel is now CLOSED, the references to account_channel_id
7733+ * will have been converted to references using account_nonchannel_id. */
7734+ void migrate_remove_chain_moves_duplicates (struct lightningd * ld , struct db * db )
7735+ {
7736+ /* This is O(n^2) but there just aren't that many! */
7737+ u64 * to_delete = tal_arr (tmpctx , u64 , 0 );
7738+ struct db_stmt * stmt ;
7739+
7740+ /* Gather */
7741+ stmt = db_prepare_v2 (db , SQL ("SELECT"
7742+ " chain_moves.id,"
7743+ " utxo,"
7744+ " spending_txid,"
7745+ " tag_bitmap,"
7746+ " account_channel_id,"
7747+ " channels.full_channel_id,"
7748+ " move_accounts.name"
7749+ " FROM chain_moves "
7750+ " LEFT JOIN move_accounts "
7751+ " ON move_accounts.id = chain_moves.account_nonchannel_id "
7752+ " LEFT JOIN channels "
7753+ " ON channels.id = chain_moves.account_channel_id "
7754+ " ORDER BY move_accounts.id;" ));
7755+ db_query_prepared (stmt );
7756+ while (db_step (stmt )) {
7757+ struct bitcoin_outpoint outpoint ;
7758+ u64 id , channel_dbid ;
7759+ struct bitcoin_txid * spending_txid ;
7760+ struct mvt_tags tags ;
7761+ const char * nonchannel_acctname ;
7762+
7763+ id = db_col_u64 (stmt , "chain_moves.id" );
7764+ db_col_outpoint (stmt , "utxo" , & outpoint );
7765+ if (db_col_is_null (stmt , "spending_txid" ))
7766+ spending_txid = NULL ;
7767+ else {
7768+ spending_txid = tal (tmpctx , struct bitcoin_txid );
7769+ db_col_txid (stmt , "spending_txid" , spending_txid );
7770+ }
7771+ tags = db_col_mvt_tags (stmt , "tag_bitmap" );
7772+ if (db_col_is_null (stmt , "account_channel_id" )) {
7773+ channel_dbid = 0 ;
7774+ nonchannel_acctname = db_col_strdup (tmpctx , stmt , "move_accounts.name" );
7775+ db_col_ignore (stmt , "channels.full_channel_id" );
7776+ } else {
7777+ struct channel_id cid ;
7778+ channel_dbid = db_col_u64 (stmt , "account_channel_id" );
7779+ db_col_channel_id (stmt , "channels.full_channel_id" , & cid );
7780+ nonchannel_acctname = fmt_channel_id (tmpctx , & cid );
7781+ }
7782+
7783+ if (find_duplicate_chain_move (db , nonchannel_acctname ,
7784+ channel_dbid ,
7785+ & outpoint ,
7786+ spending_txid ,
7787+ tags ,
7788+ id )) {
7789+ log_unusual (ld -> log ,
7790+ "Deleting redundant chain_moves %" PRIu64 " for account %s" ,
7791+ id , nonchannel_acctname );
7792+ tal_arr_expand (& to_delete , id );
7793+ }
7794+ }
7795+ tal_free (stmt );
7796+
7797+ /* Do the delete. We do it separately to avoid any db issues
7798+ * while iterating */
7799+ for (size_t i = 0 ; i < tal_count (to_delete ); i ++ ) {
7800+ stmt = db_prepare_v2 (db ,
7801+ SQL ("DELETE FROM chain_moves "
7802+ "WHERE id = ?;" ));
7803+ db_bind_u64 (stmt , to_delete [i ]);
7804+ db_exec_prepared_v2 (take (stmt ));
7805+ }
7806+ }
0 commit comments