1use 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#[cfg_attr(test, mockall::automock)]
31#[async_trait]
32pub trait MessageService: Sync + Send {
33 async fn get_epoch_settings_message(
35 &self,
36 allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
37 ) -> StdResult<EpochSettingsMessage>;
38
39 async fn get_protocol_configuration_message(
41 &self,
42 epoch: Epoch,
43 allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
44 ) -> StdResult<Option<ProtocolConfigurationMessage>>;
45
46 async fn get_certificate_message(
48 &self,
49 certificate_hash: &str,
50 ) -> StdResult<Option<CertificateMessage>>;
51
52 async fn get_latest_genesis_certificate_message(&self)
54 -> StdResult<Option<CertificateMessage>>;
55
56 async fn get_certificate_list_message(&self, limit: usize)
58 -> StdResult<CertificateListMessage>;
59
60 async fn get_snapshot_message(
62 &self,
63 signed_entity_id: &str,
64 ) -> StdResult<Option<SnapshotMessage>>;
65
66 async fn get_snapshot_list_message(&self, limit: usize) -> StdResult<SnapshotListMessage>;
69
70 async fn get_cardano_database_message(
72 &self,
73 signed_entity_id: &str,
74 ) -> StdResult<Option<CardanoDatabaseSnapshotMessage>>;
75
76 async fn get_cardano_database_list_message(
78 &self,
79 limit: usize,
80 ) -> StdResult<CardanoDatabaseSnapshotListMessage>;
81
82 async fn get_cardano_database_list_message_by_epoch(
84 &self,
85 limit: usize,
86 epoch: Epoch,
87 ) -> StdResult<CardanoDatabaseSnapshotListMessage>;
88
89 async fn get_cardano_database_digest_list_message(
91 &self,
92 ) -> StdResult<CardanoDatabaseDigestListMessage>;
93
94 async fn get_mithril_stake_distribution_message(
96 &self,
97 signed_entity_id: &str,
98 ) -> StdResult<Option<MithrilStakeDistributionMessage>>;
99
100 async fn get_mithril_stake_distribution_list_message(
102 &self,
103 limit: usize,
104 ) -> StdResult<MithrilStakeDistributionListMessage>;
105
106 async fn get_cardano_transaction_message(
108 &self,
109 signed_entity_id: &str,
110 ) -> StdResult<Option<CardanoTransactionSnapshotMessage>>;
111
112 async fn get_cardano_transaction_list_message(
114 &self,
115 limit: usize,
116 ) -> StdResult<CardanoTransactionSnapshotListMessage>;
117
118 async fn get_cardano_blocks_transactions_message(
120 &self,
121 signed_entity_id: &str,
122 ) -> StdResult<Option<CardanoBlocksTransactionsSnapshotMessage>>;
123
124 async fn get_cardano_blocks_transactions_list_message(
126 &self,
127 limit: usize,
128 ) -> StdResult<CardanoBlocksTransactionsSnapshotListMessage>;
129
130 async fn get_cardano_stake_distribution_message(
132 &self,
133 signed_entity_id: &str,
134 ) -> StdResult<Option<CardanoStakeDistributionMessage>>;
135
136 async fn get_cardano_stake_distribution_message_by_epoch(
138 &self,
139 epoch: Epoch,
140 ) -> StdResult<Option<CardanoStakeDistributionMessage>>;
141
142 async fn get_cardano_stake_distribution_list_message(
144 &self,
145 limit: usize,
146 ) -> StdResult<CardanoStakeDistributionListMessage>;
147}
148
149pub 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 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 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 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 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 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}