1use async_trait::async_trait;
2use mithril_protocol_config::model::MithrilNetworkConfiguration;
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::services::SignedEntityConfigProvider;
11use crate::store::ProtocolInitializerStorer;
12use mithril_common::StdResult;
13use mithril_common::crypto_helper::ProtocolInitializer;
14use mithril_common::entities::{
15 CardanoTransactionsSigningConfig, Epoch, PartyId, ProtocolParameters, SignedEntityConfig,
16 SignedEntityTypeDiscriminants, Signer, SignerWithStake,
17};
18use mithril_common::logging::LoggerExtensions;
19use mithril_persistence::store::StakeStorer;
20
21#[derive(Debug, Error)]
23pub enum EpochServiceError {
24 #[error(
26 "Epoch service was not initialized, the function `inform_epoch_settings` must be called first"
27 )]
28 NotYetInitialized,
29}
30
31#[async_trait]
33pub trait EpochService: Sync + Send {
34 async fn inform_epoch_settings(
37 &mut self,
38 aggregator_signer_registration_epoch: Epoch,
39 mithril_network_configuration: MithrilNetworkConfiguration,
40 current_signers: Vec<Signer>,
41 next_signers: Vec<Signer>,
42 ) -> StdResult<()>;
43
44 fn epoch_of_current_data(&self) -> StdResult<Epoch>;
46
47 fn registration_protocol_parameters(&self) -> StdResult<&ProtocolParameters>;
49
50 fn protocol_initializer(&self) -> StdResult<&Option<ProtocolInitializer>>;
54
55 fn current_signers(&self) -> StdResult<&Vec<Signer>>;
57
58 fn next_signers(&self) -> StdResult<&Vec<Signer>>;
60
61 async fn current_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>>;
63
64 async fn next_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>>;
66
67 fn allowed_discriminants(&self) -> StdResult<&BTreeSet<SignedEntityTypeDiscriminants>>;
69
70 fn cardano_transactions_signing_config(
72 &self,
73 ) -> StdResult<&Option<CardanoTransactionsSigningConfig>>;
74
75 fn can_signer_sign_current_epoch(&self, party_id: PartyId) -> StdResult<bool>;
77}
78
79pub(crate) struct EpochData {
80 pub epoch: Epoch,
81 pub registration_protocol_parameters: ProtocolParameters,
82 pub protocol_initializer: Option<ProtocolInitializer>,
83 pub current_signers: Vec<Signer>,
84 pub next_signers: Vec<Signer>,
85 pub allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
86 pub cardano_transactions_signing_config: Option<CardanoTransactionsSigningConfig>,
87}
88
89pub struct MithrilEpochService {
91 stake_storer: Arc<dyn StakeStorer>,
92 protocol_initializer_store: Arc<dyn ProtocolInitializerStorer>,
93 epoch_data: Option<EpochData>,
94 logger: Logger,
95}
96
97impl MithrilEpochService {
98 pub fn new(
100 stake_storer: Arc<dyn StakeStorer>,
101 protocol_initializer_store: Arc<dyn ProtocolInitializerStorer>,
102 logger: Logger,
103 ) -> Self {
104 Self {
105 stake_storer,
106 protocol_initializer_store,
107 epoch_data: None,
108 logger: logger.new_with_component_name::<Self>(),
109 }
110 }
111
112 async fn associate_signers_with_stake(
113 &self,
114 epoch: Epoch,
115 signers: &[Signer],
116 ) -> StdResult<Vec<SignerWithStake>> {
117 debug!(
118 self.logger,
119 ">> associate_signers_with_stake(epoch:{epoch})"
120 );
121
122 let stakes = self
123 .stake_storer
124 .get_stakes(epoch)
125 .await?
126 .ok_or_else(|| RunnerError::NoValueError(format!("stakes at epoch {epoch}")))?;
127
128 let mut signers_with_stake = vec![];
129
130 for signer in signers {
131 let stake = stakes
132 .get(&*signer.party_id)
133 .ok_or_else(|| RunnerError::NoStakeForSigner(signer.party_id.to_string()))?;
134
135 signers_with_stake.push(SignerWithStake::new(
136 signer.party_id.to_owned(),
137 signer.verification_key.to_owned(),
138 signer.verification_key_signature.to_owned(),
139 signer.operational_certificate.to_owned(),
140 signer.kes_period.to_owned(),
141 *stake,
142 ));
143 trace!(
144 self.logger,
145 " > Associating signer_id {} with stake {}", signer.party_id, *stake
146 );
147 }
148
149 Ok(signers_with_stake)
150 }
151
152 fn is_signer_included_in_current_stake_distribution(
153 &self,
154 party_id: PartyId,
155 protocol_initializer: &ProtocolInitializer,
156 ) -> StdResult<bool> {
157 Ok(self.current_signers()?.iter().any(|s| {
158 s.party_id == party_id
159 && s.verification_key == protocol_initializer.verification_key().into()
160 }))
161 }
162
163 fn unwrap_data(&self) -> Result<&EpochData, EpochServiceError> {
164 self.epoch_data.as_ref().ok_or(EpochServiceError::NotYetInitialized)
165 }
166}
167
168#[async_trait]
169impl EpochService for MithrilEpochService {
170 async fn inform_epoch_settings(
171 &mut self,
172 aggregator_signer_registration_epoch: Epoch,
173 mithril_network_configuration: MithrilNetworkConfiguration,
174 current_signers: Vec<Signer>,
175 next_signers: Vec<Signer>,
176 ) -> StdResult<()> {
177 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);
178
179 let registration_protocol_parameters = mithril_network_configuration
180 .configuration_for_registration
181 .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 = mithril_network_configuration
192 .configuration_for_aggregation
193 .enabled_signed_entity_types
194 .clone();
195
196 let cardano_transactions_signing_config = mithril_network_configuration
197 .configuration_for_aggregation
198 .signed_entity_types_config
199 .cardano_transactions
200 .clone();
201
202 self.epoch_data = Some(EpochData {
203 epoch: aggregator_signer_registration_epoch,
204 registration_protocol_parameters,
205 protocol_initializer,
206 current_signers,
207 next_signers,
208 allowed_discriminants,
209 cardano_transactions_signing_config,
210 });
211
212 Ok(())
213 }
214
215 fn epoch_of_current_data(&self) -> StdResult<Epoch> {
216 Ok(self.unwrap_data()?.epoch)
217 }
218
219 fn registration_protocol_parameters(&self) -> StdResult<&ProtocolParameters> {
220 Ok(&self.unwrap_data()?.registration_protocol_parameters)
221 }
222
223 fn protocol_initializer(&self) -> StdResult<&Option<ProtocolInitializer>> {
224 Ok(&self.unwrap_data()?.protocol_initializer)
225 }
226
227 fn current_signers(&self) -> StdResult<&Vec<Signer>> {
228 Ok(&self.unwrap_data()?.current_signers)
229 }
230
231 fn next_signers(&self) -> StdResult<&Vec<Signer>> {
232 Ok(&self.unwrap_data()?.next_signers)
233 }
234
235 async fn current_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>> {
236 let current_epoch = self.epoch_of_current_data()?;
237 self.associate_signers_with_stake(
238 current_epoch.offset_to_signer_retrieval_epoch()?,
239 self.current_signers()?,
240 )
241 .await
242 }
243
244 async fn next_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>> {
245 let current_epoch = self.epoch_of_current_data()?;
246 self.associate_signers_with_stake(
247 current_epoch.offset_to_next_signer_retrieval_epoch(),
248 self.next_signers()?,
249 )
250 .await
251 }
252
253 fn allowed_discriminants(&self) -> StdResult<&BTreeSet<SignedEntityTypeDiscriminants>> {
254 Ok(&self.unwrap_data()?.allowed_discriminants)
255 }
256
257 fn cardano_transactions_signing_config(
258 &self,
259 ) -> StdResult<&Option<CardanoTransactionsSigningConfig>> {
260 Ok(&self.unwrap_data()?.cardano_transactions_signing_config)
261 }
262
263 fn can_signer_sign_current_epoch(&self, party_id: PartyId) -> StdResult<bool> {
264 let epoch = self.epoch_of_current_data()?;
265 if let Some(protocol_initializer) = self.protocol_initializer()? {
266 debug!(
267 self.logger,
268 " > Got protocol initializer for this epoch ({epoch})"
269 );
270 if self
271 .is_signer_included_in_current_stake_distribution(party_id, protocol_initializer)?
272 {
273 return Ok(true);
274 } else {
275 debug!(
276 self.logger,
277 " > Signer not in current stake distribution. Can NOT sign"
278 );
279 }
280 } else {
281 warn!(
282 self.logger,
283 " > NO protocol initializer found for this epoch ({epoch})",
284 );
285 }
286
287 Ok(false)
288 }
289}
290
291pub struct SignerSignedEntityConfigProvider {
296 epoch_service: EpochServiceWrapper,
297}
298
299impl SignerSignedEntityConfigProvider {
300 pub fn new(epoch_service: EpochServiceWrapper) -> Self {
302 Self { epoch_service }
303 }
304}
305
306#[async_trait]
307impl SignedEntityConfigProvider for SignerSignedEntityConfigProvider {
308 async fn get(&self) -> StdResult<SignedEntityConfig> {
309 let epoch_service = self.epoch_service.read().await;
310
311 Ok(SignedEntityConfig {
312 allowed_discriminants: epoch_service.allowed_discriminants()?.clone(),
313 cardano_transactions_signing_config: epoch_service
314 .cardano_transactions_signing_config()?
315 .clone(),
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::{
437 MithrilNetworkConfigurationForEpoch, SignedEntityTypeConfiguration,
438 };
439
440 use crate::database::repository::{ProtocolInitializerRepository, StakePoolStore};
441 use crate::database::test_helper::main_db_connection;
442 use crate::services::MithrilProtocolInitializerBuilder;
443 use crate::test_tools::TestLogger;
444
445 use super::*;
446
447 #[test]
448 fn test_is_signer_included_in_current_stake_distribution_returns_error_when_epoch_settings_is_not_set()
449 {
450 let party_id = "party_id".to_string();
451 let protocol_initializer = MithrilProtocolInitializerBuilder::build(
452 &100,
453 &fake_data::protocol_parameters(),
454 None,
455 None,
456 )
457 .unwrap();
458 let connection = Arc::new(main_db_connection().unwrap());
459 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
460 let protocol_initializer_store =
461 Arc::new(ProtocolInitializerRepository::new(connection, None));
462 let service = MithrilEpochService::new(
463 stake_store,
464 protocol_initializer_store,
465 TestLogger::stdout(),
466 );
467
468 service
469 .is_signer_included_in_current_stake_distribution(party_id, &protocol_initializer)
470 .expect_err("can_signer_sign should return error when epoch settings is not set");
471 }
472
473 #[tokio::test]
474 async fn test_is_signer_included_in_current_stake_distribution_returns_true_when_signer_verification_key_and_pool_id_found()
475 {
476 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
477 let protocol_initializer = fixtures.signers_fixture()[0].protocol_initializer.to_owned();
478
479 let connection = Arc::new(main_db_connection().unwrap());
480 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
481 let protocol_initializer_store =
482 Arc::new(ProtocolInitializerRepository::new(connection, None));
483
484 let epoch = Epoch(12);
485 let mithril_network_configuration = MithrilNetworkConfiguration {
486 epoch,
487 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
488 enabled_signed_entity_types: BTreeSet::new(),
489 ..Dummy::dummy()
490 },
491 ..Dummy::dummy()
492 };
493
494 let signers = fixtures.signers();
495 let current_signers = signers[..5].to_vec();
496 let next_signers = signers[2..5].to_vec();
497
498 let mut service = MithrilEpochService::new(
499 stake_store,
500 protocol_initializer_store,
501 TestLogger::stdout(),
502 );
503 service
504 .inform_epoch_settings(
505 epoch,
506 mithril_network_configuration.clone(),
507 current_signers.clone(),
508 next_signers.clone(),
509 )
510 .await
511 .unwrap();
512
513 let party_id = fixtures.signers_fixture()[0].party_id();
514 assert!(
515 service
516 .is_signer_included_in_current_stake_distribution(
517 party_id.clone(),
518 &protocol_initializer
519 )
520 .unwrap()
521 );
522
523 let party_id_not_included = fixtures.signers_fixture()[6].party_id();
524 assert!(
525 !service
526 .is_signer_included_in_current_stake_distribution(
527 party_id_not_included,
528 &protocol_initializer
529 )
530 .unwrap()
531 );
532
533 let protocol_initializer_not_included =
534 fixtures.signers_fixture()[6].protocol_initializer.to_owned();
535 assert!(
536 !service
537 .is_signer_included_in_current_stake_distribution(
538 party_id,
539 &protocol_initializer_not_included
540 )
541 .unwrap()
542 );
543 }
544
545 mod can_signer_sign_current_epoch {
546 use super::*;
547
548 #[test]
549 fn cant_sign_if_no_protocol_initializer_are_stored() {
550 let epoch = Epoch(12);
551 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
552
553 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
554 .set_data_to_default_or_fake(epoch)
555 .alter_data(|data| {
556 data.protocol_initializer = None;
557 data.current_signers = fixtures.signers();
558 });
559
560 let can_sign_current_epoch = epoch_service
561 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
562 .unwrap();
563 assert!(!can_sign_current_epoch);
564 }
565
566 #[test]
567 fn cant_sign_if_stored_protocol_initializer_belong_to_another_party() {
568 let epoch = Epoch(12);
569 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
570
571 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
572 .set_data_to_default_or_fake(epoch)
573 .alter_data(|data| {
574 data.protocol_initializer =
575 Some(fixtures.signers_fixture()[2].protocol_initializer.clone());
576 data.current_signers = fixtures.signers();
577 });
578
579 let can_sign_current_epoch = epoch_service
580 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
581 .unwrap();
582 assert!(!can_sign_current_epoch);
583 }
584
585 #[test]
586 fn cant_sign_if_not_in_current_signers() {
587 let epoch = Epoch(12);
588 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
589
590 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
591 .set_data_to_default_or_fake(epoch)
592 .alter_data(|data| {
593 data.protocol_initializer =
594 Some(fixtures.signers_fixture()[0].protocol_initializer.clone());
595 data.current_signers = fixtures.signers()[2..].to_vec();
596 });
597
598 let can_sign_current_epoch = epoch_service
599 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
600 .unwrap();
601 assert!(!can_sign_current_epoch);
602 }
603
604 #[test]
605 fn can_sign_if_in_current_signers_and_use_the_stored_protocol_initializer() {
606 let epoch = Epoch(12);
607 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
608
609 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
610 .set_data_to_default_or_fake(epoch)
611 .alter_data(|data| {
612 data.protocol_initializer =
613 Some(fixtures.signers_fixture()[0].protocol_initializer.clone());
614 data.current_signers = fixtures.signers();
615 });
616
617 let can_sign_current_epoch = epoch_service
618 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
619 .unwrap();
620 assert!(can_sign_current_epoch);
621 }
622 }
623
624 #[tokio::test]
625 async fn test_retrieve_data_return_error_before_register_epoch_settings_was_call() {
626 let epoch = Epoch(12);
627 let signers = fake_data::signers(10);
629 let stake_distribution: StakeDistribution = signers
630 .iter()
631 .enumerate()
632 .map(|(i, signer)| (signer.party_id.clone(), (i + 1) as u64 * 100))
633 .collect();
634
635 let connection = Arc::new(main_db_connection().unwrap());
637 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
638 stake_store
639 .save_stakes(epoch, stake_distribution.clone())
640 .await
641 .expect("save_stakes should not fail");
642 let protocol_initializer_store =
643 Arc::new(ProtocolInitializerRepository::new(connection, None));
644
645 let service = MithrilEpochService::new(
647 stake_store,
648 protocol_initializer_store,
649 TestLogger::stdout(),
650 );
651 assert!(service.epoch_of_current_data().is_err());
652 assert!(service.registration_protocol_parameters().is_err());
653 assert!(service.protocol_initializer().is_err());
654 assert!(service.current_signers().is_err());
655 assert!(service.next_signers().is_err());
656 assert!(service.current_signers_with_stake().await.is_err());
657 assert!(service.next_signers_with_stake().await.is_err());
658 assert!(service.cardano_transactions_signing_config().is_err());
659 }
660
661 #[tokio::test]
662 async fn test_data_are_available_after_register_epoch_settings_call() {
663 let connection = Arc::new(main_db_connection().unwrap());
667 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
668 let protocol_initializer_store =
669 Arc::new(ProtocolInitializerRepository::new(connection, None));
670
671 let epoch = Epoch(12);
672 let mithril_network_configuration = MithrilNetworkConfiguration {
673 epoch,
674 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
675 enabled_signed_entity_types: BTreeSet::from([
676 SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
677 ]),
678 ..Dummy::dummy()
679 },
680 ..Dummy::dummy()
681 };
682
683 let signers = fake_data::signers(10);
684 let current_signers = signers[2..5].to_vec();
685 let next_signers = signers[3..7].to_vec();
686
687 let mut service = MithrilEpochService::new(
689 stake_store,
690 protocol_initializer_store,
691 TestLogger::stdout(),
692 );
693
694 service
695 .inform_epoch_settings(
696 epoch,
697 mithril_network_configuration.clone(),
698 current_signers.clone(),
699 next_signers.clone(),
700 )
701 .await
702 .unwrap();
703
704 {
706 let current_signers = service.current_signers().unwrap();
707 let expected_current_signers = current_signers.clone();
708 assert_eq!(expected_current_signers, *current_signers);
709 }
710 {
712 let next_signers = service.next_signers().unwrap();
713 let expected_next_signers = next_signers.clone();
714 assert_eq!(expected_next_signers, *next_signers);
715 }
716
717 assert_eq!(
719 mithril_network_configuration.epoch,
720 service.epoch_of_current_data().unwrap()
721 );
722 assert_eq!(
723 mithril_network_configuration
724 .configuration_for_registration
725 .protocol_parameters,
726 *service.registration_protocol_parameters().unwrap()
727 );
728 assert!(
729 service.protocol_initializer().unwrap().is_none(),
730 "protocol_initializer should be None since nothing was in store"
731 );
732
733 assert_eq!(
735 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]),
736 *service.allowed_discriminants().unwrap()
737 );
738
739 assert_eq!(
741 mithril_network_configuration
742 .configuration_for_aggregation
743 .signed_entity_types_config
744 .cardano_transactions,
745 *service.cardano_transactions_signing_config().unwrap()
746 );
747 }
748
749 #[tokio::test]
750 async fn test_signers_with_stake_are_available_after_register_epoch_settings_call() {
751 fn build_stake_distribution(signers: &[Signer], first_stake: u64) -> StakeDistribution {
752 signers
753 .iter()
754 .enumerate()
755 .map(|(i, signer)| (signer.party_id.clone(), first_stake + i as u64))
756 .collect()
757 }
758
759 let epoch = Epoch(12);
760
761 let signers = fake_data::signers(10);
763 let stake_distribution: StakeDistribution = build_stake_distribution(&signers, 100);
764 let next_stake_distribution: StakeDistribution = build_stake_distribution(&signers, 500);
765
766 let connection = Arc::new(main_db_connection().unwrap());
767 let stake_store = {
768 let store = Arc::new(StakePoolStore::new(connection.clone(), None));
769 store
770 .save_stakes(
771 epoch.offset_to_signer_retrieval_epoch().unwrap(),
772 stake_distribution.clone(),
773 )
774 .await
775 .unwrap();
776 store
777 .save_stakes(
778 epoch.offset_to_next_signer_retrieval_epoch(),
779 next_stake_distribution.clone(),
780 )
781 .await
782 .unwrap();
783 store
784 };
785 let protocol_initializer_store =
786 Arc::new(ProtocolInitializerRepository::new(connection, None));
787
788 let mithril_network_configuration = MithrilNetworkConfiguration {
790 epoch,
791 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
792 enabled_signed_entity_types: BTreeSet::new(),
793 ..Dummy::dummy()
794 },
795 ..Dummy::dummy()
796 };
797
798 let current_signers = signers[2..5].to_vec();
799 let next_signers = signers[3..7].to_vec();
800
801 let mut service = MithrilEpochService::new(
803 stake_store,
804 protocol_initializer_store,
805 TestLogger::stdout(),
806 );
807 service
808 .inform_epoch_settings(
809 epoch,
810 mithril_network_configuration,
811 current_signers.clone(),
812 next_signers.clone(),
813 )
814 .await
815 .unwrap();
816
817 {
819 let actual_current_signers = service.current_signers_with_stake().await.unwrap();
820
821 assert_eq!(current_signers.len(), actual_current_signers.len());
822 for signer in actual_current_signers {
823 let expected_stake = stake_distribution.get(&signer.party_id).unwrap();
824 assert_eq!(expected_stake, &signer.stake);
825 }
826 }
827
828 {
830 let actual_next_signers = service.next_signers_with_stake().await.unwrap();
831
832 assert_eq!(next_signers.len(), actual_next_signers.len());
833 for signer in actual_next_signers {
834 let expected_stake = next_stake_distribution.get(&signer.party_id).unwrap();
835 assert_eq!(expected_stake, &signer.stake);
836 }
837 }
838 }
839
840 #[tokio::test]
841 async fn test_protocol_initializer_is_available_after_register_epoch_settings_call_if_in_store()
842 {
843 let epoch = Epoch(12);
844 let connection = Arc::new(main_db_connection().unwrap());
845 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
846 let protocol_initializer_store =
847 Arc::new(ProtocolInitializerRepository::new(connection, None));
848 protocol_initializer_store
849 .save_protocol_initializer(
850 epoch.offset_to_signer_retrieval_epoch().unwrap(),
851 fake_data::protocol_initializer("seed", 1245),
852 )
853 .await
854 .unwrap();
855
856 let mut service = MithrilEpochService::new(
857 stake_store,
858 protocol_initializer_store,
859 TestLogger::stdout(),
860 );
861
862 let mithril_network_configuration = MithrilNetworkConfiguration {
863 epoch,
864 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
865 enabled_signed_entity_types: BTreeSet::new(),
866 ..Dummy::dummy()
867 },
868 ..Dummy::dummy()
869 };
870
871 service
872 .inform_epoch_settings(epoch, mithril_network_configuration, Vec::new(), Vec::new())
873 .await
874 .unwrap();
875
876 let protocol_initializer = service.protocol_initializer().unwrap();
877 assert_eq!(
878 Some(1245),
879 protocol_initializer.as_ref().map(|p| p.get_stake()),
880 );
881 }
882
883 #[tokio::test]
884 async fn is_source_of_signed_entity_config() {
885 let connection = Arc::new(main_db_connection().unwrap());
886 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
887 let protocol_initializer_store =
888 Arc::new(ProtocolInitializerRepository::new(connection, None));
889 let epoch_service = Arc::new(RwLock::new(MithrilEpochService::new(
890 stake_store,
891 protocol_initializer_store,
892 TestLogger::stdout(),
893 )));
894 let config_provider = SignerSignedEntityConfigProvider {
895 epoch_service: epoch_service.clone(),
896 };
897
898 {
900 config_provider.get().await.expect_err(
901 "Should fail since sources data are not set before the first inform_epoch_settings",
902 );
903 }
904 {
906 let signers = fake_data::signers(5);
907 let current_signers = signers[1..3].to_vec();
908 let next_signers = signers[2..5].to_vec();
909 let allowed_discriminants =
910 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoStakeDistribution]);
911
912 let configuration_for_aggregation = MithrilNetworkConfigurationForEpoch {
913 signed_entity_types_config: SignedEntityTypeConfiguration {
914 cardano_transactions: None,
915 },
916 enabled_signed_entity_types: allowed_discriminants.clone(),
917 ..Dummy::dummy()
918 };
919 let configuration_for_next_aggregation = MithrilNetworkConfigurationForEpoch::dummy();
920
921 epoch_service
922 .write()
923 .await
924 .inform_epoch_settings(
925 fake_data::beacon().epoch,
926 MithrilNetworkConfiguration {
927 configuration_for_aggregation,
928 configuration_for_next_aggregation,
929 ..Dummy::dummy()
930 },
931 current_signers,
932 next_signers,
933 )
934 .await
935 .unwrap();
936
937 let config = config_provider.get().await.unwrap();
938
939 assert_eq!(
940 SignedEntityConfig {
941 allowed_discriminants,
942 cardano_transactions_signing_config: None,
943 },
944 config
945 );
946 }
947 {
949 let allowed_discriminants =
950 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]);
951
952 let configuration_for_aggregation = MithrilNetworkConfigurationForEpoch {
953 enabled_signed_entity_types: allowed_discriminants.clone(),
954 ..Dummy::dummy()
955 };
956
957 let signers = fake_data::signers(5);
958 let current_signers = signers[1..3].to_vec();
959 let next_signers = signers[2..5].to_vec();
960
961 epoch_service
962 .write()
963 .await
964 .inform_epoch_settings(
965 fake_data::beacon().epoch,
966 MithrilNetworkConfiguration {
967 configuration_for_aggregation,
968 ..Dummy::dummy()
969 },
970 current_signers,
971 next_signers,
972 )
973 .await
974 .unwrap();
975
976 let config = config_provider.get().await.unwrap();
977
978 assert_eq!(
979 SignedEntityConfig {
980 allowed_discriminants,
981 cardano_transactions_signing_config: Some(
982 CardanoTransactionsSigningConfig::dummy()
983 ),
984 },
985 config
986 );
987 }
988 }
989}