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;
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")] logger: Logger,
54 ) -> Self {
55 #[cfg(feature = "fs")]
56 let logger =
57 mithril_common::logging::LoggerExtensions::new_with_component_name::<Self>(&logger);
58 Self {
59 artifact_retriever: InternalArtifactRetriever::new(aggregator_client.clone()),
60 #[cfg(feature = "fs")]
61 artifact_downloader: InternalArtifactDownloader::new(
62 http_file_downloader.clone(),
63 ancillary_verifier,
64 feedback_sender.clone(),
65 logger.clone(),
66 ),
67 #[cfg(feature = "fs")]
68 artifact_prover: InternalArtifactProver::new(
69 http_file_downloader.clone(),
70 logger.clone(),
71 ),
72 statistics_sender: InternalStatisticsSender::new(aggregator_client.clone()),
73 }
74 }
75
76 pub async fn list(&self) -> MithrilResult<Vec<CardanoDatabaseSnapshotListItem>> {
78 self.artifact_retriever.list().await
79 }
80
81 pub async fn get(&self, hash: &str) -> MithrilResult<Option<CardanoDatabaseSnapshot>> {
83 self.artifact_retriever.get(hash).await
84 }
85
86 #[cfg(feature = "fs")]
88 pub async fn download_unpack(
89 &self,
90 cardano_database_snapshot: &CardanoDatabaseSnapshotMessage,
91 immutable_file_range: &ImmutableFileRange,
92 target_dir: &Path,
93 download_unpack_options: DownloadUnpackOptions,
94 ) -> MithrilResult<()> {
95 self.artifact_downloader
96 .download_unpack(
97 cardano_database_snapshot,
98 immutable_file_range,
99 target_dir,
100 download_unpack_options,
101 )
102 .await
103 }
104
105 #[cfg(feature = "fs")]
107 pub async fn download_and_verify_digests(
108 &self,
109 certificate: &CertificateMessage,
110 cardano_database_snapshot: &CardanoDatabaseSnapshotMessage,
111 ) -> MithrilResult<VerifiedDigests> {
112 self.artifact_prover
113 .download_and_verify_digests(certificate, cardano_database_snapshot)
114 .await
115 }
116
117 #[cfg(feature = "fs")]
119 pub async fn verify_cardano_database(
120 &self,
121 certificate: &CertificateMessage,
122 cardano_database_snapshot: &CardanoDatabaseSnapshotMessage,
123 immutable_file_range: &ImmutableFileRange,
124 allow_missing: bool,
125 database_dir: &Path,
126 verified_digests: &VerifiedDigests,
127 ) -> Result<MKProof, CardanoDatabaseVerificationError> {
128 self.artifact_prover
129 .verify_cardano_database(
130 certificate,
131 cardano_database_snapshot,
132 immutable_file_range,
133 allow_missing,
134 database_dir,
135 verified_digests,
136 )
137 .await
138 }
139
140 #[cfg(feature = "fs")]
142 pub fn check_has_immutables(&self, database_dir: &Path) -> MithrilResult<()> {
143 ImmutableFile::at_least_one_immutable_files_exist_in_dir(database_dir)?;
144 Ok(())
145 }
146
147 pub async fn add_statistics(
149 &self,
150 full_restoration: bool,
151 include_ancillary: bool,
152 number_of_immutable_files_restored: u64,
153 ) -> MithrilResult<()> {
154 self.statistics_sender
155 .add_statistics(
156 full_restoration,
157 include_ancillary,
158 number_of_immutable_files_restored,
159 )
160 .await
161 }
162}
163
164#[cfg(test)]
165pub(crate) mod test_dependency_injector {
166 use super::*;
167
168 #[cfg(feature = "fs")]
169 use mithril_common::crypto_helper::ManifestVerifierVerificationKey;
170
171 use crate::aggregator_client::MockAggregatorClient;
172 #[cfg(feature = "fs")]
173 use crate::file_downloader::{FileDownloader, MockFileDownloaderBuilder};
174 #[cfg(feature = "fs")]
175 use crate::{feedback::FeedbackReceiver, test_utils::TestLogger};
176
177 pub(crate) struct CardanoDatabaseClientDependencyInjector {
179 aggregator_client: MockAggregatorClient,
180 #[cfg(feature = "fs")]
181 http_file_downloader: Arc<dyn FileDownloader>,
182 #[cfg(feature = "fs")]
183 ancillary_verifier: Option<Arc<AncillaryVerifier>>,
184 #[cfg(feature = "fs")]
185 feedback_receivers: Vec<Arc<dyn FeedbackReceiver>>,
186 #[cfg(feature = "fs")]
187 logger: Logger,
188 }
189
190 impl CardanoDatabaseClientDependencyInjector {
191 pub(crate) fn new() -> Self {
192 Self {
193 aggregator_client: MockAggregatorClient::new(),
194 #[cfg(feature = "fs")]
195 http_file_downloader: Arc::new(
196 MockFileDownloaderBuilder::default()
197 .with_compression(None)
198 .with_success()
199 .with_times(0)
200 .build(),
201 ),
202 #[cfg(feature = "fs")]
203 ancillary_verifier: None,
204 #[cfg(feature = "fs")]
205 feedback_receivers: vec![],
206 #[cfg(feature = "fs")]
207 logger: TestLogger::stdout(),
208 }
209 }
210
211 #[cfg(feature = "fs")]
212 pub(crate) fn with_logger(self, logger: Logger) -> Self {
213 #[cfg(feature = "fs")]
214 Self { logger, ..self }
215 }
216
217 pub(crate) fn with_aggregator_client_mock_config<F>(mut self, config: F) -> Self
218 where
219 F: FnOnce(&mut MockAggregatorClient),
220 {
221 config(&mut self.aggregator_client);
222
223 self
224 }
225
226 #[cfg(feature = "fs")]
227 pub(crate) fn with_http_file_downloader(
228 self,
229 http_file_downloader: Arc<dyn FileDownloader>,
230 ) -> Self {
231 Self {
232 http_file_downloader,
233 ..self
234 }
235 }
236
237 #[cfg(feature = "fs")]
238 pub(crate) fn with_ancillary_verifier<T>(self, ancillary_verification_key: T) -> Self
239 where
240 T: TryInto<ManifestVerifierVerificationKey>,
241 T::Error: std::fmt::Debug,
242 {
243 Self {
244 ancillary_verifier: Some(Arc::new(AncillaryVerifier::new(
245 ancillary_verification_key.try_into().unwrap(),
246 ))),
247 ..self
248 }
249 }
250
251 #[cfg(feature = "fs")]
252 pub(crate) fn with_feedback_receivers(
253 self,
254 feedback_receivers: &[Arc<dyn FeedbackReceiver>],
255 ) -> Self {
256 Self {
257 feedback_receivers: feedback_receivers.to_vec(),
258 ..self
259 }
260 }
261
262 #[cfg(feature = "fs")]
263 pub(crate) fn build_cardano_database_client(self) -> CardanoDatabaseClient {
264 CardanoDatabaseClient::new(
265 Arc::new(self.aggregator_client),
266 self.http_file_downloader,
267 self.ancillary_verifier,
268 FeedbackSender::new(&self.feedback_receivers),
269 self.logger,
270 )
271 }
272
273 #[cfg(not(feature = "fs"))]
274 pub(crate) fn build_cardano_database_client(self) -> CardanoDatabaseClient {
275 CardanoDatabaseClient::new(Arc::new(self.aggregator_client))
276 }
277 }
278
279 mod tests {
280 use mithril_common::test::double::Dummy;
281 use mockall::predicate;
282
283 use crate::aggregator_client::AggregatorRequest;
284 #[cfg(feature = "fs")]
285 use crate::feedback::StackFeedbackReceiver;
286
287 use super::*;
288
289 #[cfg(feature = "fs")]
290 #[test]
291 fn test_cardano_database_client_dependency_injector_builds() {
292 let _ = CardanoDatabaseClientDependencyInjector::new()
293 .with_aggregator_client_mock_config(|http_client| {
294 let message = vec![CardanoDatabaseSnapshotListItem {
295 hash: "hash-123".to_string(),
296 ..CardanoDatabaseSnapshotListItem::dummy()
297 }];
298 http_client
299 .expect_get_content()
300 .with(predicate::eq(
301 AggregatorRequest::ListCardanoDatabaseSnapshots,
302 ))
303 .return_once(move |_| Ok(serde_json::to_string(&message).unwrap()));
304 })
305 .with_http_file_downloader(Arc::new(
306 MockFileDownloaderBuilder::default()
307 .with_success()
308 .with_times(0)
309 .build(),
310 ))
311 .with_feedback_receivers(&[Arc::new(StackFeedbackReceiver::new())])
312 .build_cardano_database_client();
313 }
314
315 #[cfg(not(feature = "fs"))]
316 #[test]
317 fn test_cardano_database_client_dependency_injector_builds() {
318 let _ = CardanoDatabaseClientDependencyInjector::new()
319 .with_aggregator_client_mock_config(|http_client| {
320 let message = vec![CardanoDatabaseSnapshotListItem {
321 hash: "hash-123".to_string(),
322 ..CardanoDatabaseSnapshotListItem::dummy()
323 }];
324 http_client
325 .expect_get_content()
326 .with(predicate::eq(
327 AggregatorRequest::ListCardanoDatabaseSnapshots,
328 ))
329 .return_once(move |_| Ok(serde_json::to_string(&message).unwrap()));
330 })
331 .build_cardano_database_client();
332 }
333 }
334}