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