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