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::double::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::{
432 builder::MithrilFixtureBuilder,
433 double::{Dummy, fake_data},
434 };
435
436 use crate::database::repository::{ProtocolInitializerRepository, StakePoolStore};
437 use crate::database::test_helper::main_db_connection;
438 use crate::entities::SignerEpochSettings;
439 use crate::services::MithrilProtocolInitializerBuilder;
440 use crate::test_tools::TestLogger;
441
442 use super::*;
443
444 #[test]
445 fn test_is_signer_included_in_current_stake_distribution_returns_error_when_epoch_settings_is_not_set()
446 {
447 let party_id = "party_id".to_string();
448 let protocol_initializer = MithrilProtocolInitializerBuilder::build(
449 &100,
450 &fake_data::protocol_parameters(),
451 None,
452 None,
453 )
454 .unwrap();
455 let connection = Arc::new(main_db_connection().unwrap());
456 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
457 let protocol_initializer_store =
458 Arc::new(ProtocolInitializerRepository::new(connection, None));
459 let service = MithrilEpochService::new(
460 stake_store,
461 protocol_initializer_store,
462 TestLogger::stdout(),
463 );
464
465 service
466 .is_signer_included_in_current_stake_distribution(party_id, &protocol_initializer)
467 .expect_err("can_signer_sign should return error when epoch settings is not set");
468 }
469
470 #[tokio::test]
471 async fn test_is_signer_included_in_current_stake_distribution_returns_true_when_signer_verification_key_and_pool_id_found()
472 {
473 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
474 let protocol_initializer = fixtures.signers_fixture()[0].protocol_initializer.to_owned();
475 let epoch = Epoch(12);
476 let signers = fixtures.signers();
477
478 let connection = Arc::new(main_db_connection().unwrap());
479 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
480 let protocol_initializer_store =
481 Arc::new(ProtocolInitializerRepository::new(connection, None));
482
483 let epoch_settings = SignerEpochSettings {
484 epoch,
485 current_signers: signers[..5].to_vec(),
486 ..SignerEpochSettings::dummy().clone()
487 };
488
489 let mut service = MithrilEpochService::new(
490 stake_store,
491 protocol_initializer_store,
492 TestLogger::stdout(),
493 );
494 service
495 .inform_epoch_settings(epoch_settings.clone(), BTreeSet::new())
496 .await
497 .unwrap();
498
499 let party_id = fixtures.signers_fixture()[0].party_id();
500 assert!(
501 service
502 .is_signer_included_in_current_stake_distribution(
503 party_id.clone(),
504 &protocol_initializer
505 )
506 .unwrap()
507 );
508
509 let party_id_not_included = fixtures.signers_fixture()[6].party_id();
510 assert!(
511 !service
512 .is_signer_included_in_current_stake_distribution(
513 party_id_not_included,
514 &protocol_initializer
515 )
516 .unwrap()
517 );
518
519 let protocol_initializer_not_included =
520 fixtures.signers_fixture()[6].protocol_initializer.to_owned();
521 assert!(
522 !service
523 .is_signer_included_in_current_stake_distribution(
524 party_id,
525 &protocol_initializer_not_included
526 )
527 .unwrap()
528 );
529 }
530
531 mod can_signer_sign_current_epoch {
532 use super::*;
533
534 #[test]
535 fn cant_sign_if_no_protocol_initializer_are_stored() {
536 let epoch = Epoch(12);
537 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
538
539 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
540 .set_data_to_default_or_fake(epoch)
541 .alter_data(|data| {
542 data.protocol_initializer = None;
543 data.current_signers = fixtures.signers();
544 });
545
546 let can_sign_current_epoch = epoch_service
547 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
548 .unwrap();
549 assert!(!can_sign_current_epoch);
550 }
551
552 #[test]
553 fn cant_sign_if_stored_protocol_initializer_belong_to_another_party() {
554 let epoch = Epoch(12);
555 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
556
557 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
558 .set_data_to_default_or_fake(epoch)
559 .alter_data(|data| {
560 data.protocol_initializer =
561 Some(fixtures.signers_fixture()[2].protocol_initializer.clone());
562 data.current_signers = fixtures.signers();
563 });
564
565 let can_sign_current_epoch = epoch_service
566 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
567 .unwrap();
568 assert!(!can_sign_current_epoch);
569 }
570
571 #[test]
572 fn cant_sign_if_not_in_current_signers() {
573 let epoch = Epoch(12);
574 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
575
576 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
577 .set_data_to_default_or_fake(epoch)
578 .alter_data(|data| {
579 data.protocol_initializer =
580 Some(fixtures.signers_fixture()[0].protocol_initializer.clone());
581 data.current_signers = fixtures.signers()[2..].to_vec();
582 });
583
584 let can_sign_current_epoch = epoch_service
585 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
586 .unwrap();
587 assert!(!can_sign_current_epoch);
588 }
589
590 #[test]
591 fn can_sign_if_in_current_signers_and_use_the_stored_protocol_initializer() {
592 let epoch = Epoch(12);
593 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
594
595 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
596 .set_data_to_default_or_fake(epoch)
597 .alter_data(|data| {
598 data.protocol_initializer =
599 Some(fixtures.signers_fixture()[0].protocol_initializer.clone());
600 data.current_signers = fixtures.signers();
601 });
602
603 let can_sign_current_epoch = epoch_service
604 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
605 .unwrap();
606 assert!(can_sign_current_epoch);
607 }
608 }
609
610 #[tokio::test]
611 async fn test_retrieve_data_return_error_before_register_epoch_settings_was_call() {
612 let epoch = Epoch(12);
613 let signers = fake_data::signers(10);
615 let stake_distribution: StakeDistribution = signers
616 .iter()
617 .enumerate()
618 .map(|(i, signer)| (signer.party_id.clone(), (i + 1) as u64 * 100))
619 .collect();
620
621 let connection = Arc::new(main_db_connection().unwrap());
623 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
624 stake_store
625 .save_stakes(epoch, stake_distribution.clone())
626 .await
627 .expect("save_stakes should not fail");
628 let protocol_initializer_store =
629 Arc::new(ProtocolInitializerRepository::new(connection, None));
630
631 let service = MithrilEpochService::new(
633 stake_store,
634 protocol_initializer_store,
635 TestLogger::stdout(),
636 );
637 assert!(service.epoch_of_current_data().is_err());
638 assert!(service.registration_protocol_parameters().is_err());
639 assert!(service.protocol_initializer().is_err());
640 assert!(service.current_signers().is_err());
641 assert!(service.next_signers().is_err());
642 assert!(service.current_signers_with_stake().await.is_err());
643 assert!(service.next_signers_with_stake().await.is_err());
644 assert!(service.cardano_transactions_signing_config().is_err());
645 assert!(service.next_cardano_transactions_signing_config().is_err());
646 }
647
648 #[tokio::test]
649 async fn test_data_are_available_after_register_epoch_settings_call() {
650 let epoch = Epoch(12);
651 let signers = fake_data::signers(10);
653
654 let connection = Arc::new(main_db_connection().unwrap());
656 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
657 let protocol_initializer_store =
658 Arc::new(ProtocolInitializerRepository::new(connection, None));
659
660 let epoch_settings = SignerEpochSettings {
662 epoch,
663 current_signers: signers[2..5].to_vec(),
664 next_signers: signers[3..7].to_vec(),
665 ..SignerEpochSettings::dummy().clone()
666 };
667
668 let mut service = MithrilEpochService::new(
670 stake_store,
671 protocol_initializer_store,
672 TestLogger::stdout(),
673 );
674
675 service
676 .inform_epoch_settings(
677 epoch_settings.clone(),
678 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]),
679 )
680 .await
681 .unwrap();
682
683 {
685 let current_signers = service.current_signers().unwrap();
686 let expected_current_signers = epoch_settings.current_signers.clone();
687 assert_eq!(expected_current_signers, *current_signers);
688 }
689 {
691 let next_signers = service.next_signers().unwrap();
692 let expected_next_signers = epoch_settings.next_signers.clone();
693 assert_eq!(expected_next_signers, *next_signers);
694 }
695
696 assert_eq!(
698 epoch_settings.epoch,
699 service.epoch_of_current_data().unwrap()
700 );
701 assert_eq!(
702 epoch_settings.registration_protocol_parameters,
703 *service.registration_protocol_parameters().unwrap()
704 );
705 assert!(
706 service.protocol_initializer().unwrap().is_none(),
707 "protocol_initializer should be None since nothing was in store"
708 );
709
710 assert_eq!(
712 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]),
713 *service.allowed_discriminants().unwrap()
714 );
715
716 assert_eq!(
718 epoch_settings.cardano_transactions_signing_config,
719 *service.cardano_transactions_signing_config().unwrap()
720 );
721 assert_eq!(
723 epoch_settings.next_cardano_transactions_signing_config,
724 *service.next_cardano_transactions_signing_config().unwrap()
725 );
726 }
727
728 #[tokio::test]
729 async fn test_signers_with_stake_are_available_after_register_epoch_settings_call() {
730 fn build_stake_distribution(signers: &[Signer], first_stake: u64) -> StakeDistribution {
731 signers
732 .iter()
733 .enumerate()
734 .map(|(i, signer)| (signer.party_id.clone(), first_stake + i as u64))
735 .collect()
736 }
737
738 let epoch = Epoch(12);
739
740 let signers = fake_data::signers(10);
742 let stake_distribution: StakeDistribution = build_stake_distribution(&signers, 100);
743 let next_stake_distribution: StakeDistribution = build_stake_distribution(&signers, 500);
744
745 let connection = Arc::new(main_db_connection().unwrap());
746 let stake_store = {
747 let store = Arc::new(StakePoolStore::new(connection.clone(), None));
748 store
749 .save_stakes(
750 epoch.offset_to_signer_retrieval_epoch().unwrap(),
751 stake_distribution.clone(),
752 )
753 .await
754 .unwrap();
755 store
756 .save_stakes(
757 epoch.offset_to_next_signer_retrieval_epoch(),
758 next_stake_distribution.clone(),
759 )
760 .await
761 .unwrap();
762 store
763 };
764 let protocol_initializer_store =
765 Arc::new(ProtocolInitializerRepository::new(connection, None));
766
767 let epoch_settings = SignerEpochSettings {
769 epoch,
770 current_signers: signers[2..5].to_vec(),
771 next_signers: signers[3..7].to_vec(),
772 ..SignerEpochSettings::dummy().clone()
773 };
774
775 let mut service = MithrilEpochService::new(
777 stake_store,
778 protocol_initializer_store,
779 TestLogger::stdout(),
780 );
781 service
782 .inform_epoch_settings(epoch_settings.clone(), BTreeSet::new())
783 .await
784 .unwrap();
785
786 {
788 let current_signers = service.current_signers_with_stake().await.unwrap();
789
790 assert_eq!(epoch_settings.current_signers.len(), current_signers.len());
791 for signer in current_signers {
792 let expected_stake = stake_distribution.get(&signer.party_id).unwrap();
793 assert_eq!(expected_stake, &signer.stake);
794 }
795 }
796
797 {
799 let next_signers = service.next_signers_with_stake().await.unwrap();
800
801 assert_eq!(epoch_settings.next_signers.len(), next_signers.len());
802 for signer in next_signers {
803 let expected_stake = next_stake_distribution.get(&signer.party_id).unwrap();
804 assert_eq!(expected_stake, &signer.stake);
805 }
806 }
807 }
808
809 #[tokio::test]
810 async fn test_protocol_initializer_is_available_after_register_epoch_settings_call_if_in_store()
811 {
812 let epoch = Epoch(12);
813 let connection = Arc::new(main_db_connection().unwrap());
814 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
815 let protocol_initializer_store =
816 Arc::new(ProtocolInitializerRepository::new(connection, None));
817 protocol_initializer_store
818 .save_protocol_initializer(
819 epoch.offset_to_signer_retrieval_epoch().unwrap(),
820 fake_data::protocol_initializer("seed", 1245),
821 )
822 .await
823 .unwrap();
824
825 let mut service = MithrilEpochService::new(
826 stake_store,
827 protocol_initializer_store,
828 TestLogger::stdout(),
829 );
830 let epoch_settings = SignerEpochSettings {
831 epoch,
832 ..SignerEpochSettings::dummy().clone()
833 };
834 service
835 .inform_epoch_settings(epoch_settings, BTreeSet::new())
836 .await
837 .unwrap();
838
839 let protocol_initializer = service.protocol_initializer().unwrap();
840 assert_eq!(
841 Some(1245),
842 protocol_initializer.as_ref().map(|p| p.get_stake()),
843 );
844 }
845
846 #[tokio::test]
847 async fn is_source_of_signed_entity_config() {
848 let connection = Arc::new(main_db_connection().unwrap());
849 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
850 let protocol_initializer_store =
851 Arc::new(ProtocolInitializerRepository::new(connection, None));
852 let epoch_service = Arc::new(RwLock::new(MithrilEpochService::new(
853 stake_store,
854 protocol_initializer_store,
855 TestLogger::stdout(),
856 )));
857 let config_provider = SignerSignedEntityConfigProvider {
858 epoch_service: epoch_service.clone(),
859 };
860
861 {
863 config_provider.get().await.expect_err(
864 "Should fail since sources data are not set before the first inform_epoch_settings",
865 );
866 }
867 {
869 let allowed_discriminants =
870 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]);
871
872 epoch_service
873 .write()
874 .await
875 .inform_epoch_settings(
876 SignerEpochSettings {
877 cardano_transactions_signing_config: None,
878 ..SignerEpochSettings::dummy()
879 },
880 allowed_discriminants.clone(),
881 )
882 .await
883 .unwrap();
884
885 config_provider
886 .get()
887 .await
888 .expect_err("Should fail since cardano_transactions_signing_config is not set");
889 }
890 {
892 let allowed_discriminants =
893 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]);
894 epoch_service
895 .write()
896 .await
897 .inform_epoch_settings(
898 SignerEpochSettings {
899 cardano_transactions_signing_config: Some(
900 CardanoTransactionsSigningConfig::dummy(),
901 ),
902 ..SignerEpochSettings::dummy()
903 },
904 allowed_discriminants.clone(),
905 )
906 .await
907 .unwrap();
908
909 let config = config_provider.get().await.unwrap();
910
911 assert_eq!(
912 SignedEntityConfig {
913 allowed_discriminants,
914 cardano_transactions_signing_config: CardanoTransactionsSigningConfig::dummy(),
915 },
916 config
917 );
918 }
919 }
920}