2020struct migration {
2121 const char * sql ;
2222 void (* func )(struct lightningd * ld , struct db * db );
23+ const char * revertsql ;
24+ /* If non-NULL, returns string explaining why downgrade is impossible */
25+ const char * (* revertfn )(const tal_t * ctx , struct db * db );
2326};
2427
2528static void migrate_pr2342_feerate_per_channel (struct lightningd * ld , struct db * db );
@@ -87,6 +90,9 @@ static void migrate_initialize_channel_htlcs_wait_indexes_and_fixup_forwards(str
8790static void migrate_fail_pending_payments_without_htlcs (struct lightningd * ld ,
8891 struct db * db );
8992
93+ static const char * revert_too_early (const tal_t * ctx , struct db * db );
94+ static const char * revert_withheld_column (const tal_t * ctx , struct db * db );
95+
9096/* Do not reorder or remove elements from this array, it is used to
9197 * migrate existing databases from a previous state, based on the
9298 * string indices */
@@ -1087,9 +1093,13 @@ static struct migration dbmigrations[] = {
10871093 ")" ), NULL },
10881094 /* We do a lookup before each append, to avoid duplicates */
10891095 {SQL ("CREATE INDEX chain_moves_utxo_idx ON chain_moves (utxo)" ), NULL },
1090- {NULL , migrate_from_account_db },
1096+ {NULL , migrate_from_account_db , NULL , revert_too_early },
1097+ /* ^v25.09 */
1098+
10911099 /* We accidentally allowed duplicate entries */
1092- {NULL , migrate_remove_chain_moves_duplicates },
1100+ {NULL , migrate_remove_chain_moves_duplicates ,
1101+ /* Removing duplicates is idempotent, so no revert needed */
1102+ NULL , NULL },
10931103 {SQL ("CREATE TABLE network_events ("
10941104 " id BIGSERIAL,"
10951105 " peer_id BLOB NOT NULL,"
@@ -1099,9 +1109,16 @@ static struct migration dbmigrations[] = {
10991109 " duration_nsec BIGINT,"
11001110 " connect_attempted INTEGER NOT NULL,"
11011111 " PRIMARY KEY (id)"
1102- ")" ), NULL },
1103- {NULL , migrate_fail_pending_payments_without_htlcs },
1104- {SQL ("ALTER TABLE channels ADD withheld INTEGER DEFAULT 0;" ), NULL },
1112+ ")" ), NULL ,
1113+ /* Simply drop table. */
1114+ "DROP TABLE network_events" },
1115+ {NULL , migrate_fail_pending_payments_without_htlcs ,
1116+ /* Failing pending payments is idempotent, so no revert needed */
1117+ NULL , NULL },
1118+ {SQL ("ALTER TABLE channels ADD withheld INTEGER DEFAULT 0;" ), NULL ,
1119+ /* Need to make sure that withheld isn't used. */
1120+ NULL , revert_withheld_column },
1121+ /* ^v25.12 */
11051122};
11061123
11071124/**
@@ -2153,3 +2170,44 @@ static void migrate_fail_pending_payments_without_htlcs(struct lightningd *ld,
21532170 db_bind_int (stmt , payment_status_in_db (PAYMENT_PENDING ));
21542171 db_exec_prepared_v2 (take (stmt ));
21552172}
2173+
2174+ static const char * revert_too_early (const tal_t * ctx , struct db * db )
2175+ {
2176+ return tal_strdup (ctx , "Downgrade to before v25.09 not supported" );
2177+ }
2178+
2179+ /* Don't allow downgrade if they've *used* the withheld column. */
2180+ static const char * revert_withheld_column (const tal_t * ctx , struct db * db )
2181+ {
2182+ struct db_stmt * stmt ;
2183+ struct channel_id * cid ;
2184+ struct short_channel_id * scid ;
2185+
2186+ stmt = db_prepare_v2 (db , SQL ("SELECT full_channel_id, scid FROM channels WHERE withheld != 0" ));
2187+ db_query_prepared (stmt );
2188+ if (db_step (stmt )) {
2189+ cid = tal (tmpctx , struct channel_id );
2190+ db_col_channel_id (stmt , "full_channel_id" , cid );
2191+ if (db_col_is_null (stmt , "scid" ))
2192+ scid = NULL ;
2193+ else {
2194+ scid = tal (tmpctx , struct short_channel_id );
2195+ * scid = db_col_short_channel_id (stmt , "scid" );
2196+ }
2197+ } else {
2198+ cid = NULL ;
2199+ scid = NULL ;
2200+ }
2201+ tal_free (stmt );
2202+
2203+ if (cid ) {
2204+ return tal_fmt (tmpctx , "Channel %s (%s) used v25.12's withheld flag" ,
2205+ fmt_channel_id (tmpctx , cid ),
2206+ scid ? fmt_short_channel_id (tmpctx , * scid ) : "no short channel id" );
2207+ }
2208+
2209+ /* For sqlite3 needs "2021-03-12 (3.35.0)" or above */
2210+ stmt = db_prepare_v2 (db , SQL ("ALTER TABLE channels DROP COLUMN withheld" ));
2211+ db_exec_prepared_v2 (take (stmt ));
2212+ return NULL ;
2213+ }
0 commit comments