diff --git a/Cargo.lock b/Cargo.lock index c1bab7e3fd9..a35d5e4ac63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4172,7 +4172,7 @@ dependencies = [ [[package]] name = "mithril-client" -version = "0.12.30" +version = "0.12.31" dependencies = [ "anyhow", "async-recursion", diff --git a/mithril-client/Cargo.toml b/mithril-client/Cargo.toml index 90e68e1fc51..6b6a68dd30d 100644 --- a/mithril-client/Cargo.toml +++ b/mithril-client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-client" -version = "0.12.30" +version = "0.12.31" description = "Mithril client library" authors = { workspace = true } edition = { workspace = true } diff --git a/mithril-client/src/cardano_database_client/api.rs b/mithril-client/src/cardano_database_client/api.rs index 57419b02e69..673abfb0fb2 100644 --- a/mithril-client/src/cardano_database_client/api.rs +++ b/mithril-client/src/cardano_database_client/api.rs @@ -22,7 +22,7 @@ use crate::feedback::FeedbackSender; #[cfg(feature = "fs")] use crate::file_downloader::FileDownloader; #[cfg(feature = "fs")] -use crate::utils::AncillaryVerifier; +use crate::utils::{AncillaryVerifier, TempDirectoryProvider}; use crate::{CardanoDatabaseSnapshot, CardanoDatabaseSnapshotListItem, MithrilResult}; use super::fetch::InternalArtifactRetriever; @@ -50,6 +50,7 @@ impl CardanoDatabaseClient { #[cfg(feature = "fs")] http_file_downloader: Arc, #[cfg(feature = "fs")] ancillary_verifier: Option>, #[cfg(feature = "fs")] feedback_sender: FeedbackSender, + #[cfg(feature = "fs")] temp_directory_provider: Arc, #[cfg(feature = "fs")] logger: Logger, ) -> Self { #[cfg(feature = "fs")] @@ -67,6 +68,7 @@ impl CardanoDatabaseClient { #[cfg(feature = "fs")] artifact_prover: InternalArtifactProver::new( http_file_downloader.clone(), + temp_directory_provider.clone(), logger.clone(), ), statistics_sender: InternalStatisticsSender::new(aggregator_client.clone()), @@ -172,6 +174,8 @@ pub(crate) mod test_dependency_injector { #[cfg(feature = "fs")] use crate::file_downloader::{FileDownloader, MockFileDownloaderBuilder}; #[cfg(feature = "fs")] + use crate::utils::TimestampTempDirectoryProvider; + #[cfg(feature = "fs")] use crate::{feedback::FeedbackReceiver, test_utils::TestLogger}; /// Dependency injector for `CardanoDatabaseClient` for testing purposes. @@ -184,6 +188,8 @@ pub(crate) mod test_dependency_injector { #[cfg(feature = "fs")] feedback_receivers: Vec>, #[cfg(feature = "fs")] + temp_directory_provider: Arc, + #[cfg(feature = "fs")] logger: Logger, } @@ -204,6 +210,10 @@ pub(crate) mod test_dependency_injector { #[cfg(feature = "fs")] feedback_receivers: vec![], #[cfg(feature = "fs")] + temp_directory_provider: Arc::new(TimestampTempDirectoryProvider::new( + "cardano_database_client_test", + )), + #[cfg(feature = "fs")] logger: TestLogger::stdout(), } } @@ -259,6 +269,17 @@ pub(crate) mod test_dependency_injector { } } + #[cfg(feature = "fs")] + pub(crate) fn with_temp_directory_provider( + self, + temp_directory_provider: Arc, + ) -> Self { + Self { + temp_directory_provider, + ..self + } + } + #[cfg(feature = "fs")] pub(crate) fn build_cardano_database_client(self) -> CardanoDatabaseClient { CardanoDatabaseClient::new( @@ -266,6 +287,7 @@ pub(crate) mod test_dependency_injector { self.http_file_downloader, self.ancillary_verifier, FeedbackSender::new(&self.feedback_receivers), + self.temp_directory_provider, self.logger, ) } diff --git a/mithril-client/src/cardano_database_client/proving.rs b/mithril-client/src/cardano_database_client/proving.rs index 7e93020ec5c..8d78909f8f0 100644 --- a/mithril-client/src/cardano_database_client/proving.rs +++ b/mithril-client/src/cardano_database_client/proving.rs @@ -32,7 +32,10 @@ use crate::{ cardano_database_client::ImmutableFileRange, feedback::MithrilEvent, file_downloader::{DownloadEvent, FileDownloader, FileDownloaderUri}, - utils::{create_directory_if_not_exists, delete_directory, read_files_in_directory}, + utils::{ + TempDirectoryProvider, create_directory_if_not_exists, delete_directory, + read_files_in_directory, + }, }; /// Represents the verified digests and the Merkle tree built from them. @@ -185,14 +188,20 @@ impl VerifiedDigests { pub struct InternalArtifactProver { http_file_downloader: Arc, + temp_directory_provider: Arc, logger: slog::Logger, } impl InternalArtifactProver { /// Constructs a new `InternalArtifactProver`. - pub fn new(http_file_downloader: Arc, logger: slog::Logger) -> Self { + pub fn new( + http_file_downloader: Arc, + temp_directory_provider: Arc, + logger: slog::Logger, + ) -> Self { Self { http_file_downloader, + temp_directory_provider, logger, } } @@ -223,7 +232,7 @@ impl InternalArtifactProver { certificate: &CertificateMessage, cardano_database_snapshot: &CardanoDatabaseSnapshotMessage, ) -> MithrilResult { - let digest_target_dir = Self::digest_target_dir(); + let digest_target_dir = self.digest_target_dir(); delete_directory(&digest_target_dir)?; self.download_unpack_digest_file(&cardano_database_snapshot.digests, &digest_target_dir) .await?; @@ -423,8 +432,8 @@ impl InternalArtifactProver { Ok(digest_map) } - fn digest_target_dir() -> PathBuf { - std::env::temp_dir().join("mithril_digest") + fn digest_target_dir(&self) -> PathBuf { + self.temp_directory_provider.temp_dir() } } @@ -437,6 +446,7 @@ mod tests { use std::sync::Arc; use mithril_common::{ + current_function, entities::{CardanoDbBeacon, Epoch, HexEncodedDigest}, messages::CardanoDatabaseDigestListItemMessage, test::{TempDir, double::Dummy}, @@ -445,6 +455,7 @@ mod tests { use crate::{ cardano_database_client::CardanoDatabaseClientDependencyInjector, file_downloader::MockFileDownloaderBuilder, test_utils::TestLogger, + utils::TimestampTempDirectoryProvider, }; use super::*; @@ -561,11 +572,13 @@ mod tests { mod download_and_verify_digests { use mithril_common::{ - StdResult, + StdResult, current_function, entities::{ProtocolMessage, ProtocolMessagePartKey}, messages::DigestsMessagePart, }; + use crate::utils::TimestampTempDirectoryProvider; + use super::*; fn write_digest_file( @@ -610,7 +623,7 @@ mod tests { } #[tokio::test] - async fn download_and_verify_digest_should_return_digest_map_acording_to_beacon() { + async fn download_and_verify_digest_should_return_digest_map_according_to_beacon() { let beacon = CardanoDbBeacon { epoch: Epoch(123), immutable_file_number: 42, @@ -650,22 +663,28 @@ mod tests { }, ..CardanoDatabaseSnapshotMessage::dummy() }; + let temp_directory_provider = + Arc::new(TimestampTempDirectoryProvider::new(current_function!())); + let digest_target_dir = temp_directory_provider.temp_dir(); + let digest_target_dir_clone = digest_target_dir.clone(); + let http_file_downloader = Arc::new( + MockFileDownloaderBuilder::default() + .with_file_uri(digests_location) + .with_target_dir(digest_target_dir.clone()) + .with_compression(None) + .with_returning(Box::new(move |_, _, _, _, _| { + write_digest_file( + &digest_target_dir_clone, + &build_digests_map(hightest_immutable_number_in_digest_file), + )?; + + Ok(()) + })) + .build(), + ); let client = CardanoDatabaseClientDependencyInjector::new() - .with_http_file_downloader(Arc::new( - MockFileDownloaderBuilder::default() - .with_file_uri(digests_location) - .with_target_dir(InternalArtifactProver::digest_target_dir()) - .with_compression(None) - .with_returning(Box::new(move |_, _, _, _, _| { - write_digest_file( - &InternalArtifactProver::digest_target_dir(), - &build_digests_map(hightest_immutable_number_in_digest_file), - )?; - - Ok(()) - })) - .build(), - )) + .with_http_file_downloader(http_file_downloader) + .with_temp_directory_provider(temp_directory_provider) .build_cardano_database_client(); let verified_digests = client @@ -681,7 +700,7 @@ mod tests { .collect(); assert_eq!(verified_digests.digests, expected_digests_in_certificate); - assert!(!InternalArtifactProver::digest_target_dir().exists()); + assert!(!digest_target_dir.exists()); } } @@ -704,6 +723,7 @@ mod tests { .with_times(2) .build(), ), + Arc::new(TimestampTempDirectoryProvider::new(current_function!())), TestLogger::stdout(), ); @@ -732,6 +752,7 @@ mod tests { let target_dir = Path::new("."); let artifact_prover = InternalArtifactProver::new( Arc::new(MockFileDownloader::new()), + Arc::new(TimestampTempDirectoryProvider::new(current_function!())), TestLogger::stdout(), ); @@ -760,6 +781,7 @@ mod tests { .with_success() .build(), ), + Arc::new(TimestampTempDirectoryProvider::new(current_function!())), TestLogger::stdout(), ); @@ -794,6 +816,7 @@ mod tests { .with_success() .build(), ), + Arc::new(TimestampTempDirectoryProvider::new(current_function!())), TestLogger::stdout(), ); @@ -828,6 +851,7 @@ mod tests { .with_success() .build(), ), + Arc::new(TimestampTempDirectoryProvider::new(current_function!())), TestLogger::stdout(), ); @@ -884,6 +908,7 @@ mod tests { .with_success() .build(), ), + Arc::new(TimestampTempDirectoryProvider::new(current_function!())), TestLogger::stdout(), ); artifact_prover @@ -907,6 +932,7 @@ mod tests { .with_success() .build(), ), + Arc::new(TimestampTempDirectoryProvider::new(current_function!())), TestLogger::stdout(), ); artifact_prover @@ -929,6 +955,7 @@ mod tests { .with_success() .build(), ), + Arc::new(TimestampTempDirectoryProvider::new(current_function!())), TestLogger::stdout(), ); artifact_prover @@ -961,6 +988,7 @@ mod tests { .with_success() .build(), ), + Arc::new(TimestampTempDirectoryProvider::new(current_function!())), TestLogger::stdout(), ); diff --git a/mithril-client/src/client.rs b/mithril-client/src/client.rs index d450de3a3ca..e61e6f7b515 100644 --- a/mithril-client/src/client.rs +++ b/mithril-client/src/client.rs @@ -1,4 +1,6 @@ use anyhow::{Context, anyhow}; +#[cfg(feature = "fs")] +use chrono::Utc; use reqwest::Url; use serde::{Deserialize, Serialize}; use slog::{Logger, o}; @@ -28,6 +30,8 @@ use crate::mithril_stake_distribution_client::MithrilStakeDistributionClient; use crate::snapshot_client::SnapshotClient; #[cfg(feature = "fs")] use crate::utils::AncillaryVerifier; +#[cfg(feature = "fs")] +use crate::utils::TimestampTempDirectoryProvider; const DEFAULT_CLIENT_TYPE: &str = "LIBRARY"; @@ -312,6 +316,11 @@ impl ClientBuilder { #[cfg(feature = "fs")] feedback_sender, #[cfg(feature = "fs")] + Arc::new(TimestampTempDirectoryProvider::new(&format!( + "{}", + Utc::now().timestamp_micros() + ))), + #[cfg(feature = "fs")] logger, )); diff --git a/mithril-client/src/utils/mod.rs b/mithril-client/src/utils/mod.rs index b7392f3f6c8..dc39b65e1c7 100644 --- a/mithril-client/src/utils/mod.rs +++ b/mithril-client/src/utils/mod.rs @@ -2,19 +2,21 @@ //! This module contains tools needed mostly for the snapshot download and unpack. cfg_fs! { - pub const ANCILLARIES_NOT_SIGNED_BY_MITHRIL:&str = "Ancillary verification does not use the Mithril certification: as a mitigation, IOG owned keys are used to sign these files."; + pub const ANCILLARIES_NOT_SIGNED_BY_MITHRIL: &str = "Ancillary verification does not use the Mithril certification: as a mitigation, IOG owned keys are used to sign these files."; mod ancillary_verifier; + mod bootstrap_files; mod fs; mod stream_reader; - mod bootstrap_files; + mod temp_dir_provider; mod unexpected_downloaded_file_verifier; mod vec_deque_extensions; - pub use fs::*; - pub use vec_deque_extensions::VecDequeExtensions; pub use ancillary_verifier::AncillaryVerifier; - pub(crate) use unexpected_downloaded_file_verifier::*; - pub use stream_reader::*; pub use bootstrap_files::*; + pub use fs::*; + pub use stream_reader::*; + pub(crate) use temp_dir_provider::{TempDirectoryProvider, TimestampTempDirectoryProvider}; + pub(crate) use unexpected_downloaded_file_verifier::*; + pub use vec_deque_extensions::VecDequeExtensions; } diff --git a/mithril-client/src/utils/temp_dir_provider.rs b/mithril-client/src/utils/temp_dir_provider.rs new file mode 100644 index 00000000000..3b6ab14b395 --- /dev/null +++ b/mithril-client/src/utils/temp_dir_provider.rs @@ -0,0 +1,31 @@ +use chrono::Utc; +use std::path::PathBuf; + +/// Trait to provide a temporary directory path +#[cfg_attr(test, mockall::automock)] +pub trait TempDirectoryProvider: Send + Sync { + /// Provides a temporary directory path + fn temp_dir(&self) -> PathBuf; +} + +/// Timestamp based temporary directory provider implementation +pub struct TimestampTempDirectoryProvider { + temp_dir: PathBuf, +} + +impl TimestampTempDirectoryProvider { + /// Constructs a new `TimestampTempDirectoryProvider`. + pub fn new(prefix: &str) -> Self { + let temp_dir = std::env::temp_dir().join(format!( + "mithril_client_{prefix}_{}", + Utc::now().timestamp_micros() + )); + Self { temp_dir } + } +} + +impl TempDirectoryProvider for TimestampTempDirectoryProvider { + fn temp_dir(&self) -> PathBuf { + self.temp_dir.clone() + } +}