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