@@ -4,10 +4,13 @@ use std::{
4
4
sync:: Arc ,
5
5
} ;
6
6
7
- use anyhow:: { Context , anyhow } ;
7
+ use anyhow:: Context ;
8
8
use chrono:: 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,78 @@ impl CardanoDbVerifyCommand {
176
201
}
177
202
Ok ( ( ) )
178
203
}
204
+
205
+ fn print_immutables_verification_error ( lists : & ImmutableFilesLists , json_output : bool ) {
206
+ fn get_first_10_files_path ( files : & [ String ] , immutables_dir : & Path ) -> String {
207
+ files
208
+ . iter ( )
209
+ . take ( 10 )
210
+ . map ( |file| immutables_dir. join ( file) . to_string_lossy ( ) . to_string ( ) )
211
+ . collect :: < Vec < _ > > ( )
212
+ . join ( "\n - " )
213
+ }
214
+ let missing_files_subset = get_first_10_files_path ( & lists. missing , & lists. immutables_dir ) ;
215
+ let tampered_files_subset = get_first_10_files_path ( & lists. tampered , & lists. immutables_dir ) ;
216
+
217
+ if json_output {
218
+ let json = serde_json:: json!( {
219
+ "timestamp" : Utc :: now( ) . to_rfc3339( ) ,
220
+ "verify_error" : {
221
+ "message" : "Verifying immutables files has failed" ,
222
+ "immutables_dir" : lists. immutables_dir,
223
+ "missing_files_count" : lists. missing. len( ) ,
224
+ "tampered_files_count" : lists. tampered. len( ) ,
225
+ "missing_files" : lists. missing,
226
+ "tampered_files" : lists. tampered,
227
+ }
228
+ } ) ;
229
+ println ! ( "{json}" ) ;
230
+ } else {
231
+ if !lists. missing . is_empty ( ) {
232
+ println ! ( "Verifying immutables files has failed:" ) ;
233
+ println ! ( "Number of missing immutable files: {}" , lists. missing. len( ) ) ;
234
+ println ! ( "First 10 missing immutable files paths:" ) ;
235
+ println ! ( "{missing_files_subset}" ) ;
236
+ }
237
+ if !lists. missing . is_empty ( ) && !lists. tampered . is_empty ( ) {
238
+ println ! ( ) ;
239
+ }
240
+ if !lists. tampered . is_empty ( ) {
241
+ println ! (
242
+ "Number of tampered immutable files: {:?}" ,
243
+ lists. tampered. len( )
244
+ ) ;
245
+ println ! ( "First 10 tampered immutable files paths:" ) ;
246
+ println ! ( "{tampered_files_subset}" ) ;
247
+ }
248
+ }
249
+ }
250
+ }
251
+
252
+ fn print_immutables_range_to_verify (
253
+ cardano_db_message : & CardanoDatabaseSnapshot ,
254
+ immutable_file_range : & ImmutableFileRange ,
255
+ json_output : bool ,
256
+ ) -> Result < ( ) , anyhow:: Error > {
257
+ let range_to_verify =
258
+ immutable_file_range. to_range_inclusive ( cardano_db_message. beacon . immutable_file_number ) ?;
259
+ if json_output {
260
+ let json = serde_json:: json!( {
261
+ "timestamp" : Utc :: now( ) . to_rfc3339( ) ,
262
+ "local_immutable_range_to_verify" : {
263
+ "start" : range_to_verify. start( ) ,
264
+ "end" : range_to_verify. end( ) ,
265
+ } ,
266
+ } ) ;
267
+ println ! ( "{json}" ) ;
268
+ } else {
269
+ eprintln ! (
270
+ "Verifying local immutable files from number {} to {}" ,
271
+ range_to_verify. start( ) ,
272
+ range_to_verify. end( )
273
+ ) ;
274
+ }
275
+ Ok ( ( ) )
179
276
}
180
277
181
278
impl ConfigSource for CardanoDbVerifyCommand {
0 commit comments