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