mithril_client/cardano_database_client/
api.rs1#[cfg(feature = "fs")]
2use std::path::Path;
3use std::sync::Arc;
4
5#[cfg(feature = "fs")]
6use slog::Logger;
7
8#[cfg(feature = "fs")]
9use mithril_common::{
10 crypto_helper::MKProof,
11 messages::{CardanoDatabaseSnapshotMessage, CertificateMessage},
12};
13
14#[cfg(feature = "fs")]
15use mithril_cardano_node_internal_database::entities::ImmutableFile;
16
17use crate::aggregator_client::AggregatorClient;
18#[cfg(feature = "fs")]
19use crate::cardano_database_client::{VerifiedDigests, proving::CardanoDatabaseVerificationError};
20#[cfg(feature = "fs")]
21use crate::feedback::FeedbackSender;
22#[cfg(feature = "fs")]
23use crate::file_downloader::FileDownloader;
24#[cfg(feature = "fs")]
25use crate::utils::{AncillaryVerifier, TempDirectoryProvider};
26use crate::{CardanoDatabaseSnapshot, CardanoDatabaseSnapshotListItem, MithrilResult};
27
28use super::fetch::InternalArtifactRetriever;
29use super::statistics::InternalStatisticsSender;
30#[cfg(feature = "fs")]
31use super::{
32 DownloadUnpackOptions, ImmutableFileRange, download_unpack::InternalArtifactDownloader,
33 proving::InternalArtifactProver,
34};
35
36pub struct CardanoDatabaseClient {
38 pub(super) artifact_retriever: InternalArtifactRetriever,
39 #[cfg(feature = "fs")]
40 pub(super) artifact_downloader: InternalArtifactDownloader,
41 #[cfg(feature = "fs")]
42 pub(super) artifact_prover: InternalArtifactProver,
43 pub(super) statistics_sender: InternalStatisticsSender,
44}
45
46impl CardanoDatabaseClient {
47 pub fn new(
49 aggregator_client: Arc<dyn AggregatorClient>,
50 #[cfg(feature = "fs")] http_file_downloader: Arc<dyn FileDownloader>,
51 #[cfg(feature = "fs")] ancillary_verifier: Option<Arc<AncillaryVerifier>>,
52 #[cfg(feature = "fs")] feedback_sender: FeedbackSender,
53 #[cfg(feature = "fs")] temp_directory_provider: Arc<dyn TempDirectoryProvider>,
54 #[cfg(feature = "fs")] logger: Logger,
55 ) -> Self {
56 #[cfg(feature = "fs")]
57 let logger =
58 mithril_common::logging::LoggerExtensions::new_with_component_name::<Self>(&logger);
59 Self {
60 artifact_retriever: InternalArtifactRetriever::new(aggregator_client.clone()),
61 #[cfg(feature = "fs")]
62 artifact_downloader: InternalArtifactDownloader::new(
63 http_file_downloader.clone(),
64 ancillary_verifier,
65 feedback_sender.clone(),
66 logger.clone(),
67 ),
68 #[cfg(feature = "fs")]
69 artifact_prover: InternalArtifactProver::new(
70 http_file_downloader.clone(),
71 temp_directory_provider.clone(),
72 logger.clone(),
73 ),
74 statistics_sender: InternalStatisticsSender::new(aggregator_client.clone()),
75 }
76 }
77
78 pub async fn list(&self) -> MithrilResult<Vec<CardanoDatabaseSnapshotListItem>> {
80 self.artifact_retriever.list().await
81 }
82
83 pub async fn get(&self, hash: &str) -> MithrilResult<Option<CardanoDatabaseSnapshot>> {
85 self.artifact_retriever.get(hash).await
86 }
87
88 #[cfg(feature = "fs")]
90 pub async fn download_unpack(
91 &self,
92 cardano_database_snapshot: &CardanoDatabaseSnapshotMessage,
93 immutable_file_range: &ImmutableFileRange,
94 target_dir: &Path,
95 download_unpack_options: DownloadUnpackOptions,
96 ) -> MithrilResult<()> {
97 self.artifact_downloader
98 .download_unpack(
99 cardano_database_snapshot,
100 immutable_file_range,
101 target_dir,
102 download_unpack_options,
103 )
104 .await
105 }
106
107 #[cfg(feature = "fs")]
109 pub async fn download_and_verify_digests(
110 &self,
111 certificate: &CertificateMessage,
112 cardano_database_snapshot: &CardanoDatabaseSnapshotMessage,
113 ) -> MithrilResult<VerifiedDigests> {
114 self.artifact_prover
115 .download_and_verify_digests(certificate, cardano_database_snapshot)
116 .await
117 }
118
119 #[cfg(feature = "fs")]
121 pub async fn verify_cardano_database(
122 &self,
123 certificate: &CertificateMessage,
124 cardano_database_snapshot: &CardanoDatabaseSnapshotMessage,
125 immutable_file_range: &ImmutableFileRange,
126 allow_missing: bool,
127 database_dir: &Path,
128 verified_digests: &VerifiedDigests,
129 ) -> Result<MKProof, CardanoDatabaseVerificationError> {
130 self.artifact_prover
131 .verify_cardano_database(
132 certificate,
133 cardano_database_snapshot,
134 immutable_file_range,
135 allow_missing,
136 database_dir,
137 verified_digests,
138 )
139 .await
140 }
141
142 #[cfg(feature = "fs")]
144 pub fn check_has_immutables(&self, database_dir: &Path) -> MithrilResult<()> {
145 ImmutableFile::at_least_one_immutable_files_exist_in_dir(database_dir)?;
146 Ok(())
147 }
148
149 pub async fn add_statistics(
151 &self,
152 full_restoration: bool,
153 include_ancillary: bool,
154 number_of_immutable_files_restored: u64,
155 ) -> MithrilResult<()> {
156 self.statistics_sender
157 .add_statistics(
158 full_restoration,
159 include_ancillary,
160 number_of_immutable_files_restored,
161 )
162 .await
163 }
164}
165
166#[cfg(test)]
167pub(crate) mod test_dependency_injector {
168 use super::*;
169
170 #[cfg(feature = "fs")]
171 use mithril_common::crypto_helper::ManifestVerifierVerificationKey;
172
173 use crate::aggregator_client::MockAggregatorClient;
174 #[cfg(feature = "fs")]
175 use crate::file_downloader::{FileDownloader, MockFileDownloaderBuilder};
176 #[cfg(feature = "fs")]
177 use crate::utils::TimestampTempDirectoryProvider;
178 #[cfg(feature = "fs")]
179 use crate::{feedback::FeedbackReceiver, test_utils::TestLogger};
180
181 pub(crate) struct CardanoDatabaseClientDependencyInjector {
183 aggregator_client: MockAggregatorClient,
184 #[cfg(feature = "fs")]
185 http_file_downloader: Arc<dyn FileDownloader>,
186 #[cfg(feature = "fs")]
187 ancillary_verifier: Option<Arc<AncillaryVerifier>>,
188 #[cfg(feature = "fs")]
189 feedback_receivers: Vec<Arc<dyn FeedbackReceiver>>,
190 #[cfg(feature = "fs")]
191 temp_directory_provider: Arc<dyn TempDirectoryProvider>,
192 #[cfg(feature = "fs")]
193 logger: Logger,
194 }
195
196 impl CardanoDatabaseClientDependencyInjector {
197 pub(crate) fn new() -> Self {
198 Self {
199 aggregator_client: MockAggregatorClient::new(),
200 #[cfg(feature = "fs")]
201 http_file_downloader: Arc::new(
202 MockFileDownloaderBuilder::default()
203 .with_compression(None)
204 .with_success()
205 .with_times(0)
206 .build(),
207 ),
208 #[cfg(feature = "fs")]
209 ancillary_verifier: None,
210 #[cfg(feature = "fs")]
211 feedback_receivers: vec![],
212 #[cfg(feature = "fs")]
213 temp_directory_provider: Arc::new(TimestampTempDirectoryProvider::new(
214 "cardano_database_client_test",
215 )),
216 #[cfg(feature = "fs")]
217 logger: TestLogger::stdout(),
218 }
219 }
220
221 #[cfg(feature = "fs")]
222 pub(crate) fn with_logger(self, logger: Logger) -> Self {
223 #[cfg(feature = "fs")]
224 Self { logger, ..self }
225 }
226
227 pub(crate) fn with_aggregator_client_mock_config<F>(mut self, config: F) -> Self
228 where
229 F: FnOnce(&mut MockAggregatorClient),
230 {
231 config(&mut self.aggregator_client);
232
233 self
234 }
235
236 #[cfg(feature = "fs")]
237 pub(crate) fn with_http_file_downloader(
238 self,
239 http_file_downloader: Arc<dyn FileDownloader>,
240 ) -> Self {
241 Self {
242 http_file_downloader,
243 ..self
244 }
245 }
246
247 #[cfg(feature = "fs")]
248 pub(crate) fn with_ancillary_verifier<T>(self, ancillary_verification_key: T) -> Self
249 where
250 T: TryInto<ManifestVerifierVerificationKey>,
251 T::Error: std::fmt::Debug,
252 {
253 Self {
254 ancillary_verifier: Some(Arc::new(AncillaryVerifier::new(
255 ancillary_verification_key.try_into().unwrap(),
256 ))),
257 ..self
258 }
259 }
260
261 #[cfg(feature = "fs")]
262 pub(crate) fn with_feedback_receivers(
263 self,
264 feedback_receivers: &[Arc<dyn FeedbackReceiver>],
265 ) -> Self {
266 Self {
267 feedback_receivers: feedback_receivers.to_vec(),
268 ..self
269 }
270 }
271
272 #[cfg(feature = "fs")]
273 pub(crate) fn with_temp_directory_provider(
274 self,
275 temp_directory_provider: Arc<dyn TempDirectoryProvider>,
276 ) -> Self {
277 Self {
278 temp_directory_provider,
279 ..self
280 }
281 }
282
283 #[cfg(feature = "fs")]
284 pub(crate) fn build_cardano_database_client(self) -> CardanoDatabaseClient {
285 CardanoDatabaseClient::new(
286 Arc::new(self.aggregator_client),
287 self.http_file_downloader,
288 self.ancillary_verifier,
289 FeedbackSender::new(&self.feedback_receivers),
290 self.temp_directory_provider,
291 self.logger,
292 )
293 }
294
295 #[cfg(not(feature = "fs"))]
296 pub(crate) fn build_cardano_database_client(self) -> CardanoDatabaseClient {
297 CardanoDatabaseClient::new(Arc::new(self.aggregator_client))
298 }
299 }
300
301 mod tests {
302 use mithril_common::test::double::Dummy;
303 use mockall::predicate;
304
305 use crate::aggregator_client::AggregatorRequest;
306 #[cfg(feature = "fs")]
307 use crate::feedback::StackFeedbackReceiver;
308
309 use super::*;
310
311 #[cfg(feature = "fs")]
312 #[test]
313 fn test_cardano_database_client_dependency_injector_builds() {
314 let _ = CardanoDatabaseClientDependencyInjector::new()
315 .with_aggregator_client_mock_config(|http_client| {
316 let message = vec![CardanoDatabaseSnapshotListItem {
317 hash: "hash-123".to_string(),
318 ..CardanoDatabaseSnapshotListItem::dummy()
319 }];
320 http_client
321 .expect_get_content()
322 .with(predicate::eq(
323 AggregatorRequest::ListCardanoDatabaseSnapshots,
324 ))
325 .return_once(move |_| Ok(serde_json::to_string(&message).unwrap()));
326 })
327 .with_http_file_downloader(Arc::new(
328 MockFileDownloaderBuilder::default()
329 .with_success()
330 .with_times(0)
331 .build(),
332 ))
333 .with_feedback_receivers(&[Arc::new(StackFeedbackReceiver::new())])
334 .build_cardano_database_client();
335 }
336
337 #[cfg(not(feature = "fs"))]
338 #[test]
339 fn test_cardano_database_client_dependency_injector_builds() {
340 let _ = CardanoDatabaseClientDependencyInjector::new()
341 .with_aggregator_client_mock_config(|http_client| {
342 let message = vec![CardanoDatabaseSnapshotListItem {
343 hash: "hash-123".to_string(),
344 ..CardanoDatabaseSnapshotListItem::dummy()
345 }];
346 http_client
347 .expect_get_content()
348 .with(predicate::eq(
349 AggregatorRequest::ListCardanoDatabaseSnapshots,
350 ))
351 .return_once(move |_| Ok(serde_json::to_string(&message).unwrap()));
352 })
353 .build_cardano_database_client();
354 }
355 }
356}