Skip to content

List invalid or tampered immutable files in verify command #2637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0e76447
feature(client-lib, client-cli): introduce a function to download dig…
turmelclem Jul 7, 2025
ccd8595
refactor(client-lib): move merkleproof creation and verification insi…
turmelclem Jul 9, 2025
0898dc1
refactor(client-lib): remove compute_merkle_proof since logic is move…
turmelclem Jul 9, 2025
2992846
feature(client-lib): list missing immutable files when computing card…
turmelclem Jul 10, 2025
b07677c
feature(client-lib): add function in VerifiedDigests to list tampered…
turmelclem Jul 10, 2025
8fd5c7a
feature(client-lib): compute cardano database message verify tampered…
turmelclem Jul 10, 2025
3b4bb5e
feature(client-lib): display 10 elements of each missing and/or tampe…
turmelclem Jul 11, 2025
e979632
feature(client-cli): adapt call of compute_cardano_database_message t…
turmelclem Jul 11, 2025
d9a9367
feature(client-cli): display missing and/or tampered immutables when
turmelclem Jul 11, 2025
29831c0
feature(client-lib,client-cli): add arg --allow-missing in cardano-db…
turmelclem Jul 16, 2025
266b2a3
fix(examples): realign immutables range with release-preprod environment
turmelclem Jul 16, 2025
0b3de45
feature(client-lib, examples): adapt examples with the new compute_ca…
turmelclem Jul 16, 2025
da1ee2c
docs: update mithril client doc with new verify command arguments
turmelclem Jul 18, 2025
0fca1a1
feature(client-lib): return also list of non verified files in case o…
turmelclem Jul 18, 2025
857cc80
feature(client-cli): improve verify command output with non verifiabl…
turmelclem Jul 21, 2025
ee28690
refactoring(client-lib,client-cli): improve name of cardano database …
turmelclem Jul 22, 2025
2605f94
refactoring(client-lib): reorganize imports
turmelclem Jul 22, 2025
9eaf920
feature(client-lib): rename ComputeCardanoDatabaseMessageError errors…
turmelclem Jul 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/website/root/manual/develop/nodes/mithril-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,9 @@ Here is a list of the available parameters:
| `digest` | - | - | - | Digest of the Cardano db snapshot to verify or `latest` for the latest artifact | - | - | :heavy_check_mark: |
| `db_dir` | `--db-dir` | - | - | Directory from where the immutable will be verified | - | - | - |
| `genesis_verification_key` | `--genesis-verification-key` | - | `GENESIS_VERIFICATION_KEY` | Genesis verification key to check the certificate chain | - | - | - |
| `start` | `--start` | - | - | The first immutable file number to verify | - | - | - |
| `end` | `--end` | - | - | The last immutable file number to verify | - | - | - |
| `allow_missing` | `--allow-missing` | - | - | If set, the verification will not fail if some immutable files are missing | `false` | - | - |
| `run_mode` | `--run-mode` | - | `RUN_MODE` | Run Mode | `dev` | - | - |
| `verbose` | `--verbose` | `-v` | - | Verbosity level (-v=warning, -vv=info, -vvv=debug, -vvvv=trace) | `0` | - | - |
| `config_directory` | `--config-directory` | - | - | Directory where configuration file is located | `./config` | - | - |
Expand Down
39 changes: 21 additions & 18 deletions examples/client-cardano-database-v2/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::time::Duration;
use tokio::sync::RwLock;

use mithril_client::feedback::{FeedbackReceiver, MithrilEvent, MithrilEventCardanoDatabase};
use mithril_client::{ClientBuilder, MessageBuilder, MithrilResult};
use mithril_client::{ClientBuilder, MessageBuilder, MithrilError, MithrilResult};

