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