Skip to content

Commit 6416372

Browse files
committed
feature(client-cli): display missing and/or tampered immutables when
verify command fail
1 parent 7191912 commit 6416372

File tree

1 file changed

+110
-5
lines changed
  • mithril-client-cli/src/commands/cardano_db

1 file changed

+110
-5
lines changed

mithril-client-cli/src/commands/cardano_db/verify.rs

Lines changed: 110 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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};
99
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+
};
1114

1215
use 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

4358
impl 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,
@@ -128,6 +149,10 @@ impl CardanoDbVerifyCommand {
128149
Err(e) => match e.downcast_ref::<ComputeCardanoDatabaseMessageError>() {
129150
Some(ComputeCardanoDatabaseMessageError::ImmutableFilesVerification(lists)) => {
130151
// let missing_files = lists.missing;
152+
Self::print_immutables_verification_error(
153+
lists,
154+
context.is_json_output_enabled(),
155+
);
131156
Ok(())
132157
}
133158
_ => Err(e),
@@ -176,6 +201,86 @@ impl CardanoDbVerifyCommand {
176201
}
177202
Ok(())
178203
}
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(())
179284
}
180285

181286
impl ConfigSource for CardanoDbVerifyCommand {

0 commit comments

Comments
 (0)