77#include <ccan/tal/path/path.h>
88#include <ccan/tal/str/str.h>
99#include <common/configdir.h>
10+ #include <common/node_id.h>
1011#include <common/utils.h>
1112#include <db/bindings.h>
1213#include <db/common.h>
1314#include <db/exec.h>
1415#include <db/utils.h>
16+ #include <plugins/askrene/datastore_wire.h>
1517#include <stdio.h>
1618#include <unistd.h>
19+ #include <wallet/datastore.h>
1720#include <wallet/migrations.h>
21+ #include <wire/wire.h>
1822
1923#define ERROR_DBVERSION 1
2024#define ERROR_DBFAIL 2
2630struct db_version {
2731 const char * name ;
2832 size_t db_height ;
33+ const char * (* downgrade_datastore )(const tal_t * ctx , struct db * db );
2934 bool gossip_store_compatible ;
3035};
3136
37+ struct layer {
38+ const char * * key ;
39+ const u8 * data ;
40+ };
41+
42+ static void copy_data (u8 * * out , const u8 * in , size_t len )
43+ {
44+ size_t oldlen = tal_bytelen (* out );
45+
46+ tal_resize (out , oldlen + len );
47+ memcpy (* out + oldlen , in , len );
48+ }
49+
50+ /* askrene added DSTORE_CHANNEL_BIAS_V2 (convertable) and
51+ * DSTORE_NODE_BIAS (not convertable) */
52+ static const char * convert_layer_data (const tal_t * ctx ,
53+ const char * layername ,
54+ const u8 * data_in ,
55+ const u8 * * data_out )
56+ {
57+ size_t len = tal_bytelen (data_in );
58+ struct node_id n ;
59+ struct short_channel_id scid ;
60+ struct amount_msat msat , * msat_ptr ;
61+ struct short_channel_id_dir scidd ;
62+ bool * bool_ptr ;
63+ u64 timestamp ;
64+ u32 * u32_ptr ;
65+ u16 * u16_ptr ;
66+ s8 bias ;
67+ const char * string ;
68+ u8 * out = tal_arr (ctx , u8 , 0 );
69+
70+ /* Unfortunately, there are no explicit lengths, so we have
71+ * to read all records even if we don't care about them. */
72+ while (len != 0 ) {
73+ enum dstore_layer_type type ;
74+ const u8 * olddata = data_in ;
75+ type = fromwire_peektypen (data_in , len );
76+
77+ switch (type ) {
78+ /* These are all simply digested and copied */
79+ case DSTORE_CHANNEL :
80+ if (fromwire_dstore_channel (& data_in , & len ,
81+ & n , & n , & scid , & msat ))
82+ copy_data (& out , data_in , olddata - data_in );
83+ continue ;
84+ case DSTORE_CHANNEL_UPDATE :
85+ if (fromwire_dstore_channel_update (tmpctx , & data_in , & len ,
86+ & scidd , & bool_ptr ,
87+ & msat_ptr , & msat_ptr , & msat_ptr ,
88+ & u32_ptr , & u16_ptr ))
89+ copy_data (& out , data_in , olddata - data_in );
90+ continue ;
91+ case DSTORE_CHANNEL_CONSTRAINT :
92+ if (fromwire_dstore_channel_constraint (tmpctx , & data_in , & len ,
93+ & scidd , & timestamp ,
94+ & msat_ptr , & msat_ptr ))
95+ copy_data (& out , data_in , olddata - data_in );
96+ continue ;
97+ case DSTORE_CHANNEL_BIAS :
98+ if (fromwire_dstore_channel_bias (tmpctx , & data_in , & len ,
99+ & scidd , & bias ,
100+ & string ))
101+ copy_data (& out , data_in , olddata - data_in );
102+ continue ;
103+ case DSTORE_DISABLED_NODE :
104+ if (fromwire_dstore_disabled_node (& data_in , & len , & n ))
105+ copy_data (& out , data_in , olddata - data_in );
106+ continue ;
107+
108+ /* Convert back, lose timestamp */
109+ case DSTORE_CHANNEL_BIAS_V2 :
110+ if (fromwire_dstore_channel_bias_v2 (tmpctx , & data_in , & len ,
111+ & scidd , & bias ,
112+ & string , & timestamp )) {
113+ towire_dstore_channel_bias (& out , & scidd , bias , string );
114+ }
115+ continue ;
116+
117+ case DSTORE_NODE_BIAS :
118+ return "Askrene has a node bias, which is not supported in v25.09" ;
119+ }
120+
121+ return tal_fmt (ctx , "Unknown askrene layer record %u in %s" , type , layername );
122+ }
123+
124+ if (!data_in )
125+ return tal_fmt (ctx , "Corrupt askrene layer record for %s" , layername );
126+
127+ * data_out = out ;
128+ return NULL ;
129+ }
130+
131+ static const char * downgrade_askrene_layers (const tal_t * ctx , struct db * db )
132+ {
133+ const char * * base , * * k ;
134+ const u8 * data ;
135+ struct db_stmt * stmt ;
136+ struct layer * * layers = tal_arr (tmpctx , struct layer * , 0 );
137+
138+ base = tal_arr (tmpctx , const char * , 2 );
139+ base [0 ] = "askrene" ;
140+ base [1 ] = "layers" ;
141+
142+ /* Gather and convert */
143+ for (stmt = db_datastore_first (tmpctx , db , base ,
144+ & k , & data , NULL );
145+ stmt ;
146+ stmt = db_datastore_next (tmpctx , stmt , base ,
147+ & k , & data , NULL )) {
148+ struct layer * layer ;
149+ const char * err ;
150+
151+ if (!data )
152+ continue ;
153+ layer = tal (layers , struct layer );
154+ layer -> key = tal_steal (layer , k );
155+ err = convert_layer_data (layer , k [2 ], data , & layer -> data );
156+ if (err ) {
157+ tal_free (stmt );
158+ return err ;
159+ }
160+ tal_arr_expand (& layers , layer );
161+ }
162+
163+ /* Write back */
164+ for (size_t i = 0 ; i < tal_count (layers ); i ++ )
165+ db_datastore_update (db , layers [i ]-> key , layers [i ]-> data );
166+ return NULL ;
167+ }
168+
32169static const struct db_version db_versions [] = {
33- { "v25.09" , 276 , false },
170+ { "v25.09" , 276 , downgrade_askrene_layers , false },
34171 /* When we implement v25.12 downgrade: { "v25.12", 280, ???}, */
35172};
36173
@@ -66,7 +203,8 @@ static void opt_log_stderr_exit_usage(const char *fmt, ...)
66203int main (int argc , char * argv [])
67204{
68205 char * config_filename , * base_dir , * net_dir , * rpc_filename , * wallet_dsn = NULL ;
69- size_t current , prev_version_height , num_migrations ;
206+ const struct db_version * prev_version ;
207+ size_t current , num_migrations ;
70208 struct db * db ;
71209 const struct db_migration * migrations ;
72210 struct db_stmt * stmt ;
@@ -99,7 +237,7 @@ int main(int argc, char *argv[])
99237 }
100238
101239 migrations = get_db_migrations (& num_migrations );
102- prev_version_height = version_db (PREV_VERSION )-> db_height ;
240+ prev_version = version_db (PREV_VERSION );
103241
104242 /* Open db, check it's the expected version */
105243 db = db_open (tmpctx , wallet_dsn , false, false, db_error , NULL );
@@ -111,10 +249,10 @@ int main(int argc, char *argv[])
111249 db -> data_version = db_data_version_get (db );
112250 current = db_get_version (db );
113251
114- if (current < prev_version_height )
252+ if (current < prev_version -> db_height )
115253 errx (ERROR_DBVERSION , "Database version %zu already less than %zu expected for %s" ,
116- current , prev_version_height , PREV_VERSION );
117- if (current == prev_version_height ) {
254+ current , prev_version -> db_height , PREV_VERSION );
255+ if (current == prev_version -> db_height ) {
118256 printf ("Already compatible with %s\n" , PREV_VERSION );
119257 exit (0 );
120258 }
@@ -123,7 +261,7 @@ int main(int argc, char *argv[])
123261 current , num_migrations , stringify (CLN_NEXT_VERSION ));
124262
125263 /* current version is the last migration we did. */
126- while (current > prev_version_height ) {
264+ while (current > prev_version -> db_height ) {
127265 if (migrations [current ].revertsql ) {
128266 stmt = db_prepare_v2 (db , migrations [current ].revertsql );
129267 db_exec_prepared_v2 (stmt );
@@ -137,6 +275,12 @@ int main(int argc, char *argv[])
137275 current -- ;
138276 }
139277
278+ if (prev_version -> downgrade_datastore ) {
279+ const char * error = prev_version -> downgrade_datastore (tmpctx , db );
280+ if (error )
281+ errx (ERROR_DBFAIL , "Downgrade failed: %s" , error );
282+ }
283+
140284 /* Finally update the version number in the version table */
141285 stmt = db_prepare_v2 (db , SQL ("UPDATE version SET version=?;" ));
142286 db_bind_int (stmt , current );
0 commit comments