11use std:: {
22 env, fmt,
3- fs:: { create_dir, read_dir} ,
3+ fs:: { create_dir, read_dir, remove_dir_all , rename } ,
44 path:: { Path , PathBuf } ,
55 process:: Command ,
66} ;
@@ -87,6 +87,10 @@ pub struct SnapshotConverterCommand {
8787 /// UTxO-HD flavor to convert the ledger snapshot to.
8888 #[ clap( long) ]
8989 utxo_hd_flavor : UTxOHDFlavor ,
90+
91+ /// If set, the converted snapshot replaces the current one in the db directory.
92+ #[ clap( long) ]
93+ commit : bool ,
9094}
9195
9296impl SnapshotConverterCommand {
@@ -133,6 +137,7 @@ impl SnapshotConverterCommand {
133137 & distribution_dir,
134138 & self . cardano_network ,
135139 & self . utxo_hd_flavor ,
140+ self . commit ,
136141 )
137142 . with_context ( || {
138143 format ! (
@@ -188,6 +193,7 @@ impl SnapshotConverterCommand {
188193 distribution_dir : & Path ,
189194 cardano_network : & CardanoNetwork ,
190195 utxo_hd_flavor : & UTxOHDFlavor ,
196+ commit : bool ,
191197 ) -> MithrilResult < ( ) > {
192198 let snapshots_path = work_dir. join ( SNAPSHOTS_DIR ) ;
193199 let copied_snapshot_path =
@@ -210,6 +216,17 @@ impl SnapshotConverterCommand {
210216 utxo_hd_flavor,
211217 ) ?;
212218
219+ if commit {
220+ Self :: commit_converted_snapshot ( db_dir, & converted_snapshot_path) . with_context (
221+ || "Failed to overwrite the ledger state with the converted snapshot." ,
222+ ) ?;
223+ } else {
224+ println ! (
225+ "Converted snapshot available at: {} (use --commit to replace original)" ,
226+ converted_snapshot_path. display( )
227+ ) ;
228+ }
229+
213230 Ok ( ( ) )
214231 }
215232
@@ -359,18 +376,64 @@ impl SnapshotConverterCommand {
359376 . parse :: < u64 > ( )
360377 . with_context ( || format ! ( "Invalid slot number in path filename: {}" , file_name_str) )
361378 }
379+
380+ /// Commits the converted snapshot by replacing the current ledger state snapshots in the database directory.
381+ fn commit_converted_snapshot (
382+ db_dir : & Path ,
383+ converted_snapshot_path : & Path ,
384+ ) -> MithrilResult < ( ) > {
385+ let ledger_dir = db_dir. join ( LEDGER_DIR ) ;
386+ println ! (
387+ "Replacing ledger state snapshots located in '{}' with converted snapshot at: '{}'" ,
388+ ledger_dir. display( ) ,
389+ converted_snapshot_path. display( )
390+ ) ;
391+
392+ let filename = converted_snapshot_path
393+ . file_name ( )
394+ . ok_or_else ( || anyhow ! ( "Missing filename in converted snapshot path" ) ) ?
395+ . to_string_lossy ( ) ;
396+
397+ let ( slot_number, _) = filename
398+ . split_once ( '_' )
399+ . ok_or_else ( || anyhow ! ( "Invalid converted snapshot name format: {}" , filename) ) ?;
400+
401+ remove_dir_all ( & ledger_dir) . with_context ( || {
402+ format ! (
403+ "Failed to remove old ledger state snapshot directory: {}" ,
404+ ledger_dir. display( )
405+ )
406+ } ) ?;
407+
408+ create_dir ( & ledger_dir) . with_context ( || {
409+ format ! (
410+ "Failed to recreate ledger state snapshot directory: {}" ,
411+ ledger_dir. display( )
412+ )
413+ } ) ?;
414+
415+ let destination = ledger_dir. join ( slot_number) ;
416+ rename ( converted_snapshot_path, & destination) . with_context ( || {
417+ format ! (
418+ "Failed to move converted snapshot to ledger directory: {}" ,
419+ destination. display( )
420+ )
421+ } ) ?;
422+
423+ Ok ( ( ) )
424+ }
362425}
363426
364427#[ cfg( test) ]
365428mod tests {
429+ use mithril_common:: temp_dir_create;
430+
366431 use super :: * ;
367432
368433 mod download_cardano_node_distribution {
369434 use mockall:: predicate:: eq;
370435 use reqwest:: Url ;
371436
372- use mithril_common:: temp_dir_create;
373-
374437 use crate :: utils:: { GitHubRelease , MockGitHubReleaseRetriever , MockHttpDownloader } ;
375438
376439 use super :: * ;
@@ -740,4 +803,46 @@ mod tests {
740803 . expect_err ( "Should return error if no valid ledger snapshot directory found" ) ;
741804 }
742805 }
806+
807+ mod commit_converted_snapshot {
808+ use std:: fs:: File ;
809+
810+ use super :: * ;
811+
812+ #[ test]
813+ fn moves_converted_snapshot_to_ledger_directory ( ) {
814+ let tmp_dir = temp_dir_create ! ( ) ;
815+ let ledger_dir = tmp_dir. join ( LEDGER_DIR ) ;
816+ create_dir ( & ledger_dir) . unwrap ( ) ;
817+ let previous_snapshot = ledger_dir. join ( "123" ) ;
818+ File :: create ( & previous_snapshot) . unwrap ( ) ;
819+
820+ let converted_snapshot = tmp_dir. join ( "456_lmdb" ) ;
821+ File :: create ( & converted_snapshot) . unwrap ( ) ;
822+
823+ assert ! ( previous_snapshot. exists( ) ) ;
824+ SnapshotConverterCommand :: commit_converted_snapshot ( & tmp_dir, & converted_snapshot)
825+ . unwrap ( ) ;
826+
827+ assert ! ( !previous_snapshot. exists( ) ) ;
828+ assert ! ( ledger_dir. join( "456" ) . exists( ) ) ;
829+ }
830+
831+ #[ test]
832+ fn fails_if_converted_snapshot_has_invalid_filename ( ) {
833+ let tmp_dir = temp_dir_create ! ( ) ;
834+ let ledger_dir = tmp_dir. join ( LEDGER_DIR ) ;
835+ create_dir ( & ledger_dir) . unwrap ( ) ;
836+ let previous_snapshot = ledger_dir. join ( "123" ) ;
837+ File :: create ( & previous_snapshot) . unwrap ( ) ;
838+
839+ let converted_snapshot = tmp_dir. join ( "456" ) ;
840+ File :: create ( & converted_snapshot) . unwrap ( ) ;
841+
842+ SnapshotConverterCommand :: commit_converted_snapshot ( & tmp_dir, & converted_snapshot)
843+ . expect_err ( "Should fail if converted snapshot has invalid filename" ) ;
844+
845+ assert ! ( previous_snapshot. exists( ) ) ;
846+ }
847+ }
743848}
0 commit comments