#[derive(Parser, Debug)]
#[command(version)]
Expand Down Expand Up @@ -82,7 +82,7 @@ async fn main() -> MithrilResult<()> {
.verify_chain(&cardano_database_snapshot.certificate_hash)
.await?;

let immutable_file_range = ImmutableFileRange::From(15000);
let immutable_file_range = ImmutableFileRange::From(4000);
let download_unpack_options = DownloadUnpackOptions {
allow_override: true,
include_ancillary: true,
Expand All @@ -98,19 +98,11 @@ async fn main() -> MithrilResult<()> {
)
.await?;

println!("Computing Cardano database Merkle proof...",);
let merkle_proof = client
println!("Downloading and verifying digests file authenticity...");
let verified_digests = client
.cardano_database_v2()
.compute_merkle_proof(
&certificate,
&cardano_database_snapshot,
&immutable_file_range,
&unpacked_dir,
)
.download_and_verify_digests(&certificate, &cardano_database_snapshot)
.await?;
merkle_proof
.verify()
.with_context(|| "Merkle proof verification failed")?;

println!("Sending usage statistics to the aggregator...");
let full_restoration = immutable_file_range == ImmutableFileRange::Full;
Expand All @@ -133,9 +125,17 @@ async fn main() -> MithrilResult<()> {
"Computing Cardano database snapshot '{}' message...",
cardano_database_snapshot.hash
);
let allow_missing_immutables_files = false;
let message = wait_spinner(
&progress_bar,
MessageBuilder::new().compute_cardano_database_message(&certificate, &merkle_proof),
MessageBuilder::new().compute_cardano_database_message(
&certificate,
&cardano_database_snapshot,
&immutable_file_range,
allow_missing_immutables_files,
&unpacked_dir,
&verified_digests,
),
)
.await?;

Expand Down Expand Up @@ -261,10 +261,13 @@ fn get_temp_dir() -> MithrilResult<PathBuf> {
Ok(dir)
}

async fn wait_spinner<T>(
pub async fn wait_spinner<T, E>(
progress_bar: &MultiProgress,
future: impl Future<Output = MithrilResult<T>>,
) -> MithrilResult<T> {
future: impl Future<Output = Result<T, E>>,
) -> MithrilResult<T>
where
MithrilError: From<E>,
{
let pb = progress_bar.add(ProgressBar::new_spinner());
let spinner = async move {
loop {
Expand All @@ -275,6 +278,6 @@ async fn wait_spinner<T>(

tokio::select! {
_ = spinner => Err(anyhow!("timeout")),
res = future => res,
res = future => res.map_err(Into::into),
}
}
26 changes: 20 additions & 6 deletions mithril-client-cli/src/commands/cardano_db/download/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ use mithril_client::{
use crate::{
CommandContext,
commands::{
cardano_db::{download::DB_DIRECTORY_NAME, shared_steps},
cardano_db::{
download::DB_DIRECTORY_NAME,
shared_steps::{self, ComputeCardanoDatabaseMessageOptions},
},
client_builder,
},
utils::{
Expand Down Expand Up @@ -124,22 +127,33 @@ impl PreparedCardanoDbV2Download {
)
})?;

let merkle_proof = shared_steps::compute_verify_merkle_proof(
let verified_digests = shared_steps::download_and_verify_digests(
4,
&progress_printer,
&client,
&certificate,
&cardano_db_message,
&restoration_options.immutable_file_range,
&restoration_options.db_dir,
)
.await?;
.await
.with_context(|| {
format!(
"Can not download and verify digests file for cardano db snapshot with hash: '{}'",
self.hash
)
})?;

let options = ComputeCardanoDatabaseMessageOptions {
db_dir: restoration_options.db_dir.clone(),
immutable_file_range: restoration_options.immutable_file_range,
allow_missing: false,
};
Comment on lines +145 to +149
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this should be part of the client library directly to reduce the number of arguments of compute_cardano_database_message.

let message = shared_steps::compute_cardano_db_snapshot_message(
5,
&progress_printer,
&certificate,
&merkle_proof,
&cardano_db_message,
&options,
&verified_digests,
)
.await?;

Expand Down
49 changes: 26 additions & 23 deletions mithril-client-cli/src/commands/cardano_db/shared_steps.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
use anyhow::{Context, anyhow};
use chrono::Utc;
use slog::{Logger, debug, warn};
use std::path::Path;
use std::path::{Path, PathBuf};

use mithril_client::{
CardanoDatabaseSnapshot, Client, MessageBuilder, MithrilCertificate, MithrilResult,
cardano_database_client::ImmutableFileRange,
common::{ImmutableFileNumber, MKProof, ProtocolMessage},
cardano_database_client::{ImmutableFileRange, VerifiedDigests},
common::{ImmutableFileNumber, ProtocolMessage},
};

use crate::utils::{CardanoDbUtils, ProgressPrinter};

pub struct ComputeCardanoDatabaseMessageOptions {
pub db_dir: PathBuf,
pub immutable_file_range: ImmutableFileRange,
pub allow_missing: bool,
}

pub async fn fetch_certificate_and_verifying_chain(
step_number: u16,
progress_printer: &ProgressPrinter,
Expand Down Expand Up @@ -47,45 +53,42 @@ pub fn immutable_file_range(
}
}

/// Computes and verifies the Merkle proof for the given certificate and database snapshot.
pub async fn compute_verify_merkle_proof(
pub async fn download_and_verify_digests(
step_number: u16,
progress_printer: &ProgressPrinter,
client: &Client,
certificate: &MithrilCertificate,
cardano_database_snapshot: &CardanoDatabaseSnapshot,
immutable_file_range: &ImmutableFileRange,
unpacked_dir: &Path,
) -> MithrilResult<MKProof> {
progress_printer.report_step(step_number, "Computing and verifying the Merkle proof…")?;
let merkle_proof = client
) -> MithrilResult<VerifiedDigests> {
progress_printer.report_step(step_number, "Downloading and verifying digests…")?;
let verified_digests = client
.cardano_database_v2()
.compute_merkle_proof(
certificate,
cardano_database_snapshot,
immutable_file_range,
Path::new(&unpacked_dir),
)
.download_and_verify_digests(certificate, cardano_database_snapshot)
.await?;

merkle_proof
.verify()
.with_context(|| "Merkle proof verification failed")?;

Ok(merkle_proof)
Ok(verified_digests)
}

/// Computes the Cardano database snapshot message using the provided certificate and Merkle proof.
pub async fn compute_cardano_db_snapshot_message(
step_number: u16,
progress_printer: &ProgressPrinter,
certificate: &MithrilCertificate,
merkle_proof: &MKProof,
cardano_database_snapshot: &CardanoDatabaseSnapshot,
options: &ComputeCardanoDatabaseMessageOptions,
verified_digest: &VerifiedDigests,
) -> MithrilResult<ProtocolMessage> {
progress_printer.report_step(step_number, "Computing the cardano db snapshot message")?;
let message = CardanoDbUtils::wait_spinner(
progress_printer,
MessageBuilder::new().compute_cardano_database_message(certificate, merkle_proof),
MessageBuilder::new().compute_cardano_database_message(
certificate,
cardano_database_snapshot,
&options.immutable_file_range,
options.allow_missing,
&options.db_dir,
verified_digest,
),
)
.await
.with_context(|| "Can not compute the cardano db snapshot message")?;
Expand Down
Loading
Loading