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 ledger state 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 ! (
@@ -197,6 +202,7 @@ impl SnapshotConverterCommand {
197202 distribution_dir : & Path ,
198203 cardano_network : & CardanoNetwork ,
199204 utxo_hd_flavor : & UTxOHDFlavor ,
205+ commit : bool ,
200206 ) -> MithrilResult < ( ) > {
201207 println ! (
202208 "Converting ledger state snapshot to '{}' flavor" ,
@@ -223,6 +229,14 @@ impl SnapshotConverterCommand {
223229 utxo_hd_flavor,
224230 ) ?;
225231
232+ if commit {
233+ Self :: commit_converted_snapshot ( db_dir, & converted_snapshot_path) . with_context (
234+ || "Failed to overwrite the ledger state with the converted snapshot." ,
235+ ) ?;
236+ } else {
237+ println ! ( "Snapshot location: {}" , converted_snapshot_path. display( ) ) ;
238+ }
239+
226240 Ok ( ( ) )
227241 }
228242
@@ -361,18 +375,64 @@ impl SnapshotConverterCommand {
361375 . parse :: < u64 > ( )
362376 . with_context ( || format ! ( "Invalid slot number in path filename: {}" , file_name_str) )
363377 }
378+
379+ /// Commits the converted snapshot by replacing the current ledger state snapshots in the database directory.
380+ fn commit_converted_snapshot (
381+ db_dir : & Path ,
382+ converted_snapshot_path : & Path ,
383+ ) -> MithrilResult < ( ) > {
384+ let ledger_dir = db_dir. join ( LEDGER_DIR ) ;
385+ println ! (
386+ "Upgrading and replacing ledger state in {} with converted snapshot: {}" ,
387+ ledger_dir. display( ) ,
388+ converted_snapshot_path. display( )
389+ ) ;
390+
391+ let filename = converted_snapshot_path
392+ . file_name ( )
393+ . ok_or_else ( || anyhow ! ( "Missing filename in converted snapshot path" ) ) ?
394+ . to_string_lossy ( ) ;
395+
396+ let ( slot_number, _) = filename
397+ . split_once ( '_' )
398+ . ok_or_else ( || anyhow ! ( "Invalid converted snapshot name format: {}" , filename) ) ?;
399+
400+ remove_dir_all ( & ledger_dir) . with_context ( || {
401+ format ! (
402+ "Failed to remove old ledger state snapshot directory: {}" ,
403+ ledger_dir. display( )
404+ )
405+ } ) ?;
406+
407+ create_dir ( & ledger_dir) . with_context ( || {
408+ format ! (
409+ "Failed to recreate ledger state snapshot directory: {}" ,
410+ ledger_dir. display( )
411+ )
412+ } ) ?;
413+
414+ let destination = ledger_dir. join ( slot_number) ;
415+ rename ( converted_snapshot_path, & destination) . with_context ( || {
416+ format ! (
417+ "Failed to move converted snapshot to ledger directory: {}" ,
418+ destination. display( )
419+ )
420+ } ) ?;
421+
422+ Ok ( ( ) )
423+ }
364424}
365425
366426#[ cfg( test) ]
367427mod tests {
428+ use mithril_common:: temp_dir_create;
429+
368430 use super :: * ;
369431
370432 mod download_cardano_node_distribution {
371433 use mockall:: predicate:: eq;
372434 use reqwest:: Url ;
373435
374- use mithril_common:: temp_dir_create;
375-
376436 use crate :: utils:: { GitHubRelease , MockGitHubReleaseRetriever , MockHttpDownloader } ;
377437
378438 use super :: * ;
@@ -742,4 +802,46 @@ mod tests {
742802 . expect_err ( "Should return error if no valid ledger snapshot directory found" ) ;
743803 }
744804 }
805+
806+ mod commit_converted_snapshot {
807+ use std:: fs:: File ;
808+
809+ use super :: * ;
810+
811+ #[ test]
812+ fn moves_converted_snapshot_to_ledger_directory ( ) {
813+ let tmp_dir = temp_dir_create ! ( ) ;
814+ let ledger_dir = tmp_dir. join ( LEDGER_DIR ) ;
815+ create_dir ( & ledger_dir) . unwrap ( ) ;
816+ let previous_snapshot = ledger_dir. join ( "123" ) ;
817+ File :: create ( & previous_snapshot) . unwrap ( ) ;
818+
819+ let converted_snapshot = tmp_dir. join ( "456_lmdb" ) ;
820+ File :: create ( & converted_snapshot) . unwrap ( ) ;
821+
822+ assert ! ( previous_snapshot. exists( ) ) ;
823+ SnapshotConverterCommand :: commit_converted_snapshot ( & tmp_dir, & converted_snapshot)
824+ . unwrap ( ) ;
825+
826+ assert ! ( !previous_snapshot. exists( ) ) ;
827+ assert ! ( ledger_dir. join( "456" ) . exists( ) ) ;
828+ }
829+
830+ #[ test]
831+ fn fails_if_converted_snapshot_has_invalid_filename ( ) {
832+ let tmp_dir = temp_dir_create ! ( ) ;
833+ let ledger_dir = tmp_dir. join ( LEDGER_DIR ) ;
834+ create_dir ( & ledger_dir) . unwrap ( ) ;
835+ let previous_snapshot = ledger_dir. join ( "123" ) ;
836+ File :: create ( & previous_snapshot) . unwrap ( ) ;
837+
838+ let converted_snapshot = tmp_dir. join ( "456" ) ;
839+ File :: create ( & converted_snapshot) . unwrap ( ) ;
840+
841+ SnapshotConverterCommand :: commit_converted_snapshot ( & tmp_dir, & converted_snapshot)
842+ . expect_err ( "Should fail if converted snapshot has invalid filename" ) ;
843+
844+ assert ! ( previous_snapshot. exists( ) ) ;
845+ }
846+ }
745847}
0 commit comments