1use anyhow::anyhow;
2use async_trait::async_trait;
3use slog::{debug, trace, warn, Logger};
4use std::collections::BTreeSet;
5use std::sync::Arc;
6use thiserror::Error;
7
8use crate::dependency_injection::EpochServiceWrapper;
9use crate::entities::SignerEpochSettings;
10use crate::services::SignedEntityConfigProvider;
11use crate::store::ProtocolInitializerStorer;
12use crate::RunnerError;
13use mithril_common::crypto_helper::ProtocolInitializer;
14use mithril_common::entities::{
15 CardanoTransactionsSigningConfig, Epoch, PartyId, ProtocolParameters, SignedEntityConfig,
16 SignedEntityTypeDiscriminants, Signer, SignerWithStake,
17};
18use mithril_common::logging::LoggerExtensions;
19use mithril_common::StdResult;
20use mithril_persistence::store::StakeStorer;
21
22#[derive(Debug, Error)]
24pub enum EpochServiceError {
25 #[error("Epoch service was not initialized, the function `inform_epoch_settings` must be called first")]
27 NotYetInitialized,
28}
29
30#[async_trait]
32pub trait EpochService: Sync + Send {
33 async fn inform_epoch_settings(
36 &mut self,
37 epoch_settings: SignerEpochSettings,
38 allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
39 ) -> StdResult<()>;
40
41 fn epoch_of_current_data(&self) -> StdResult<Epoch>;
43
44 fn registration_protocol_parameters(&self) -> StdResult<&ProtocolParameters>;
46
47 fn protocol_initializer(&self) -> StdResult<&Option<ProtocolInitializer>>;
51
52 fn current_signers(&self) -> StdResult<&Vec<Signer>>;
54
55 fn next_signers(&self) -> StdResult<&Vec<Signer>>;
57
58 async fn current_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>>;
60
61 async fn next_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>>;
63
64 fn allowed_discriminants(&self) -> StdResult<&BTreeSet<SignedEntityTypeDiscriminants>>;
66
67 fn cardano_transactions_signing_config(
69 &self,
70 ) -> StdResult<&Option<CardanoTransactionsSigningConfig>>;
71
72 fn next_cardano_transactions_signing_config(
74 &self,
75 ) -> StdResult<&Option<CardanoTransactionsSigningConfig>>;
76
77 fn can_signer_sign_current_epoch(&self, party_id: PartyId) -> StdResult<bool>;
79}
80
81pub(crate) struct EpochData {
82 pub epoch: Epoch,
83 pub registration_protocol_parameters: ProtocolParameters,
84 pub protocol_initializer: Option<ProtocolInitializer>,
85 pub current_signers: Vec<Signer>,
86 pub next_signers: Vec<Signer>,
87 pub allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
88 pub cardano_transactions_signing_config: Option<CardanoTransactionsSigningConfig>,
89 pub next_cardano_transactions_signing_config: Option<CardanoTransactionsSigningConfig>,
90}
91
92pub struct MithrilEpochService {
94 stake_storer: Arc<dyn StakeStorer>,
95 protocol_initializer_store: Arc<dyn ProtocolInitializerStorer>,
96 epoch_data: Option<EpochData>,
97 logger: Logger,
98}
99
100impl MithrilEpochService {
101 pub fn new(
103 stake_storer: Arc<dyn StakeStorer>,
104 protocol_initializer_store: Arc<dyn ProtocolInitializerStorer>,
105 logger: Logger,
106 ) -> Self {
107 Self {
108 stake_storer,
109 protocol_initializer_store,
110 epoch_data: None,
111 logger: logger.new_with_component_name::<Self>(),
112 }
113 }
114
115 async fn associate_signers_with_stake(
116 &self,
117 epoch: Epoch,
118 signers: &[Signer],
119 ) -> StdResult<Vec<SignerWithStake>> {
120 debug!(
121 self.logger,
122 ">> associate_signers_with_stake(epoch:{epoch})"
123 );
124
125 let stakes = self
126 .stake_storer
127 .get_stakes(epoch)
128 .await?
129 .ok_or_else(|| RunnerError::NoValueError(format!("stakes at epoch {epoch}")))?;
130
131 let mut signers_with_stake = vec![];
132
133 for signer in signers {
134 let stake = stakes
135 .get(&*signer.party_id)
136 .ok_or_else(|| RunnerError::NoStakeForSigner(signer.party_id.to_string()))?;
137
138 signers_with_stake.push(SignerWithStake::new(
139 signer.party_id.to_owned(),
140 signer.verification_key.to_owned(),
141 signer.verification_key_signature.to_owned(),
142 signer.operational_certificate.to_owned(),
143 signer.kes_period.to_owned(),
144 *stake,
145 ));
146 trace!(
147 self.logger,
148 " > Associating signer_id {} with stake {}",
149 signer.party_id,
150 *stake
151 );
152 }
153
154 Ok(signers_with_stake)
155 }
156
157 fn is_signer_included_in_current_stake_distribution(
158 &self,
159 party_id: PartyId,
160 protocol_initializer: &ProtocolInitializer,
161 ) -> StdResult<bool> {
162 Ok(self.current_signers()?.iter().any(|s| {
163 s.party_id == party_id
164 && s.verification_key == protocol_initializer.verification_key().into()
165 }))
166 }
167
168 fn unwrap_data(&self) -> Result<&EpochData, EpochServiceError> {
169 self.epoch_data
170 .as_ref()
171 .ok_or(EpochServiceError::NotYetInitialized)
172 }
173}
174
175#[async_trait]
176impl EpochService for MithrilEpochService {
177 async fn inform_epoch_settings(
178 &mut self,
179 epoch_settings: SignerEpochSettings,
180 allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
181 ) -> StdResult<()> {
182 debug!(self.logger, ">> inform_epoch_settings"; "epoch_settings" => ?epoch_settings);
183
184 let epoch = epoch_settings.epoch;
185 let protocol_initializer = self
186 .protocol_initializer_store
187 .get_protocol_initializer(epoch.offset_to_signer_retrieval_epoch()?)
188 .await?;
189
190 self.epoch_data = Some(EpochData {
191 epoch,
192 registration_protocol_parameters: epoch_settings.registration_protocol_parameters,
193 protocol_initializer,
194 current_signers: epoch_settings.current_signers,
195 next_signers: epoch_settings.next_signers,
196 allowed_discriminants,
197 cardano_transactions_signing_config: epoch_settings.cardano_transactions_signing_config,
198 next_cardano_transactions_signing_config: epoch_settings
199 .next_cardano_transactions_signing_config,
200 });
201
202 Ok(())
203 }
204
205 fn epoch_of_current_data(&self) -> StdResult<Epoch> {
206 Ok(self.unwrap_data()?.epoch)
207 }
208
209 fn registration_protocol_parameters(&self) -> StdResult<&ProtocolParameters> {
210 Ok(&self.unwrap_data()?.registration_protocol_parameters)
211 }
212
213 fn protocol_initializer(&self) -> StdResult<&Option<ProtocolInitializer>> {
214 Ok(&self.unwrap_data()?.protocol_initializer)
215 }
216
217 fn current_signers(&self) -> StdResult<&Vec<Signer>> {
218 Ok(&self.unwrap_data()?.current_signers)
219 }
220
221 fn next_signers(&self) -> StdResult<&Vec<Signer>> {
222 Ok(&self.unwrap_data()?.next_signers)
223 }
224
225 async fn current_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>> {
226 let current_epoch = self.epoch_of_current_data()?;
227 self.associate_signers_with_stake(
228 current_epoch.offset_to_signer_retrieval_epoch()?,
229 self.current_signers()?,
230 )
231 .await
232 }
233
234 async fn next_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>> {
235 let current_epoch = self.epoch_of_current_data()?;
236 self.associate_signers_with_stake(
237 current_epoch.offset_to_next_signer_retrieval_epoch(),
238 self.next_signers()?,
239 )
240 .await
241 }
242
243 fn allowed_discriminants(&self) -> StdResult<&BTreeSet<SignedEntityTypeDiscriminants>> {
244 Ok(&self.unwrap_data()?.allowed_discriminants)
245 }
246
247 fn cardano_transactions_signing_config(
248 &self,
249 ) -> StdResult<&Option<CardanoTransactionsSigningConfig>> {
250 Ok(&self.unwrap_data()?.cardano_transactions_signing_config)
251 }
252
253 fn next_cardano_transactions_signing_config(
254 &self,
255 ) -> StdResult<&Option<CardanoTransactionsSigningConfig>> {
256 Ok(&self.unwrap_data()?.next_cardano_transactions_signing_config)
257 }
258
259 fn can_signer_sign_current_epoch(&self, party_id: PartyId) -> StdResult<bool> {
260 let epoch = self.epoch_of_current_data()?;
261 if let Some(protocol_initializer) = self.protocol_initializer()? {
262 debug!(
263 self.logger,
264 " > Got protocol initializer for this epoch ({epoch})"
265 );
266 if self
267 .is_signer_included_in_current_stake_distribution(party_id, protocol_initializer)?
268 {
269 return Ok(true);
270 } else {
271 debug!(
272 self.logger,
273 " > Signer not in current stake distribution. Can NOT sign"
274 );
275 }
276 } else {
277 warn!(
278 self.logger,
279 " > NO protocol initializer found for this epoch ({epoch})",
280 );
281 }
282
283 Ok(false)
284 }
285}
286
287pub struct SignerSignedEntityConfigProvider {
292 epoch_service: EpochServiceWrapper,
293}
294
295impl SignerSignedEntityConfigProvider {
296 pub fn new(epoch_service: EpochServiceWrapper) -> Self {
298 Self { epoch_service }
299 }
300}
301
302#[async_trait]
303impl SignedEntityConfigProvider for SignerSignedEntityConfigProvider {
304 async fn get(&self) -> StdResult<SignedEntityConfig> {
305 let epoch_service = self.epoch_service.read().await;
306 let cardano_transactions_signing_config =
307 match epoch_service.cardano_transactions_signing_config()? {
308 Some(config) => Ok(config.clone()),
309 None => Err(anyhow!("No cardano transaction signing config available")),
310 }?;
311
312 Ok(SignedEntityConfig {
313 allowed_discriminants: epoch_service.allowed_discriminants()?.clone(),
314 cardano_transactions_signing_config,
315 })
316 }
317}
318
319#[cfg(test)]
320use crate::database::repository::ProtocolInitializerRepository;
321
322#[cfg(test)]
323impl MithrilEpochService {
324 pub fn new_with_dumb_dependencies() -> Self {
326 use crate::database::repository::StakePoolStore;
327 use crate::database::test_helper::main_db_connection;
328 use crate::test_tools::TestLogger;
329
330 let sqlite_connection = Arc::new(main_db_connection().unwrap());
331 let stake_store = Arc::new(StakePoolStore::new(sqlite_connection.clone(), None));
332 let protocol_initializer_store =
333 Arc::new(ProtocolInitializerRepository::new(sqlite_connection, None));
334
335 Self::new(
336 stake_store,
337 protocol_initializer_store,
338 TestLogger::stdout(),
339 )
340 }
341
342 pub fn set_data_to_default_or_fake(mut self, epoch: Epoch) -> Self {
345 use mithril_common::test_utils::fake_data;
346
347 let epoch_data = EpochData {
348 epoch,
349 registration_protocol_parameters: fake_data::protocol_parameters(),
350 protocol_initializer: None,
351 current_signers: vec![],
352 next_signers: vec![],
353 allowed_discriminants: BTreeSet::new(),
354 cardano_transactions_signing_config: None,
355 next_cardano_transactions_signing_config: None,
356 };
357 self.epoch_data = Some(epoch_data);
358 self
359 }
360
361 pub(crate) fn alter_data(mut self, data_config: impl FnOnce(&mut EpochData)) -> Self {
363 if let Some(data) = self.epoch_data.as_mut() {
364 data_config(data);
365 }
366 self
367 }
368}
369
370#[cfg(test)]
371pub(crate) mod mock_epoch_service {
372 use mockall::mock;
373
374 use super::*;
375
376 mock! {
377 pub EpochServiceImpl {}
378
379 #[async_trait]
380 impl EpochService for EpochServiceImpl {
381 async fn inform_epoch_settings(
382 &mut self,
383 epoch_settings: SignerEpochSettings,
384 allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
385 ) -> StdResult<()>;
386
387 fn epoch_of_current_data(&self) -> StdResult<Epoch>;
388
389 fn registration_protocol_parameters(&self) -> StdResult<&'static ProtocolParameters>;
390
391 fn protocol_initializer(&self) -> StdResult<&'static Option<ProtocolInitializer>>;
392
393 fn current_signers(&self) -> StdResult<&'static Vec<Signer>>;
394
395 fn next_signers(&self) -> StdResult<&'static Vec<Signer>>;
396
397 async fn current_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>>;
398
399 async fn next_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>>;
400
401 fn allowed_discriminants(&self) -> StdResult<&'static BTreeSet<SignedEntityTypeDiscriminants>>;
402
403 fn cardano_transactions_signing_config(
404 &self,
405 ) -> StdResult<&'static Option<CardanoTransactionsSigningConfig>>;
406
407 fn next_cardano_transactions_signing_config(
408 &self,
409 ) -> StdResult<&'static Option<CardanoTransactionsSigningConfig>>;
410
411 fn can_signer_sign_current_epoch(&self, party_id: PartyId) -> StdResult<bool>;
412 }
413 }
414
415 impl MockEpochServiceImpl {
416 pub fn new_with_config(
417 config: impl FnOnce(&mut MockEpochServiceImpl),
418 ) -> MockEpochServiceImpl {
419 let mut epoch_service_mock = MockEpochServiceImpl::new();
420 config(&mut epoch_service_mock);
421
422 epoch_service_mock
423 }
424 }
425}
426
427#[cfg(test)]
428mod tests {
429 use std::sync::Arc;
430 use tokio::sync::RwLock;
431
432 use mithril_common::entities::{Epoch, StakeDistribution};
433 use mithril_common::test_utils::{fake_data, MithrilFixtureBuilder};
434
435 use crate::database::repository::{ProtocolInitializerRepository, StakePoolStore};
436 use crate::database::test_helper::main_db_connection;
437 use crate::entities::SignerEpochSettings;
438 use crate::services::MithrilProtocolInitializerBuilder;
439 use crate::test_tools::TestLogger;
440
441 use super::*;
442
443 #[test]
444 fn test_is_signer_included_in_current_stake_distribution_returns_error_when_epoch_settings_is_not_set(
445 ) {
446 let party_id = "party_id".to_string();
447 let protocol_initializer = MithrilProtocolInitializerBuilder::build(
448 &100,
449 &fake_data::protocol_parameters(),
450 None,
451 None,
452 )
453 .unwrap();
454 let connection = Arc::new(main_db_connection().unwrap());
455 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
456 let protocol_initializer_store =
457 Arc::new(ProtocolInitializerRepository::new(connection, None));
458 let service = MithrilEpochService::new(
459 stake_store,
460 protocol_initializer_store,
461 TestLogger::stdout(),
462 );
463
464 service
465 .is_signer_included_in_current_stake_distribution(party_id, &protocol_initializer)
466 .expect_err("can_signer_sign should return error when epoch settings is not set");
467 }
468
469 #[tokio::test]
470 async fn test_is_signer_included_in_current_stake_distribution_returns_true_when_signer_verification_key_and_pool_id_found(
471 ) {
472 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
473 let protocol_initializer = fixtures.signers_fixture()[0]
474 .protocol_initializer
475 .to_owned();
476 let epoch = Epoch(12);
477 let signers = fixtures.signers();
478
479 let connection = Arc::new(main_db_connection().unwrap());
480 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
481 let protocol_initializer_store =
482 Arc::new(ProtocolInitializerRepository::new(connection, None));
483
484 let epoch_settings = SignerEpochSettings {
485 epoch,
486 current_signers: signers[..5].to_vec(),
487 ..SignerEpochSettings::dummy().clone()
488 };
489
490 let mut service = MithrilEpochService::new(
491 stake_store,
492 protocol_initializer_store,
493 TestLogger::stdout(),
494 );
495 service
496 .inform_epoch_settings(epoch_settings.clone(), BTreeSet::new())
497 .await
498 .unwrap();
499
500 let party_id = fixtures.signers_fixture()[0].party_id();
501 assert!(service
502 .is_signer_included_in_current_stake_distribution(
503 party_id.clone(),
504 &protocol_initializer
505 )
506 .unwrap());
507
508 let party_id_not_included = fixtures.signers_fixture()[6].party_id();
509 assert!(!service
510 .is_signer_included_in_current_stake_distribution(
511 party_id_not_included,
512 &protocol_initializer
513 )
514 .unwrap());
515
516 let protocol_initializer_not_included = fixtures.signers_fixture()[6]
517 .protocol_initializer
518 .to_owned();
519 assert!(!service
520 .is_signer_included_in_current_stake_distribution(
521 party_id,
522 &protocol_initializer_not_included
523 )
524 .unwrap());
525 }
526
527 mod can_signer_sign_current_epoch {
528 use super::*;
529
530 #[test]
531 fn cant_sign_if_no_protocol_initializer_are_stored() {
532 let epoch = Epoch(12);
533 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
534
535 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
536 .set_data_to_default_or_fake(epoch)
537 .alter_data(|data| {
538 data.protocol_initializer = None;
539 data.current_signers = fixtures.signers();
540 });
541
542 let can_sign_current_epoch = epoch_service
543 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
544 .unwrap();
545 assert!(!can_sign_current_epoch);
546 }
547
548 #[test]
549 fn cant_sign_if_stored_protocol_initializer_belong_to_another_party() {
550 let epoch = Epoch(12);
551 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
552
553 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
554 .set_data_to_default_or_fake(epoch)
555 .alter_data(|data| {
556 data.protocol_initializer =
557 Some(fixtures.signers_fixture()[2].protocol_initializer.clone());
558 data.current_signers = fixtures.signers();
559 });
560
561 let can_sign_current_epoch = epoch_service
562 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
563 .unwrap();
564 assert!(!can_sign_current_epoch);
565 }
566
567 #[test]
568 fn cant_sign_if_not_in_current_signers() {
569 let epoch = Epoch(12);
570 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
571
572 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
573 .set_data_to_default_or_fake(epoch)
574 .alter_data(|data| {
575 data.protocol_initializer =
576 Some(fixtures.signers_fixture()[0].protocol_initializer.clone());
577 data.current_signers = fixtures.signers()[2..].to_vec();
578 });
579
580 let can_sign_current_epoch = epoch_service
581 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
582 .unwrap();
583 assert!(!can_sign_current_epoch);
584 }
585
586 #[test]
587 fn can_sign_if_in_current_signers_and_use_the_stored_protocol_initializer() {
588 let epoch = Epoch(12);
589 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
590
591 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
592 .set_data_to_default_or_fake(epoch)
593 .alter_data(|data| {
594 data.protocol_initializer =
595 Some(fixtures.signers_fixture()[0].protocol_initializer.clone());
596 data.current_signers = fixtures.signers();
597 });
598
599 let can_sign_current_epoch = epoch_service
600 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
601 .unwrap();
602 assert!(can_sign_current_epoch);
603 }
604 }
605
606 #[tokio::test]
607 async fn test_retrieve_data_return_error_before_register_epoch_settings_was_call() {
608 let epoch = Epoch(12);
609 let signers = fake_data::signers(10);
611 let stake_distribution: StakeDistribution = signers
612 .iter()
613 .enumerate()
614 .map(|(i, signer)| (signer.party_id.clone(), (i + 1) as u64 * 100))
615 .collect();
616
617 let connection = Arc::new(main_db_connection().unwrap());
619 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
620 stake_store
621 .save_stakes(epoch, stake_distribution.clone())
622 .await
623 .expect("save_stakes should not fail");
624 let protocol_initializer_store =
625 Arc::new(ProtocolInitializerRepository::new(connection, None));
626
627 let service = MithrilEpochService::new(
629 stake_store,
630 protocol_initializer_store,
631 TestLogger::stdout(),
632 );
633 assert!(service.epoch_of_current_data().is_err());
634 assert!(service.registration_protocol_parameters().is_err());
635 assert!(service.protocol_initializer().is_err());
636 assert!(service.current_signers().is_err());
637 assert!(service.next_signers().is_err());
638 assert!(service.current_signers_with_stake().await.is_err());
639 assert!(service.next_signers_with_stake().await.is_err());
640 assert!(service.cardano_transactions_signing_config().is_err());
641 assert!(service.next_cardano_transactions_signing_config().is_err());
642 }
643
644 #[tokio::test]
645 async fn test_data_are_available_after_register_epoch_settings_call() {
646 let epoch = Epoch(12);
647 let signers = fake_data::signers(10);
649
650 let connection = Arc::new(main_db_connection().unwrap());
652 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
653 let protocol_initializer_store =
654 Arc::new(ProtocolInitializerRepository::new(connection, None));
655
656 let epoch_settings = SignerEpochSettings {
658 epoch,
659 current_signers: signers[2..5].to_vec(),
660 next_signers: signers[3..7].to_vec(),
661 ..SignerEpochSettings::dummy().clone()
662 };
663
664 let mut service = MithrilEpochService::new(
666 stake_store,
667 protocol_initializer_store,
668 TestLogger::stdout(),
669 );
670
671 service
672 .inform_epoch_settings(
673 epoch_settings.clone(),
674 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]),
675 )
676 .await
677 .unwrap();
678
679 {
681 let current_signers = service.current_signers().unwrap();
682 let expected_current_signers = epoch_settings.current_signers.clone();
683 assert_eq!(expected_current_signers, *current_signers);
684 }
685 {
687 let next_signers = service.next_signers().unwrap();
688 let expected_next_signers = epoch_settings.next_signers.clone();
689 assert_eq!(expected_next_signers, *next_signers);
690 }
691
692 assert_eq!(
694 epoch_settings.epoch,
695 service.epoch_of_current_data().unwrap()
696 );
697 assert_eq!(
698 epoch_settings.registration_protocol_parameters,
699 *service.registration_protocol_parameters().unwrap()
700 );
701 assert!(
702 service.protocol_initializer().unwrap().is_none(),
703 "protocol_initializer should be None since nothing was in store"
704 );
705
706 assert_eq!(
708 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]),
709 *service.allowed_discriminants().unwrap()
710 );
711
712 assert_eq!(
714 epoch_settings.cardano_transactions_signing_config,
715 *service.cardano_transactions_signing_config().unwrap()
716 );
717 assert_eq!(
719 epoch_settings.next_cardano_transactions_signing_config,
720 *service.next_cardano_transactions_signing_config().unwrap()
721 );
722 }
723
724 #[tokio::test]
725 async fn test_signers_with_stake_are_available_after_register_epoch_settings_call() {
726 fn build_stake_distribution(signers: &[Signer], first_stake: u64) -> StakeDistribution {
727 signers
728 .iter()
729 .enumerate()
730 .map(|(i, signer)| (signer.party_id.clone(), first_stake + i as u64))
731 .collect()
732 }
733
734 let epoch = Epoch(12);
735
736 let signers = fake_data::signers(10);
738 let stake_distribution: StakeDistribution = build_stake_distribution(&signers, 100);
739 let next_stake_distribution: StakeDistribution = build_stake_distribution(&signers, 500);
740
741 let connection = Arc::new(main_db_connection().unwrap());
742 let stake_store = {
743 let store = Arc::new(StakePoolStore::new(connection.clone(), None));
744 store
745 .save_stakes(
746 epoch.offset_to_signer_retrieval_epoch().unwrap(),
747 stake_distribution.clone(),
748 )
749 .await
750 .unwrap();
751 store
752 .save_stakes(
753 epoch.offset_to_next_signer_retrieval_epoch(),
754 next_stake_distribution.clone(),
755 )
756 .await
757 .unwrap();
758 store
759 };
760 let protocol_initializer_store =
761 Arc::new(ProtocolInitializerRepository::new(connection, None));
762
763 let epoch_settings = SignerEpochSettings {
765 epoch,
766 current_signers: signers[2..5].to_vec(),
767 next_signers: signers[3..7].to_vec(),
768 ..SignerEpochSettings::dummy().clone()
769 };
770
771 let mut service = MithrilEpochService::new(
773 stake_store,
774 protocol_initializer_store,
775 TestLogger::stdout(),
776 );
777 service
778 .inform_epoch_settings(epoch_settings.clone(), BTreeSet::new())
779 .await
780 .unwrap();
781
782 {
784 let current_signers = service.current_signers_with_stake().await.unwrap();
785
786 assert_eq!(epoch_settings.current_signers.len(), current_signers.len());
787 for signer in current_signers {
788 let expected_stake = stake_distribution.get(&signer.party_id).unwrap();
789 assert_eq!(expected_stake, &signer.stake);
790 }
791 }
792
793 {
795 let next_signers = service.next_signers_with_stake().await.unwrap();
796
797 assert_eq!(epoch_settings.next_signers.len(), next_signers.len());
798 for signer in next_signers {
799 let expected_stake = next_stake_distribution.get(&signer.party_id).unwrap();
800 assert_eq!(expected_stake, &signer.stake);
801 }
802 }
803 }
804
805 #[tokio::test]
806 async fn test_protocol_initializer_is_available_after_register_epoch_settings_call_if_in_store()
807 {
808 let epoch = Epoch(12);
809 let connection = Arc::new(main_db_connection().unwrap());
810 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
811 let protocol_initializer_store =
812 Arc::new(ProtocolInitializerRepository::new(connection, None));
813 protocol_initializer_store
814 .save_protocol_initializer(
815 epoch.offset_to_signer_retrieval_epoch().unwrap(),
816 fake_data::protocol_initializer("seed", 1245),
817 )
818 .await
819 .unwrap();
820
821 let mut service = MithrilEpochService::new(
822 stake_store,
823 protocol_initializer_store,
824 TestLogger::stdout(),
825 );
826 let epoch_settings = SignerEpochSettings {
827 epoch,
828 ..SignerEpochSettings::dummy().clone()
829 };
830 service
831 .inform_epoch_settings(epoch_settings, BTreeSet::new())
832 .await
833 .unwrap();
834
835 let protocol_initializer = service.protocol_initializer().unwrap();
836 assert_eq!(
837 Some(1245),
838 protocol_initializer.as_ref().map(|p| p.get_stake()),
839 );
840 }
841
842 #[tokio::test]
843 async fn is_source_of_signed_entity_config() {
844 let connection = Arc::new(main_db_connection().unwrap());
845 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
846 let protocol_initializer_store =
847 Arc::new(ProtocolInitializerRepository::new(connection, None));
848 let epoch_service = Arc::new(RwLock::new(MithrilEpochService::new(
849 stake_store,
850 protocol_initializer_store,
851 TestLogger::stdout(),
852 )));
853 let config_provider = SignerSignedEntityConfigProvider {
854 epoch_service: epoch_service.clone(),
855 };
856
857 {
859 config_provider.get().await.expect_err(
860 "Should fail since sources data are not set before the first inform_epoch_settings",
861 );
862 }
863 {
865 let allowed_discriminants =
866 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]);
867
868 epoch_service
869 .write()
870 .await
871 .inform_epoch_settings(
872 SignerEpochSettings {
873 cardano_transactions_signing_config: None,
874 ..SignerEpochSettings::dummy()
875 },
876 allowed_discriminants.clone(),
877 )
878 .await
879 .unwrap();
880
881 config_provider
882 .get()
883 .await
884 .expect_err("Should fail since cardano_transactions_signing_config is not set");
885 }
886 {
888 let allowed_discriminants =
889 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]);
890 epoch_service
891 .write()
892 .await
893 .inform_epoch_settings(
894 SignerEpochSettings {
895 cardano_transactions_signing_config: Some(
896 CardanoTransactionsSigningConfig::dummy(),
897 ),
898 ..SignerEpochSettings::dummy()
899 },
900 allowed_discriminants.clone(),
901 )
902 .await
903 .unwrap();
904
905 let config = config_provider.get().await.unwrap();
906
907 assert_eq!(
908 SignedEntityConfig {
909 allowed_discriminants,
910 cardano_transactions_signing_config: CardanoTransactionsSigningConfig::dummy(),
911 },
912 config
913 );
914 }
915 }
916}