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 .configuration_for_registration
182 .protocol_parameters
183 .clone();
184
185 let protocol_initializer = self
186 .protocol_initializer_store
187 .get_protocol_initializer(
188 aggregator_signer_registration_epoch.offset_to_signer_retrieval_epoch()?,
189 )
190 .await?;
191
192 let allowed_discriminants = mithril_network_configuration
193 .configuration_for_aggregation
194 .enabled_signed_entity_types
195 .clone();
196
197 let cardano_transactions_signing_config = mithril_network_configuration
198 .configuration_for_aggregation
199 .signed_entity_types_config
200 .cardano_transactions
201 .clone();
202
203 self.epoch_data = Some(EpochData {
204 epoch: aggregator_signer_registration_epoch,
205 registration_protocol_parameters,
206 protocol_initializer,
207 current_signers,
208 next_signers,
209 allowed_discriminants,
210 cardano_transactions_signing_config,
211 });
212
213 Ok(())
214 }
215
216 fn epoch_of_current_data(&self) -> StdResult<Epoch> {
217 Ok(self.unwrap_data()?.epoch)
218 }
219
220 fn registration_protocol_parameters(&self) -> StdResult<&ProtocolParameters> {
221 Ok(&self.unwrap_data()?.registration_protocol_parameters)
222 }
223
224 fn protocol_initializer(&self) -> StdResult<&Option<ProtocolInitializer>> {
225 Ok(&self.unwrap_data()?.protocol_initializer)
226 }
227
228 fn current_signers(&self) -> StdResult<&Vec<Signer>> {
229 Ok(&self.unwrap_data()?.current_signers)
230 }
231
232 fn next_signers(&self) -> StdResult<&Vec<Signer>> {
233 Ok(&self.unwrap_data()?.next_signers)
234 }
235
236 async fn current_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>> {
237 let current_epoch = self.epoch_of_current_data()?;
238 self.associate_signers_with_stake(
239 current_epoch.offset_to_signer_retrieval_epoch()?,
240 self.current_signers()?,
241 )
242 .await
243 }
244
245 async fn next_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>> {
246 let current_epoch = self.epoch_of_current_data()?;
247 self.associate_signers_with_stake(
248 current_epoch.offset_to_next_signer_retrieval_epoch(),
249 self.next_signers()?,
250 )
251 .await
252 }
253
254 fn allowed_discriminants(&self) -> StdResult<&BTreeSet<SignedEntityTypeDiscriminants>> {
255 Ok(&self.unwrap_data()?.allowed_discriminants)
256 }
257
258 fn cardano_transactions_signing_config(
259 &self,
260 ) -> StdResult<&Option<CardanoTransactionsSigningConfig>> {
261 Ok(&self.unwrap_data()?.cardano_transactions_signing_config)
262 }
263
264 fn can_signer_sign_current_epoch(&self, party_id: PartyId) -> StdResult<bool> {
265 let epoch = self.epoch_of_current_data()?;
266 if let Some(protocol_initializer) = self.protocol_initializer()? {
267 debug!(
268 self.logger,
269 " > Got protocol initializer for this epoch ({epoch})"
270 );
271 if self
272 .is_signer_included_in_current_stake_distribution(party_id, protocol_initializer)?
273 {
274 return Ok(true);
275 } else {
276 debug!(
277 self.logger,
278 " > Signer not in current stake distribution. Can NOT sign"
279 );
280 }
281 } else {
282 warn!(
283 self.logger,
284 " > NO protocol initializer found for this epoch ({epoch})",
285 );
286 }
287
288 Ok(false)
289 }
290}
291
292pub struct SignerSignedEntityConfigProvider {
297 epoch_service: EpochServiceWrapper,
298}
299
300impl SignerSignedEntityConfigProvider {
301 pub fn new(epoch_service: EpochServiceWrapper) -> Self {
303 Self { epoch_service }
304 }
305}
306
307#[async_trait]
308impl SignedEntityConfigProvider for SignerSignedEntityConfigProvider {
309 async fn get(&self) -> StdResult<SignedEntityConfig> {
310 let epoch_service = self.epoch_service.read().await;
311 let cardano_transactions_signing_config =
312 match epoch_service.cardano_transactions_signing_config()? {
313 Some(config) => Ok(config.clone()),
314 None => Err(anyhow!("No cardano transaction signing config available")),
315 }?;
316
317 Ok(SignedEntityConfig {
318 allowed_discriminants: epoch_service.allowed_discriminants()?.clone(),
319 cardano_transactions_signing_config,
320 })
321 }
322}
323
324#[cfg(test)]
325use crate::database::repository::ProtocolInitializerRepository;
326
327#[cfg(test)]
328impl MithrilEpochService {
329 pub fn new_with_dumb_dependencies() -> Self {
331 use crate::database::repository::StakePoolStore;
332 use crate::database::test_helper::main_db_connection;
333 use crate::test_tools::TestLogger;
334
335 let sqlite_connection = Arc::new(main_db_connection().unwrap());
336 let stake_store = Arc::new(StakePoolStore::new(sqlite_connection.clone(), None));
337 let protocol_initializer_store =
338 Arc::new(ProtocolInitializerRepository::new(sqlite_connection, None));
339
340 Self::new(
341 stake_store,
342 protocol_initializer_store,
343 TestLogger::stdout(),
344 )
345 }
346
347 pub fn set_data_to_default_or_fake(mut self, epoch: Epoch) -> Self {
350 use mithril_common::test::double::fake_data;
351
352 let epoch_data = EpochData {
353 epoch,
354 registration_protocol_parameters: fake_data::protocol_parameters(),
355 protocol_initializer: None,
356 current_signers: vec![],
357 next_signers: vec![],
358 allowed_discriminants: BTreeSet::new(),
359 cardano_transactions_signing_config: None,
360 };
361 self.epoch_data = Some(epoch_data);
362 self
363 }
364
365 pub(crate) fn alter_data(mut self, data_config: impl FnOnce(&mut EpochData)) -> Self {
367 if let Some(data) = self.epoch_data.as_mut() {
368 data_config(data);
369 }
370 self
371 }
372}
373
374#[cfg(test)]
375pub(crate) mod mock_epoch_service {
376 use mockall::mock;
377
378 use super::*;
379
380 mock! {
381 pub EpochServiceImpl {}
382
383 #[async_trait]
384 impl EpochService for EpochServiceImpl {
385 async fn inform_epoch_settings(
386 &mut self,
387 aggregator_signer_registration_epoch: Epoch,
388 mithril_network_configuration: MithrilNetworkConfiguration,
389 current_signers: Vec<Signer>,
390 next_signers: Vec<Signer>,
391 ) -> StdResult<()>;
392
393 fn epoch_of_current_data(&self) -> StdResult<Epoch>;
394
395 fn registration_protocol_parameters(&self) -> StdResult<&'static ProtocolParameters>;
396
397 fn protocol_initializer(&self) -> StdResult<&'static Option<ProtocolInitializer>>;
398
399 fn current_signers(&self) -> StdResult<&'static Vec<Signer>>;
400
401 fn next_signers(&self) -> StdResult<&'static Vec<Signer>>;
402
403 async fn current_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>>;
404
405 async fn next_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>>;
406
407 fn allowed_discriminants(&self) -> StdResult<&'static BTreeSet<SignedEntityTypeDiscriminants>>;
408
409 fn cardano_transactions_signing_config(
410 &self,
411 ) -> StdResult<&'static Option<CardanoTransactionsSigningConfig>>;
412
413 fn can_signer_sign_current_epoch(&self, party_id: PartyId) -> StdResult<bool>;
414 }
415 }
416
417 impl MockEpochServiceImpl {
418 pub fn new_with_config(
419 config: impl FnOnce(&mut MockEpochServiceImpl),
420 ) -> MockEpochServiceImpl {
421 let mut epoch_service_mock = MockEpochServiceImpl::new();
422 config(&mut epoch_service_mock);
423
424 epoch_service_mock
425 }
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use std::sync::Arc;
432 use tokio::sync::RwLock;
433
434 use mithril_common::entities::{Epoch, StakeDistribution};
435 use mithril_common::test::{
436 builder::MithrilFixtureBuilder,
437 double::{Dummy, fake_data},
438 };
439
440 use mithril_protocol_config::model::{
441 MithrilNetworkConfigurationForEpoch, SignedEntityTypeConfiguration,
442 };
443
444 use crate::database::repository::{ProtocolInitializerRepository, StakePoolStore};
445 use crate::database::test_helper::main_db_connection;
446 use crate::services::MithrilProtocolInitializerBuilder;
447 use crate::test_tools::TestLogger;
448
449 use super::*;
450
451 #[test]
452 fn test_is_signer_included_in_current_stake_distribution_returns_error_when_epoch_settings_is_not_set()
453 {
454 let party_id = "party_id".to_string();
455 let protocol_initializer = MithrilProtocolInitializerBuilder::build(
456 &100,
457 &fake_data::protocol_parameters(),
458 None,
459 None,
460 )
461 .unwrap();
462 let connection = Arc::new(main_db_connection().unwrap());
463 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
464 let protocol_initializer_store =
465 Arc::new(ProtocolInitializerRepository::new(connection, None));
466 let service = MithrilEpochService::new(
467 stake_store,
468 protocol_initializer_store,
469 TestLogger::stdout(),
470 );
471
472 service
473 .is_signer_included_in_current_stake_distribution(party_id, &protocol_initializer)
474 .expect_err("can_signer_sign should return error when epoch settings is not set");
475 }
476
477 #[tokio::test]
478 async fn test_is_signer_included_in_current_stake_distribution_returns_true_when_signer_verification_key_and_pool_id_found()
479 {
480 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
481 let protocol_initializer = fixtures.signers_fixture()[0].protocol_initializer.to_owned();
482
483 let connection = Arc::new(main_db_connection().unwrap());
484 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
485 let protocol_initializer_store =
486 Arc::new(ProtocolInitializerRepository::new(connection, None));
487
488 let epoch = Epoch(12);
489 let mithril_network_configuration = MithrilNetworkConfiguration {
490 epoch,
491 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
492 enabled_signed_entity_types: BTreeSet::new(),
493 ..Dummy::dummy()
494 },
495 ..Dummy::dummy()
496 };
497
498 let signers = fixtures.signers();
499 let current_signers = signers[..5].to_vec();
500 let next_signers = signers[2..5].to_vec();
501
502 let mut service = MithrilEpochService::new(
503 stake_store,
504 protocol_initializer_store,
505 TestLogger::stdout(),
506 );
507 service
508 .inform_epoch_settings(
509 epoch,
510 mithril_network_configuration.clone(),
511 current_signers.clone(),
512 next_signers.clone(),
513 )
514 .await
515 .unwrap();
516
517 let party_id = fixtures.signers_fixture()[0].party_id();
518 assert!(
519 service
520 .is_signer_included_in_current_stake_distribution(
521 party_id.clone(),
522 &protocol_initializer
523 )
524 .unwrap()
525 );
526
527 let party_id_not_included = fixtures.signers_fixture()[6].party_id();
528 assert!(
529 !service
530 .is_signer_included_in_current_stake_distribution(
531 party_id_not_included,
532 &protocol_initializer
533 )
534 .unwrap()
535 );
536
537 let protocol_initializer_not_included =
538 fixtures.signers_fixture()[6].protocol_initializer.to_owned();
539 assert!(
540 !service
541 .is_signer_included_in_current_stake_distribution(
542 party_id,
543 &protocol_initializer_not_included
544 )
545 .unwrap()
546 );
547 }
548
549 mod can_signer_sign_current_epoch {
550 use super::*;
551
552 #[test]
553 fn cant_sign_if_no_protocol_initializer_are_stored() {
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 = None;
561 data.current_signers = fixtures.signers();
562 });
563
564 let can_sign_current_epoch = epoch_service
565 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
566 .unwrap();
567 assert!(!can_sign_current_epoch);
568 }
569
570 #[test]
571 fn cant_sign_if_stored_protocol_initializer_belong_to_another_party() {
572 let epoch = Epoch(12);
573 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
574
575 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
576 .set_data_to_default_or_fake(epoch)
577 .alter_data(|data| {
578 data.protocol_initializer =
579 Some(fixtures.signers_fixture()[2].protocol_initializer.clone());
580 data.current_signers = fixtures.signers();
581 });
582
583 let can_sign_current_epoch = epoch_service
584 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
585 .unwrap();
586 assert!(!can_sign_current_epoch);
587 }
588
589 #[test]
590 fn cant_sign_if_not_in_current_signers() {
591 let epoch = Epoch(12);
592 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
593
594 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
595 .set_data_to_default_or_fake(epoch)
596 .alter_data(|data| {
597 data.protocol_initializer =
598 Some(fixtures.signers_fixture()[0].protocol_initializer.clone());
599 data.current_signers = fixtures.signers()[2..].to_vec();
600 });
601
602 let can_sign_current_epoch = epoch_service
603 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
604 .unwrap();
605 assert!(!can_sign_current_epoch);
606 }
607
608 #[test]
609 fn can_sign_if_in_current_signers_and_use_the_stored_protocol_initializer() {
610 let epoch = Epoch(12);
611 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
612
613 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
614 .set_data_to_default_or_fake(epoch)
615 .alter_data(|data| {
616 data.protocol_initializer =
617 Some(fixtures.signers_fixture()[0].protocol_initializer.clone());
618 data.current_signers = fixtures.signers();
619 });
620
621 let can_sign_current_epoch = epoch_service
622 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
623 .unwrap();
624 assert!(can_sign_current_epoch);
625 }
626 }
627
628 #[tokio::test]
629 async fn test_retrieve_data_return_error_before_register_epoch_settings_was_call() {
630 let epoch = Epoch(12);
631 let signers = fake_data::signers(10);
633 let stake_distribution: StakeDistribution = signers
634 .iter()
635 .enumerate()
636 .map(|(i, signer)| (signer.party_id.clone(), (i + 1) as u64 * 100))
637 .collect();
638
639 let connection = Arc::new(main_db_connection().unwrap());
641 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
642 stake_store
643 .save_stakes(epoch, stake_distribution.clone())
644 .await
645 .expect("save_stakes should not fail");
646 let protocol_initializer_store =
647 Arc::new(ProtocolInitializerRepository::new(connection, None));
648
649 let service = MithrilEpochService::new(
651 stake_store,
652 protocol_initializer_store,
653 TestLogger::stdout(),
654 );
655 assert!(service.epoch_of_current_data().is_err());
656 assert!(service.registration_protocol_parameters().is_err());
657 assert!(service.protocol_initializer().is_err());
658 assert!(service.current_signers().is_err());
659 assert!(service.next_signers().is_err());
660 assert!(service.current_signers_with_stake().await.is_err());
661 assert!(service.next_signers_with_stake().await.is_err());
662 assert!(service.cardano_transactions_signing_config().is_err());
663 }
664
665 #[tokio::test]
666 async fn test_data_are_available_after_register_epoch_settings_call() {
667 let connection = Arc::new(main_db_connection().unwrap());
671 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
672 let protocol_initializer_store =
673 Arc::new(ProtocolInitializerRepository::new(connection, None));
674
675 let epoch = Epoch(12);
676 let mithril_network_configuration = MithrilNetworkConfiguration {
677 epoch,
678 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
679 enabled_signed_entity_types: BTreeSet::from([
680 SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
681 ]),
682 ..Dummy::dummy()
683 },
684 ..Dummy::dummy()
685 };
686
687 let signers = fake_data::signers(10);
688 let current_signers = signers[2..5].to_vec();
689 let next_signers = signers[3..7].to_vec();
690
691 let mut service = MithrilEpochService::new(
693 stake_store,
694 protocol_initializer_store,
695 TestLogger::stdout(),
696 );
697
698 service
699 .inform_epoch_settings(
700 epoch,
701 mithril_network_configuration.clone(),
702 current_signers.clone(),
703 next_signers.clone(),
704 )
705 .await
706 .unwrap();
707
708 {
710 let current_signers = service.current_signers().unwrap();
711 let expected_current_signers = current_signers.clone();
712 assert_eq!(expected_current_signers, *current_signers);
713 }
714 {
716 let next_signers = service.next_signers().unwrap();
717 let expected_next_signers = next_signers.clone();
718 assert_eq!(expected_next_signers, *next_signers);
719 }
720
721 assert_eq!(
723 mithril_network_configuration.epoch,
724 service.epoch_of_current_data().unwrap()
725 );
726 assert_eq!(
727 mithril_network_configuration
728 .configuration_for_registration
729 .protocol_parameters,
730 *service.registration_protocol_parameters().unwrap()
731 );
732 assert!(
733 service.protocol_initializer().unwrap().is_none(),
734 "protocol_initializer should be None since nothing was in store"
735 );
736
737 assert_eq!(
739 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]),
740 *service.allowed_discriminants().unwrap()
741 );
742
743 assert_eq!(
745 mithril_network_configuration
746 .configuration_for_aggregation
747 .signed_entity_types_config
748 .cardano_transactions,
749 *service.cardano_transactions_signing_config().unwrap()
750 );
751 }
752
753 #[tokio::test]
754 async fn test_signers_with_stake_are_available_after_register_epoch_settings_call() {
755 fn build_stake_distribution(signers: &[Signer], first_stake: u64) -> StakeDistribution {
756 signers
757 .iter()
758 .enumerate()
759 .map(|(i, signer)| (signer.party_id.clone(), first_stake + i as u64))
760 .collect()
761 }
762
763 let epoch = Epoch(12);
764
765 let signers = fake_data::signers(10);
767 let stake_distribution: StakeDistribution = build_stake_distribution(&signers, 100);
768 let next_stake_distribution: StakeDistribution = build_stake_distribution(&signers, 500);
769
770 let connection = Arc::new(main_db_connection().unwrap());
771 let stake_store = {
772 let store = Arc::new(StakePoolStore::new(connection.clone(), None));
773 store
774 .save_stakes(
775 epoch.offset_to_signer_retrieval_epoch().unwrap(),
776 stake_distribution.clone(),
777 )
778 .await
779 .unwrap();
780 store
781 .save_stakes(
782 epoch.offset_to_next_signer_retrieval_epoch(),
783 next_stake_distribution.clone(),
784 )
785 .await
786 .unwrap();
787 store
788 };
789 let protocol_initializer_store =
790 Arc::new(ProtocolInitializerRepository::new(connection, None));
791
792 let mithril_network_configuration = MithrilNetworkConfiguration {
794 epoch,
795 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
796 enabled_signed_entity_types: BTreeSet::new(),
797 ..Dummy::dummy()
798 },
799 ..Dummy::dummy()
800 };
801
802 let current_signers = signers[2..5].to_vec();
803 let next_signers = signers[3..7].to_vec();
804
805 let mut service = MithrilEpochService::new(
807 stake_store,
808 protocol_initializer_store,
809 TestLogger::stdout(),
810 );
811 service
812 .inform_epoch_settings(
813 epoch,
814 mithril_network_configuration,
815 current_signers.clone(),
816 next_signers.clone(),
817 )
818 .await
819 .unwrap();
820
821 {
823 let actual_current_signers = service.current_signers_with_stake().await.unwrap();
824
825 assert_eq!(current_signers.len(), actual_current_signers.len());
826 for signer in actual_current_signers {
827 let expected_stake = stake_distribution.get(&signer.party_id).unwrap();
828 assert_eq!(expected_stake, &signer.stake);
829 }
830 }
831
832 {
834 let actual_next_signers = service.next_signers_with_stake().await.unwrap();
835
836 assert_eq!(next_signers.len(), actual_next_signers.len());
837 for signer in actual_next_signers {
838 let expected_stake = next_stake_distribution.get(&signer.party_id).unwrap();
839 assert_eq!(expected_stake, &signer.stake);
840 }
841 }
842 }
843
844 #[tokio::test]
845 async fn test_protocol_initializer_is_available_after_register_epoch_settings_call_if_in_store()
846 {
847 let epoch = Epoch(12);
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 protocol_initializer_store
853 .save_protocol_initializer(
854 epoch.offset_to_signer_retrieval_epoch().unwrap(),
855 fake_data::protocol_initializer("seed", 1245),
856 )
857 .await
858 .unwrap();
859
860 let mut service = MithrilEpochService::new(
861 stake_store,
862 protocol_initializer_store,
863 TestLogger::stdout(),
864 );
865
866 let mithril_network_configuration = MithrilNetworkConfiguration {
867 epoch,
868 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
869 enabled_signed_entity_types: BTreeSet::new(),
870 ..Dummy::dummy()
871 },
872 ..Dummy::dummy()
873 };
874
875 service
876 .inform_epoch_settings(epoch, mithril_network_configuration, Vec::new(), Vec::new())
877 .await
878 .unwrap();
879
880 let protocol_initializer = service.protocol_initializer().unwrap();
881 assert_eq!(
882 Some(1245),
883 protocol_initializer.as_ref().map(|p| p.get_stake()),
884 );
885 }
886
887 #[tokio::test]
888 async fn is_source_of_signed_entity_config() {
889 let connection = Arc::new(main_db_connection().unwrap());
890 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
891 let protocol_initializer_store =
892 Arc::new(ProtocolInitializerRepository::new(connection, None));
893 let epoch_service = Arc::new(RwLock::new(MithrilEpochService::new(
894 stake_store,
895 protocol_initializer_store,
896 TestLogger::stdout(),
897 )));
898 let config_provider = SignerSignedEntityConfigProvider {
899 epoch_service: epoch_service.clone(),
900 };
901
902 {
904 config_provider.get().await.expect_err(
905 "Should fail since sources data are not set before the first inform_epoch_settings",
906 );
907 }
908 {
910 let signers = fake_data::signers(5);
911 let current_signers = signers[1..3].to_vec();
912 let next_signers = signers[2..5].to_vec();
913
914 let configuration_for_aggregation = MithrilNetworkConfigurationForEpoch {
915 signed_entity_types_config: SignedEntityTypeConfiguration {
916 cardano_transactions: None,
917 },
918 enabled_signed_entity_types: BTreeSet::new(),
919 ..Dummy::dummy()
920 };
921 let configuration_for_next_aggregation = MithrilNetworkConfigurationForEpoch::dummy();
922
923 epoch_service
924 .write()
925 .await
926 .inform_epoch_settings(
927 fake_data::beacon().epoch,
928 MithrilNetworkConfiguration {
929 configuration_for_aggregation,
930 configuration_for_next_aggregation,
931 ..Dummy::dummy()
932 },
933 current_signers,
934 next_signers,
935 )
936 .await
937 .unwrap();
938
939 config_provider
940 .get()
941 .await
942 .expect_err("Should fail since cardano_transactions_signing_config is not set");
943 }
944 {
946 let allowed_discriminants =
947 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]);
948
949 let configuration_for_aggregation = MithrilNetworkConfigurationForEpoch {
950 enabled_signed_entity_types: allowed_discriminants.clone(),
951 ..Dummy::dummy()
952 };
953
954 let signers = fake_data::signers(5);
955 let current_signers = signers[1..3].to_vec();
956 let next_signers = signers[2..5].to_vec();
957
958 epoch_service
959 .write()
960 .await
961 .inform_epoch_settings(
962 fake_data::beacon().epoch,
963 MithrilNetworkConfiguration {
964 configuration_for_aggregation,
965 ..Dummy::dummy()
966 },
967 current_signers,
968 next_signers,
969 )
970 .await
971 .unwrap();
972
973 let config = config_provider.get().await.unwrap();
974
975 assert_eq!(
976 SignedEntityConfig {
977 allowed_discriminants,
978 cardano_transactions_signing_config: CardanoTransactionsSigningConfig::dummy(),
979 },
980 config
981 );
982 }
983 }
984}