1use std::collections::BTreeSet;
4use std::sync::Arc;
5
6use async_trait::async_trait;
7
8use mithril_common::{
9 entities::{Epoch, SignedEntityTypeDiscriminants},
10 messages::{
11 CardanoDatabaseDigestListItemMessage, CardanoDatabaseDigestListMessage,
12 CardanoDatabaseSnapshotListMessage, CardanoDatabaseSnapshotMessage,
13 CardanoStakeDistributionListMessage, CardanoStakeDistributionMessage,
14 CardanoTransactionSnapshotListMessage, CardanoTransactionSnapshotMessage,
15 CertificateListMessage, CertificateMessage, EpochSettingsMessage,
16 MithrilStakeDistributionListMessage, MithrilStakeDistributionMessage, SignerMessagePart,
17 SnapshotListMessage, SnapshotMessage,
18 },
19 StdResult,
20};
21
22use crate::{
23 database::repository::{CertificateRepository, SignedEntityStorer},
24 dependency_injection::EpochServiceWrapper,
25 ImmutableFileDigestMapper,
26};
27
28#[cfg_attr(test, mockall::automock)]
30#[async_trait]
31pub trait MessageService: Sync + Send {
32 async fn get_epoch_settings_message(
34 &self,
35 allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
36 ) -> StdResult<EpochSettingsMessage>;
37
38 async fn get_certificate_message(
40 &self,
41 certificate_hash: &str,
42 ) -> StdResult<Option<CertificateMessage>>;
43
44 async fn get_latest_genesis_certificate_message(&self)
46 -> StdResult<Option<CertificateMessage>>;
47
48 async fn get_certificate_list_message(&self, limit: usize)
50 -> StdResult<CertificateListMessage>;
51
52 async fn get_snapshot_message(
54 &self,
55 signed_entity_id: &str,
56 ) -> StdResult<Option<SnapshotMessage>>;
57
58 async fn get_snapshot_list_message(&self, limit: usize) -> StdResult<SnapshotListMessage>;
61
62 async fn get_cardano_database_message(
64 &self,
65 signed_entity_id: &str,
66 ) -> StdResult<Option<CardanoDatabaseSnapshotMessage>>;
67
68 async fn get_cardano_database_list_message(
70 &self,
71 limit: usize,
72 ) -> StdResult<CardanoDatabaseSnapshotListMessage>;
73
74 async fn get_cardano_database_digest_list_message(
76 &self,
77 ) -> StdResult<CardanoDatabaseDigestListMessage>;
78
79 async fn get_mithril_stake_distribution_message(
81 &self,
82 signed_entity_id: &str,
83 ) -> StdResult<Option<MithrilStakeDistributionMessage>>;
84
85 async fn get_mithril_stake_distribution_list_message(
87 &self,
88 limit: usize,
89 ) -> StdResult<MithrilStakeDistributionListMessage>;
90
91 async fn get_cardano_transaction_message(
93 &self,
94 signed_entity_id: &str,
95 ) -> StdResult<Option<CardanoTransactionSnapshotMessage>>;
96
97 async fn get_cardano_transaction_list_message(
99 &self,
100 limit: usize,
101 ) -> StdResult<CardanoTransactionSnapshotListMessage>;
102
103 async fn get_cardano_stake_distribution_message(
105 &self,
106 signed_entity_id: &str,
107 ) -> StdResult<Option<CardanoStakeDistributionMessage>>;
108
109 async fn get_cardano_stake_distribution_message_by_epoch(
111 &self,
112 epoch: Epoch,
113 ) -> StdResult<Option<CardanoStakeDistributionMessage>>;
114
115 async fn get_cardano_stake_distribution_list_message(
117 &self,
118 limit: usize,
119 ) -> StdResult<CardanoStakeDistributionListMessage>;
120}
121
122pub struct MithrilMessageService {
124 certificate_repository: Arc<CertificateRepository>,
125 signed_entity_storer: Arc<dyn SignedEntityStorer>,
126 immutable_file_digest_mapper: Arc<dyn ImmutableFileDigestMapper>,
127 epoch_service: EpochServiceWrapper,
128}
129
130impl MithrilMessageService {
131 pub fn new(
133 certificate_repository: Arc<CertificateRepository>,
134 signed_entity_storer: Arc<dyn SignedEntityStorer>,
135 immutable_file_digest_mapper: Arc<dyn ImmutableFileDigestMapper>,
136 epoch_service: EpochServiceWrapper,
137 ) -> Self {
138 Self {
139 certificate_repository,
140 signed_entity_storer,
141 immutable_file_digest_mapper,
142 epoch_service,
143 }
144 }
145}
146
147#[async_trait]
148impl MessageService for MithrilMessageService {
149 async fn get_epoch_settings_message(
150 &self,
151 allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
152 ) -> StdResult<EpochSettingsMessage> {
153 let epoch_service = self.epoch_service.read().await;
154
155 let epoch = epoch_service.epoch_of_current_data()?;
156 let signer_registration_protocol_parameters = epoch_service
157 .signer_registration_protocol_parameters()?
158 .clone();
159 let current_signers = epoch_service.current_signers()?;
160 let next_signers = epoch_service.next_signers()?;
161
162 let cardano_transactions_discriminant =
163 allowed_discriminants.get(&SignedEntityTypeDiscriminants::CardanoTransactions);
164
165 let cardano_transactions_signing_config = cardano_transactions_discriminant
166 .map(|_| epoch_service.current_cardano_transactions_signing_config())
167 .transpose()?
168 .cloned();
169 let next_cardano_transactions_signing_config = cardano_transactions_discriminant
170 .map(|_| epoch_service.next_cardano_transactions_signing_config())
171 .transpose()?
172 .cloned();
173
174 let epoch_settings_message = EpochSettingsMessage {
175 epoch,
176 signer_registration_protocol_parameters,
177 current_signers: SignerMessagePart::from_signers(current_signers.to_vec()),
178 next_signers: SignerMessagePart::from_signers(next_signers.to_vec()),
179 cardano_transactions_signing_config,
180 next_cardano_transactions_signing_config,
181 };
182
183 Ok(epoch_settings_message)
184 }
185
186 async fn get_certificate_message(
187 &self,
188 certificate_hash: &str,
189 ) -> StdResult<Option<CertificateMessage>> {
190 self.certificate_repository
191 .get_certificate(certificate_hash)
192 .await
193 }
194
195 async fn get_latest_genesis_certificate_message(
196 &self,
197 ) -> StdResult<Option<CertificateMessage>> {
198 self.certificate_repository
199 .get_latest_genesis_certificate()
200 .await
201 }
202
203 async fn get_certificate_list_message(
204 &self,
205 limit: usize,
206 ) -> StdResult<CertificateListMessage> {
207 self.certificate_repository
208 .get_latest_certificates(limit)
209 .await
210 }
211
212 async fn get_snapshot_message(
213 &self,
214 signed_entity_id: &str,
215 ) -> StdResult<Option<SnapshotMessage>> {
216 let signed_entity = self
217 .signed_entity_storer
218 .get_signed_entity(signed_entity_id)
219 .await?;
220
221 signed_entity.map(|s| s.try_into()).transpose()
222 }
223
224 async fn get_snapshot_list_message(&self, limit: usize) -> StdResult<SnapshotListMessage> {
225 let signed_entity_type_id = SignedEntityTypeDiscriminants::CardanoImmutableFilesFull;
226 let entities = self
227 .signed_entity_storer
228 .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
229 .await?;
230
231 entities.into_iter().map(|i| i.try_into()).collect()
232 }
233
234 async fn get_cardano_database_message(
235 &self,
236 signed_entity_id: &str,
237 ) -> StdResult<Option<CardanoDatabaseSnapshotMessage>> {
238 let signed_entity = self
239 .signed_entity_storer
240 .get_signed_entity(signed_entity_id)
241 .await?;
242
243 signed_entity.map(|v| v.try_into()).transpose()
244 }
245
246 async fn get_cardano_database_list_message(
247 &self,
248 limit: usize,
249 ) -> StdResult<CardanoDatabaseSnapshotListMessage> {
250 let signed_entity_type_id = SignedEntityTypeDiscriminants::CardanoDatabase;
251 let entities = self
252 .signed_entity_storer
253 .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
254 .await?;
255
256 entities.into_iter().map(|i| i.try_into()).collect()
257 }
258
259 async fn get_cardano_database_digest_list_message(
260 &self,
261 ) -> StdResult<CardanoDatabaseDigestListMessage> {
262 Ok(self
263 .immutable_file_digest_mapper
264 .get_immutable_file_digest_map()
265 .await?
266 .into_iter()
267 .map(
268 |(immutable_file_name, digest)| CardanoDatabaseDigestListItemMessage {
269 immutable_file_name,
270 digest,
271 },
272 )
273 .collect::<Vec<_>>())
274 }
275
276 async fn get_mithril_stake_distribution_message(
277 &self,
278 signed_entity_id: &str,
279 ) -> StdResult<Option<MithrilStakeDistributionMessage>> {
280 let signed_entity = self
281 .signed_entity_storer
282 .get_signed_entity(signed_entity_id)
283 .await?;
284
285 signed_entity.map(|v| v.try_into()).transpose()
286 }
287
288 async fn get_mithril_stake_distribution_list_message(
289 &self,
290 limit: usize,
291 ) -> StdResult<MithrilStakeDistributionListMessage> {
292 let signed_entity_type_id = SignedEntityTypeDiscriminants::MithrilStakeDistribution;
293 let entities = self
294 .signed_entity_storer
295 .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
296 .await?;
297
298 entities.into_iter().map(|i| i.try_into()).collect()
299 }
300
301 async fn get_cardano_transaction_message(
302 &self,
303 signed_entity_id: &str,
304 ) -> StdResult<Option<CardanoTransactionSnapshotMessage>> {
305 let signed_entity = self
306 .signed_entity_storer
307 .get_signed_entity(signed_entity_id)
308 .await?;
309
310 signed_entity.map(|v| v.try_into()).transpose()
311 }
312
313 async fn get_cardano_transaction_list_message(
314 &self,
315 limit: usize,
316 ) -> StdResult<CardanoTransactionSnapshotListMessage> {
317 let signed_entity_type_id = SignedEntityTypeDiscriminants::CardanoTransactions;
318 let entities = self
319 .signed_entity_storer
320 .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
321 .await?;
322
323 entities.into_iter().map(|i| i.try_into()).collect()
324 }
325
326 async fn get_cardano_stake_distribution_message(
327 &self,
328 signed_entity_id: &str,
329 ) -> StdResult<Option<CardanoStakeDistributionMessage>> {
330 let signed_entity = self
331 .signed_entity_storer
332 .get_signed_entity(signed_entity_id)
333 .await?;
334
335 signed_entity.map(|v| v.try_into()).transpose()
336 }
337
338 async fn get_cardano_stake_distribution_message_by_epoch(
339 &self,
340 epoch: Epoch,
341 ) -> StdResult<Option<CardanoStakeDistributionMessage>> {
342 let signed_entity = self
343 .signed_entity_storer
344 .get_cardano_stake_distribution_signed_entity_by_epoch(epoch)
345 .await?;
346
347 signed_entity.map(|v| v.try_into()).transpose()
348 }
349
350 async fn get_cardano_stake_distribution_list_message(
351 &self,
352 limit: usize,
353 ) -> StdResult<CardanoStakeDistributionListMessage> {
354 let signed_entity_type_id = SignedEntityTypeDiscriminants::CardanoStakeDistribution;
355 let entities = self
356 .signed_entity_storer
357 .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
358 .await?;
359
360 entities.into_iter().map(|i| i.try_into()).collect()
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use mithril_common::entities::{BlockNumber, Certificate, SignedEntityType};
367 use mithril_common::test_utils::fake_data;
368 use tokio::sync::RwLock;
369
370 use crate::database::record::SignedEntityRecord;
371 use crate::database::repository::{ImmutableFileDigestRepository, SignedEntityStore};
372 use crate::database::test_helper::main_db_connection;
373 use crate::services::FakeEpochService;
374
375 use super::*;
376
377 struct MessageServiceBuilder {
378 certificates: Vec<Certificate>,
379 signed_entity_records: Vec<SignedEntityRecord>,
380 immutable_file_digest_messages: Vec<CardanoDatabaseDigestListItemMessage>,
381 epoch_service: Option<FakeEpochService>,
382 }
383
384 impl MessageServiceBuilder {
385 fn new() -> Self {
386 Self {
387 certificates: Vec::new(),
388 signed_entity_records: Vec::new(),
389 immutable_file_digest_messages: Vec::new(),
390 epoch_service: None,
391 }
392 }
393
394 fn with_certificates(mut self, certificates: &[Certificate]) -> Self {
395 self.certificates.extend_from_slice(certificates);
396
397 self
398 }
399
400 fn with_signed_entity_records(
401 mut self,
402 signed_entity_record: &[SignedEntityRecord],
403 ) -> Self {
404 self.signed_entity_records
405 .extend_from_slice(signed_entity_record);
406
407 self
408 }
409
410 fn with_immutable_file_digest_messages(
411 mut self,
412 digests: &[CardanoDatabaseDigestListItemMessage],
413 ) -> Self {
414 self.immutable_file_digest_messages
415 .extend_from_slice(digests);
416
417 self
418 }
419
420 fn with_epoch_service(mut self, epoch_service: FakeEpochService) -> Self {
421 self.epoch_service = Some(epoch_service);
422
423 self
424 }
425
426 async fn build(self) -> MithrilMessageService {
427 let connection = Arc::new(main_db_connection().unwrap());
428 let certificate_repository = CertificateRepository::new(connection.clone());
429 let signed_entity_store = SignedEntityStore::new(connection.clone());
430 let immutable_file_digest_mapper =
431 ImmutableFileDigestRepository::new(connection.clone());
432 let epoch_service = self
433 .epoch_service
434 .unwrap_or(FakeEpochService::without_data());
435
436 certificate_repository
437 .create_many_certificates(self.certificates)
438 .await
439 .unwrap();
440 for record in self.signed_entity_records {
441 signed_entity_store
442 .store_signed_entity(&record)
443 .await
444 .unwrap();
445 }
446
447 for digest_message in self.immutable_file_digest_messages {
448 immutable_file_digest_mapper
449 .upsert_immutable_file_digest(
450 &digest_message.immutable_file_name,
451 &digest_message.digest,
452 )
453 .await
454 .unwrap();
455 }
456
457 MithrilMessageService::new(
458 Arc::new(certificate_repository),
459 Arc::new(signed_entity_store),
460 Arc::new(immutable_file_digest_mapper),
461 Arc::new(RwLock::new(epoch_service)),
462 )
463 }
464 }
465
466 mod epoch_settings {
467 use mithril_common::{
468 entities::{CardanoTransactionsSigningConfig, ProtocolParameters},
469 test_utils::MithrilFixtureBuilder,
470 };
471
472 use crate::{entities::AggregatorEpochSettings, services::FakeEpochServiceBuilder};
473
474 use super::*;
475
476 #[tokio::test]
477 async fn get_epoch_settings_message() {
478 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
479 let epoch_service = FakeEpochService::from_fixture(Epoch(4), &fixture);
480 let message_service = MessageServiceBuilder::new()
481 .with_epoch_service(epoch_service)
482 .build()
483 .await;
484
485 let message = message_service
486 .get_epoch_settings_message(SignedEntityTypeDiscriminants::all())
487 .await
488 .unwrap();
489
490 assert_eq!(message.epoch, Epoch(4));
491 assert_eq!(
492 message.signer_registration_protocol_parameters,
493 ProtocolParameters::new(5, 100, 0.65)
494 );
495 assert_eq!(message.current_signers.len(), 3);
496 assert_eq!(message.next_signers.len(), 3);
497 assert_eq!(
498 message.cardano_transactions_signing_config,
499 Some(CardanoTransactionsSigningConfig::new(
500 BlockNumber(0),
501 BlockNumber(15)
502 ))
503 );
504 assert_eq!(
505 message.next_cardano_transactions_signing_config,
506 Some(CardanoTransactionsSigningConfig::new(
507 BlockNumber(0),
508 BlockNumber(15)
509 ))
510 );
511 }
512
513 #[tokio::test]
514 async fn get_epoch_settings_message_with_cardano_transactions_enabled() {
515 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
516 let epoch_service = FakeEpochService::from_fixture(Epoch(4), &fixture);
517 let message_service = MessageServiceBuilder::new()
518 .with_epoch_service(epoch_service)
519 .build()
520 .await;
521
522 let message = message_service
523 .get_epoch_settings_message(BTreeSet::from([
524 SignedEntityTypeDiscriminants::CardanoTransactions,
525 ]))
526 .await
527 .unwrap();
528
529 assert!(message.cardano_transactions_signing_config.is_some());
530 assert!(message.next_cardano_transactions_signing_config.is_some(),);
531 }
532
533 #[tokio::test]
534 async fn get_epoch_settings_message_with_cardano_transactions_not_enabled() {
535 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
536 let epoch_service = FakeEpochService::from_fixture(Epoch(4), &fixture);
537 let message_service = MessageServiceBuilder::new()
538 .with_epoch_service(epoch_service)
539 .build()
540 .await;
541
542 let message = message_service
543 .get_epoch_settings_message(BTreeSet::new())
544 .await
545 .unwrap();
546
547 assert_eq!(message.cardano_transactions_signing_config, None);
548 assert_eq!(message.next_cardano_transactions_signing_config, None);
549 }
550
551 #[tokio::test]
552 async fn get_epoch_settings_message_retrieves_protocol_parameters_from_epoch_service() {
553 let current_epoch_settings = AggregatorEpochSettings {
554 protocol_parameters: ProtocolParameters::new(101, 10, 0.5),
555 ..AggregatorEpochSettings::dummy()
556 };
557 let next_epoch_settings = AggregatorEpochSettings {
558 protocol_parameters: ProtocolParameters::new(102, 20, 0.5),
559 ..AggregatorEpochSettings::dummy()
560 };
561 let signer_registration_epoch_settings = AggregatorEpochSettings {
562 protocol_parameters: ProtocolParameters::new(103, 30, 0.5),
563 ..AggregatorEpochSettings::dummy()
564 };
565 let epoch_service = FakeEpochServiceBuilder {
566 current_epoch_settings,
567 next_epoch_settings: next_epoch_settings.clone(),
568 signer_registration_epoch_settings: signer_registration_epoch_settings.clone(),
569 current_signers_with_stake: fake_data::signers_with_stakes(5),
570 next_signers_with_stake: fake_data::signers_with_stakes(3),
571 ..FakeEpochServiceBuilder::dummy(Epoch(1))
572 }
573 .build();
574 let message_service = MessageServiceBuilder::new()
575 .with_epoch_service(epoch_service)
576 .build()
577 .await;
578
579 let message = message_service
580 .get_epoch_settings_message(SignedEntityTypeDiscriminants::all())
581 .await
582 .unwrap();
583
584 assert_eq!(
585 message.signer_registration_protocol_parameters,
586 signer_registration_epoch_settings.protocol_parameters
587 );
588 }
589
590 #[tokio::test]
591 async fn get_epoch_settings_message_retrieves_signing_configuration_from_epoch_service() {
592 let current_epoch_settings = AggregatorEpochSettings {
593 cardano_transactions_signing_config: CardanoTransactionsSigningConfig::new(
594 BlockNumber(100),
595 BlockNumber(15),
596 ),
597 ..AggregatorEpochSettings::dummy()
598 };
599 let next_epoch_settings = AggregatorEpochSettings {
600 cardano_transactions_signing_config: CardanoTransactionsSigningConfig::new(
601 BlockNumber(200),
602 BlockNumber(15),
603 ),
604 ..AggregatorEpochSettings::dummy()
605 };
606 let epoch_service = FakeEpochServiceBuilder {
607 current_epoch_settings: current_epoch_settings.clone(),
608 next_epoch_settings: next_epoch_settings.clone(),
609 signer_registration_epoch_settings: AggregatorEpochSettings::dummy(),
610 current_signers_with_stake: fake_data::signers_with_stakes(5),
611 next_signers_with_stake: fake_data::signers_with_stakes(3),
612 ..FakeEpochServiceBuilder::dummy(Epoch(1))
613 }
614 .build();
615 let message_service = MessageServiceBuilder::new()
616 .with_epoch_service(epoch_service)
617 .build()
618 .await;
619
620 let message = message_service
621 .get_epoch_settings_message(SignedEntityTypeDiscriminants::all())
622 .await
623 .unwrap();
624
625 assert_eq!(
626 message.cardano_transactions_signing_config,
627 Some(current_epoch_settings.cardano_transactions_signing_config),
628 );
629 assert_eq!(
630 message.next_cardano_transactions_signing_config,
631 Some(next_epoch_settings.cardano_transactions_signing_config),
632 );
633 }
634 }
635
636 mod certificate {
637 use super::*;
638
639 #[tokio::test]
640 async fn get_no_certificate() {
641 let service = MessageServiceBuilder::new().build().await;
642
643 let certificate_hash = "whatever";
644 let certificate_message = service
645 .get_certificate_message(certificate_hash)
646 .await
647 .unwrap();
648 assert!(certificate_message.is_none());
649 }
650
651 #[tokio::test]
652 async fn get_certificate() {
653 let genesis_certificate = fake_data::genesis_certificate("genesis_hash");
654 let service = MessageServiceBuilder::new()
655 .with_certificates(&[genesis_certificate.clone()])
656 .build()
657 .await;
658
659 let certificate_message = service
660 .get_certificate_message(&genesis_certificate.hash)
661 .await
662 .unwrap()
663 .expect("There should be a certificate.");
664 assert_eq!(genesis_certificate.hash, certificate_message.hash);
665 }
666
667 #[tokio::test]
668 async fn get_no_latest_genesis_certificate() {
669 let service = MessageServiceBuilder::new().build().await;
670
671 let certificate_message = service
672 .get_latest_genesis_certificate_message()
673 .await
674 .unwrap();
675 assert_eq!(None, certificate_message);
676 }
677
678 #[tokio::test]
679 async fn get_latest_genesis_certificate() {
680 let certificates = [
681 fake_data::genesis_certificate("certificate_1"),
682 fake_data::genesis_certificate("certificate_2"),
683 fake_data::certificate("certificate_3"),
684 ];
685 let last_genesis_hash = certificates[1].hash.clone();
686 let service = MessageServiceBuilder::new()
687 .with_certificates(&certificates)
688 .build()
689 .await;
690
691 let certificate_message = service
692 .get_latest_genesis_certificate_message()
693 .await
694 .unwrap()
695 .expect("There should be a genesis certificate.");
696 assert_eq!(last_genesis_hash, certificate_message.hash);
697 }
698
699 #[tokio::test]
700 async fn get_last_certificates() {
701 let certificates = [
702 fake_data::genesis_certificate("certificate_1"),
703 fake_data::genesis_certificate("certificate_2"),
704 ];
705 let last_certificate_hash = certificates[1].hash.clone();
706 let service = MessageServiceBuilder::new()
707 .with_certificates(&certificates)
708 .build()
709 .await;
710
711 let certificate_messages = service.get_certificate_list_message(5).await.unwrap();
712
713 assert_eq!(2, certificate_messages.len());
714 assert_eq!(last_certificate_hash, certificate_messages[0].hash);
715 }
716 }
717
718 mod snapshot {
719 use super::*;
720
721 #[tokio::test]
722 async fn get_snapshot_not_exist() {
723 let service = MessageServiceBuilder::new().build().await;
724 let snapshot = service.get_snapshot_message("whatever").await.unwrap();
725
726 assert!(snapshot.is_none());
727 }
728
729 #[tokio::test]
730 async fn get_snapshot() {
731 let record = SignedEntityRecord {
732 signed_entity_id: "signed_entity_id".to_string(),
733 signed_entity_type: SignedEntityType::CardanoImmutableFilesFull(fake_data::beacon()),
734 certificate_id: "cert_id".to_string(),
735 artifact: serde_json::to_string(&fake_data::snapshots(1)[0]).unwrap(),
736 created_at: Default::default(),
737 };
738 let message: SnapshotMessage = record.clone().try_into().unwrap();
739
740 let service = MessageServiceBuilder::new()
741 .with_signed_entity_records(&[record.clone()])
742 .build()
743 .await;
744
745 let response = service
746 .get_snapshot_message(&record.signed_entity_id)
747 .await
748 .unwrap()
749 .expect("A SnapshotMessage was expected.");
750
751 assert_eq!(message, response);
752 }
753
754 #[tokio::test]
755 async fn get_snapshot_list_message() {
756 let records = vec![
757 SignedEntityRecord {
758 signed_entity_id: "signed_entity_id-1".to_string(),
759 signed_entity_type: SignedEntityType::CardanoImmutableFilesFull(
760 fake_data::beacon(),
761 ),
762 certificate_id: "cert_id-1".to_string(),
763 artifact: serde_json::to_string(&fake_data::snapshots(1)[0]).unwrap(),
764 created_at: Default::default(),
765 },
766 SignedEntityRecord {
767 signed_entity_id: "signed_entity_id-2".to_string(),
768 signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
769 certificate_id: "cert_id-2".to_string(),
770 artifact: serde_json::to_string(&fake_data::cardano_database_snapshots(1)[0])
771 .unwrap(),
772 created_at: Default::default(),
773 },
774 ];
775 let message: SnapshotListMessage = vec![records[0].clone().try_into().unwrap()];
776
777 let service = MessageServiceBuilder::new()
778 .with_signed_entity_records(&records)
779 .build()
780 .await;
781
782 let response = service.get_snapshot_list_message(0).await.unwrap();
783 assert!(response.is_empty());
784
785 let response = service.get_snapshot_list_message(3).await.unwrap();
786 assert_eq!(message, response);
787 }
788 }
789
790 mod cardano_database {
791 use super::*;
792
793 #[tokio::test]
794 async fn get_cardano_database_when_record_does_not_exist() {
795 let service = MessageServiceBuilder::new().build().await;
796 let snapshot = service
797 .get_cardano_database_message("whatever")
798 .await
799 .unwrap();
800
801 assert!(snapshot.is_none());
802 }
803
804 #[tokio::test]
805 async fn get_cardano_database() {
806 let record = SignedEntityRecord {
807 signed_entity_id: "signed_entity_id".to_string(),
808 signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
809 certificate_id: "cert_id".to_string(),
810 artifact: serde_json::to_string(&fake_data::cardano_database_snapshots(1)[0])
811 .unwrap(),
812 created_at: Default::default(),
813 };
814 let message: CardanoDatabaseSnapshotMessage = record.clone().try_into().unwrap();
815
816 let service = MessageServiceBuilder::new()
817 .with_signed_entity_records(&[record.clone()])
818 .build()
819 .await;
820
821 let response = service
822 .get_cardano_database_message(&record.signed_entity_id)
823 .await
824 .unwrap()
825 .expect("A CardanoDatabaseSnapshotMessage was expected.");
826
827 assert_eq!(message, response);
828 }
829
830 #[tokio::test]
831 async fn get_cardano_database_list_message() {
832 let records = vec![
833 SignedEntityRecord {
834 signed_entity_id: "signed_entity_id-1".to_string(),
835 signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
836 certificate_id: "cert_id-1".to_string(),
837 artifact: serde_json::to_string(&fake_data::cardano_database_snapshots(1)[0])
838 .unwrap(),
839 created_at: Default::default(),
840 },
841 SignedEntityRecord {
842 signed_entity_id: "signed_entity_id-2".to_string(),
843 signed_entity_type: SignedEntityType::CardanoImmutableFilesFull(
844 fake_data::beacon(),
845 ),
846 certificate_id: "cert_id-2".to_string(),
847 artifact: serde_json::to_string(&fake_data::snapshots(1)[0]).unwrap(),
848 created_at: Default::default(),
849 },
850 ];
851 let message: CardanoDatabaseSnapshotListMessage =
852 vec![records[0].clone().try_into().unwrap()];
853
854 let service = MessageServiceBuilder::new()
855 .with_signed_entity_records(&records)
856 .build()
857 .await;
858
859 let response = service.get_cardano_database_list_message(0).await.unwrap();
860 assert!(response.is_empty());
861
862 let response = service.get_cardano_database_list_message(3).await.unwrap();
863 assert_eq!(message, response);
864 }
865
866 #[tokio::test]
867 async fn get_cardano_database_digest_list_message() {
868 let messages: CardanoDatabaseDigestListMessage = vec![
869 CardanoDatabaseDigestListItemMessage {
870 immutable_file_name: "06685.chunk".to_string(),
871 digest: "0af556ab2620dd9363bf76963a231abe8948a500ea6be31b131d87907ab09b1e"
872 .to_string(),
873 },
874 CardanoDatabaseDigestListItemMessage {
875 immutable_file_name: "06685.primary".to_string(),
876 digest: "32dfd6b722d87f253e78eb8b478fb94f1e13463826e674d6ec7b6bf0892b2e39"
877 .to_string(),
878 },
879 ];
880
881 let service = MessageServiceBuilder::new()
882 .with_immutable_file_digest_messages(&messages)
883 .build()
884 .await;
885
886 let response = service
887 .get_cardano_database_digest_list_message()
888 .await
889 .unwrap();
890
891 assert_eq!(messages, response);
892 }
893 }
894
895 mod mithril_stake_distribution {
896 use super::*;
897
898 #[tokio::test]
899 async fn get_mithril_stake_distribution() {
900 let record = SignedEntityRecord {
901 signed_entity_id: "signed_entity_id".to_string(),
902 signed_entity_type: SignedEntityType::MithrilStakeDistribution(Epoch(18)),
903 certificate_id: "cert_id".to_string(),
904 artifact: serde_json::to_string(&fake_data::mithril_stake_distributions(1)[0])
905 .unwrap(),
906 created_at: Default::default(),
907 };
908 let message: MithrilStakeDistributionMessage = record.clone().try_into().unwrap();
909
910 let service = MessageServiceBuilder::new()
911 .with_signed_entity_records(&[record.clone()])
912 .build()
913 .await;
914
915 let response = service
916 .get_mithril_stake_distribution_message(&record.signed_entity_id)
917 .await
918 .unwrap()
919 .expect("A MithrilStakeDistributionMessage was expected.");
920
921 assert_eq!(message, response);
922 }
923
924 #[tokio::test]
925 async fn get_mithril_stake_distribution_not_exist() {
926 let service = MessageServiceBuilder::new().build().await;
927
928 let response = service
929 .get_mithril_stake_distribution_message("whatever")
930 .await
931 .unwrap();
932
933 assert!(response.is_none());
934 }
935
936 #[tokio::test]
937 async fn get_mithril_stake_distribution_list_message() {
938 let records = vec![
939 SignedEntityRecord {
940 signed_entity_id: "signed_entity_id-1".to_string(),
941 signed_entity_type: SignedEntityType::MithrilStakeDistribution(Epoch(18)),
942 certificate_id: "cert_id-1".to_string(),
943 artifact: serde_json::to_string(&fake_data::mithril_stake_distributions(1)[0])
944 .unwrap(),
945 created_at: Default::default(),
946 },
947 SignedEntityRecord {
948 signed_entity_id: "signed_entity_id-2".to_string(),
949 signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
950 certificate_id: "cert_id-2".to_string(),
951 artifact: serde_json::to_string(&fake_data::cardano_database_snapshots(1)[0])
952 .unwrap(),
953 created_at: Default::default(),
954 },
955 ];
956 let message: MithrilStakeDistributionListMessage =
957 vec![records[0].clone().try_into().unwrap()];
958
959 let service = MessageServiceBuilder::new()
960 .with_signed_entity_records(&records)
961 .build()
962 .await;
963
964 let response = service
965 .get_mithril_stake_distribution_list_message(0)
966 .await
967 .unwrap();
968 assert!(response.is_empty());
969
970 let response = service
971 .get_mithril_stake_distribution_list_message(3)
972 .await
973 .unwrap();
974 assert_eq!(message, response);
975 }
976 }
977
978 mod cardano_transaction {
979 use super::*;
980
981 #[tokio::test]
982 async fn get_cardano_transaction() {
983 let record = SignedEntityRecord {
984 signed_entity_id: "signed_entity_id".to_string(),
985 signed_entity_type: SignedEntityType::CardanoTransactions(
986 Epoch(18),
987 BlockNumber(120),
988 ),
989 certificate_id: "cert_id".to_string(),
990 artifact: serde_json::to_string(&fake_data::cardano_transactions_snapshot(1)[0])
991 .unwrap(),
992 created_at: Default::default(),
993 };
994 let message: CardanoTransactionSnapshotMessage = record.clone().try_into().unwrap();
995
996 let service = MessageServiceBuilder::new()
997 .with_signed_entity_records(&[record.clone()])
998 .build()
999 .await;
1000
1001 let response = service
1002 .get_cardano_transaction_message(&record.signed_entity_id)
1003 .await
1004 .unwrap()
1005 .expect("A CardanoTransactionMessage was expected.");
1006
1007 assert_eq!(message, response);
1008 }
1009
1010 #[tokio::test]
1011 async fn get_cardano_transaction_not_exist() {
1012 let service = MessageServiceBuilder::new().build().await;
1013
1014 let response = service
1015 .get_cardano_transaction_message("whatever")
1016 .await
1017 .unwrap();
1018
1019 assert!(response.is_none());
1020 }
1021
1022 #[tokio::test]
1023 async fn get_cardano_transaction_list_message() {
1024 let records = vec![
1025 SignedEntityRecord {
1026 signed_entity_id: "signed_entity_id-1".to_string(),
1027 signed_entity_type: SignedEntityType::CardanoTransactions(
1028 Epoch(18),
1029 BlockNumber(120),
1030 ),
1031 certificate_id: "cert_id-1".to_string(),
1032 artifact: serde_json::to_string(
1033 &fake_data::cardano_transactions_snapshot(1)[0],
1034 )
1035 .unwrap(),
1036 created_at: Default::default(),
1037 },
1038 SignedEntityRecord {
1039 signed_entity_id: "signed_entity_id-2".to_string(),
1040 signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
1041 certificate_id: "cert_id-2".to_string(),
1042 artifact: serde_json::to_string(&fake_data::cardano_database_snapshots(1)[0])
1043 .unwrap(),
1044 created_at: Default::default(),
1045 },
1046 ];
1047 let message: CardanoTransactionSnapshotListMessage =
1048 vec![records[0].clone().try_into().unwrap()];
1049
1050 let service = MessageServiceBuilder::new()
1051 .with_signed_entity_records(&records)
1052 .build()
1053 .await;
1054
1055 let response = service
1056 .get_cardano_transaction_list_message(0)
1057 .await
1058 .unwrap();
1059 assert!(response.is_empty());
1060
1061 let response = service
1062 .get_cardano_transaction_list_message(3)
1063 .await
1064 .unwrap();
1065 assert_eq!(message, response);
1066 }
1067 }
1068
1069 mod cardano_stake_distribution {
1070 use super::*;
1071
1072 #[tokio::test]
1073 async fn get_cardano_stake_distribution() {
1074 let record = SignedEntityRecord {
1075 signed_entity_id: "signed_entity_id".to_string(),
1076 signed_entity_type: SignedEntityType::CardanoStakeDistribution(Epoch(18)),
1077 certificate_id: "cert_id".to_string(),
1078 artifact: serde_json::to_string(&fake_data::cardano_stake_distributions(1)[0])
1079 .unwrap(),
1080 created_at: Default::default(),
1081 };
1082 let message: CardanoStakeDistributionMessage = record.clone().try_into().unwrap();
1083
1084 let service = MessageServiceBuilder::new()
1085 .with_signed_entity_records(&[record.clone()])
1086 .build()
1087 .await;
1088
1089 let response = service
1090 .get_cardano_stake_distribution_message(&record.signed_entity_id)
1091 .await
1092 .unwrap()
1093 .expect("A CardanoStakeDistributionMessage was expected.");
1094
1095 assert_eq!(message, response);
1096 }
1097
1098 #[tokio::test]
1099 async fn get_cardano_stake_distribution_not_exist() {
1100 let service = MessageServiceBuilder::new().build().await;
1101
1102 let response = service
1103 .get_cardano_stake_distribution_message("whatever")
1104 .await
1105 .unwrap();
1106
1107 assert!(response.is_none());
1108 }
1109
1110 #[tokio::test]
1111 async fn get_cardano_stake_distribution_by_epoch() {
1112 let record = SignedEntityRecord {
1113 signed_entity_id: "signed_entity_id".to_string(),
1114 signed_entity_type: SignedEntityType::CardanoStakeDistribution(Epoch(18)),
1115 certificate_id: "cert_id".to_string(),
1116 artifact: serde_json::to_string(&fake_data::cardano_stake_distributions(1)[0])
1117 .unwrap(),
1118 created_at: Default::default(),
1119 };
1120 let message: CardanoStakeDistributionMessage = record.clone().try_into().unwrap();
1121
1122 let service = MessageServiceBuilder::new()
1123 .with_signed_entity_records(&[record.clone()])
1124 .build()
1125 .await;
1126
1127 let response = service
1128 .get_cardano_stake_distribution_message_by_epoch(
1129 record.signed_entity_type.get_epoch(),
1130 )
1131 .await
1132 .unwrap()
1133 .expect("A CardanoStakeDistributionMessage was expected.");
1134
1135 assert_eq!(message, response);
1136 }
1137
1138 #[tokio::test]
1139 async fn get_cardano_stake_distribution_by_epoch_not_exist() {
1140 let service = MessageServiceBuilder::new().build().await;
1141
1142 let response = service
1143 .get_cardano_stake_distribution_message_by_epoch(Epoch(999))
1144 .await
1145 .unwrap();
1146
1147 assert!(response.is_none());
1148 }
1149
1150 #[tokio::test]
1151 async fn get_cardano_stake_distribution_list_message() {
1152 let records = vec![
1153 SignedEntityRecord {
1154 signed_entity_id: "signed_entity_id-1".to_string(),
1155 signed_entity_type: SignedEntityType::CardanoStakeDistribution(Epoch(18)),
1156 certificate_id: "cert_id-1".to_string(),
1157 artifact: serde_json::to_string(&fake_data::cardano_stake_distributions(1)[0])
1158 .unwrap(),
1159 created_at: Default::default(),
1160 },
1161 SignedEntityRecord {
1162 signed_entity_id: "signed_entity_id-2".to_string(),
1163 signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
1164 certificate_id: "cert_id-2".to_string(),
1165 artifact: serde_json::to_string(&fake_data::cardano_database_snapshots(1)[0])
1166 .unwrap(),
1167 created_at: Default::default(),
1168 },
1169 ];
1170 let message: CardanoStakeDistributionListMessage =
1171 vec![records[0].clone().try_into().unwrap()];
1172
1173 let service = MessageServiceBuilder::new()
1174 .with_signed_entity_records(&records)
1175 .build()
1176 .await;
1177
1178 let response = service
1179 .get_cardano_stake_distribution_list_message(0)
1180 .await
1181 .unwrap();
1182 assert!(response.is_empty());
1183
1184 let response = service
1185 .get_cardano_stake_distribution_list_message(3)
1186 .await
1187 .unwrap();
1188 assert_eq!(message, response);
1189 }
1190 }
1191}