@@ -4,10 +4,13 @@ use std::{
44 sync:: Arc ,
55} ;
66
7- use anyhow:: { Context , anyhow } ;
8- use chrono:: Utc ;
7+ use anyhow:: Context ;
8+ use chrono:: { DateTime , Utc } ;
99use clap:: Parser ;
10- use mithril_client:: { ComputeCardanoDatabaseMessageError , MithrilResult } ;
10+ use mithril_client:: {
11+ CardanoDatabaseSnapshot , ComputeCardanoDatabaseMessageError , ImmutableFilesLists ,
12+ MithrilResult , cardano_database_client:: ImmutableFileRange , common:: ImmutableFileNumber ,
13+ } ;
1114
1215use crate :: {
1316 CommandContext ,
@@ -38,6 +41,18 @@ pub struct CardanoDbVerifyCommand {
3841 /// Genesis verification key to check the certificate chain.
3942 #[ clap( long, env = "GENESIS_VERIFICATION_KEY" ) ]
4043 genesis_verification_key : Option < String > ,
44+
45+ /// The first immutable file number to verify.
46+ ///
47+ /// If not set, the verify process will start from the first immutable file.
48+ #[ clap( long) ]
49+ start : Option < ImmutableFileNumber > ,
50+
51+ /// The last immutable file number to verify.
52+ ///
53+ /// If not set, the verify will continue until the last certified immutable file.
54+ #[ clap( long) ]
55+ end : Option < ImmutableFileNumber > ,
4156}
4257
4358impl CardanoDbVerifyCommand {
@@ -94,6 +109,14 @@ impl CardanoDbVerifyCommand {
94109 . await ?
95110 . with_context ( || format ! ( "Can not get the cardano db for hash: '{}'" , self . digest) ) ?;
96111
112+ let immutable_file_range = shared_steps:: immutable_file_range ( self . start , self . end ) ;
113+
114+ print_immutables_range_to_verify (
115+ & cardano_db_message,
116+ & immutable_file_range,
117+ context. is_json_output_enabled ( ) ,
118+ ) ?;
119+
97120 let certificate = shared_steps:: fetch_certificate_and_verifying_chain (
98121 1 ,
99122 & progress_printer,
@@ -102,8 +125,6 @@ impl CardanoDbVerifyCommand {
102125 )
103126 . await ?;
104127
105- let immutable_file_range = shared_steps:: immutable_file_range ( None , None ) ;
106-
107128 let verified_digests = shared_steps:: download_and_verify_digests (
108129 2 ,
109130 & progress_printer,
@@ -127,7 +148,10 @@ impl CardanoDbVerifyCommand {
127148 match message {
128149 Err ( e) => match e. downcast_ref :: < ComputeCardanoDatabaseMessageError > ( ) {
129150 Some ( ComputeCardanoDatabaseMessageError :: ImmutableFilesVerification ( lists) ) => {
130- // let missing_files = lists.missing;
151+ Self :: print_immutables_verification_error (
152+ lists,
153+ context. is_json_output_enabled ( ) ,
154+ ) ;
131155 Ok ( ( ) )
132156 }
133157 _ => Err ( e) ,
@@ -176,6 +200,86 @@ impl CardanoDbVerifyCommand {
176200 }
177201 Ok ( ( ) )
178202 }
203+
204+ fn print_immutables_verification_error ( lists : & ImmutableFilesLists , json_output : bool ) {
205+ let utc_now = Utc :: now ( ) ;
206+ let json_file_path = write_json_file_error ( utc_now, lists) ;
207+ let error_message = "Verifying immutables files has failed" ;
208+ if json_output {
209+ let json = serde_json:: json!( {
210+ "timestamp" : utc_now. to_rfc3339( ) ,
211+ "verify_error" : {
212+ "message" : error_message,
213+ "immutables_verification_error_file" : json_file_path,
214+ "immutables_dir" : lists. immutables_dir,
215+ "missing_files_count" : lists. missing. len( ) ,
216+ "tampered_files_count" : lists. tampered. len( )
217+ }
218+ } ) ;
219+
220+ println ! ( "{json}" ) ;
221+ } else {
222+ println ! ( "{error_message}" ) ;
223+ println ! (
224+ "See the lists of all missing and tampered files in {}" ,
225+ json_file_path. display( )
226+ ) ;
227+ if !lists. missing . is_empty ( ) {
228+ println ! ( "Number of missing immutable files: {}" , lists. missing. len( ) ) ;
229+ }
230+ if !lists. tampered . is_empty ( ) {
231+ println ! (
232+ "Number of tampered immutable files: {:?}" ,
233+ lists. tampered. len( )
234+ ) ;
235+ }
236+ }
237+ }
238+ }
239+
240+ fn write_json_file_error ( date : DateTime < Utc > , lists : & ImmutableFilesLists ) -> PathBuf {
241+ let file_path = PathBuf :: from ( format ! (
242+ "immutables_verification_error-{}.json" ,
243+ date. timestamp( )
244+ ) ) ;
245+ std:: fs:: write (
246+ & file_path,
247+ serde_json:: to_string_pretty ( & serde_json:: json!( {
248+ "timestamp" : date. to_rfc3339( ) ,
249+ "immutables_dir" : lists. immutables_dir,
250+ "missing-files" : lists. missing,
251+ "tampered-files" : lists. tampered,
252+ } ) )
253+ . unwrap ( ) ,
254+ )
255+ . expect ( "Could not write immutables verification error to file" ) ;
256+ file_path
257+ }
258+
259+ fn print_immutables_range_to_verify (
260+ cardano_db_message : & CardanoDatabaseSnapshot ,
261+ immutable_file_range : & ImmutableFileRange ,
262+ json_output : bool ,
263+ ) -> Result < ( ) , anyhow:: Error > {
264+ let range_to_verify =
265+ immutable_file_range. to_range_inclusive ( cardano_db_message. beacon . immutable_file_number ) ?;
266+ if json_output {
267+ let json = serde_json:: json!( {
268+ "timestamp" : Utc :: now( ) . to_rfc3339( ) ,
269+ "local_immutable_range_to_verify" : {
270+ "start" : range_to_verify. start( ) ,
271+ "end" : range_to_verify. end( ) ,
272+ } ,
273+ } ) ;
274+ println ! ( "{json}" ) ;
275+ } else {
276+ eprintln ! (
277+ "Verifying local immutable files from number {} to {}" ,
278+ range_to_verify. start( ) ,
279+ range_to_verify. end( )
280+ ) ;
281+ }
282+ Ok ( ( ) )
179283}
180284
181285impl ConfigSource for CardanoDbVerifyCommand {
0 commit comments