Skip to content

Commit 3e27367

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

File tree

1 file changed

+101
-4
lines changed
  • mithril-client-cli/src/commands/cardano_db

1 file changed

+101
-4
lines changed

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

Lines changed: 101 additions & 4 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};
7+
use anyhow::Context;
88
use chrono::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,78 @@ impl CardanoDbVerifyCommand {
176201
}
177202
Ok(())
178203
}
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(())
179276
}
180277

181278
impl ConfigSource for CardanoDbVerifyCommand {

0 commit comments

Comments
 (0)