2
2
// - Add logs.
3
3
// - Remove the temporary directory in all cases (error or success).
4
4
use std:: path:: Path ;
5
+ use std:: process:: Command ;
5
6
use std:: { env, fmt, path:: PathBuf } ;
6
7
7
8
use anyhow:: { anyhow, Context } ;
@@ -22,6 +23,14 @@ const PRERELEASE_DISTRIBUTION_TAG: &str = "prerelease";
22
23
23
24
const CARDANO_DISTRIBUTION_TEMP_DIR : & str = "cardano-node-distribution-tmp" ;
24
25
26
+ const SNAPSHOT_CONVERTER_BIN_DIR : & str = "bin" ;
27
+ const SNAPSHOT_CONVERTER_BIN_NAME_UNIX : & str = "snapshot-converter" ;
28
+ const SNAPSHOT_CONVERTER_BIN_NAME_WINDOWS : & str = "snapshot-converter.exe" ;
29
+ const SNAPSHOT_CONVERTER_CONFIG_DIR : & str = "share" ;
30
+ const SNAPSHOT_CONVERTER_CONFIG_FILE : & str = "config.json" ;
31
+
32
+ const LEDGER_DIR : & str = "ledger" ;
33
+
25
34
#[ derive( Debug , Clone , ValueEnum ) ]
26
35
enum UTxOHDFlavor {
27
36
#[ clap( name = "Legacy" ) ]
@@ -39,6 +48,23 @@ impl fmt::Display for UTxOHDFlavor {
39
48
}
40
49
}
41
50
51
+ #[ derive( Debug , Clone , ValueEnum ) ]
52
+ enum CardanoNetwork {
53
+ Preview ,
54
+ Preprod ,
55
+ Mainnet ,
56
+ }
57
+
58
+ impl fmt:: Display for CardanoNetwork {
59
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
60
+ match self {
61
+ Self :: Preview => write ! ( f, "preview" ) ,
62
+ Self :: Preprod => write ! ( f, "preprod" ) ,
63
+ Self :: Mainnet => write ! ( f, "mainnet" ) ,
64
+ }
65
+ }
66
+ }
67
+
42
68
/// Clap command to convert a restored `InMemory` Mithril snapshot to another flavor.
43
69
#[ derive( Parser , Debug , Clone ) ]
44
70
pub struct SnapshotConverterCommand {
@@ -52,6 +78,10 @@ pub struct SnapshotConverterCommand {
52
78
#[ clap( long) ]
53
79
cardano_node_version : String ,
54
80
81
+ /// Cardano network.
82
+ #[ clap( long) ]
83
+ cardano_network : CardanoNetwork ,
84
+
55
85
/// UTxO-HD flavor to convert the ledger snapshot to.
56
86
#[ clap( long) ]
57
87
utxo_hd_flavor : UTxOHDFlavor ,
@@ -88,6 +118,19 @@ impl SnapshotConverterCommand {
88
118
)
89
119
} ) ?;
90
120
121
+ Self :: convert_ledger_snapshot (
122
+ & self . db_directory ,
123
+ & self . cardano_network ,
124
+ & distribution_temp_dir,
125
+ & self . utxo_hd_flavor ,
126
+ )
127
+ . with_context ( || {
128
+ format ! (
129
+ "Failed to convert ledger snapshot to flavor: {}" ,
130
+ self . utxo_hd_flavor
131
+ )
132
+ } ) ?;
133
+
91
134
Ok ( ( ) )
92
135
}
93
136
@@ -128,6 +171,120 @@ impl SnapshotConverterCommand {
128
171
129
172
Ok ( archive_path)
130
173
}
174
+
175
+ // 1. Find the `snapshot-converter` binary
176
+ // 2. Find the configuration file
177
+ // 3. Find the less recent ledger snapshot in the db directory
178
+ // 4. Copy the ledger snapshot to the distribution directory (backup)
179
+ // 5. Run the `snapshot-converter` command with the appropriate arguments
180
+ // - Legacy: snapshot-converter Mem <PATH-IN> Legacy <PATH-OUT> cardano --config <CONFIG>
181
+ // - LMDB: snapshot-converter Mem <PATH-IN> LMDB <PATH-OUT> cardano --config <CONFIG>
182
+ fn convert_ledger_snapshot (
183
+ db_dir : & Path ,
184
+ cardano_network : & CardanoNetwork ,
185
+ distribution_dir : & Path ,
186
+ utxo_hd_flavor : & UTxOHDFlavor ,
187
+ ) -> MithrilResult < ( ) > {
188
+ let snapshot_converter_bin_path =
189
+ Self :: get_snapshot_converter_binary_path ( distribution_dir, env:: consts:: OS ) ?;
190
+ // TODO: check if this configuration file is enough to convert the snapshot.
191
+ let config_path =
192
+ Self :: get_snapshot_converter_config_path ( distribution_dir, cardano_network) ;
193
+
194
+ let ( slot_number, ledger_snapshot_path) = Self :: find_less_recent_ledger_snapshot ( db_dir) ?;
195
+ let snapshot_backup_path = distribution_dir. join ( ledger_snapshot_path. file_name ( ) . unwrap ( ) ) ;
196
+ std:: fs:: copy ( ledger_snapshot_path. clone ( ) , snapshot_backup_path. clone ( ) ) ?;
197
+
198
+ let snapshot_converted_output_path = distribution_dir
199
+ . join ( slot_number. to_string ( ) )
200
+ . join ( utxo_hd_flavor. to_string ( ) . to_lowercase ( ) ) ;
201
+
202
+ // TODO: verify if the paths are correct, the command needs relative path.
203
+ Command :: new ( snapshot_converter_bin_path. clone ( ) )
204
+ . arg ( "Mem" )
205
+ . arg ( snapshot_backup_path)
206
+ . arg ( utxo_hd_flavor. to_string ( ) )
207
+ . arg ( snapshot_converted_output_path)
208
+ . arg ( "cardano" )
209
+ . arg ( "--config" )
210
+ . arg ( config_path)
211
+ . status ( )
212
+ . with_context ( || {
213
+ format ! (
214
+ "Failed to get help of snapshot-converter: {}" ,
215
+ snapshot_converter_bin_path. display( )
216
+ )
217
+ } ) ?;
218
+
219
+ println ! (
220
+ "Snapshot converter executed successfully. The ledger snapshot has been converted to {} flavor in {}." ,
221
+ utxo_hd_flavor,
222
+ distribution_dir. display( )
223
+ ) ;
224
+ Ok ( ( ) )
225
+ }
226
+
227
+ fn get_snapshot_converter_binary_path (
228
+ distribution_dir : & Path ,
229
+ target_os : & str ,
230
+ ) -> MithrilResult < PathBuf > {
231
+ let base_path = distribution_dir. join ( SNAPSHOT_CONVERTER_BIN_DIR ) ;
232
+
233
+ let binary_name = match target_os {
234
+ "linux" | "macos" => SNAPSHOT_CONVERTER_BIN_NAME_UNIX ,
235
+ "windows" => SNAPSHOT_CONVERTER_BIN_NAME_WINDOWS ,
236
+ _ => return Err ( anyhow ! ( "Unsupported platform: {}" , target_os) ) ,
237
+ } ;
238
+
239
+ Ok ( base_path. join ( binary_name) )
240
+ }
241
+
242
+ fn get_snapshot_converter_config_path (
243
+ distribution_dir : & Path ,
244
+ network : & CardanoNetwork ,
245
+ ) -> PathBuf {
246
+ distribution_dir
247
+ . join ( SNAPSHOT_CONVERTER_CONFIG_DIR )
248
+ . join ( network. to_string ( ) )
249
+ . join ( SNAPSHOT_CONVERTER_CONFIG_FILE )
250
+ }
251
+
252
+ // TODO: quick dirty code to go further in `convert_ledger_snapshot` function, must be enhanced and tested.
253
+ fn find_less_recent_ledger_snapshot ( db_dir : & Path ) -> MithrilResult < ( u64 , PathBuf ) > {
254
+ let ledger_dir = db_dir. join ( LEDGER_DIR ) ;
255
+
256
+ let entries = std:: fs:: read_dir ( & ledger_dir) . with_context ( || {
257
+ format ! ( "Failed to read ledger directory: {}" , ledger_dir. display( ) )
258
+ } ) ?;
259
+
260
+ let mut min_slot: Option < ( u64 , PathBuf ) > = None ;
261
+
262
+ for entry in entries {
263
+ let entry = entry?;
264
+ let file_name = entry. file_name ( ) ;
265
+ let file_name_str = file_name. to_str ( ) . unwrap ( ) ;
266
+
267
+ let slot = match file_name_str. parse :: < u64 > ( ) {
268
+ Ok ( n) => n,
269
+ Err ( _) => continue ,
270
+ } ;
271
+
272
+ let path = entry. path ( ) ;
273
+ if path. is_dir ( ) {
274
+ match & min_slot {
275
+ Some ( ( current_min, _) ) if * current_min <= slot => { }
276
+ _ => min_slot = Some ( ( slot, path) ) ,
277
+ }
278
+ }
279
+ }
280
+
281
+ min_slot. ok_or_else ( || {
282
+ anyhow ! (
283
+ "No valid ledger snapshot found in: {}" ,
284
+ ledger_dir. display( )
285
+ )
286
+ } )
287
+ }
131
288
}
132
289
133
290
#[ cfg( test) ]
@@ -244,4 +401,115 @@ mod tests {
244
401
. await
245
402
. unwrap ( ) ;
246
403
}
404
+
405
+ #[ test]
406
+ fn get_snapshot_converter_binary_path_linux ( ) {
407
+ let distribution_dir = PathBuf :: from ( "/path/to/distribution" ) ;
408
+
409
+ let binary_path = SnapshotConverterCommand :: get_snapshot_converter_binary_path (
410
+ & distribution_dir,
411
+ "linux" ,
412
+ )
413
+ . unwrap ( ) ;
414
+
415
+ assert_eq ! (
416
+ binary_path,
417
+ distribution_dir
418
+ . join( SNAPSHOT_CONVERTER_BIN_DIR )
419
+ . join( SNAPSHOT_CONVERTER_BIN_NAME_UNIX )
420
+ ) ;
421
+ }
422
+
423
+ #[ test]
424
+ fn get_snapshot_converter_binary_path_macos ( ) {
425
+ let distribution_dir = PathBuf :: from ( "/path/to/distribution" ) ;
426
+
427
+ let binary_path = SnapshotConverterCommand :: get_snapshot_converter_binary_path (
428
+ & distribution_dir,
429
+ "macos" ,
430
+ )
431
+ . unwrap ( ) ;
432
+
433
+ assert_eq ! (
434
+ binary_path,
435
+ distribution_dir
436
+ . join( SNAPSHOT_CONVERTER_BIN_DIR )
437
+ . join( SNAPSHOT_CONVERTER_BIN_NAME_UNIX )
438
+ ) ;
439
+ }
440
+
441
+ #[ test]
442
+ fn get_snapshot_converter_binary_path_windows ( ) {
443
+ let distribution_dir = PathBuf :: from ( "/path/to/distribution" ) ;
444
+
445
+ let binary_path = SnapshotConverterCommand :: get_snapshot_converter_binary_path (
446
+ & distribution_dir,
447
+ "windows" ,
448
+ )
449
+ . unwrap ( ) ;
450
+
451
+ assert_eq ! (
452
+ binary_path,
453
+ distribution_dir
454
+ . join( SNAPSHOT_CONVERTER_BIN_DIR )
455
+ . join( SNAPSHOT_CONVERTER_BIN_NAME_WINDOWS )
456
+ ) ;
457
+ }
458
+
459
+ #[ test]
460
+ fn get_snapshot_converter_config_path_mainnet ( ) {
461
+ let distribution_dir = PathBuf :: from ( "/path/to/distribution" ) ;
462
+ let network = CardanoNetwork :: Mainnet ;
463
+
464
+ let config_path = SnapshotConverterCommand :: get_snapshot_converter_config_path (
465
+ & distribution_dir,
466
+ & network,
467
+ ) ;
468
+
469
+ assert_eq ! (
470
+ config_path,
471
+ distribution_dir
472
+ . join( SNAPSHOT_CONVERTER_CONFIG_DIR )
473
+ . join( network. to_string( ) )
474
+ . join( SNAPSHOT_CONVERTER_CONFIG_FILE )
475
+ ) ;
476
+ }
477
+
478
+ #[ test]
479
+ fn get_snapshot_converter_config_path_preprod ( ) {
480
+ let distribution_dir = PathBuf :: from ( "/path/to/distribution" ) ;
481
+ let network = CardanoNetwork :: Preprod ;
482
+
483
+ let config_path = SnapshotConverterCommand :: get_snapshot_converter_config_path (
484
+ & distribution_dir,
485
+ & network,
486
+ ) ;
487
+
488
+ assert_eq ! (
489
+ config_path,
490
+ distribution_dir
491
+ . join( SNAPSHOT_CONVERTER_CONFIG_DIR )
492
+ . join( network. to_string( ) )
493
+ . join( SNAPSHOT_CONVERTER_CONFIG_FILE )
494
+ ) ;
495
+ }
496
+
497
+ #[ test]
498
+ fn get_snapshot_converter_config_path_preview ( ) {
499
+ let distribution_dir = PathBuf :: from ( "/path/to/distribution" ) ;
500
+ let network = CardanoNetwork :: Preview ;
501
+
502
+ let config_path = SnapshotConverterCommand :: get_snapshot_converter_config_path (
503
+ & distribution_dir,
504
+ & network,
505
+ ) ;
506
+
507
+ assert_eq ! (
508
+ config_path,
509
+ distribution_dir
510
+ . join( SNAPSHOT_CONVERTER_CONFIG_DIR )
511
+ . join( network. to_string( ) )
512
+ . join( SNAPSHOT_CONVERTER_CONFIG_FILE )
513
+ ) ;
514
+ }
247
515
}
0 commit comments