mithril_aggregator/services/
message.rs

1//! This service is responsible for providing HTTP server with messages as fast as possible.
2
3use std::collections::BTreeSet;
4use std::sync::Arc;
5
6use async_trait::async_trait;
7
8use mithril_common::{
9    StdResult,
10    entities::{Epoch, SignedEntityTypeDiscriminants},
11    messages::{
12        CardanoBlocksTransactionsSnapshotListMessage, CardanoBlocksTransactionsSnapshotMessage,
13        CardanoDatabaseDigestListItemMessage, CardanoDatabaseDigestListMessage,
14        CardanoDatabaseSnapshotListMessage, CardanoDatabaseSnapshotMessage,
15        CardanoStakeDistributionListMessage, CardanoStakeDistributionMessage,
16        CardanoTransactionSnapshotListMessage, CardanoTransactionSnapshotMessage,
17        CertificateListMessage, CertificateMessage, EpochSettingsMessage,
18        MithrilStakeDistributionListMessage, MithrilStakeDistributionMessage,
19        ProtocolConfigurationMessage, SignerMessagePart, SnapshotListMessage, SnapshotMessage,
20    },
21};
22
23use crate::{
24    EpochSettingsStorer, ImmutableFileDigestMapper,
25    database::repository::{CertificateRepository, SignedEntityStorer},
26    dependency_injection::EpochServiceWrapper,
27};
28
29/// HTTP Message service trait.
30#[cfg_attr(test, mockall::automock)]
31#[async_trait]
32pub trait MessageService: Sync + Send {
33    /// Return the epoch settings message if it exists.
34    async fn get_epoch_settings_message(
35        &self,
36        allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
37    ) -> StdResult<EpochSettingsMessage>;
38
39    /// Return the protocol configuration message for the given epoch if it exists.
40    async fn get_protocol_configuration_message(
41        &self,
42        epoch: Epoch,
43        allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
44    ) -> StdResult<Option<ProtocolConfigurationMessage>>;
45
46    /// Return the message representation of a certificate if it exists.
47    async fn get_certificate_message(
48        &self,
49        certificate_hash: &str,
50    ) -> StdResult<Option<CertificateMessage>>;
51
52    /// Return the message representation of the latest genesis certificate.
53    async fn get_latest_genesis_certificate_message(&self)
54    -> StdResult<Option<CertificateMessage>>;
55
56    /// Return the message representation of the last N certificates.
57    async fn get_certificate_list_message(&self, limit: usize)
58    -> StdResult<CertificateListMessage>;
59
60    /// Return the information regarding the given snapshot.
61    async fn get_snapshot_message(
62        &self,
63        signed_entity_id: &str,
64    ) -> StdResult<Option<SnapshotMessage>>;
65
66    /// Return the list of the last signed snapshots. The limit of the list is
67    /// passed as argument.
68    async fn get_snapshot_list_message(&self, limit: usize) -> StdResult<SnapshotListMessage>;
69
70    /// Return the information regarding the Cardano database for the given identifier.
71    async fn get_cardano_database_message(
72        &self,
73        signed_entity_id: &str,
74    ) -> StdResult<Option<CardanoDatabaseSnapshotMessage>>;
75
76    /// Return the list of the last Cardano database message.
77    async fn get_cardano_database_list_message(
78        &self,
79        limit: usize,
80    ) -> StdResult<CardanoDatabaseSnapshotListMessage>;
81
82    /// Return the list of the last Cardano database message.
83    async fn get_cardano_database_list_message_by_epoch(
84        &self,
85        limit: usize,
86        epoch: Epoch,
87    ) -> StdResult<CardanoDatabaseSnapshotListMessage>;
88
89    /// Return the list of the Cardano database immutable file names and their digests.
90    async fn get_cardano_database_digest_list_message(
91        &self,
92    ) -> StdResult<CardanoDatabaseDigestListMessage>;
93
94    /// Return the information regarding the Mithril stake distribution for the given identifier.
95    async fn get_mithril_stake_distribution_message(
96        &self,
97        signed_entity_id: &str,
98    ) -> StdResult<Option<MithrilStakeDistributionMessage>>;
99
100    /// Return the list of the last Mithril stake distributions message.
101    async fn get_mithril_stake_distribution_list_message(
102        &self,
103        limit: usize,
104    ) -> StdResult<MithrilStakeDistributionListMessage>;
105
106    /// Return the information regarding the Cardano transactions set for the given identifier.
107    async fn get_cardano_transaction_message(
108        &self,
109        signed_entity_id: &str,
110    ) -> StdResult<Option<CardanoTransactionSnapshotMessage>>;
111
112    /// Return the list of the last Cardano transactions set message.
113    async fn get_cardano_transaction_list_message(
114        &self,
115        limit: usize,
116    ) -> StdResult<CardanoTransactionSnapshotListMessage>;
117
118    /// Return the information regarding the Cardano blocks transactions set for the given identifier.
119    async fn get_cardano_blocks_transactions_message(
120        &self,
121        signed_entity_id: &str,
122    ) -> StdResult<Option<CardanoBlocksTransactionsSnapshotMessage>>;
123
124    /// Return the list of the last Cardano blocks transactions set message.
125    async fn get_cardano_blocks_transactions_list_message(
126        &self,
127        limit: usize,
128    ) -> StdResult<CardanoBlocksTransactionsSnapshotListMessage>;
129
130    /// Return the information regarding the Cardano stake distribution for the given identifier.
131    async fn get_cardano_stake_distribution_message(
132        &self,
133        signed_entity_id: &str,
134    ) -> StdResult<Option<CardanoStakeDistributionMessage>>;
135
136    /// Return the information regarding the Cardano stake distribution for the given epoch.
137    async fn get_cardano_stake_distribution_message_by_epoch(
138        &self,
139        epoch: Epoch,
140    ) -> StdResult<Option<CardanoStakeDistributionMessage>>;
141
142    /// Return the list of the last Cardano stake distributions message.
143    async fn get_cardano_stake_distribution_list_message(
144        &self,
145        limit: usize,
146    ) -> StdResult<CardanoStakeDistributionListMessage>;
147}
148
149/// Implementation of the [MessageService]
150pub struct MithrilMessageService {
151    certificate_repository: Arc<CertificateRepository>,
152    signed_entity_storer: Arc<dyn SignedEntityStorer>,
153    epoch_settings_storer: Arc<dyn EpochSettingsStorer>,
154    immutable_file_digest_mapper: Arc<dyn ImmutableFileDigestMapper>,
155    epoch_service: EpochServiceWrapper,
156}
157
158impl MithrilMessageService {
159    /// Constructor
160    pub fn new(
161        certificate_repository: Arc<CertificateRepository>,
162        signed_entity_storer: Arc<dyn SignedEntityStorer>,
163        epoch_settings_storer: Arc<dyn EpochSettingsStorer>,
164        immutable_file_digest_mapper: Arc<dyn ImmutableFileDigestMapper>,
165        epoch_service: EpochServiceWrapper,
166    ) -> Self {
167        Self {
168            certificate_repository,
169            signed_entity_storer,
170            epoch_settings_storer,
171            immutable_file_digest_mapper,
172            epoch_service,
173        }
174    }
175}
176
177#[async_trait]
178impl MessageService for MithrilMessageService {
179    async fn get_epoch_settings_message(
180        &self,
181        allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
182    ) -> StdResult<EpochSettingsMessage> {
183        let epoch_service = self.epoch_service.read().await;
184
185        let epoch = epoch_service.epoch_of_current_data()?;
186        let signer_registration_protocol_parameters =
187            epoch_service.signer_registration_protocol_parameters()?.clone();
188        let current_signers = epoch_service.current_signers()?;
189        let next_signers = epoch_service.next_signers()?;
190
191        let cardano_transactions_discriminant =
192            allowed_discriminants.get(&SignedEntityTypeDiscriminants::CardanoTransactions);
193
194        let signed_entity_config = cardano_transactions_discriminant
195            .map(|_| epoch_service.signed_entity_config())
196            .transpose()?
197            .cloned();
198
199        #[allow(deprecated)]
200        let epoch_settings_message = EpochSettingsMessage {
201            epoch,
202            signer_registration_protocol_parameters: Some(signer_registration_protocol_parameters),
203            current_signers: SignerMessagePart::from_signers(current_signers.to_vec()),
204            next_signers: SignerMessagePart::from_signers(next_signers.to_vec()),
205            cardano_transactions_signing_config: signed_entity_config
206                .and_then(|c| c.cardano_transactions_signing_config),
207        };
208
209        Ok(epoch_settings_message)
210    }
211
212    async fn get_protocol_configuration_message(
213        &self,
214        epoch: Epoch,
215        enabled_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
216    ) -> StdResult<Option<ProtocolConfigurationMessage>> {
217        let epoch_settings = match self.epoch_settings_storer.get_epoch_settings(epoch).await? {
218            Some(settings) => settings,
219            None => return Ok(None),
220        };
221
222        let cardano_transactions_discriminant =
223            enabled_discriminants.get(&SignedEntityTypeDiscriminants::CardanoTransactions);
224
225        let cardano_transactions_signing_config = cardano_transactions_discriminant
226            .and(epoch_settings.cardano_transactions_signing_config);
227
228        let cardano_blocks_transactions_discriminant =
229            enabled_discriminants.get(&SignedEntityTypeDiscriminants::CardanoBlocksTransactions);
230
231        let cardano_blocks_transactions_signing_config = cardano_blocks_transactions_discriminant
232            .and(epoch_settings.cardano_blocks_transactions_signing_config);
233
234        let protocol_configuration_message = ProtocolConfigurationMessage {
235            protocol_parameters: epoch_settings.protocol_parameters,
236            cardano_transactions_signing_config,
237            cardano_blocks_transactions_signing_config,
238            available_signed_entity_types: enabled_discriminants,
239        };
240        Ok(Some(protocol_configuration_message))
241    }
242
243    async fn get_certificate_message(
244        &self,
245        certificate_hash: &str,
246    ) -> StdResult<Option<CertificateMessage>> {
247        self.certificate_repository.get_certificate(certificate_hash).await
248    }
249
250    async fn get_latest_genesis_certificate_message(
251        &self,
252    ) -> StdResult<Option<CertificateMessage>> {
253        self.certificate_repository.get_latest_genesis_certificate().await
254    }
255
256    async fn get_certificate_list_message(
257        &self,
258        limit: usize,
259    ) -> StdResult<CertificateListMessage> {
260        self.certificate_repository.get_latest_certificates(limit).await
261    }
262
263    async fn get_snapshot_message(
264        &self,
265        signed_entity_id: &str,
266    ) -> StdResult<Option<SnapshotMessage>> {
267        let signed_entity = self.signed_entity_storer.get_signed_entity(signed_entity_id).await?;
268
269        signed_entity.map(|s| s.try_into()).transpose()
270    }
271
272    async fn get_snapshot_list_message(&self, limit: usize) -> StdResult<SnapshotListMessage> {
273        let signed_entity_type_id = SignedEntityTypeDiscriminants::CardanoImmutableFilesFull;
274        let entities = self
275            .signed_entity_storer
276            .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
277            .await?;
278
279        entities.into_iter().map(|i| i.try_into()).collect()
280    }
281
282    async fn get_cardano_database_message(
283        &self,
284        signed_entity_id: &str,
285    ) -> StdResult<Option<CardanoDatabaseSnapshotMessage>> {
286        let signed_entity = self.signed_entity_storer.get_signed_entity(signed_entity_id).await?;
287
288        signed_entity.map(|v| v.try_into()).transpose()
289    }
290
291    async fn get_cardano_database_list_message(
292        &self,
293        limit: usize,
294    ) -> StdResult<CardanoDatabaseSnapshotListMessage> {
295        let signed_entity_type_id = SignedEntityTypeDiscriminants::CardanoDatabase;
296        let entities = self
297            .signed_entity_storer
298            .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
299            .await?;
300
301        entities.into_iter().map(|i| i.try_into()).collect()
302    }
303
304    async fn get_cardano_database_list_message_by_epoch(
305        &self,
306        limit: usize,
307        epoch: Epoch,
308    ) -> StdResult<CardanoDatabaseSnapshotListMessage> {
309        let signed_entity_type_id = SignedEntityTypeDiscriminants::CardanoDatabase;
310        let entities = self
311            .signed_entity_storer
312            .get_last_signed_entities_by_type_and_epoch(&signed_entity_type_id, epoch, limit)
313            .await?;
314
315        entities.into_iter().map(|i| i.try_into()).collect()
316    }
317
318    async fn get_cardano_database_digest_list_message(
319        &self,
320    ) -> StdResult<CardanoDatabaseDigestListMessage> {
321        Ok(self
322            .immutable_file_digest_mapper
323            .get_immutable_file_digest_map()
324            .await?
325            .into_iter()
326            .map(
327                |(immutable_file_name, digest)| CardanoDatabaseDigestListItemMessage {
328                    immutable_file_name,
329                    digest,
330                },
331            )
332            .collect::<Vec<_>>())
333    }
334
335    async fn get_mithril_stake_distribution_message(
336        &self,
337        signed_entity_id: &str,
338    ) -> StdResult<Option<MithrilStakeDistributionMessage>> {
339        let signed_entity = self.signed_entity_storer.get_signed_entity(signed_entity_id).await?;
340
341        signed_entity.map(|v| v.try_into()).transpose()
342    }
343
344    async fn get_mithril_stake_distribution_list_message(
345        &self,
346        limit: usize,
347    ) -> StdResult<MithrilStakeDistributionListMessage> {
348        let signed_entity_type_id = SignedEntityTypeDiscriminants::MithrilStakeDistribution;
349        let entities = self
350            .signed_entity_storer
351            .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
352            .await?;
353
354        entities.into_iter().map(|i| i.try_into()).collect()
355    }
356
357    async fn get_cardano_transaction_message(
358        &self,
359        signed_entity_id: &str,
360    ) -> StdResult<Option<CardanoTransactionSnapshotMessage>> {
361        let signed_entity = self.signed_entity_storer.get_signed_entity(signed_entity_id).await?;
362
363        signed_entity.map(|v| v.try_into()).transpose()
364    }
365
366    async fn get_cardano_transaction_list_message(
367        &self,
368        limit: usize,
369    ) -> StdResult<CardanoTransactionSnapshotListMessage> {
370        let signed_entity_type_id = SignedEntityTypeDiscriminants::CardanoTransactions;
371        let entities = self
372            .signed_entity_storer
373            .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
374            .await?;
375
376        entities.into_iter().map(|i| i.try_into()).collect()
377    }
378
379    async fn get_cardano_blocks_transactions_message(
380        &self,
381        signed_entity_id: &str,
382    ) -> StdResult<Option<CardanoBlocksTransactionsSnapshotMessage>> {
383        let signed_entity = self.signed_entity_storer.get_signed_entity(signed_entity_id).await?;
384
385        signed_entity.map(|v| v.try_into()).transpose()
386    }
387
388    async fn get_cardano_blocks_transactions_list_message(
389        &self,
390        limit: usize,
391    ) -> StdResult<CardanoBlocksTransactionsSnapshotListMessage> {
392        let signed_entity_type_id = SignedEntityTypeDiscriminants::CardanoBlocksTransactions;
393        let entities = self
394            .signed_entity_storer
395            .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
396            .await?;
397
398        entities.into_iter().map(|i| i.try_into()).collect()
399    }
400
401    async fn get_cardano_stake_distribution_message(
402        &self,
403        signed_entity_id: &str,
404    ) -> StdResult<Option<CardanoStakeDistributionMessage>> {
405        let signed_entity = self.signed_entity_storer.get_signed_entity(signed_entity_id).await?;
406
407        signed_entity.map(|v| v.try_into()).transpose()
408    }
409
410    async fn get_cardano_stake_distribution_message_by_epoch(
411        &self,
412        epoch: Epoch,
413    ) -> StdResult<Option<CardanoStakeDistributionMessage>> {
414        let signed_entity = self
415            .signed_entity_storer
416            .get_cardano_stake_distribution_signed_entity_by_epoch(epoch)
417            .await?;
418
419        signed_entity.map(|v| v.try_into()).transpose()
420    }
421
422    async fn get_cardano_stake_distribution_list_message(
423        &self,
424        limit: usize,
425    ) -> StdResult<CardanoStakeDistributionListMessage> {
426        let signed_entity_type_id = SignedEntityTypeDiscriminants::CardanoStakeDistribution;
427        let entities = self
428            .signed_entity_storer
429            .get_last_signed_entities_by_type(&signed_entity_type_id, limit)
430            .await?;
431
432        entities.into_iter().map(|i| i.try_into()).collect()
433    }
434}
435
436#[cfg(test)]
437mod tests {
438    use std::collections::BTreeMap;
439
440    use mithril_common::entities::{BlockNumber, CardanoDbBeacon, Certificate, SignedEntityType};
441    use mithril_common::test::double::{Dummy, fake_data};
442    use tokio::sync::RwLock;
443
444    use crate::database::record::SignedEntityRecord;
445    use crate::database::repository::{
446        EpochSettingsStore, ImmutableFileDigestRepository, SignedEntityStore,
447    };
448    use crate::database::test_helper::main_db_connection;
449    use crate::entities::AggregatorEpochSettings;
450    use crate::services::FakeEpochService;
451
452    use super::*;
453
454    struct MessageServiceBuilder {
455        certificates: Vec<Certificate>,
456        signed_entity_records: Vec<SignedEntityRecord>,
457        epoch_settings_map: BTreeMap<Epoch, AggregatorEpochSettings>,
458        immutable_file_digest_messages: Vec<CardanoDatabaseDigestListItemMessage>,
459        epoch_service: Option<FakeEpochService>,
460    }
461
462    impl MessageServiceBuilder {
463        fn new() -> Self {
464            Self {
465                certificates: Vec::new(),
466                signed_entity_records: Vec::new(),
467                epoch_settings_map: BTreeMap::new(),
468                immutable_file_digest_messages: Vec::new(),
469                epoch_service: None,
470            }
471        }
472
473        fn with_certificates(mut self, certificates: &[Certificate]) -> Self {
474            self.certificates.extend_from_slice(certificates);
475
476            self
477        }
478
479        fn with_signed_entity_records(
480            mut self,
481            signed_entity_record: &[SignedEntityRecord],
482        ) -> Self {
483            self.signed_entity_records.extend_from_slice(signed_entity_record);
484
485            self
486        }
487
488        fn with_epoch_settings(
489            mut self,
490            epoch_settings_map: BTreeMap<Epoch, AggregatorEpochSettings>,
491        ) -> Self {
492            self.epoch_settings_map = epoch_settings_map;
493
494            self
495        }
496
497        fn with_immutable_file_digest_messages(
498            mut self,
499            digests: &[CardanoDatabaseDigestListItemMessage],
500        ) -> Self {
501            self.immutable_file_digest_messages.extend_from_slice(digests);
502
503            self
504        }
505
506        fn with_epoch_service(mut self, epoch_service: FakeEpochService) -> Self {
507            self.epoch_service = Some(epoch_service);
508
509            self
510        }
511
512        async fn build(self) -> MithrilMessageService {
513            let connection = Arc::new(main_db_connection().unwrap());
514            let certificate_repository = CertificateRepository::new(connection.clone());
515            let signed_entity_store = SignedEntityStore::new(connection.clone());
516            let epoch_settings_store = EpochSettingsStore::new(connection.clone(), None);
517            let immutable_file_digest_mapper =
518                ImmutableFileDigestRepository::new(connection.clone());
519            let epoch_service = self.epoch_service.unwrap_or(FakeEpochService::without_data());
520
521            certificate_repository
522                .create_many_certificates(self.certificates)
523                .await
524                .unwrap();
525            for record in self.signed_entity_records {
526                signed_entity_store.store_signed_entity(&record).await.unwrap();
527            }
528
529            for (epoch, epoch_settings) in self.epoch_settings_map {
530                epoch_settings_store
531                    .save_epoch_settings(epoch, epoch_settings)
532                    .await
533                    .unwrap();
534            }
535
536            for digest_message in self.immutable_file_digest_messages {
537                immutable_file_digest_mapper
538                    .upsert_immutable_file_digest(
539                        &digest_message.immutable_file_name,
540                        &digest_message.digest,
541                    )
542                    .await
543                    .unwrap();
544            }
545
546            MithrilMessageService::new(
547                Arc::new(certificate_repository),
548                Arc::new(signed_entity_store),
549                Arc::new(epoch_settings_store),
550                Arc::new(immutable_file_digest_mapper),
551                Arc::new(RwLock::new(epoch_service)),
552            )
553        }
554    }
555
556    #[allow(deprecated)]
557    mod epoch_settings {
558        use mithril_common::{
559            entities::{CardanoTransactionsSigningConfig, ProtocolParameters, SignedEntityConfig},
560            test::builder::MithrilFixtureBuilder,
561        };
562
563        use crate::{entities::AggregatorEpochSettings, services::FakeEpochServiceBuilder};
564
565        use super::*;
566
567        #[tokio::test]
568        async fn get_epoch_settings_message() {
569            let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
570            let epoch_service = FakeEpochService::from_fixture(Epoch(4), &fixture);
571            let message_service = MessageServiceBuilder::new()
572                .with_epoch_service(epoch_service)
573                .build()
574                .await;
575
576            let message = message_service
577                .get_epoch_settings_message(SignedEntityTypeDiscriminants::all())
578                .await
579                .unwrap();
580
581            assert_eq!(message.epoch, Epoch(4));
582            assert_eq!(
583                message.signer_registration_protocol_parameters,
584                Some(ProtocolParameters::new(5, 100, 0.65))
585            );
586            assert_eq!(message.current_signers.len(), 3);
587            assert_eq!(message.next_signers.len(), 3);
588            assert_eq!(
589                message.cardano_transactions_signing_config,
590                Some(CardanoTransactionsSigningConfig {
591                    security_parameter: BlockNumber(0),
592                    step: BlockNumber(15)
593                })
594            );
595        }
596
597        #[tokio::test]
598        async fn get_epoch_settings_message_with_cardano_transactions_enabled() {
599            let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
600            let epoch_service = FakeEpochService::from_fixture(Epoch(4), &fixture);
601            let message_service = MessageServiceBuilder::new()
602                .with_epoch_service(epoch_service)
603                .build()
604                .await;
605
606            let message = message_service
607                .get_epoch_settings_message(BTreeSet::from([
608                    SignedEntityTypeDiscriminants::CardanoTransactions,
609                ]))
610                .await
611                .unwrap();
612
613            assert!(message.cardano_transactions_signing_config.is_some());
614        }
615
616        #[tokio::test]
617        async fn get_epoch_settings_message_with_cardano_transactions_not_enabled() {
618            let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
619            let epoch_service = FakeEpochService::from_fixture(Epoch(4), &fixture);
620            let message_service = MessageServiceBuilder::new()
621                .with_epoch_service(epoch_service)
622                .build()
623                .await;
624
625            let message = message_service
626                .get_epoch_settings_message(BTreeSet::new())
627                .await
628                .unwrap();
629
630            assert_eq!(message.cardano_transactions_signing_config, None);
631        }
632
633        #[tokio::test]
634        async fn get_epoch_settings_message_retrieves_protocol_parameters_from_epoch_service() {
635            let current_epoch_settings = AggregatorEpochSettings {
636                protocol_parameters: ProtocolParameters::new(101, 10, 0.5),
637                ..AggregatorEpochSettings::dummy()
638            };
639            let next_epoch_settings = AggregatorEpochSettings {
640                protocol_parameters: ProtocolParameters::new(102, 20, 0.5),
641                ..AggregatorEpochSettings::dummy()
642            };
643            let signer_registration_epoch_settings = AggregatorEpochSettings {
644                protocol_parameters: ProtocolParameters::new(103, 30, 0.5),
645                ..AggregatorEpochSettings::dummy()
646            };
647            let epoch_service = FakeEpochServiceBuilder {
648                current_epoch_settings,
649                next_epoch_settings: next_epoch_settings.clone(),
650                signer_registration_epoch_settings: signer_registration_epoch_settings.clone(),
651                current_signers_with_stake: fake_data::signers_with_stakes(5),
652                next_signers_with_stake: fake_data::signers_with_stakes(3),
653                ..FakeEpochServiceBuilder::dummy(Epoch(1))
654            }
655            .build();
656            let message_service = MessageServiceBuilder::new()
657                .with_epoch_service(epoch_service)
658                .build()
659                .await;
660
661            let message = message_service
662                .get_epoch_settings_message(SignedEntityTypeDiscriminants::all())
663                .await
664                .unwrap();
665
666            assert_eq!(
667                message.signer_registration_protocol_parameters,
668                Some(signer_registration_epoch_settings.protocol_parameters)
669            );
670        }
671
672        #[tokio::test]
673        async fn get_epoch_settings_message_retrieves_signing_configuration_from_epoch_service() {
674            let expected_ctx_config = CardanoTransactionsSigningConfig {
675                security_parameter: BlockNumber(100),
676                step: BlockNumber(15),
677            };
678            let epoch_service = FakeEpochServiceBuilder {
679                signed_entity_config: SignedEntityConfig {
680                    cardano_transactions_signing_config: Some(expected_ctx_config.clone()),
681                    ..Dummy::dummy()
682                },
683                ..FakeEpochServiceBuilder::dummy(Epoch(1))
684            }
685            .build();
686            let message_service = MessageServiceBuilder::new()
687                .with_epoch_service(epoch_service)
688                .build()
689                .await;
690
691            let message = message_service
692                .get_epoch_settings_message(SignedEntityTypeDiscriminants::all())
693                .await
694                .unwrap();
695
696            assert_eq!(
697                message.cardano_transactions_signing_config,
698                Some(expected_ctx_config),
699            );
700        }
701    }
702
703    mod protocol_configuration {
704        use super::*;
705
706        use mithril_common::entities::{
707            CardanoBlocksTransactionsSigningConfig, CardanoTransactionsSigningConfig,
708            ProtocolParameters,
709        };
710
711        use crate::entities::AggregatorEpochSettings;
712
713        #[tokio::test]
714        async fn get_protocol_configuration_message() {
715            let epoch = Epoch(4);
716            let aggregator_epoch_settings = AggregatorEpochSettings {
717                protocol_parameters: ProtocolParameters::new(5, 100, 0.65),
718                cardano_transactions_signing_config: Some(CardanoTransactionsSigningConfig {
719                    security_parameter: BlockNumber(10),
720                    step: BlockNumber(15),
721                }),
722                cardano_blocks_transactions_signing_config: Some(
723                    CardanoBlocksTransactionsSigningConfig {
724                        security_parameter: BlockNumber(20),
725                        step: BlockNumber(30),
726                    },
727                ),
728            };
729            let message_service = MessageServiceBuilder::new()
730                .with_epoch_settings(BTreeMap::from([(epoch, aggregator_epoch_settings)]))
731                .build()
732                .await;
733
734            let message = message_service
735                .get_protocol_configuration_message(epoch, SignedEntityTypeDiscriminants::all())
736                .await
737                .unwrap()
738                .expect("Protocol configuration message should exist.");
739
740            assert_eq!(
741                message.protocol_parameters,
742                ProtocolParameters::new(5, 100, 0.65)
743            );
744            assert_eq!(
745                message.cardano_transactions_signing_config,
746                Some(CardanoTransactionsSigningConfig {
747                    security_parameter: BlockNumber(10),
748                    step: BlockNumber(15)
749                })
750            );
751            assert_eq!(
752                message.cardano_blocks_transactions_signing_config,
753                Some(CardanoBlocksTransactionsSigningConfig {
754                    security_parameter: BlockNumber(20),
755                    step: BlockNumber(30)
756                })
757            );
758            assert_eq!(
759                message.available_signed_entity_types,
760                SignedEntityTypeDiscriminants::all()
761            );
762        }
763
764        #[tokio::test]
765        async fn get_protocol_configuration_message_with_multiple_epochs_settings_stored() {
766            let message_service = MessageServiceBuilder::new()
767                .with_epoch_settings(BTreeMap::from([
768                    (
769                        Epoch(7),
770                        AggregatorEpochSettings {
771                            protocol_parameters: ProtocolParameters::new(1, 10, 0.11),
772                            ..Dummy::dummy()
773                        },
774                    ),
775                    (
776                        Epoch(8),
777                        AggregatorEpochSettings {
778                            protocol_parameters: ProtocolParameters::new(2, 20, 0.22),
779                            ..Dummy::dummy()
780                        },
781                    ),
782                    (
783                        Epoch(9),
784                        AggregatorEpochSettings {
785                            protocol_parameters: ProtocolParameters::new(3, 30, 0.33),
786                            ..Dummy::dummy()
787                        },
788                    ),
789                ]))
790                .build()
791                .await;
792
793            let message = message_service
794                .get_protocol_configuration_message(Epoch(8), SignedEntityTypeDiscriminants::all())
795                .await
796                .unwrap()
797                .expect("Protocol configuration message should exist.");
798
799            assert_eq!(
800                message.protocol_parameters,
801                ProtocolParameters::new(2, 20, 0.22)
802            );
803        }
804
805        #[tokio::test]
806        async fn get_protocol_configuration_message_with_cardano_transactions_enabled() {
807            let epoch = Epoch(4);
808            let message_service = MessageServiceBuilder::new()
809                .with_epoch_settings(BTreeMap::from([(epoch, AggregatorEpochSettings::dummy())]))
810                .build()
811                .await;
812
813            let message = message_service
814                .get_protocol_configuration_message(
815                    epoch,
816                    BTreeSet::from([SignedEntityTypeDiscriminants::CardanoTransactions]),
817                )
818                .await
819                .unwrap()
820                .expect("Protocol configuration message should exist.");
821
822            assert!(message.cardano_transactions_signing_config.is_some());
823        }
824
825        #[tokio::test]
826        async fn get_protocol_configuration_message_without_cardano_transactions_does_not_return_signing_config()
827         {
828            let epoch = Epoch(4);
829            let message_service = MessageServiceBuilder::new()
830                .with_epoch_settings(BTreeMap::from([(epoch, AggregatorEpochSettings::dummy())]))
831                .build()
832                .await;
833
834            let message = message_service
835                .get_protocol_configuration_message(epoch, BTreeSet::new())
836                .await
837                .unwrap()
838                .expect("Protocol configuration message should exist.");
839
840            assert_eq!(message.cardano_transactions_signing_config, None);
841        }
842
843        #[tokio::test]
844        async fn get_protocol_configuration_message_return_none_if_epoch_not_found() {
845            let epoch_number = 7;
846            let epoch_without_correspondence = epoch_number + 42;
847            let message_service = MessageServiceBuilder::new()
848                .with_epoch_settings(BTreeMap::from([(
849                    Epoch(epoch_number),
850                    AggregatorEpochSettings::dummy(),
851                )]))
852                .build()
853                .await;
854
855            let message = message_service
856                .get_protocol_configuration_message(
857                    Epoch(epoch_without_correspondence),
858                    SignedEntityTypeDiscriminants::all(),
859                )
860                .await
861                .unwrap();
862
863            assert_eq!(message, None);
864        }
865    }
866
867    mod certificate {
868        use super::*;
869
870        #[tokio::test]
871        async fn get_no_certificate() {
872            let service = MessageServiceBuilder::new().build().await;
873
874            let certificate_hash = "whatever";
875            let certificate_message =
876                service.get_certificate_message(certificate_hash).await.unwrap();
877            assert!(certificate_message.is_none());
878        }
879
880        #[tokio::test]
881        async fn get_certificate() {
882            let genesis_certificate = fake_data::genesis_certificate("genesis_hash");
883            let service = MessageServiceBuilder::new()
884                .with_certificates(std::slice::from_ref(&genesis_certificate))
885                .build()
886                .await;
887
888            let certificate_message = service
889                .get_certificate_message(&genesis_certificate.hash)
890                .await
891                .unwrap()
892                .expect("There should be a certificate.");
893            assert_eq!(genesis_certificate.hash, certificate_message.hash);
894        }
895
896        #[tokio::test]
897        async fn get_no_latest_genesis_certificate() {
898            let service = MessageServiceBuilder::new().build().await;
899
900            let certificate_message =
901                service.get_latest_genesis_certificate_message().await.unwrap();
902            assert_eq!(None, certificate_message);
903        }
904
905        #[tokio::test]
906        async fn get_latest_genesis_certificate() {
907            let certificates = [
908                fake_data::genesis_certificate("certificate_1"),
909                fake_data::genesis_certificate("certificate_2"),
910                fake_data::certificate("certificate_3"),
911            ];
912            let last_genesis_hash = certificates[1].hash.clone();
913            let service = MessageServiceBuilder::new()
914                .with_certificates(&certificates)
915                .build()
916                .await;
917
918            let certificate_message = service
919                .get_latest_genesis_certificate_message()
920                .await
921                .unwrap()
922                .expect("There should be a genesis certificate.");
923            assert_eq!(last_genesis_hash, certificate_message.hash);
924        }
925
926        #[tokio::test]
927        async fn get_last_certificates() {
928            let certificates = [
929                fake_data::genesis_certificate("certificate_1"),
930                fake_data::genesis_certificate("certificate_2"),
931            ];
932            let last_certificate_hash = certificates[1].hash.clone();
933            let service = MessageServiceBuilder::new()
934                .with_certificates(&certificates)
935                .build()
936                .await;
937
938            let certificate_messages = service.get_certificate_list_message(5).await.unwrap();
939
940            assert_eq!(2, certificate_messages.len());
941            assert_eq!(last_certificate_hash, certificate_messages[0].hash);
942        }
943    }
944
945    mod snapshot {
946        use super::*;
947
948        #[tokio::test]
949        async fn get_snapshot_not_exist() {
950            let service = MessageServiceBuilder::new().build().await;
951            let snapshot = service.get_snapshot_message("whatever").await.unwrap();
952
953            assert!(snapshot.is_none());
954        }
955
956        #[tokio::test]
957        async fn get_snapshot() {
958            let record = SignedEntityRecord {
959                signed_entity_id: "signed_entity_id".to_string(),
960                signed_entity_type: SignedEntityType::CardanoImmutableFilesFull(fake_data::beacon()),
961                certificate_id: "cert_id".to_string(),
962                artifact: serde_json::to_string(&fake_data::snapshot(1)).unwrap(),
963                created_at: Default::default(),
964            };
965            let message: SnapshotMessage = record.clone().try_into().unwrap();
966
967            let service = MessageServiceBuilder::new()
968                .with_signed_entity_records(std::slice::from_ref(&record))
969                .build()
970                .await;
971
972            let response = service
973                .get_snapshot_message(&record.signed_entity_id)
974                .await
975                .unwrap()
976                .expect("A SnapshotMessage was expected.");
977
978            assert_eq!(message, response);
979        }
980
981        #[tokio::test]
982        async fn get_snapshot_list_message() {
983            let records = vec![
984                SignedEntityRecord {
985                    signed_entity_id: "signed_entity_id-1".to_string(),
986                    signed_entity_type: SignedEntityType::CardanoImmutableFilesFull(
987                        fake_data::beacon(),
988                    ),
989                    certificate_id: "cert_id-1".to_string(),
990                    artifact: serde_json::to_string(&fake_data::snapshot(1)).unwrap(),
991                    created_at: Default::default(),
992                },
993                SignedEntityRecord {
994                    signed_entity_id: "signed_entity_id-2".to_string(),
995                    signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
996                    certificate_id: "cert_id-2".to_string(),
997                    artifact: serde_json::to_string(&fake_data::cardano_database_snapshot(1))
998                        .unwrap(),
999                    created_at: Default::default(),
1000                },
1001            ];
1002            let message: SnapshotListMessage = vec![records[0].clone().try_into().unwrap()];
1003
1004            let service = MessageServiceBuilder::new()
1005                .with_signed_entity_records(&records)
1006                .build()
1007                .await;
1008
1009            let response = service.get_snapshot_list_message(0).await.unwrap();
1010            assert!(response.is_empty());
1011
1012            let response = service.get_snapshot_list_message(3).await.unwrap();
1013            assert_eq!(message, response);
1014        }
1015    }
1016
1017    mod cardano_database {
1018        use super::*;
1019
1020        #[tokio::test]
1021        async fn get_cardano_database_when_record_does_not_exist() {
1022            let service = MessageServiceBuilder::new().build().await;
1023            let snapshot = service.get_cardano_database_message("whatever").await.unwrap();
1024
1025            assert!(snapshot.is_none());
1026        }
1027
1028        #[tokio::test]
1029        async fn get_cardano_database() {
1030            let record = SignedEntityRecord {
1031                signed_entity_id: "signed_entity_id".to_string(),
1032                signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
1033                certificate_id: "cert_id".to_string(),
1034                artifact: serde_json::to_string(&fake_data::cardano_database_snapshot(1)).unwrap(),
1035                created_at: Default::default(),
1036            };
1037            let message: CardanoDatabaseSnapshotMessage = record.clone().try_into().unwrap();
1038
1039            let service = MessageServiceBuilder::new()
1040                .with_signed_entity_records(std::slice::from_ref(&record))
1041                .build()
1042                .await;
1043
1044            let response = service
1045                .get_cardano_database_message(&record.signed_entity_id)
1046                .await
1047                .unwrap()
1048                .expect("A CardanoDatabaseSnapshotMessage was expected.");
1049
1050            assert_eq!(message, response);
1051        }
1052
1053        #[tokio::test]
1054        async fn get_cardano_database_list_message() {
1055            let records = vec![
1056                SignedEntityRecord {
1057                    signed_entity_id: "signed_entity_id-1".to_string(),
1058                    signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
1059                    certificate_id: "cert_id-1".to_string(),
1060                    artifact: serde_json::to_string(&fake_data::cardano_database_snapshot(1))
1061                        .unwrap(),
1062                    created_at: Default::default(),
1063                },
1064                SignedEntityRecord {
1065                    signed_entity_id: "signed_entity_id-2".to_string(),
1066                    signed_entity_type: SignedEntityType::CardanoImmutableFilesFull(
1067                        fake_data::beacon(),
1068                    ),
1069                    certificate_id: "cert_id-2".to_string(),
1070                    artifact: serde_json::to_string(&fake_data::snapshot(1)).unwrap(),
1071                    created_at: Default::default(),
1072                },
1073            ];
1074            let message: CardanoDatabaseSnapshotListMessage =
1075                vec![records[0].clone().try_into().unwrap()];
1076
1077            let service = MessageServiceBuilder::new()
1078                .with_signed_entity_records(&records)
1079                .build()
1080                .await;
1081
1082            let response = service.get_cardano_database_list_message(0).await.unwrap();
1083            assert!(response.is_empty());
1084
1085            let response = service.get_cardano_database_list_message(3).await.unwrap();
1086            assert_eq!(message, response);
1087        }
1088
1089        #[tokio::test]
1090        async fn get_cardano_database_list_message_by_epoch() {
1091            let records = vec![
1092                // Cardano database on epoch 3
1093                SignedEntityRecord {
1094                    signed_entity_id: "signed_entity_id-1".to_string(),
1095                    signed_entity_type: SignedEntityType::CardanoDatabase(CardanoDbBeacon::new(
1096                        3, 100,
1097                    )),
1098                    certificate_id: "cert_id-1".to_string(),
1099                    artifact: serde_json::to_string(&fake_data::cardano_database_snapshot(100))
1100                        .unwrap(),
1101                    created_at: Default::default(),
1102                },
1103                // Another signed entity type on the same epoch
1104                SignedEntityRecord {
1105                    signed_entity_id: "signed_entity_id-2".to_string(),
1106                    signed_entity_type: SignedEntityType::CardanoImmutableFilesFull(
1107                        CardanoDbBeacon::new(3, 100),
1108                    ),
1109                    certificate_id: "cert_id-2".to_string(),
1110                    artifact: serde_json::to_string(&fake_data::snapshot(1)).unwrap(),
1111                    created_at: Default::default(),
1112                },
1113                // Cardano database also on epoch 3
1114                SignedEntityRecord {
1115                    signed_entity_id: "signed_entity_id-3".to_string(),
1116                    signed_entity_type: SignedEntityType::CardanoDatabase(CardanoDbBeacon::new(
1117                        3, 102,
1118                    )),
1119                    certificate_id: "cert_id-3".to_string(),
1120                    artifact: serde_json::to_string(&fake_data::cardano_database_snapshot(102))
1121                        .unwrap(),
1122                    created_at: Default::default(),
1123                },
1124                // Cardano database also another epoch
1125                SignedEntityRecord {
1126                    signed_entity_id: "signed_entity_id-4".to_string(),
1127                    signed_entity_type: SignedEntityType::CardanoDatabase(CardanoDbBeacon::new(
1128                        4, 104,
1129                    )),
1130                    certificate_id: "cert_id-4".to_string(),
1131                    artifact: serde_json::to_string(&fake_data::cardano_database_snapshot(104))
1132                        .unwrap(),
1133                    created_at: Default::default(),
1134                },
1135            ];
1136            let message: CardanoDatabaseSnapshotListMessage = vec![
1137                records[2].clone().try_into().unwrap(),
1138                records[0].clone().try_into().unwrap(),
1139            ];
1140
1141            let service = MessageServiceBuilder::new()
1142                .with_signed_entity_records(&records)
1143                .build()
1144                .await;
1145
1146            let response = service
1147                .get_cardano_database_list_message_by_epoch(0, Epoch(3))
1148                .await
1149                .unwrap();
1150            assert!(response.is_empty());
1151
1152            let response = service
1153                .get_cardano_database_list_message_by_epoch(3, Epoch(3))
1154                .await
1155                .unwrap();
1156            assert_eq!(message, response);
1157        }
1158
1159        #[tokio::test]
1160        async fn get_cardano_database_digest_list_message() {
1161            let messages: CardanoDatabaseDigestListMessage = vec![
1162                CardanoDatabaseDigestListItemMessage {
1163                    immutable_file_name: "06685.chunk".to_string(),
1164                    digest: "0af556ab2620dd9363bf76963a231abe8948a500ea6be31b131d87907ab09b1e"
1165                        .to_string(),
1166                },
1167                CardanoDatabaseDigestListItemMessage {
1168                    immutable_file_name: "06685.primary".to_string(),
1169                    digest: "32dfd6b722d87f253e78eb8b478fb94f1e13463826e674d6ec7b6bf0892b2e39"
1170                        .to_string(),
1171                },
1172            ];
1173
1174            let service = MessageServiceBuilder::new()
1175                .with_immutable_file_digest_messages(&messages)
1176                .build()
1177                .await;
1178
1179            let response = service.get_cardano_database_digest_list_message().await.unwrap();
1180
1181            assert_eq!(messages, response);
1182        }
1183    }
1184
1185    mod mithril_stake_distribution {
1186        use super::*;
1187
1188        #[tokio::test]
1189        async fn get_mithril_stake_distribution() {
1190            let record = SignedEntityRecord {
1191                signed_entity_id: "signed_entity_id".to_string(),
1192                signed_entity_type: SignedEntityType::MithrilStakeDistribution(Epoch(18)),
1193                certificate_id: "cert_id".to_string(),
1194                artifact: serde_json::to_string(&fake_data::mithril_stake_distribution(
1195                    Epoch(1),
1196                    vec![],
1197                ))
1198                .unwrap(),
1199                created_at: Default::default(),
1200            };
1201            let message: MithrilStakeDistributionMessage = record.clone().try_into().unwrap();
1202
1203            let service = MessageServiceBuilder::new()
1204                .with_signed_entity_records(std::slice::from_ref(&record))
1205                .build()
1206                .await;
1207
1208            let response = service
1209                .get_mithril_stake_distribution_message(&record.signed_entity_id)
1210                .await
1211                .unwrap()
1212                .expect("A MithrilStakeDistributionMessage was expected.");
1213
1214            assert_eq!(message, response);
1215        }
1216
1217        #[tokio::test]
1218        async fn get_mithril_stake_distribution_not_exist() {
1219            let service = MessageServiceBuilder::new().build().await;
1220
1221            let response = service
1222                .get_mithril_stake_distribution_message("whatever")
1223                .await
1224                .unwrap();
1225
1226            assert!(response.is_none());
1227        }
1228
1229        #[tokio::test]
1230        async fn get_mithril_stake_distribution_list_message() {
1231            let records = vec![
1232                SignedEntityRecord {
1233                    signed_entity_id: "signed_entity_id-1".to_string(),
1234                    signed_entity_type: SignedEntityType::MithrilStakeDistribution(Epoch(18)),
1235                    certificate_id: "cert_id-1".to_string(),
1236                    artifact: serde_json::to_string(&fake_data::mithril_stake_distribution(
1237                        Epoch(1),
1238                        vec![],
1239                    ))
1240                    .unwrap(),
1241                    created_at: Default::default(),
1242                },
1243                SignedEntityRecord {
1244                    signed_entity_id: "signed_entity_id-2".to_string(),
1245                    signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
1246                    certificate_id: "cert_id-2".to_string(),
1247                    artifact: serde_json::to_string(&fake_data::cardano_database_snapshot(1))
1248                        .unwrap(),
1249                    created_at: Default::default(),
1250                },
1251            ];
1252            let message: MithrilStakeDistributionListMessage =
1253                vec![records[0].clone().try_into().unwrap()];
1254
1255            let service = MessageServiceBuilder::new()
1256                .with_signed_entity_records(&records)
1257                .build()
1258                .await;
1259
1260            let response = service.get_mithril_stake_distribution_list_message(0).await.unwrap();
1261            assert!(response.is_empty());
1262
1263            let response = service.get_mithril_stake_distribution_list_message(3).await.unwrap();
1264            assert_eq!(message, response);
1265        }
1266    }
1267
1268    mod cardano_transaction {
1269        use super::*;
1270
1271        #[tokio::test]
1272        async fn get_cardano_transaction() {
1273            let record = SignedEntityRecord {
1274                signed_entity_id: "signed_entity_id".to_string(),
1275                signed_entity_type: SignedEntityType::CardanoTransactions(
1276                    Epoch(18),
1277                    BlockNumber(120),
1278                ),
1279                certificate_id: "cert_id".to_string(),
1280                artifact: serde_json::to_string(&fake_data::cardano_transactions_snapshot(
1281                    BlockNumber(1),
1282                ))
1283                .unwrap(),
1284                created_at: Default::default(),
1285            };
1286            let message: CardanoTransactionSnapshotMessage = record.clone().try_into().unwrap();
1287
1288            let service = MessageServiceBuilder::new()
1289                .with_signed_entity_records(std::slice::from_ref(&record))
1290                .build()
1291                .await;
1292
1293            let response = service
1294                .get_cardano_transaction_message(&record.signed_entity_id)
1295                .await
1296                .unwrap()
1297                .expect("A CardanoTransactionMessage was expected.");
1298
1299            assert_eq!(message, response);
1300        }
1301
1302        #[tokio::test]
1303        async fn get_cardano_transaction_not_exist() {
1304            let service = MessageServiceBuilder::new().build().await;
1305
1306            let response = service.get_cardano_transaction_message("whatever").await.unwrap();
1307
1308            assert!(response.is_none());
1309        }
1310
1311        #[tokio::test]
1312        async fn get_cardano_transaction_list_message() {
1313            let records = vec![
1314                SignedEntityRecord {
1315                    signed_entity_id: "signed_entity_id-1".to_string(),
1316                    signed_entity_type: SignedEntityType::CardanoTransactions(
1317                        Epoch(18),
1318                        BlockNumber(120),
1319                    ),
1320                    certificate_id: "cert_id-1".to_string(),
1321                    artifact: serde_json::to_string(&fake_data::cardano_transactions_snapshot(
1322                        BlockNumber(1),
1323                    ))
1324                    .unwrap(),
1325                    created_at: Default::default(),
1326                },
1327                SignedEntityRecord {
1328                    signed_entity_id: "signed_entity_id-2".to_string(),
1329                    signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
1330                    certificate_id: "cert_id-2".to_string(),
1331                    artifact: serde_json::to_string(&fake_data::cardano_database_snapshot(1))
1332                        .unwrap(),
1333                    created_at: Default::default(),
1334                },
1335            ];
1336            let message: CardanoTransactionSnapshotListMessage =
1337                vec![records[0].clone().try_into().unwrap()];
1338
1339            let service = MessageServiceBuilder::new()
1340                .with_signed_entity_records(&records)
1341                .build()
1342                .await;
1343
1344            let response = service.get_cardano_transaction_list_message(0).await.unwrap();
1345            assert!(response.is_empty());
1346
1347            let response = service.get_cardano_transaction_list_message(3).await.unwrap();
1348            assert_eq!(message, response);
1349        }
1350    }
1351    mod cardano_blocks_transactions {
1352        use super::*;
1353
1354        #[tokio::test]
1355        async fn get_cardano_blocks_transactions() {
1356            let record = SignedEntityRecord {
1357                signed_entity_id: "signed_entity_id".to_string(),
1358                signed_entity_type: SignedEntityType::CardanoBlocksTransactions(
1359                    Epoch(18),
1360                    BlockNumber(120),
1361                ),
1362                certificate_id: "cert_id".to_string(),
1363                artifact: serde_json::to_string(&fake_data::cardano_blocks_transactions_snapshot(
1364                    BlockNumber(1),
1365                    BlockNumber(15),
1366                ))
1367                .unwrap(),
1368                created_at: Default::default(),
1369            };
1370            let message: CardanoBlocksTransactionsSnapshotMessage =
1371                record.clone().try_into().unwrap();
1372
1373            let service = MessageServiceBuilder::new()
1374                .with_signed_entity_records(std::slice::from_ref(&record))
1375                .build()
1376                .await;
1377
1378            let response = service
1379                .get_cardano_blocks_transactions_message(&record.signed_entity_id)
1380                .await
1381                .unwrap()
1382                .expect("A CardanoBlocksTransactionsMessage was expected.");
1383
1384            assert_eq!(message, response);
1385        }
1386
1387        #[tokio::test]
1388        async fn get_cardano_blocks_transactions_not_exist() {
1389            let service = MessageServiceBuilder::new().build().await;
1390
1391            let response = service
1392                .get_cardano_blocks_transactions_message("whatever")
1393                .await
1394                .unwrap();
1395
1396            assert!(response.is_none());
1397        }
1398
1399        #[tokio::test]
1400        async fn get_cardano_blocks_transactions_list_message() {
1401            let records = vec![
1402                SignedEntityRecord {
1403                    signed_entity_id: "signed_entity_id-1".to_string(),
1404                    signed_entity_type: SignedEntityType::CardanoBlocksTransactions(
1405                        Epoch(18),
1406                        BlockNumber(120),
1407                    ),
1408                    certificate_id: "cert_id-1".to_string(),
1409                    artifact: serde_json::to_string(
1410                        &fake_data::cardano_blocks_transactions_snapshot(
1411                            BlockNumber(1),
1412                            BlockNumber(15),
1413                        ),
1414                    )
1415                    .unwrap(),
1416                    created_at: Default::default(),
1417                },
1418                SignedEntityRecord {
1419                    signed_entity_id: "signed_entity_id-2".to_string(),
1420                    signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
1421                    certificate_id: "cert_id-2".to_string(),
1422                    artifact: serde_json::to_string(&fake_data::cardano_database_snapshot(1))
1423                        .unwrap(),
1424                    created_at: Default::default(),
1425                },
1426            ];
1427            let message: CardanoBlocksTransactionsSnapshotListMessage =
1428                vec![records[0].clone().try_into().unwrap()];
1429
1430            let service = MessageServiceBuilder::new()
1431                .with_signed_entity_records(&records)
1432                .build()
1433                .await;
1434
1435            let response = service.get_cardano_blocks_transactions_list_message(0).await.unwrap();
1436            assert!(response.is_empty());
1437
1438            let response = service.get_cardano_blocks_transactions_list_message(3).await.unwrap();
1439            assert_eq!(message, response);
1440        }
1441    }
1442
1443    mod cardano_stake_distribution {
1444        use super::*;
1445
1446        #[tokio::test]
1447        async fn get_cardano_stake_distribution() {
1448            let record = SignedEntityRecord {
1449                signed_entity_id: "signed_entity_id".to_string(),
1450                signed_entity_type: SignedEntityType::CardanoStakeDistribution(Epoch(18)),
1451                certificate_id: "cert_id".to_string(),
1452                artifact: serde_json::to_string(&fake_data::cardano_stake_distribution(Epoch(1)))
1453                    .unwrap(),
1454                created_at: Default::default(),
1455            };
1456            let message: CardanoStakeDistributionMessage = record.clone().try_into().unwrap();
1457
1458            let service = MessageServiceBuilder::new()
1459                .with_signed_entity_records(std::slice::from_ref(&record))
1460                .build()
1461                .await;
1462
1463            let response = service
1464                .get_cardano_stake_distribution_message(&record.signed_entity_id)
1465                .await
1466                .unwrap()
1467                .expect("A CardanoStakeDistributionMessage was expected.");
1468
1469            assert_eq!(message, response);
1470        }
1471
1472        #[tokio::test]
1473        async fn get_cardano_stake_distribution_not_exist() {
1474            let service = MessageServiceBuilder::new().build().await;
1475
1476            let response = service
1477                .get_cardano_stake_distribution_message("whatever")
1478                .await
1479                .unwrap();
1480
1481            assert!(response.is_none());
1482        }
1483
1484        #[tokio::test]
1485        async fn get_cardano_stake_distribution_by_epoch() {
1486            let record = SignedEntityRecord {
1487                signed_entity_id: "signed_entity_id".to_string(),
1488                signed_entity_type: SignedEntityType::CardanoStakeDistribution(Epoch(18)),
1489                certificate_id: "cert_id".to_string(),
1490                artifact: serde_json::to_string(&fake_data::cardano_stake_distribution(Epoch(1)))
1491                    .unwrap(),
1492                created_at: Default::default(),
1493            };
1494            let message: CardanoStakeDistributionMessage = record.clone().try_into().unwrap();
1495
1496            let service = MessageServiceBuilder::new()
1497                .with_signed_entity_records(std::slice::from_ref(&record))
1498                .build()
1499                .await;
1500
1501            let response = service
1502                .get_cardano_stake_distribution_message_by_epoch(
1503                    record.signed_entity_type.get_epoch(),
1504                )
1505                .await
1506                .unwrap()
1507                .expect("A CardanoStakeDistributionMessage was expected.");
1508
1509            assert_eq!(message, response);
1510        }
1511
1512        #[tokio::test]
1513        async fn get_cardano_stake_distribution_by_epoch_not_exist() {
1514            let service = MessageServiceBuilder::new().build().await;
1515
1516            let response = service
1517                .get_cardano_stake_distribution_message_by_epoch(Epoch(999))
1518                .await
1519                .unwrap();
1520
1521            assert!(response.is_none());
1522        }
1523
1524        #[tokio::test]
1525        async fn get_cardano_stake_distribution_list_message() {
1526            let records = vec![
1527                SignedEntityRecord {
1528                    signed_entity_id: "signed_entity_id-1".to_string(),
1529                    signed_entity_type: SignedEntityType::CardanoStakeDistribution(Epoch(18)),
1530                    certificate_id: "cert_id-1".to_string(),
1531                    artifact: serde_json::to_string(&fake_data::cardano_stake_distribution(Epoch(
1532                        1,
1533                    )))
1534                    .unwrap(),
1535                    created_at: Default::default(),
1536                },
1537                SignedEntityRecord {
1538                    signed_entity_id: "signed_entity_id-2".to_string(),
1539                    signed_entity_type: SignedEntityType::CardanoDatabase(fake_data::beacon()),
1540                    certificate_id: "cert_id-2".to_string(),
1541                    artifact: serde_json::to_string(&fake_data::cardano_database_snapshot(1))
1542                        .unwrap(),
1543                    created_at: Default::default(),
1544                },
1545            ];
1546            let message: CardanoStakeDistributionListMessage =
1547                vec![records[0].clone().try_into().unwrap()];
1548
1549            let service = MessageServiceBuilder::new()
1550                .with_signed_entity_records(&records)
1551                .build()
1552                .await;
1553
1554            let response = service.get_cardano_stake_distribution_list_message(0).await.unwrap();
1555            assert!(response.is_empty());
1556
1557            let response = service.get_cardano_stake_distribution_list_message(3).await.unwrap();
1558            assert_eq!(message, response);
1559        }
1560    }
1561}