Skip to content

Commit 4c29eca

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

File tree

1 file changed

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

1 file changed

+110
-6
lines changed

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

Lines changed: 110 additions & 6 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,
@@ -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

181285
impl ConfigSource for CardanoDbVerifyCommand {

0 commit comments

Comments
 (0)