From 86992c149d390342bd8611424dc50c823feb20cf Mon Sep 17 00:00:00 2001 From: Damien Lachaume <135982616+dlachaume@users.noreply.github.com> Date: Wed, 29 Jan 2025 17:13:36 +0100 Subject: [PATCH 1/9] feat: create unstable `cardano-db-v2` command - add 'cdbv2' alias for 'cardano-db-v2' - implement 'cardano-db-v2 list' command --- .../src/commands/cardano_db_v2/list.rs | 66 +++++++++++++++++++ .../src/commands/cardano_db_v2/mod.rs | 42 ++++++++++++ mithril-client-cli/src/commands/mod.rs | 1 + mithril-client-cli/src/main.rs | 57 +++++++++++----- 4 files changed, 149 insertions(+), 17 deletions(-) create mode 100644 mithril-client-cli/src/commands/cardano_db_v2/list.rs create mode 100644 mithril-client-cli/src/commands/cardano_db_v2/mod.rs diff --git a/mithril-client-cli/src/commands/cardano_db_v2/list.rs b/mithril-client-cli/src/commands/cardano_db_v2/list.rs new file mode 100644 index 00000000000..0588f13e944 --- /dev/null +++ b/mithril-client-cli/src/commands/cardano_db_v2/list.rs @@ -0,0 +1,66 @@ +use clap::Parser; +use cli_table::{format::Justify, print_stdout, Cell, Table}; + +use mithril_client::MithrilResult; + +use crate::{ + commands::{client_builder_with_fallback_genesis_key, SharedArgs}, + CommandContext, +}; + +/// Clap command to list existing cardano db snapshots +#[derive(Parser, Debug, Clone)] +pub struct CardanoDbListCommand { + #[clap(flatten)] + shared_args: SharedArgs, +} + +impl CardanoDbListCommand { + /// Is JSON output enabled + pub fn is_json_output_enabled(&self) -> bool { + self.shared_args.json + } + + /// Main command execution + pub async fn execute(&self, context: CommandContext) -> MithrilResult<()> { + let params = context.config_parameters()?; + let client = client_builder_with_fallback_genesis_key(¶ms)? + .with_logger(context.logger().clone()) + .build()?; + let items = client.cardano_database().list().await?; + + if self.is_json_output_enabled() { + println!("{}", serde_json::to_string(&items)?); + } else { + let items = items + .into_iter() + .map(|item| { + vec![ + format!("{}", item.beacon.epoch).cell(), + format!("{}", item.beacon.immutable_file_number).cell(), + item.hash.cell(), + item.merkle_root.cell(), + item.total_db_size_uncompressed.cell(), + format!("{}", item.compression_algorithm).cell(), + item.cardano_node_version.cell(), + item.created_at.to_string().cell(), + ] + }) + .collect::>() + .table() + .title(vec![ + "Epoch".cell(), + "Immutable".cell(), + "Hash".cell(), + "Merkle root".cell(), + "Database size".cell().justify(Justify::Right), + "Compression".cell(), + "Cardano node".cell(), + "Created".cell().justify(Justify::Right), + ]); + print_stdout(items)?; + } + + Ok(()) + } +} diff --git a/mithril-client-cli/src/commands/cardano_db_v2/mod.rs b/mithril-client-cli/src/commands/cardano_db_v2/mod.rs new file mode 100644 index 00000000000..023891eec0f --- /dev/null +++ b/mithril-client-cli/src/commands/cardano_db_v2/mod.rs @@ -0,0 +1,42 @@ +//! Commands for the cardano db v2 artifact +mod list; + +pub use list::*; + +use crate::CommandContext; +use clap::Subcommand; +use mithril_client::MithrilResult; + +/// Cardano db v2 management (alias: cdbv2) +#[derive(Subcommand, Debug, Clone)] +pub enum CardanoDbV2Commands { + /// Cardano db snapshot v2 commands + #[clap(subcommand)] + Snapshot(CardanoDbV2SnapshotCommands), +} + +/// Cardano db v2 snapshots +#[derive(Subcommand, Debug, Clone)] +pub enum CardanoDbV2SnapshotCommands { + /// List available cardano db v2 snapshots + #[clap(arg_required_else_help = false)] + List(CardanoDbListCommand), +} + +impl CardanoDbV2Commands { + /// Execute Cardano db v2 command + pub async fn execute(&self, config_builder: CommandContext) -> MithrilResult<()> { + match self { + Self::Snapshot(cmd) => cmd.execute(config_builder).await, + } + } +} + +impl CardanoDbV2SnapshotCommands { + /// Execute Cardano db v2 snapshot command + pub async fn execute(&self, config_builder: CommandContext) -> MithrilResult<()> { + match self { + Self::List(cmd) => cmd.execute(config_builder).await, + } + } +} diff --git a/mithril-client-cli/src/commands/mod.rs b/mithril-client-cli/src/commands/mod.rs index 45905aafe3b..d692a24fadc 100644 --- a/mithril-client-cli/src/commands/mod.rs +++ b/mithril-client-cli/src/commands/mod.rs @@ -4,6 +4,7 @@ //! pub mod cardano_db; +pub mod cardano_db_v2; pub mod cardano_stake_distribution; pub mod cardano_transaction; mod deprecation; diff --git a/mithril-client-cli/src/main.rs b/mithril-client-cli/src/main.rs index 95eb9250d28..4522a813385 100644 --- a/mithril-client-cli/src/main.rs +++ b/mithril-client-cli/src/main.rs @@ -13,21 +13,13 @@ use mithril_client::MithrilResult; use mithril_doc::{Documenter, GenerateDocCommands, StructDoc}; use mithril_client_cli::commands::{ - cardano_db::CardanoDbCommands, cardano_stake_distribution::CardanoStakeDistributionCommands, + cardano_db::CardanoDbCommands, cardano_db_v2::CardanoDbV2Commands, + cardano_stake_distribution::CardanoStakeDistributionCommands, cardano_transaction::CardanoTransactionCommands, mithril_stake_distribution::MithrilStakeDistributionCommands, DeprecatedCommand, Deprecation, }; use mithril_client_cli::{ClapError, CommandContext}; -macro_rules! allow_unstable_dead_code { - ($($item:item)*) => { - $( - #[allow(dead_code)] - $item - )* - } -} - enum LogOutputType { StdErr, File(String), @@ -205,6 +197,9 @@ enum ArtifactCommands { #[clap(subcommand, alias("csd"))] CardanoStakeDistribution(CardanoStakeDistributionCommands), + #[clap(subcommand, alias("cdbv2"))] + CardanoDbV2(CardanoDbV2Commands), + #[clap(alias("doc"), hide(true))] GenerateDoc(GenerateDocCommands), } @@ -216,20 +211,28 @@ impl ArtifactCommands { Self::MithrilStakeDistribution(cmd) => cmd.execute(context).await, Self::CardanoTransaction(cmd) => cmd.execute(context).await, Self::CardanoStakeDistribution(cmd) => cmd.execute(context).await, + Self::CardanoDbV2(cmd) => { + if !context.is_unstable_enabled() { + Err(anyhow!(Self::unstable_flag_missing_message( + "cardano-db-v2", + "list" + ))) + } else { + cmd.execute(context).await + } + } Self::GenerateDoc(cmd) => cmd .execute(&mut Args::command()) .map_err(|message| anyhow!(message)), } } - allow_unstable_dead_code! { - fn unstable_flag_missing_message(sub_command: &str, command_example: &str) -> String { - format!( - "The \"{}\" subcommand is only accepted using the --unstable flag.\n\n\ + fn unstable_flag_missing_message(sub_command: &str, command_example: &str) -> String { + format!( + "The \"{}\" subcommand is only accepted using the --unstable flag.\n\n\ ie: \"mithril-client --unstable {} {}\"", - sub_command, sub_command, command_example - ) - } + sub_command, sub_command, command_example + ) } } @@ -246,3 +249,23 @@ async fn main() -> MithrilResult<()> { args.execute(logger).await } + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn fail_if_cardano_database_v2_command_is_used_without_unstable_flag() { + let args = + Args::try_parse_from(["mithril-client", "cardano-db-v2", "snapshot", "list"]).unwrap(); + + let error = args + .execute(Logger::root(slog::Discard, slog::o!())) + .await + .expect_err("Should fail if unstable flag missing"); + + assert!(error + .to_string() + .contains("subcommand is only accepted using the --unstable flag.")); + } +} From c10ca30eff6788abd3d412cf68f281c759252602 Mon Sep 17 00:00:00 2001 From: Damien Lachaume <135982616+dlachaume@users.noreply.github.com> Date: Thu, 30 Jan 2025 17:09:01 +0100 Subject: [PATCH 2/9] feat: implement `show` subcommand for unstable `cardano-db-v2 snapshot` command --- .../src/commands/cardano_db_v2/mod.rs | 7 + .../src/commands/cardano_db_v2/show.rs | 298 ++++++++++++++++++ mithril-client/src/type_alias.rs | 7 +- .../src/entities/cardano_database.rs | 8 +- mithril-common/src/entities/mod.rs | 3 +- 5 files changed, 317 insertions(+), 6 deletions(-) create mode 100644 mithril-client-cli/src/commands/cardano_db_v2/show.rs diff --git a/mithril-client-cli/src/commands/cardano_db_v2/mod.rs b/mithril-client-cli/src/commands/cardano_db_v2/mod.rs index 023891eec0f..d45807a58a0 100644 --- a/mithril-client-cli/src/commands/cardano_db_v2/mod.rs +++ b/mithril-client-cli/src/commands/cardano_db_v2/mod.rs @@ -1,7 +1,9 @@ //! Commands for the cardano db v2 artifact mod list; +mod show; pub use list::*; +pub use show::*; use crate::CommandContext; use clap::Subcommand; @@ -21,6 +23,10 @@ pub enum CardanoDbV2SnapshotCommands { /// List available cardano db v2 snapshots #[clap(arg_required_else_help = false)] List(CardanoDbListCommand), + + /// Show detailed information about a cardano db v2 snapshot + #[clap(arg_required_else_help = true)] + Show(CardanoDbShowCommand), } impl CardanoDbV2Commands { @@ -37,6 +43,7 @@ impl CardanoDbV2SnapshotCommands { pub async fn execute(&self, config_builder: CommandContext) -> MithrilResult<()> { match self { Self::List(cmd) => cmd.execute(config_builder).await, + Self::Show(cmd) => cmd.execute(config_builder).await, } } } diff --git a/mithril-client-cli/src/commands/cardano_db_v2/show.rs b/mithril-client-cli/src/commands/cardano_db_v2/show.rs new file mode 100644 index 00000000000..342657be466 --- /dev/null +++ b/mithril-client-cli/src/commands/cardano_db_v2/show.rs @@ -0,0 +1,298 @@ +use anyhow::{anyhow, Context}; +use clap::Parser; +use cli_table::{print_stdout, Cell, CellStruct, Table}; + +use crate::{ + commands::{client_builder_with_fallback_genesis_key, SharedArgs}, + utils::ExpanderUtils, + CommandContext, +}; + +use mithril_client::{ + common::{ + AncillaryLocation, AncillaryLocationDiscriminants, DigestLocation, + DigestLocationDiscriminants, ImmutablesLocation, ImmutablesLocationDiscriminants, + MultiFilesUri, + }, + MithrilResult, +}; + +/// Clap command to show a given cardano db +#[derive(Parser, Debug, Clone)] +pub struct CardanoDbShowCommand { + #[clap(flatten)] + shared_args: SharedArgs, + + /// Cardano DB snapshot hash. + /// + /// If `latest` is specified as hash, the command will return the latest cardano db snapshot. + hash: String, +} + +impl CardanoDbShowCommand { + /// Is JSON output enabled + pub fn is_json_output_enabled(&self) -> bool { + self.shared_args.json + } + + /// Cardano DB snapshot Show command + pub async fn execute(&self, context: CommandContext) -> MithrilResult<()> { + let params = context.config_parameters()?; + let client = client_builder_with_fallback_genesis_key(¶ms)? + .with_logger(context.logger().clone()) + .build()?; + + let get_list_of_artifact_ids = || async { + let cardano_dbs = client.cardano_database().list().await.with_context(|| { + "Can not get the list of artifacts while retrieving the latest cardano db snapshot hash" + })?; + + Ok(cardano_dbs + .iter() + .map(|cardano_db| cardano_db.hash.to_owned()) + .collect::>()) + }; + + let cardano_db_message = client + .cardano_database() + .get( + &ExpanderUtils::expand_eventual_id_alias(&self.hash, get_list_of_artifact_ids()) + .await?, + ) + .await? + .ok_or_else(|| anyhow!("Cardano DB snapshot not found for hash: '{}'", &self.hash))?; + + if self.is_json_output_enabled() { + println!("{}", serde_json::to_string(&cardano_db_message)?); + } else { + let mut cardano_db_table = vec![ + vec![ + "Epoch".cell(), + format!("{}", &cardano_db_message.beacon.epoch).cell(), + ], + vec![ + "Immutable File Number".cell(), + format!("{}", &cardano_db_message.beacon.immutable_file_number).cell(), + ], + vec!["Hash".cell(), cardano_db_message.hash.cell()], + vec!["Merkle root".cell(), cardano_db_message.merkle_root.cell()], + vec![ + "Database size".cell(), + format!("{}", &cardano_db_message.total_db_size_uncompressed).cell(), + ], + vec![ + "Cardano node version".cell(), + cardano_db_message.cardano_node_version.cell(), + ], + ]; + + let mut digest_location_index = 1; + for digest_location_type in [ + DigestLocationDiscriminants::Aggregator, + DigestLocationDiscriminants::CloudStorage, + ] { + if let Some(digest_location) = digest_location_row( + digest_location_index, + digest_location_type, + &cardano_db_message.locations.digests, + ) { + cardano_db_table.push(digest_location); + digest_location_index += 1; + } + } + + if let Some(immutables_location) = immutables_location_row( + ImmutablesLocationDiscriminants::CloudStorage, + &cardano_db_message.locations.immutables, + ) { + cardano_db_table.push(immutables_location); + } + + if let Some(ancillary_location) = ancillary_location_row( + AncillaryLocationDiscriminants::CloudStorage, + &cardano_db_message.locations.ancillary, + ) { + cardano_db_table.push(ancillary_location); + } + + cardano_db_table.push(vec![ + "Created".cell(), + cardano_db_message.created_at.to_string().cell(), + ]); + cardano_db_table.push(vec![ + "Compression Algorithm".cell(), + format!("{}", &cardano_db_message.compression_algorithm).cell(), + ]); + + print_stdout(cardano_db_table.table())?; + } + + Ok(()) + } +} + +fn digest_location_row( + index: usize, + location_type: DigestLocationDiscriminants, + locations: &[DigestLocation], +) -> Option> { + let uris = locations + .iter() + .filter_map(|location| match (location, location_type) { + (DigestLocation::Aggregator { uri }, DigestLocationDiscriminants::Aggregator) => { + Some(format!("uri: \"{}\"", uri)) + } + (DigestLocation::CloudStorage { uri }, DigestLocationDiscriminants::CloudStorage) => { + Some(format!("uri: \"{}\"", uri)) + } + _ => None, + }) + .collect::>() + .join(","); + + if uris.is_empty() { + None + } else { + Some(vec![ + format!("Digest location ({index})").cell(), + format!("{location_type:?}, {uris}").cell(), + ]) + } +} + +fn immutables_location_row( + location_type: ImmutablesLocationDiscriminants, + locations: &[ImmutablesLocation], +) -> Option> { + let uris = locations + .iter() + .map(|location| match (location, location_type) { + ( + ImmutablesLocation::CloudStorage { uri }, + ImmutablesLocationDiscriminants::CloudStorage, + ) => match uri { + MultiFilesUri::Template(template_uri) => { + format!("template_uri: \"{}\"", template_uri.0) + } + }, + }) + .collect::>() + .join(","); + + if uris.is_empty() { + None + } else { + Some(vec![ + "Immutables location".to_string().cell(), + format!( + "{:?}, {}", + ImmutablesLocationDiscriminants::CloudStorage, + uris + ) + .cell(), + ]) + } +} + +fn ancillary_location_row( + location_type: AncillaryLocationDiscriminants, + locations: &[AncillaryLocation], +) -> Option> { + let uris = locations + .iter() + .map(|location| match (location, location_type) { + ( + AncillaryLocation::CloudStorage { uri }, + AncillaryLocationDiscriminants::CloudStorage, + ) => format!("uri: \"{}\"", uri), + }) + .collect::>() + .join(","); + + if uris.is_empty() { + None + } else { + Some(vec![ + "Ancillary location".to_string().cell(), + format!( + "{:?}, {}", + AncillaryLocationDiscriminants::CloudStorage, + uris + ) + .cell(), + ]) + } +} + +#[cfg(test)] +mod tests { + use mithril_client::common::TemplateUri; + + use super::*; + + #[test] + fn digest_location_row_returns_none_when_no_uri_found_for_location_type() { + let locations = vec![DigestLocation::Aggregator { + uri: "http://aggregator.net/".to_string(), + }]; + + let row = digest_location_row(123, DigestLocationDiscriminants::CloudStorage, &locations); + + assert!(row.is_none()); + } + + #[test] + fn digest_location_row_returns_some_when_uri_found_for_location_type() { + let locations = vec![ + DigestLocation::Aggregator { + uri: "http://aggregator.net/".to_string(), + }, + DigestLocation::CloudStorage { + uri: "http://cloudstorage.com/".to_string(), + }, + ]; + + let row = digest_location_row(123, DigestLocationDiscriminants::CloudStorage, &locations); + assert!(row.is_some()); + + let row = digest_location_row(456, DigestLocationDiscriminants::Aggregator, &locations); + assert!(row.is_some()); + } + + #[test] + fn immutables_location_row_returns_none_when_no_uri_found_for_location_type() { + let row = immutables_location_row(ImmutablesLocationDiscriminants::CloudStorage, &[]); + + assert!(row.is_none()); + } + + #[test] + fn immutables_location_row_returns_some_when_uri_found_for_location_type() { + let locations = vec![ImmutablesLocation::CloudStorage { + uri: MultiFilesUri::Template(TemplateUri("http://cloudstorage.com/".to_string())), + }]; + + let row = + immutables_location_row(ImmutablesLocationDiscriminants::CloudStorage, &locations); + + assert!(row.is_some()); + } + + #[test] + fn ancillary_location_row_returns_none_when_no_uri_found_for_location_type() { + let row = ancillary_location_row(AncillaryLocationDiscriminants::CloudStorage, &[]); + + assert!(row.is_none()); + } + + #[test] + fn ancillary_location_row_returns_some_when_uri_found_for_location_type() { + let locations = vec![AncillaryLocation::CloudStorage { + uri: "http://cloudstorage.com/".to_string(), + }]; + + let row = ancillary_location_row(AncillaryLocationDiscriminants::CloudStorage, &locations); + + assert!(row.is_some()); + } +} diff --git a/mithril-client/src/type_alias.rs b/mithril-client/src/type_alias.rs index 15722afb584..b1b90b66b9e 100644 --- a/mithril-client/src/type_alias.rs +++ b/mithril-client/src/type_alias.rs @@ -68,9 +68,10 @@ pub use mithril_common::messages::CardanoStakeDistributionListItemMessage as Car /// `mithril-common` re-exports pub mod common { pub use mithril_common::entities::{ - BlockHash, BlockNumber, CardanoDbBeacon, ChainPoint, CompressionAlgorithm, Epoch, - ImmutableFileNumber, ProtocolMessage, ProtocolMessagePartKey, ProtocolParameters, - SlotNumber, StakeDistribution, TransactionHash, + AncillaryLocationDiscriminants, BlockHash, BlockNumber, CardanoDbBeacon, ChainPoint, + CompressionAlgorithm, DigestLocationDiscriminants, Epoch, ImmutableFileNumber, + ImmutablesLocationDiscriminants, ProtocolMessage, ProtocolMessagePartKey, + ProtocolParameters, SlotNumber, StakeDistribution, TransactionHash, }; cfg_unstable! { pub use mithril_common::entities::{ diff --git a/mithril-common/src/entities/cardano_database.rs b/mithril-common/src/entities/cardano_database.rs index fa9e35f246d..24bfb9c5ea1 100644 --- a/mithril-common/src/entities/cardano_database.rs +++ b/mithril-common/src/entities/cardano_database.rs @@ -71,7 +71,9 @@ impl CardanoDatabaseSnapshot { } /// Locations of the immutable file digests. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[derive( + Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, EnumDiscriminants, +)] #[serde(rename_all = "snake_case", tag = "type")] pub enum DigestLocation { /// Aggregator digest route location. @@ -87,7 +89,9 @@ pub enum DigestLocation { } /// Locations of the immutable files. -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +#[derive( + Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, EnumDiscriminants, +)] #[serde(rename_all = "snake_case", tag = "type")] pub enum ImmutablesLocation { /// Cloud storage location. diff --git a/mithril-common/src/entities/mod.rs b/mithril-common/src/entities/mod.rs index 2c0eeb04f3c..5223a4b8b25 100644 --- a/mithril-common/src/entities/mod.rs +++ b/mithril-common/src/entities/mod.rs @@ -36,7 +36,8 @@ pub use block_range::{BlockRange, BlockRangeLength, BlockRangesSequence}; pub use cardano_chain_point::{BlockHash, ChainPoint}; pub use cardano_database::{ AncillaryLocation, AncillaryLocationDiscriminants, ArtifactsLocations, CardanoDatabaseSnapshot, - DigestLocation, ImmutablesLocation, + DigestLocation, DigestLocationDiscriminants, ImmutablesLocation, + ImmutablesLocationDiscriminants, }; pub use cardano_db_beacon::CardanoDbBeacon; pub use cardano_network::CardanoNetwork; From 1aa79b15f21f7c6f34e5323a2fb501825eaabdbb Mon Sep 17 00:00:00 2001 From: Damien Lachaume <135982616+dlachaume@users.noreply.github.com> Date: Fri, 31 Jan 2025 12:28:47 +0100 Subject: [PATCH 3/9] test: verify `cardano-db-v2` commands in the E2E test --- .../src/assertions/check.rs | 22 ++++++++++-- .../mithril-end-to-end/src/end_to_end_spec.rs | 3 ++ .../mithril-end-to-end/src/mithril/client.rs | 35 +++++++++++++++++++ .../mithril-end-to-end/src/mithril/mod.rs | 4 +-- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/mithril-test-lab/mithril-end-to-end/src/assertions/check.rs b/mithril-test-lab/mithril-end-to-end/src/assertions/check.rs index f2968a93642..830b43ef6db 100644 --- a/mithril-test-lab/mithril-end-to-end/src/assertions/check.rs +++ b/mithril-test-lab/mithril-end-to-end/src/assertions/check.rs @@ -18,8 +18,9 @@ use mithril_common::{ }; use crate::{ - attempt, utils::AttemptResult, CardanoDbCommand, CardanoStakeDistributionCommand, - CardanoTransactionCommand, Client, ClientCommand, MithrilStakeDistributionCommand, + attempt, utils::AttemptResult, CardanoDbCommand, CardanoDbV2Command, + CardanoStakeDistributionCommand, CardanoTransactionCommand, Client, ClientCommand, + MithrilStakeDistributionCommand, }; async fn get_json_response(url: String) -> StdResult> { @@ -498,6 +499,23 @@ pub async fn assert_client_can_verify_snapshot(client: &mut Client, digest: &str Ok(()) } +pub async fn assert_client_can_verify_cardano_database( + client: &mut Client, + hash: &str, +) -> StdResult<()> { + client + .run(ClientCommand::CardanoDbV2(CardanoDbV2Command::List)) + .await?; + client + .run(ClientCommand::CardanoDbV2(CardanoDbV2Command::Show { + hash: hash.to_string(), + })) + .await?; + info!("Client list & show the cardano database snapshot"; "hash" => &hash); + + Ok(()) +} + pub async fn assert_client_can_verify_mithril_stake_distribution( client: &mut Client, hash: &str, diff --git a/mithril-test-lab/mithril-end-to-end/src/end_to_end_spec.rs b/mithril-test-lab/mithril-end-to-end/src/end_to_end_spec.rs index 030b5c8a8bf..4dc5e8a309a 100644 --- a/mithril-test-lab/mithril-end-to-end/src/end_to_end_spec.rs +++ b/mithril-test-lab/mithril-end-to-end/src/end_to_end_spec.rs @@ -207,6 +207,9 @@ impl<'a> Spec<'a> { assertions::assert_node_producing_cardano_database_digests_map(&aggregator_endpoint) .await?; + + let mut client = self.infrastructure.build_client()?; + assertions::assert_client_can_verify_cardano_database(&mut client, &hash).await?; } // Verify that Cardano transactions artifacts are produced and signed correctly diff --git a/mithril-test-lab/mithril-end-to-end/src/mithril/client.rs b/mithril-test-lab/mithril-end-to-end/src/mithril/client.rs index 7da6f1500eb..b9938838ef1 100644 --- a/mithril-test-lab/mithril-end-to-end/src/mithril/client.rs +++ b/mithril-test-lab/mithril-end-to-end/src/mithril/client.rs @@ -40,6 +40,32 @@ impl CardanoDbCommand { } } +#[derive(Debug)] +pub enum CardanoDbV2Command { + List, + Show { hash: String }, +} + +impl CardanoDbV2Command { + fn name(&self) -> String { + match self { + CardanoDbV2Command::List => "list".to_string(), + CardanoDbV2Command::Show { hash } => format!("show-{hash}"), + } + } + + fn cli_arg(&self) -> Vec { + match self { + CardanoDbV2Command::List => { + vec!["snapshot".to_string(), "list".to_string()] + } + CardanoDbV2Command::Show { hash } => { + vec!["snapshot".to_string(), "show".to_string(), hash.clone()] + } + } + } +} + #[derive(Debug)] pub enum MithrilStakeDistributionCommand { List, @@ -137,6 +163,7 @@ pub enum ClientCommand { MithrilStakeDistribution(MithrilStakeDistributionCommand), CardanoTransaction(CardanoTransactionCommand), CardanoStakeDistribution(CardanoStakeDistributionCommand), + CardanoDbV2(CardanoDbV2Command), } impl ClientCommand { @@ -152,6 +179,9 @@ impl ClientCommand { ClientCommand::CardanoStakeDistribution(cmd) => { format!("csd-{}", cmd.name()) } + ClientCommand::CardanoDbV2(cmd) => { + format!("cdbv2-{}", cmd.name()) + } } } @@ -173,6 +203,11 @@ impl ClientCommand { cmd.cli_arg(), ] .concat(), + ClientCommand::CardanoDbV2(cmd) => [ + vec!["--unstable".to_string(), "cardano-db-v2".to_string()], + cmd.cli_arg(), + ] + .concat(), }; args.push("--json".to_string()); diff --git a/mithril-test-lab/mithril-end-to-end/src/mithril/mod.rs b/mithril-test-lab/mithril-end-to-end/src/mithril/mod.rs index 73f36024817..118bb0e7fed 100644 --- a/mithril-test-lab/mithril-end-to-end/src/mithril/mod.rs +++ b/mithril-test-lab/mithril-end-to-end/src/mithril/mod.rs @@ -8,8 +8,8 @@ mod signer; pub use aggregator::{Aggregator, AggregatorConfig}; pub use client::{ - CardanoDbCommand, CardanoStakeDistributionCommand, CardanoTransactionCommand, Client, - ClientCommand, MithrilStakeDistributionCommand, + CardanoDbCommand, CardanoDbV2Command, CardanoStakeDistributionCommand, + CardanoTransactionCommand, Client, ClientCommand, MithrilStakeDistributionCommand, }; pub use infrastructure::{MithrilInfrastructure, MithrilInfrastructureConfig}; pub use relay_aggregator::RelayAggregator; From 69fa57e565e05ceb096dc9ea21b6a2180532a5c8 Mon Sep 17 00:00:00 2001 From: Damien Lachaume <135982616+dlachaume@users.noreply.github.com> Date: Fri, 31 Jan 2025 14:56:39 +0100 Subject: [PATCH 4/9] chore: makes variable names clearer by removing abbreviations in Mithril Client multi-platform test --- .github/workflows/test-client.yml | 48 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/test-client.yml b/.github/workflows/test-client.yml index 53c8c8c7f92..b8bf00e51e9 100644 --- a/.github/workflows/test-client.yml +++ b/.github/workflows/test-client.yml @@ -98,10 +98,10 @@ jobs: if: runner.os != 'Windows' shell: bash run: | - CTX_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoTransactions"])') - CSD_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoStakeDistribution"])') - echo "ctx_enabled=$CTX_CAPABILITY" >> $GITHUB_OUTPUT - echo "csd_enabled=$CSD_CAPABILITY" >> $GITHUB_OUTPUT + CARDANO_TRANSACTIONS_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoTransactions"])') + CARDANO_STAKE_DISTRIBUTION_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoStakeDistribution"])') + echo "cardano_transactions_enabled=$CARDANO_TRANSACTIONS_CAPABILITY" >> $GITHUB_OUTPUT + echo "cardano_stake_distribution_enabled=$CARDANO_STAKE_DISTRIBUTION_CAPABILITY" >> $GITHUB_OUTPUT - name: Assessing aggregator capabilities (Windows) id: aggregator_capability_windows @@ -109,10 +109,10 @@ jobs: shell: bash run: | aria2c -o aggregator_capabilities.json $AGGREGATOR_ENDPOINT - CTX_CAPABILITY=$(jq '.capabilities.signed_entity_types | contains(["CardanoTransactions"])' aggregator_capabilities.json) - CSD_CAPABILITY=$(jq '.capabilities.signed_entity_types | contains(["CardanoStakeDistribution"])' aggregator_capabilities.json) - echo "ctx_enabled=$CTX_CAPABILITY" >> $GITHUB_OUTPUT - echo "csd_enabled=$CSD_CAPABILITY" >> $GITHUB_OUTPUT + CARDANO_TRANSACTIONS_CAPABILITY=$(jq '.capabilities.signed_entity_types | contains(["CardanoTransactions"])' aggregator_capabilities.json) + CARDANO_STAKE_DISTRIBUTION_CAPABILITY=$(jq '.capabilities.signed_entity_types | contains(["CardanoStakeDistribution"])' aggregator_capabilities.json) + echo "cardano_transactions_enabled=$CARDANO_TRANSACTIONS_CAPABILITY" >> $GITHUB_OUTPUT + echo "cardano_stake_distribution_enabled=$CARDANO_STAKE_DISTRIBUTION_CAPABILITY" >> $GITHUB_OUTPUT - name: Checkout binary uses: dawidd6/action-download-artifact@v6 @@ -159,7 +159,7 @@ jobs: run: ./mithril-client ${{ steps.prepare.outputs.debug_level }} mithril-stake-distribution download $MITHRIL_STAKE_DISTRIBUTION_HASH - name: Cardano transaction / list and get last snapshot - if: steps.aggregator_capability_unix.outputs.ctx_enabled == 'true' || steps.aggregator_capability_windows.outputs.ctx_enabled == 'true' + if: steps.aggregator_capability_unix.outputs.cardano_transactions_enabled == 'true' || steps.aggregator_capability_windows.outputs.cardano_transactions_enabled == 'true' shell: bash working-directory: ./bin run: | @@ -167,19 +167,19 @@ jobs: echo "CTX_SNAPSHOT_HASH=$(./mithril-client cardano-transaction snapshot list --json | jq -r '.[0].hash')" >> $GITHUB_ENV - name: Cardano transaction / show snapshot - if: steps.aggregator_capability_unix.outputs.ctx_enabled == 'true' || steps.aggregator_capability_windows.outputs.ctx_enabled == 'true' + if: steps.aggregator_capability_unix.outputs.cardano_transactions_enabled == 'true' || steps.aggregator_capability_windows.outputs.cardano_transactions_enabled == 'true' shell: bash working-directory: ./bin run: ./mithril-client cardano-transaction snapshot show $CTX_SNAPSHOT_HASH - name: Cardano transaction certify - if: steps.aggregator_capability_unix.outputs.ctx_enabled == 'true' || steps.aggregator_capability_windows.outputs.ctx_enabled == 'true' + if: steps.aggregator_capability_unix.outputs.cardano_transactions_enabled == 'true' || steps.aggregator_capability_windows.outputs.cardano_transactions_enabled == 'true' shell: bash working-directory: ./bin run: ./mithril-client ${{ steps.prepare.outputs.debug_level }} cardano-transaction certify $TRANSACTIONS_HASHES_TO_CERTIFY - name: Cardano Stake Distribution / list and get last epoch and hash - if: steps.aggregator_capability_unix.outputs.csd_enabled == 'true' || steps.aggregator_capability_windows.outputs.csd_enabled == 'true' + if: steps.aggregator_capability_unix.outputs.cardano_stake_distribution_enabled == 'true' || steps.aggregator_capability_windows.outputs.cardano_stake_distribution_enabled == 'true' shell: bash working-directory: ./bin run: | @@ -189,13 +189,13 @@ jobs: echo "CARDANO_STAKE_DISTRIBUTION_HASH=$(echo "$CMD_OUTPUT" | jq -r '.[0].hash')" >> $GITHUB_ENV - name: Cardano Stake Distribution / download & restore latest by epoch - if: steps.aggregator_capability_unix.outputs.csd_enabled == 'true' || steps.aggregator_capability_windows.outputs.csd_enabled == 'true' + if: steps.aggregator_capability_unix.outputs.cardano_stake_distribution_enabled == 'true' || steps.aggregator_capability_windows.outputs.cardano_stake_distribution_enabled == 'true' shell: bash working-directory: ./bin run: ./mithril-client ${{ steps.prepare.outputs.debug_level }} cardano-stake-distribution download $CARDANO_STAKE_DISTRIBUTION_EPOCH - name: Cardano Stake Distribution / download & restore latest by hash - if: steps.aggregator_capability_unix.outputs.csd_enabled == 'true' || steps.aggregator_capability_windows.outputs.csd_enabled == 'true' + if: steps.aggregator_capability_unix.outputs.cardano_stake_distribution_enabled == 'true' || steps.aggregator_capability_windows.outputs.cardano_stake_distribution_enabled == 'true' shell: bash working-directory: ./bin run: ./mithril-client ${{ steps.prepare.outputs.debug_level }} cardano-stake-distribution download $CARDANO_STAKE_DISTRIBUTION_HASH @@ -225,10 +225,10 @@ jobs: id: aggregator_capability shell: bash run: | - CTX_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoTransactions"])') - CSD_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoStakeDistribution"])') - echo "ctx_enabled=$CTX_CAPABILITY" >> $GITHUB_OUTPUT - echo "csd_enabled=$CSD_CAPABILITY" >> $GITHUB_OUTPUT + CARDANO_TRANSACTIONS_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoTransactions"])') + CARDANO_STAKE_DISTRIBUTION_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoStakeDistribution"])') + echo "cardano_transactions_enabled=$CARDANO_TRANSACTIONS_CAPABILITY" >> $GITHUB_OUTPUT + echo "cardano_stake_distribution_enabled=$CARDANO_STAKE_DISTRIBUTION_CAPABILITY" >> $GITHUB_OUTPUT - name: Prepare Mithril client command id: command @@ -261,24 +261,24 @@ jobs: run: ${{ steps.command.outputs.mithril_client }} ${{ steps.prepare.outputs.debug_level }} mithril-stake-distribution download $MITHRIL_STAKE_DISTRIBUTION_HASH --download-dir /app - name: Cardano transaction / list and get last snapshot - if: steps.aggregator_capability.outputs.ctx_enabled == 'true' + if: steps.aggregator_capability.outputs.cardano_transactions_enabled == 'true' shell: bash run: | ${{ steps.command.outputs.mithril_client }} cardano-transaction snapshot list echo "CTX_SNAPSHOT_HASH=$(${{ steps.command.outputs.mithril_client }} cardano-transaction snapshot list --json | jq -r '.[0].hash')" >> $GITHUB_ENV - name: Cardano transaction / show snapshot - if: steps.aggregator_capability.outputs.ctx_enabled == 'true' + if: steps.aggregator_capability.outputs.cardano_transactions_enabled == 'true' shell: bash run: ${{ steps.command.outputs.mithril_client }} cardano-transaction snapshot show $CTX_SNAPSHOT_HASH - name: Cardano transaction certify - if: steps.aggregator_capability.outputs.ctx_enabled == 'true' + if: steps.aggregator_capability.outputs.cardano_transactions_enabled == 'true' shell: bash run: ${{ steps.command.outputs.mithril_client }} ${{ steps.prepare.outputs.debug_level }} cardano-transaction certify $TRANSACTIONS_HASHES_TO_CERTIFY - name: Cardano Stake Distribution / list and get last epoch and hash - if: steps.aggregator_capability.outputs.csd_enabled == 'true' + if: steps.aggregator_capability.outputs.cardano_stake_distribution_enabled == 'true' shell: bash run: | ${{ steps.command.outputs.mithril_client }} cardano-stake-distribution list @@ -287,12 +287,12 @@ jobs: echo "CARDANO_STAKE_DISTRIBUTION_HASH=$(echo "$CMD_OUTPUT" | jq -r '.[0].hash')" >> $GITHUB_ENV - name: Cardano Stake Distribution / download & restore latest by epoch - if: steps.aggregator_capability.outputs.csd_enabled == 'true' + if: steps.aggregator_capability.outputs.cardano_stake_distribution_enabled == 'true' shell: bash run: ${{ steps.command.outputs.mithril_client }} ${{ steps.prepare.outputs.debug_level }} cardano-stake-distribution download $CARDANO_STAKE_DISTRIBUTION_EPOCH --download-dir /app - name: Cardano Stake Distribution / download & restore latest by hash - if: steps.aggregator_capability.outputs.csd_enabled == 'true' + if: steps.aggregator_capability.outputs.cardano_stake_distribution_enabled == 'true' shell: bash run: ${{ steps.command.outputs.mithril_client }} ${{ steps.prepare.outputs.debug_level }} cardano-stake-distribution download $CARDANO_STAKE_DISTRIBUTION_HASH --download-dir /app From 0aea1f7a5f7f8981b35213784be52f0b9745a47d Mon Sep 17 00:00:00 2001 From: Damien Lachaume <135982616+dlachaume@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:11:29 +0100 Subject: [PATCH 5/9] test: add new verification steps for `cardano-db-v2` commands in Mithril Client multi-platform test --- .github/workflows/test-client.yml | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/.github/workflows/test-client.yml b/.github/workflows/test-client.yml index b8bf00e51e9..306623eadf6 100644 --- a/.github/workflows/test-client.yml +++ b/.github/workflows/test-client.yml @@ -100,8 +100,10 @@ jobs: run: | CARDANO_TRANSACTIONS_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoTransactions"])') CARDANO_STAKE_DISTRIBUTION_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoStakeDistribution"])') + CARDANO_DATABASE_V2_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoDatabase"])') echo "cardano_transactions_enabled=$CARDANO_TRANSACTIONS_CAPABILITY" >> $GITHUB_OUTPUT echo "cardano_stake_distribution_enabled=$CARDANO_STAKE_DISTRIBUTION_CAPABILITY" >> $GITHUB_OUTPUT + echo "cardano_database_v2_enabled=$CARDANO_DATABASE_V2_CAPABILITY" >> $GITHUB_OUTPUT - name: Assessing aggregator capabilities (Windows) id: aggregator_capability_windows @@ -111,8 +113,10 @@ jobs: aria2c -o aggregator_capabilities.json $AGGREGATOR_ENDPOINT CARDANO_TRANSACTIONS_CAPABILITY=$(jq '.capabilities.signed_entity_types | contains(["CardanoTransactions"])' aggregator_capabilities.json) CARDANO_STAKE_DISTRIBUTION_CAPABILITY=$(jq '.capabilities.signed_entity_types | contains(["CardanoStakeDistribution"])' aggregator_capabilities.json) + CARDANO_DATABASE_V2_CAPABILITY=$(jq '.capabilities.signed_entity_types | contains(["CardanoDatabase"])' aggregator_capabilities.json) echo "cardano_transactions_enabled=$CARDANO_TRANSACTIONS_CAPABILITY" >> $GITHUB_OUTPUT echo "cardano_stake_distribution_enabled=$CARDANO_STAKE_DISTRIBUTION_CAPABILITY" >> $GITHUB_OUTPUT + echo "cardano_database_v2_enabled=$CARDANO_DATABASE_V2_CAPABILITY" >> $GITHUB_OUTPUT - name: Checkout binary uses: dawidd6/action-download-artifact@v6 @@ -200,6 +204,20 @@ jobs: working-directory: ./bin run: ./mithril-client ${{ steps.prepare.outputs.debug_level }} cardano-stake-distribution download $CARDANO_STAKE_DISTRIBUTION_HASH + - name: Cardano Database V2 Snapshot / list and get last hash + if: steps.aggregator_capability_unix.outputs.cardano_database_v2_enabled == 'true' || steps.aggregator_capability_windows.outputs.cardano_database_v2_enabled == 'true' + shell: bash + working-directory: ./bin + run: | + ./mithril-client ${{ steps.prepare.outputs.debug_level }} --unstable cardano-db-v2 snapshot list + echo "CARDANO_DATABASE_V2_SNAPSHOT_HASH=$(./mithril-client --unstable cardano-db-v2 snapshot list --json | jq -r '.[0].hash')" >> $GITHUB_ENV + + - name: Cardano Database V2 Snapshot / show snapshot + if: steps.aggregator_capability_unix.outputs.cardano_database_v2_enabled == 'true' || steps.aggregator_capability_windows.outputs.cardano_database_v2_enabled == 'true' + shell: bash + working-directory: ./bin + run: ./mithril-client --unstable cardano-db-v2 snapshot show $CARDANO_DATABASE_V2_SNAPSHOT_HASH + test-docker: strategy: fail-fast: false @@ -227,8 +245,10 @@ jobs: run: | CARDANO_TRANSACTIONS_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoTransactions"])') CARDANO_STAKE_DISTRIBUTION_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoStakeDistribution"])') + CARDANO_DATABASE_V2_CAPABILITY=$(wget -q -O - $AGGREGATOR_ENDPOINT | jq '.capabilities.signed_entity_types | contains(["CardanoDatabase"])') echo "cardano_transactions_enabled=$CARDANO_TRANSACTIONS_CAPABILITY" >> $GITHUB_OUTPUT echo "cardano_stake_distribution_enabled=$CARDANO_STAKE_DISTRIBUTION_CAPABILITY" >> $GITHUB_OUTPUT + echo "cardano_database_v2_enabled=$CARDANO_DATABASE_V2_CAPABILITY" >> $GITHUB_OUTPUT - name: Prepare Mithril client command id: command @@ -296,6 +316,18 @@ jobs: shell: bash run: ${{ steps.command.outputs.mithril_client }} ${{ steps.prepare.outputs.debug_level }} cardano-stake-distribution download $CARDANO_STAKE_DISTRIBUTION_HASH --download-dir /app + - name: Cardano Database V2 Snapshot / list and get last digest + if: steps.aggregator_capability.outputs.cardano_database_v2_enabled == 'true' + shell: bash + run: | + ${{ steps.command.outputs.mithril_client }} --unstable cardano-db-v2 snapshot list + echo "CARDANO_DATABASE_V2_SNAPSHOT_HASH=$(${{ steps.command.outputs.mithril_client }} --unstable cardano-db-v2 snapshot list --json | jq -r '.[0].hash')" >> $GITHUB_ENV + + - name: Cardano Database V2 Snapshot / show snapshot + if: steps.aggregator_capability.outputs.cardano_database_v2_enabled == 'true' + shell: bash + run: ${{ steps.command.outputs.mithril_client }} --unstable cardano-db-v2 snapshot show $CARDANO_DATABASE_V2_SNAPSHOT_HASH + test-mithril-client-wasm: strategy: fail-fast: false From 35f658fa47b7780ba1716ece0067f17148f9cb73 Mon Sep 17 00:00:00 2001 From: Damien Lachaume <135982616+dlachaume@users.noreply.github.com> Date: Mon, 3 Feb 2025 09:50:54 +0100 Subject: [PATCH 6/9] test: rename step names for consistency between Cardano Database v1 and v2 in Mithril Client multi-platform test --- .github/workflows/test-client.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-client.yml b/.github/workflows/test-client.yml index 306623eadf6..d5c4368276e 100644 --- a/.github/workflows/test-client.yml +++ b/.github/workflows/test-client.yml @@ -138,14 +138,14 @@ jobs: working-directory: ./bin run: ./mithril-client ${{ steps.prepare.outputs.debug_level }} --version - - name: Cardano-db / list and get last digest + - name: Cardano Database Snapshot / list and get last digest shell: bash working-directory: ./bin run: | ./mithril-client ${{ steps.prepare.outputs.debug_level }} cardano-db snapshot list echo "CDB_SNAPSHOT_DIGEST=$(./mithril-client cardano-db snapshot list --json | jq -r '.[0].digest')" >> $GITHUB_ENV - - name: Cardano-db / download & restore latest + - name: Cardano Database Snapshot / download & restore latest shell: bash working-directory: ./bin run: ./mithril-client ${{ steps.prepare.outputs.debug_level }} cardano-db download $CDB_SNAPSHOT_DIGEST @@ -260,13 +260,13 @@ jobs: shell: bash run: ${{ steps.command.outputs.mithril_client }} ${{ steps.prepare.outputs.debug_level }} --version - - name: Cardano-db / list and get last digest + - name: Cardano Database Snapshot / list and get last digest shell: bash run: | ${{ steps.command.outputs.mithril_client }} cardano-db snapshot list echo "CDB_SNAPSHOT_DIGEST=$(${{ steps.command.outputs.mithril_client }} cardano-db snapshot list --json | jq -r '.[0].digest')" >> $GITHUB_ENV - - name: Cardano-db / download & restore latest + - name: Cardano Database Snapshot / download & restore latest shell: bash run: ${{ steps.command.outputs.mithril_client }} ${{ steps.prepare.outputs.debug_level }} cardano-db download $CDB_SNAPSHOT_DIGEST --download-dir /app From 9cd26373338e11f3c1f089a22529132e7fc49aaf Mon Sep 17 00:00:00 2001 From: Damien Lachaume <135982616+dlachaume@users.noreply.github.com> Date: Mon, 3 Feb 2025 10:48:11 +0100 Subject: [PATCH 7/9] refactor: display sizes in a human readable format --- .../src/commands/cardano_db/list.rs | 3 +- .../src/commands/cardano_db/show.rs | 4 +-- .../src/commands/cardano_db_v2/list.rs | 4 ++- .../src/commands/cardano_db_v2/show.rs | 7 +++-- mithril-client-cli/src/utils/cardano_db.rs | 28 +++++++++++++++++++ 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/mithril-client-cli/src/commands/cardano_db/list.rs b/mithril-client-cli/src/commands/cardano_db/list.rs index bf6ff52ab99..92757d8820b 100644 --- a/mithril-client-cli/src/commands/cardano_db/list.rs +++ b/mithril-client-cli/src/commands/cardano_db/list.rs @@ -3,6 +3,7 @@ use cli_table::{format::Justify, print_stdout, Cell, Table}; use crate::{ commands::{client_builder_with_fallback_genesis_key, SharedArgs}, + utils::CardanoDbUtils, CommandContext, }; use mithril_client::MithrilResult; @@ -39,7 +40,7 @@ impl CardanoDbListCommand { format!("{}", item.beacon.immutable_file_number).cell(), item.network.cell(), item.digest.cell(), - item.size.cell(), + CardanoDbUtils::format_bytes_to_gigabytes(item.size).cell(), format!("{}", item.locations.len()).cell(), item.created_at.to_string().cell(), ] diff --git a/mithril-client-cli/src/commands/cardano_db/show.rs b/mithril-client-cli/src/commands/cardano_db/show.rs index 1b6069e4bef..6cd0c2e9c3a 100644 --- a/mithril-client-cli/src/commands/cardano_db/show.rs +++ b/mithril-client-cli/src/commands/cardano_db/show.rs @@ -4,7 +4,7 @@ use cli_table::{print_stdout, Cell, Table}; use crate::{ commands::{client_builder_with_fallback_genesis_key, SharedArgs}, - utils::ExpanderUtils, + utils::{CardanoDbUtils, ExpanderUtils}, CommandContext, }; use mithril_client::MithrilResult; @@ -70,7 +70,7 @@ impl CardanoDbShowCommand { vec!["Digest".cell(), cardano_db_message.digest.cell()], vec![ "Size".cell(), - format!("{}", &cardano_db_message.size).cell(), + CardanoDbUtils::format_bytes_to_gigabytes(cardano_db_message.size).cell(), ], vec![ "Cardano node version".cell(), diff --git a/mithril-client-cli/src/commands/cardano_db_v2/list.rs b/mithril-client-cli/src/commands/cardano_db_v2/list.rs index 0588f13e944..c536289c865 100644 --- a/mithril-client-cli/src/commands/cardano_db_v2/list.rs +++ b/mithril-client-cli/src/commands/cardano_db_v2/list.rs @@ -5,6 +5,7 @@ use mithril_client::MithrilResult; use crate::{ commands::{client_builder_with_fallback_genesis_key, SharedArgs}, + utils::CardanoDbUtils, CommandContext, }; @@ -40,7 +41,8 @@ impl CardanoDbListCommand { format!("{}", item.beacon.immutable_file_number).cell(), item.hash.cell(), item.merkle_root.cell(), - item.total_db_size_uncompressed.cell(), + CardanoDbUtils::format_bytes_to_gigabytes(item.total_db_size_uncompressed) + .cell(), format!("{}", item.compression_algorithm).cell(), item.cardano_node_version.cell(), item.created_at.to_string().cell(), diff --git a/mithril-client-cli/src/commands/cardano_db_v2/show.rs b/mithril-client-cli/src/commands/cardano_db_v2/show.rs index 342657be466..b607b1d7f7b 100644 --- a/mithril-client-cli/src/commands/cardano_db_v2/show.rs +++ b/mithril-client-cli/src/commands/cardano_db_v2/show.rs @@ -4,7 +4,7 @@ use cli_table::{print_stdout, Cell, CellStruct, Table}; use crate::{ commands::{client_builder_with_fallback_genesis_key, SharedArgs}, - utils::ExpanderUtils, + utils::{CardanoDbUtils, ExpanderUtils}, CommandContext, }; @@ -78,7 +78,10 @@ impl CardanoDbShowCommand { vec!["Merkle root".cell(), cardano_db_message.merkle_root.cell()], vec![ "Database size".cell(), - format!("{}", &cardano_db_message.total_db_size_uncompressed).cell(), + CardanoDbUtils::format_bytes_to_gigabytes( + cardano_db_message.total_db_size_uncompressed, + ) + .cell(), ], vec![ "Cardano node version".cell(), diff --git a/mithril-client-cli/src/utils/cardano_db.rs b/mithril-client-cli/src/utils/cardano_db.rs index 62d326a7258..a04e59697db 100644 --- a/mithril-client-cli/src/utils/cardano_db.rs +++ b/mithril-client-cli/src/utils/cardano_db.rs @@ -42,6 +42,12 @@ impl CardanoDbUtils { res = future => res, } } + + pub fn format_bytes_to_gigabytes(bytes: u64) -> String { + let size_in_giga = bytes as f64 / (1024.0 * 1024.0 * 1024.0); + + format!("{:.2} GiB", size_in_giga) + } } #[cfg(test)] @@ -80,4 +86,26 @@ mod test { error ); } + + #[test] + fn format_bytes_to_gigabytes_zero() { + let one_gigabyte = 1024 * 1024 * 1024; + + assert_eq!(CardanoDbUtils::format_bytes_to_gigabytes(0), "0.00 GiB"); + + assert_eq!( + CardanoDbUtils::format_bytes_to_gigabytes(one_gigabyte), + "1.00 GiB" + ); + + assert_eq!( + CardanoDbUtils::format_bytes_to_gigabytes(one_gigabyte / 2), + "0.50 GiB" + ); + + assert_eq!( + CardanoDbUtils::format_bytes_to_gigabytes(one_gigabyte * 10), + "10.00 GiB" + ); + } } From b7f3557c811783791cb6a351f3e5eaed368dc68a Mon Sep 17 00:00:00 2001 From: Damien Lachaume <135982616+dlachaume@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:43:24 +0100 Subject: [PATCH 8/9] refactor: return one line per location instead of concatenating multiple locations with commas. --- .../src/commands/cardano_db_v2/show.rs | 241 ++++++++---------- mithril-client/src/type_alias.rs | 7 +- .../src/entities/cardano_database.rs | 13 +- mithril-common/src/entities/mod.rs | 5 +- 4 files changed, 116 insertions(+), 150 deletions(-) diff --git a/mithril-client-cli/src/commands/cardano_db_v2/show.rs b/mithril-client-cli/src/commands/cardano_db_v2/show.rs index b607b1d7f7b..c2b885792d9 100644 --- a/mithril-client-cli/src/commands/cardano_db_v2/show.rs +++ b/mithril-client-cli/src/commands/cardano_db_v2/show.rs @@ -9,11 +9,7 @@ use crate::{ }; use mithril_client::{ - common::{ - AncillaryLocation, AncillaryLocationDiscriminants, DigestLocation, - DigestLocationDiscriminants, ImmutablesLocation, ImmutablesLocationDiscriminants, - MultiFilesUri, - }, + common::{AncillaryLocation, DigestLocation, ImmutablesLocation, MultiFilesUri}, MithrilResult, }; @@ -89,32 +85,19 @@ impl CardanoDbShowCommand { ], ]; - let mut digest_location_index = 1; - for digest_location_type in [ - DigestLocationDiscriminants::Aggregator, - DigestLocationDiscriminants::CloudStorage, - ] { - if let Some(digest_location) = digest_location_row( - digest_location_index, - digest_location_type, - &cardano_db_message.locations.digests, - ) { - cardano_db_table.push(digest_location); - digest_location_index += 1; - } + for digest_location in digest_location_rows(&cardano_db_message.locations.digests) { + cardano_db_table.push(digest_location); } - if let Some(immutables_location) = immutables_location_row( - ImmutablesLocationDiscriminants::CloudStorage, - &cardano_db_message.locations.immutables, - ) { + for immutables_location in + immutables_location_rows(&cardano_db_message.locations.immutables) + { cardano_db_table.push(immutables_location); } - if let Some(ancillary_location) = ancillary_location_row( - AncillaryLocationDiscriminants::CloudStorage, - &cardano_db_message.locations.ancillary, - ) { + for ancillary_location in + ancillary_location_rows(&cardano_db_message.locations.ancillary) + { cardano_db_table.push(ancillary_location); } @@ -134,97 +117,63 @@ impl CardanoDbShowCommand { } } -fn digest_location_row( - index: usize, - location_type: DigestLocationDiscriminants, - locations: &[DigestLocation], -) -> Option> { - let uris = locations +fn digest_location_rows(locations: &[DigestLocation]) -> Vec> { + let location_name = "Digest location"; + + locations .iter() - .filter_map(|location| match (location, location_type) { - (DigestLocation::Aggregator { uri }, DigestLocationDiscriminants::Aggregator) => { - Some(format!("uri: \"{}\"", uri)) + .enumerate() + .map(|(index, location)| match location { + DigestLocation::Aggregator { uri } => { + vec![ + format!("{location_name} ({})", index + 1).cell(), + format!("Aggregator, uri: \"{}\"", uri).cell(), + ] } - (DigestLocation::CloudStorage { uri }, DigestLocationDiscriminants::CloudStorage) => { - Some(format!("uri: \"{}\"", uri)) + DigestLocation::CloudStorage { uri } => { + vec![ + format!("{location_name} ({})", index + 1).cell(), + format!("CloudStorage, uri: \"{}\"", uri).cell(), + ] } - _ => None, }) - .collect::>() - .join(","); - - if uris.is_empty() { - None - } else { - Some(vec![ - format!("Digest location ({index})").cell(), - format!("{location_type:?}, {uris}").cell(), - ]) - } + .collect() } -fn immutables_location_row( - location_type: ImmutablesLocationDiscriminants, - locations: &[ImmutablesLocation], -) -> Option> { - let uris = locations +fn immutables_location_rows(locations: &[ImmutablesLocation]) -> Vec> { + let location_name = "Immutables location"; + + locations .iter() - .map(|location| match (location, location_type) { - ( - ImmutablesLocation::CloudStorage { uri }, - ImmutablesLocationDiscriminants::CloudStorage, - ) => match uri { + .enumerate() + .map(|(index, location)| match location { + ImmutablesLocation::CloudStorage { uri } => match uri { MultiFilesUri::Template(template_uri) => { - format!("template_uri: \"{}\"", template_uri.0) + vec![ + format!("{location_name} ({})", index + 1).cell(), + format!("CloudStorage, template_uri: \"{}\"", template_uri.0).cell(), + ] } }, }) - .collect::>() - .join(","); - - if uris.is_empty() { - None - } else { - Some(vec![ - "Immutables location".to_string().cell(), - format!( - "{:?}, {}", - ImmutablesLocationDiscriminants::CloudStorage, - uris - ) - .cell(), - ]) - } + .collect() } -fn ancillary_location_row( - location_type: AncillaryLocationDiscriminants, - locations: &[AncillaryLocation], -) -> Option> { - let uris = locations +fn ancillary_location_rows(locations: &[AncillaryLocation]) -> Vec> { + let location_name = "Ancillary location"; + + locations .iter() - .map(|location| match (location, location_type) { - ( - AncillaryLocation::CloudStorage { uri }, - AncillaryLocationDiscriminants::CloudStorage, - ) => format!("uri: \"{}\"", uri), + .enumerate() + .map(|(index, location)| match location { + AncillaryLocation::CloudStorage { uri } => { + vec![ + format!("{location_name} ({})", index + 1).cell(), + format!("CloudStorage, uri: \"{}\"", uri).cell(), + ] + } }) - .collect::>() - .join(","); - - if uris.is_empty() { - None - } else { - Some(vec![ - "Ancillary location".to_string().cell(), - format!( - "{:?}, {}", - AncillaryLocationDiscriminants::CloudStorage, - uris - ) - .cell(), - ]) - } + .collect() } #[cfg(test)] @@ -234,18 +183,14 @@ mod tests { use super::*; #[test] - fn digest_location_row_returns_none_when_no_uri_found_for_location_type() { - let locations = vec![DigestLocation::Aggregator { - uri: "http://aggregator.net/".to_string(), - }]; - - let row = digest_location_row(123, DigestLocationDiscriminants::CloudStorage, &locations); + fn digest_location_rows_when_no_uri_found() { + let rows = digest_location_rows(&[]); - assert!(row.is_none()); + assert!(rows.is_empty()); } #[test] - fn digest_location_row_returns_some_when_uri_found_for_location_type() { + fn digest_location_rows_when_uris_found() { let locations = vec![ DigestLocation::Aggregator { uri: "http://aggregator.net/".to_string(), @@ -255,47 +200,77 @@ mod tests { }, ]; - let row = digest_location_row(123, DigestLocationDiscriminants::CloudStorage, &locations); - assert!(row.is_some()); + let rows = digest_location_rows(&locations); + assert!(rows.len() == 2); - let row = digest_location_row(456, DigestLocationDiscriminants::Aggregator, &locations); - assert!(row.is_some()); + let table = rows.table(); + let rows_rendered = table.display().unwrap().to_string(); + + assert!(rows_rendered.contains("Digest location (1)")); + assert!(rows_rendered.contains("CloudStorage, uri: \"http://cloudstorage.com/\"")); + assert!(rows_rendered.contains("Digest location (2)")); + assert!(rows_rendered.contains("Aggregator, uri: \"http://aggregator.net/\"")); } #[test] - fn immutables_location_row_returns_none_when_no_uri_found_for_location_type() { - let row = immutables_location_row(ImmutablesLocationDiscriminants::CloudStorage, &[]); + fn immutables_location_rows_when_no_uri_found() { + let rows = immutables_location_rows(&[]); - assert!(row.is_none()); + assert!(rows.is_empty()); } #[test] - fn immutables_location_row_returns_some_when_uri_found_for_location_type() { - let locations = vec![ImmutablesLocation::CloudStorage { - uri: MultiFilesUri::Template(TemplateUri("http://cloudstorage.com/".to_string())), - }]; + fn immutables_location_row_returns_some_when_uri_found() { + let locations = vec![ + ImmutablesLocation::CloudStorage { + uri: MultiFilesUri::Template(TemplateUri("http://cloudstorage1.com/".to_string())), + }, + ImmutablesLocation::CloudStorage { + uri: MultiFilesUri::Template(TemplateUri("http://cloudstorage2.com/".to_string())), + }, + ]; + + let rows = immutables_location_rows(&locations); + + assert!(rows.len() == 2); - let row = - immutables_location_row(ImmutablesLocationDiscriminants::CloudStorage, &locations); + let table = rows.table(); + let rows_rendered = table.display().unwrap().to_string(); - assert!(row.is_some()); + assert!(rows_rendered.contains("Immutables location (1)")); + assert!(rows_rendered.contains("CloudStorage, template_uri: \"http://cloudstorage1.com/\"")); + assert!(rows_rendered.contains("Immutables location (2)")); + assert!(rows_rendered.contains("CloudStorage, template_uri: \"http://cloudstorage2.com/\"")); } #[test] - fn ancillary_location_row_returns_none_when_no_uri_found_for_location_type() { - let row = ancillary_location_row(AncillaryLocationDiscriminants::CloudStorage, &[]); + fn ancillary_location_rows_when_no_uri_found() { + let rows = ancillary_location_rows(&[]); - assert!(row.is_none()); + assert!(rows.is_empty()); } #[test] - fn ancillary_location_row_returns_some_when_uri_found_for_location_type() { - let locations = vec![AncillaryLocation::CloudStorage { - uri: "http://cloudstorage.com/".to_string(), - }]; + fn ancillary_location_rows_when_uris_found() { + let locations = vec![ + AncillaryLocation::CloudStorage { + uri: "http://cloudstorage1.com/".to_string(), + }, + AncillaryLocation::CloudStorage { + uri: "http://cloudstorage2.com/".to_string(), + }, + ]; + + let rows = ancillary_location_rows(&locations); + + assert!(rows.len() == 2); - let row = ancillary_location_row(AncillaryLocationDiscriminants::CloudStorage, &locations); + let table = rows.table(); + let rows_rendered = table.display().unwrap().to_string(); - assert!(row.is_some()); + assert!(rows_rendered.contains("Ancillary location (1)")); + assert!(rows_rendered.contains("CloudStorage, uri: \"http://cloudstorage1.com/\"")); + assert!(rows_rendered.contains("Ancillary location (2)")); + assert!(rows_rendered.contains("CloudStorage, uri: \"http://cloudstorage2.com/\"")); } } diff --git a/mithril-client/src/type_alias.rs b/mithril-client/src/type_alias.rs index b1b90b66b9e..15722afb584 100644 --- a/mithril-client/src/type_alias.rs +++ b/mithril-client/src/type_alias.rs @@ -68,10 +68,9 @@ pub use mithril_common::messages::CardanoStakeDistributionListItemMessage as Car /// `mithril-common` re-exports pub mod common { pub use mithril_common::entities::{ - AncillaryLocationDiscriminants, BlockHash, BlockNumber, CardanoDbBeacon, ChainPoint, - CompressionAlgorithm, DigestLocationDiscriminants, Epoch, ImmutableFileNumber, - ImmutablesLocationDiscriminants, ProtocolMessage, ProtocolMessagePartKey, - ProtocolParameters, SlotNumber, StakeDistribution, TransactionHash, + BlockHash, BlockNumber, CardanoDbBeacon, ChainPoint, CompressionAlgorithm, Epoch, + ImmutableFileNumber, ProtocolMessage, ProtocolMessagePartKey, ProtocolParameters, + SlotNumber, StakeDistribution, TransactionHash, }; cfg_unstable! { pub use mithril_common::entities::{ diff --git a/mithril-common/src/entities/cardano_database.rs b/mithril-common/src/entities/cardano_database.rs index 24bfb9c5ea1..9c6fe2254a4 100644 --- a/mithril-common/src/entities/cardano_database.rs +++ b/mithril-common/src/entities/cardano_database.rs @@ -1,7 +1,6 @@ use semver::Version; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; -use strum::EnumDiscriminants; use crate::{ entities::{CardanoDbBeacon, CompressionAlgorithm}, @@ -71,9 +70,7 @@ impl CardanoDatabaseSnapshot { } /// Locations of the immutable file digests. -#[derive( - Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, EnumDiscriminants, -)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] #[serde(rename_all = "snake_case", tag = "type")] pub enum DigestLocation { /// Aggregator digest route location. @@ -89,9 +86,7 @@ pub enum DigestLocation { } /// Locations of the immutable files. -#[derive( - Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, EnumDiscriminants, -)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] #[serde(rename_all = "snake_case", tag = "type")] pub enum ImmutablesLocation { /// Cloud storage location. @@ -102,9 +97,7 @@ pub enum ImmutablesLocation { } /// Locations of the ancillary files. -#[derive( - Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, EnumDiscriminants, -)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] #[serde(rename_all = "snake_case", tag = "type")] pub enum AncillaryLocation { /// Cloud storage location. diff --git a/mithril-common/src/entities/mod.rs b/mithril-common/src/entities/mod.rs index 5223a4b8b25..a7b5d7ae8d2 100644 --- a/mithril-common/src/entities/mod.rs +++ b/mithril-common/src/entities/mod.rs @@ -35,9 +35,8 @@ pub use block_number::BlockNumber; pub use block_range::{BlockRange, BlockRangeLength, BlockRangesSequence}; pub use cardano_chain_point::{BlockHash, ChainPoint}; pub use cardano_database::{ - AncillaryLocation, AncillaryLocationDiscriminants, ArtifactsLocations, CardanoDatabaseSnapshot, - DigestLocation, DigestLocationDiscriminants, ImmutablesLocation, - ImmutablesLocationDiscriminants, + AncillaryLocation, ArtifactsLocations, CardanoDatabaseSnapshot, DigestLocation, + ImmutablesLocation, }; pub use cardano_db_beacon::CardanoDbBeacon; pub use cardano_network::CardanoNetwork; From 25a9fdea9d444e1ba33ddec813cfa8a4a6a9808d Mon Sep 17 00:00:00 2001 From: Damien Lachaume <135982616+dlachaume@users.noreply.github.com> Date: Mon, 3 Feb 2025 14:46:52 +0100 Subject: [PATCH 9/9] chore: upgrade crate versions * mithril-client-cli from `0.10.8` to `0.10.9` * mithril-common from `0.4.110` to `0.4.111` * mithril-end-to-end from `0.4.65` to `0.4.66` --- Cargo.lock | 6 +++--- mithril-client-cli/Cargo.toml | 2 +- mithril-common/Cargo.toml | 2 +- mithril-test-lab/mithril-end-to-end/Cargo.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 155b3bc3b1a..cfd7c828183 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3689,7 +3689,7 @@ dependencies = [ [[package]] name = "mithril-client-cli" -version = "0.10.8" +version = "0.10.9" dependencies = [ "anyhow", "async-trait", @@ -3735,7 +3735,7 @@ dependencies = [ [[package]] name = "mithril-common" -version = "0.4.110" +version = "0.4.111" dependencies = [ "anyhow", "async-trait", @@ -3806,7 +3806,7 @@ dependencies = [ [[package]] name = "mithril-end-to-end" -version = "0.4.65" +version = "0.4.66" dependencies = [ "anyhow", "async-recursion", diff --git a/mithril-client-cli/Cargo.toml b/mithril-client-cli/Cargo.toml index b9d9a8daf41..658a9582058 100644 --- a/mithril-client-cli/Cargo.toml +++ b/mithril-client-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-client-cli" -version = "0.10.8" +version = "0.10.9" description = "A Mithril Client" authors = { workspace = true } edition = { workspace = true } diff --git a/mithril-common/Cargo.toml b/mithril-common/Cargo.toml index 5883447db92..b5bac28424f 100644 --- a/mithril-common/Cargo.toml +++ b/mithril-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-common" -version = "0.4.110" +version = "0.4.111" description = "Common types, interfaces, and utilities for Mithril nodes." authors = { workspace = true } edition = { workspace = true } diff --git a/mithril-test-lab/mithril-end-to-end/Cargo.toml b/mithril-test-lab/mithril-end-to-end/Cargo.toml index 5a02bf7325d..0526e9146f8 100644 --- a/mithril-test-lab/mithril-end-to-end/Cargo.toml +++ b/mithril-test-lab/mithril-end-to-end/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-end-to-end" -version = "0.4.65" +version = "0.4.66" authors = { workspace = true } edition = { workspace = true } documentation = { workspace = true }