@@ -4,10 +4,13 @@ use std::{
4
4
sync:: Arc ,
5
5
} ;
6
6
7
- use anyhow:: { Context , anyhow } ;
8
- use chrono:: Utc ;
7
+ use anyhow:: Context ;
8
+ use chrono:: { DateTime , Utc } ;
9
9
use 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
+ } ;
11
14
12
15
use crate :: {
13
16
CommandContext ,
@@ -38,6 +41,18 @@ pub struct CardanoDbVerifyCommand {
38
41
/// Genesis verification key to check the certificate chain.
39
42
#[ clap( long, env = "GENESIS_VERIFICATION_KEY" ) ]
40
43
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 > ,
41
56
}
42
57
43
58
impl CardanoDbVerifyCommand {
@@ -94,6 +109,14 @@ impl CardanoDbVerifyCommand {
94
109
. await ?
95
110
. with_context ( || format ! ( "Can not get the cardano db for hash: '{}'" , self . digest) ) ?;
96
111
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
+
97
120
let certificate = shared_steps:: fetch_certificate_and_verifying_chain (
98
121
1 ,
99
122
& progress_printer,
@@ -102,8 +125,6 @@ impl CardanoDbVerifyCommand {
102
125
)
103
126
. await ?;
104
127
105
- let immutable_file_range = shared_steps:: immutable_file_range ( None , None ) ;
106
-
107
128
let verified_digests = shared_steps:: download_and_verify_digests (
108
129
2 ,
109
130
& progress_printer,
@@ -128,6 +149,10 @@ impl CardanoDbVerifyCommand {
128
149
Err ( e) => match e. downcast_ref :: < ComputeCardanoDatabaseMessageError > ( ) {
129
150
Some ( ComputeCardanoDatabaseMessageError :: ImmutableFilesVerification ( lists) ) => {
130
151
// let missing_files = lists.missing;
152
+ Self :: print_immutables_verification_error (
153
+ lists,
154
+ context. is_json_output_enabled ( ) ,
155
+ ) ;
131
156
Ok ( ( ) )
132
157
}
133
158
_ => Err ( e) ,
@@ -176,6 +201,86 @@ impl CardanoDbVerifyCommand {
176
201
}
177
202
Ok ( ( ) )
178
203
}
204
+
205
+ fn print_immutables_verification_error ( lists : & ImmutableFilesLists , json_output : bool ) {
206
+ let utc_now = Utc :: now ( ) ;
207
+ let json_file_path = write_json_file_error ( utc_now, lists) ;
208
+ let error_message = "Verifying immutables files has failed" ;
209
+ if json_output {
210
+ let json = serde_json:: json!( {
211
+ "timestamp" : utc_now. to_rfc3339( ) ,
212
+ "verify_error" : {
213
+ "message" : error_message,
214
+ "immutables_verification_error_file" : json_file_path,
215
+ "immutables_dir" : lists. immutables_dir,
216
+ "missing_files_count" : lists. missing. len( ) ,
217
+ "tampered_files_count" : lists. tampered. len( )
218
+ }
219
+ } ) ;
220
+
221
+ println ! ( "{json}" ) ;
222
+ } else {
223
+ println ! ( "{error_message}" ) ;
224
+ println ! (
225
+ "See the lists of all missing and tampered files in {}" ,
226
+ json_file_path. display( )
227
+ ) ;
228
+ if !lists. missing . is_empty ( ) {
229
+ println ! ( "Number of missing immutable files: {}" , lists. missing. len( ) ) ;
230
+ }
231
+ if !lists. tampered . is_empty ( ) {
232
+ println ! (
233
+ "Number of tampered immutable files: {:?}" ,
234
+ lists. tampered. len( )
235
+ ) ;
236
+ }
237
+ }
238
+ }
239
+ }
240
+
241
+ fn write_json_file_error ( date : DateTime < Utc > , lists : & ImmutableFilesLists ) -> PathBuf {
242
+ let file_path = PathBuf :: from ( format ! (
243
+ "immutables_verification_error-{}.json" ,
244
+ date. timestamp( )
245
+ ) ) ;
246
+ std:: fs:: write (
247
+ & file_path,
248
+ serde_json:: to_string_pretty ( & serde_json:: json!( {
249
+ "timestamp" : date. to_rfc3339( ) ,
250
+ "immutables_dir" : lists. immutables_dir,
251
+ "missing-files" : lists. missing,
252
+ "tampered-files" : lists. tampered,
253
+ } ) )
254
+ . unwrap ( ) ,
255
+ )
256
+ . expect ( "Could not write immutables verification error to file" ) ;
257
+ file_path
258
+ }
259
+
260
+ fn print_immutables_range_to_verify (
261
+ cardano_db_message : & CardanoDatabaseSnapshot ,
262
+ immutable_file_range : & ImmutableFileRange ,
263
+ json_output : bool ,
264
+ ) -> Result < ( ) , anyhow:: Error > {
265
+ let range_to_verify =
266
+ immutable_file_range. to_range_inclusive ( cardano_db_message. beacon . immutable_file_number ) ?;
267
+ if json_output {
268
+ let json = serde_json:: json!( {
269
+ "timestamp" : Utc :: now( ) . to_rfc3339( ) ,
270
+ "local_immutable_range_to_verify" : {
271
+ "start" : range_to_verify. start( ) ,
272
+ "end" : range_to_verify. end( ) ,
273
+ } ,
274
+ } ) ;
275
+ println ! ( "{json}" ) ;
276
+ } else {
277
+ eprintln ! (
278
+ "Verifying local immutable files from number {} to {}" ,
279
+ range_to_verify. start( ) ,
280
+ range_to_verify. end( )
281
+ ) ;
282
+ }
283
+ Ok ( ( ) )
179
284
}
180
285
181
286
impl ConfigSource for CardanoDbVerifyCommand {
0 commit comments