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