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 CardanoBlocksTransactionsSigningConfig, CardanoTransactionsSigningConfig, Epoch, PartyId,
16 ProtocolParameters, SignedEntityConfig, 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 cardano_blocks_transactions_signing_config(
77 &self,
78 ) -> StdResult<&Option<CardanoBlocksTransactionsSigningConfig>>;
79
80 fn can_signer_sign_current_epoch(&self, party_id: PartyId) -> StdResult<bool>;
82}
83
84pub(crate) struct EpochData {
85 pub epoch: Epoch,
86 pub registration_protocol_parameters: ProtocolParameters,
87 pub protocol_initializer: Option<ProtocolInitializer>,
88 pub current_signers: Vec<Signer>,
89 pub next_signers: Vec<Signer>,
90 pub allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
91 pub cardano_transactions_signing_config: Option<CardanoTransactionsSigningConfig>,
92 pub cardano_blocks_transactions_signing_config: Option<CardanoBlocksTransactionsSigningConfig>,
93}
94
95pub struct MithrilEpochService {
97 stake_storer: Arc<dyn StakeStorer>,
98 protocol_initializer_store: Arc<dyn ProtocolInitializerStorer>,
99 epoch_data: Option<EpochData>,
100 logger: Logger,
101}
102
103impl MithrilEpochService {
104 pub fn new(
106 stake_storer: Arc<dyn StakeStorer>,
107 protocol_initializer_store: Arc<dyn ProtocolInitializerStorer>,
108 logger: Logger,
109 ) -> Self {
110 Self {
111 stake_storer,
112 protocol_initializer_store,
113 epoch_data: None,
114 logger: logger.new_with_component_name::<Self>(),
115 }
116 }
117
118 async fn associate_signers_with_stake(
119 &self,
120 epoch: Epoch,
121 signers: &[Signer],
122 ) -> StdResult<Vec<SignerWithStake>> {
123 debug!(
124 self.logger,
125 ">> associate_signers_with_stake(epoch:{epoch})"
126 );
127
128 let stakes = self
129 .stake_storer
130 .get_stakes(epoch)
131 .await?
132 .ok_or_else(|| RunnerError::NoValueError(format!("stakes at epoch {epoch}")))?;
133
134 let mut signers_with_stake = vec![];
135
136 for signer in signers {
137 let stake = stakes
138 .get(&*signer.party_id)
139 .ok_or_else(|| RunnerError::NoStakeForSigner(signer.party_id.to_string()))?;
140
141 signers_with_stake.push(SignerWithStake {
142 party_id: signer.party_id.to_owned(),
143 verification_key_for_concatenation: signer
144 .verification_key_for_concatenation
145 .to_owned(),
146 verification_key_signature_for_concatenation: signer
147 .verification_key_signature_for_concatenation
148 .to_owned(),
149 operational_certificate: signer.operational_certificate.to_owned(),
150 kes_evolutions: signer.kes_evolutions.to_owned(),
151 stake: *stake,
152 #[cfg(feature = "future_snark")]
153 verification_key_for_snark: signer.verification_key_for_snark.to_owned(),
154 #[cfg(feature = "future_snark")]
155 verification_key_signature_for_snark: signer
156 .verification_key_signature_for_snark
157 .to_owned(),
158 });
159 trace!(
160 self.logger,
161 " > Associating signer_id {} with stake {}", signer.party_id, *stake
162 );
163 }
164
165 Ok(signers_with_stake)
166 }
167
168 fn is_signer_included_in_current_stake_distribution(
169 &self,
170 party_id: PartyId,
171 protocol_initializer: &ProtocolInitializer,
172 ) -> StdResult<bool> {
173 Ok(self.current_signers()?.iter().any(|s| {
174 s.party_id == party_id
175 && s.verification_key_for_concatenation
176 == protocol_initializer.verification_key_for_concatenation().into()
177 }))
178 }
179
180 fn unwrap_data(&self) -> Result<&EpochData, EpochServiceError> {
181 self.epoch_data.as_ref().ok_or(EpochServiceError::NotYetInitialized)
182 }
183}
184
185#[async_trait]
186impl EpochService for MithrilEpochService {
187 async fn inform_epoch_settings(
188 &mut self,
189 aggregator_signer_registration_epoch: Epoch,
190 mithril_network_configuration: MithrilNetworkConfiguration,
191 current_signers: Vec<Signer>,
192 next_signers: Vec<Signer>,
193 ) -> StdResult<()> {
194 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);
195
196 let registration_protocol_parameters = mithril_network_configuration
197 .configuration_for_registration
198 .protocol_parameters
199 .clone();
200
201 let protocol_initializer = self
202 .protocol_initializer_store
203 .get_protocol_initializer(
204 aggregator_signer_registration_epoch.offset_to_signer_retrieval_epoch()?,
205 )
206 .await?;
207
208 let allowed_discriminants = mithril_network_configuration
209 .configuration_for_aggregation
210 .enabled_signed_entity_types
211 .clone();
212
213 let signed_entity_types_config = &mithril_network_configuration
214 .configuration_for_aggregation
215 .signed_entity_types_config;
216
217 let cardano_transactions_signing_config =
218 signed_entity_types_config.cardano_transactions.clone();
219
220 let cardano_blocks_transactions_signing_config =
221 signed_entity_types_config.cardano_blocks_transactions.clone();
222
223 self.epoch_data = Some(EpochData {
224 epoch: aggregator_signer_registration_epoch,
225 registration_protocol_parameters,
226 protocol_initializer,
227 current_signers,
228 next_signers,
229 allowed_discriminants,
230 cardano_transactions_signing_config,
231 cardano_blocks_transactions_signing_config,
232 });
233
234 Ok(())
235 }
236
237 fn epoch_of_current_data(&self) -> StdResult<Epoch> {
238 Ok(self.unwrap_data()?.epoch)
239 }
240
241 fn registration_protocol_parameters(&self) -> StdResult<&ProtocolParameters> {
242 Ok(&self.unwrap_data()?.registration_protocol_parameters)
243 }
244
245 fn protocol_initializer(&self) -> StdResult<&Option<ProtocolInitializer>> {
246 Ok(&self.unwrap_data()?.protocol_initializer)
247 }
248
249 fn current_signers(&self) -> StdResult<&Vec<Signer>> {
250 Ok(&self.unwrap_data()?.current_signers)
251 }
252
253 fn next_signers(&self) -> StdResult<&Vec<Signer>> {
254 Ok(&self.unwrap_data()?.next_signers)
255 }
256
257 async fn current_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>> {
258 let current_epoch = self.epoch_of_current_data()?;
259 self.associate_signers_with_stake(
260 current_epoch.offset_to_signer_retrieval_epoch()?,
261 self.current_signers()?,
262 )
263 .await
264 }
265
266 async fn next_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>> {
267 let current_epoch = self.epoch_of_current_data()?;
268 self.associate_signers_with_stake(
269 current_epoch.offset_to_next_signer_retrieval_epoch(),
270 self.next_signers()?,
271 )
272 .await
273 }
274
275 fn allowed_discriminants(&self) -> StdResult<&BTreeSet<SignedEntityTypeDiscriminants>> {
276 Ok(&self.unwrap_data()?.allowed_discriminants)
277 }
278
279 fn cardano_transactions_signing_config(
280 &self,
281 ) -> StdResult<&Option<CardanoTransactionsSigningConfig>> {
282 Ok(&self.unwrap_data()?.cardano_transactions_signing_config)
283 }
284
285 fn cardano_blocks_transactions_signing_config(
286 &self,
287 ) -> StdResult<&Option<CardanoBlocksTransactionsSigningConfig>> {
288 Ok(&self.unwrap_data()?.cardano_blocks_transactions_signing_config)
289 }
290
291 fn can_signer_sign_current_epoch(&self, party_id: PartyId) -> StdResult<bool> {
292 let epoch = self.epoch_of_current_data()?;
293 if let Some(protocol_initializer) = self.protocol_initializer()? {
294 debug!(
295 self.logger,
296 " > Got protocol initializer for this epoch ({epoch})"
297 );
298 if self
299 .is_signer_included_in_current_stake_distribution(party_id, protocol_initializer)?
300 {
301 return Ok(true);
302 } else {
303 debug!(
304 self.logger,
305 " > Signer not in current stake distribution. Can NOT sign"
306 );
307 }
308 } else {
309 warn!(
310 self.logger,
311 " > NO protocol initializer found for this epoch ({epoch})",
312 );
313 }
314
315 Ok(false)
316 }
317}
318
319pub struct SignerSignedEntityConfigProvider {
324 epoch_service: EpochServiceWrapper,
325}
326
327impl SignerSignedEntityConfigProvider {
328 pub fn new(epoch_service: EpochServiceWrapper) -> Self {
330 Self { epoch_service }
331 }
332}
333
334#[async_trait]
335impl SignedEntityConfigProvider for SignerSignedEntityConfigProvider {
336 async fn get(&self) -> StdResult<SignedEntityConfig> {
337 let epoch_service = self.epoch_service.read().await;
338
339 Ok(SignedEntityConfig {
340 allowed_discriminants: epoch_service.allowed_discriminants()?.clone(),
341 cardano_transactions_signing_config: epoch_service
342 .cardano_transactions_signing_config()?
343 .clone(),
344 cardano_blocks_transactions_signing_config: epoch_service
345 .cardano_blocks_transactions_signing_config()?
346 .clone(),
347 })
348 }
349}
350
351#[cfg(test)]
352use crate::database::repository::ProtocolInitializerRepository;
353
354#[cfg(test)]
355impl MithrilEpochService {
356 pub fn new_with_dumb_dependencies() -> Self {
358 use crate::database::repository::StakePoolStore;
359 use crate::database::test_helper::main_db_connection;
360 use crate::test::TestLogger;
361
362 let sqlite_connection = Arc::new(main_db_connection().unwrap());
363 let stake_store = Arc::new(StakePoolStore::new(sqlite_connection.clone(), None));
364 let protocol_initializer_store =
365 Arc::new(ProtocolInitializerRepository::new(sqlite_connection, None));
366
367 Self::new(
368 stake_store,
369 protocol_initializer_store,
370 TestLogger::stdout(),
371 )
372 }
373
374 pub fn set_data_to_default_or_fake(mut self, epoch: Epoch) -> Self {
377 use mithril_common::test::double::fake_data;
378
379 let epoch_data = EpochData {
380 epoch,
381 registration_protocol_parameters: fake_data::protocol_parameters(),
382 protocol_initializer: None,
383 current_signers: vec![],
384 next_signers: vec![],
385 allowed_discriminants: BTreeSet::new(),
386 cardano_transactions_signing_config: None,
387 cardano_blocks_transactions_signing_config: None,
388 };
389 self.epoch_data = Some(epoch_data);
390 self
391 }
392
393 pub(crate) fn alter_data(mut self, data_config: impl FnOnce(&mut EpochData)) -> Self {
395 if let Some(data) = self.epoch_data.as_mut() {
396 data_config(data);
397 }
398 self
399 }
400}
401
402#[cfg(test)]
403pub(crate) mod mock_epoch_service {
404 use mockall::mock;
405
406 use super::*;
407
408 mock! {
409 pub EpochServiceImpl {}
410
411 #[async_trait]
412 impl EpochService for EpochServiceImpl {
413 async fn inform_epoch_settings(
414 &mut self,
415 aggregator_signer_registration_epoch: Epoch,
416 mithril_network_configuration: MithrilNetworkConfiguration,
417 current_signers: Vec<Signer>,
418 next_signers: Vec<Signer>,
419 ) -> StdResult<()>;
420
421 fn epoch_of_current_data(&self) -> StdResult<Epoch>;
422
423 fn registration_protocol_parameters(&self) -> StdResult<&'static ProtocolParameters>;
424
425 fn protocol_initializer(&self) -> StdResult<&'static Option<ProtocolInitializer>>;
426
427 fn current_signers(&self) -> StdResult<&'static Vec<Signer>>;
428
429 fn next_signers(&self) -> StdResult<&'static Vec<Signer>>;
430
431 async fn current_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>>;
432
433 async fn next_signers_with_stake(&self) -> StdResult<Vec<SignerWithStake>>;
434
435 fn allowed_discriminants(&self) -> StdResult<&'static BTreeSet<SignedEntityTypeDiscriminants>>;
436
437 fn cardano_transactions_signing_config(
438 &self,
439 ) -> StdResult<&'static Option<CardanoTransactionsSigningConfig>>;
440
441 fn cardano_blocks_transactions_signing_config(
442 &self,
443 ) -> StdResult<&'static Option<CardanoBlocksTransactionsSigningConfig>>;
444
445 fn can_signer_sign_current_epoch(&self, party_id: PartyId) -> StdResult<bool>;
446 }
447 }
448
449 impl MockEpochServiceImpl {
450 pub fn new_with_config(
451 config: impl FnOnce(&mut MockEpochServiceImpl),
452 ) -> MockEpochServiceImpl {
453 let mut epoch_service_mock = MockEpochServiceImpl::new();
454 config(&mut epoch_service_mock);
455
456 epoch_service_mock
457 }
458 }
459}
460
461#[cfg(test)]
462mod tests {
463 use std::sync::Arc;
464 use tokio::sync::RwLock;
465
466 use mithril_common::entities::{Epoch, StakeDistribution};
467 use mithril_common::test::{
468 builder::MithrilFixtureBuilder,
469 double::{Dummy, fake_data},
470 };
471
472 use mithril_protocol_config::model::{
473 MithrilNetworkConfigurationForEpoch, SignedEntityTypeConfiguration,
474 };
475
476 use crate::database::repository::{ProtocolInitializerRepository, StakePoolStore};
477 use crate::database::test_helper::main_db_connection;
478 use crate::services::MithrilProtocolInitializerBuilder;
479 use crate::test::TestLogger;
480
481 use super::*;
482
483 #[test]
484 fn test_is_signer_included_in_current_stake_distribution_returns_error_when_epoch_settings_is_not_set()
485 {
486 let party_id = "party_id".to_string();
487 let protocol_initializer = MithrilProtocolInitializerBuilder::build(
488 &100,
489 &fake_data::protocol_parameters(),
490 None,
491 None,
492 )
493 .unwrap();
494 let connection = Arc::new(main_db_connection().unwrap());
495 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
496 let protocol_initializer_store =
497 Arc::new(ProtocolInitializerRepository::new(connection, None));
498 let service = MithrilEpochService::new(
499 stake_store,
500 protocol_initializer_store,
501 TestLogger::stdout(),
502 );
503
504 service
505 .is_signer_included_in_current_stake_distribution(party_id, &protocol_initializer)
506 .expect_err("can_signer_sign should return error when epoch settings is not set");
507 }
508
509 #[tokio::test]
510 async fn test_is_signer_included_in_current_stake_distribution_returns_true_when_signer_verification_key_and_pool_id_found()
511 {
512 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
513 let protocol_initializer = fixtures.signers_fixture()[0].protocol_initializer.to_owned();
514
515 let connection = Arc::new(main_db_connection().unwrap());
516 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
517 let protocol_initializer_store =
518 Arc::new(ProtocolInitializerRepository::new(connection, None));
519
520 let epoch = Epoch(12);
521 let mithril_network_configuration = MithrilNetworkConfiguration {
522 epoch,
523 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
524 enabled_signed_entity_types: BTreeSet::new(),
525 ..Dummy::dummy()
526 },
527 ..Dummy::dummy()
528 };
529
530 let signers = fixtures.signers();
531 let current_signers = signers[..5].to_vec();
532 let next_signers = signers[2..5].to_vec();
533
534 let mut service = MithrilEpochService::new(
535 stake_store,
536 protocol_initializer_store,
537 TestLogger::stdout(),
538 );
539 service
540 .inform_epoch_settings(
541 epoch,
542 mithril_network_configuration.clone(),
543 current_signers.clone(),
544 next_signers.clone(),
545 )
546 .await
547 .unwrap();
548
549 let party_id = fixtures.signers_fixture()[0].party_id();
550 assert!(
551 service
552 .is_signer_included_in_current_stake_distribution(
553 party_id.clone(),
554 &protocol_initializer
555 )
556 .unwrap()
557 );
558
559 let party_id_not_included = fixtures.signers_fixture()[6].party_id();
560 assert!(
561 !service
562 .is_signer_included_in_current_stake_distribution(
563 party_id_not_included,
564 &protocol_initializer
565 )
566 .unwrap()
567 );
568
569 let protocol_initializer_not_included =
570 fixtures.signers_fixture()[6].protocol_initializer.to_owned();
571 assert!(
572 !service
573 .is_signer_included_in_current_stake_distribution(
574 party_id,
575 &protocol_initializer_not_included
576 )
577 .unwrap()
578 );
579 }
580
581 mod can_signer_sign_current_epoch {
582 use super::*;
583
584 #[test]
585 fn cant_sign_if_no_protocol_initializer_are_stored() {
586 let epoch = Epoch(12);
587 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
588
589 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
590 .set_data_to_default_or_fake(epoch)
591 .alter_data(|data| {
592 data.protocol_initializer = None;
593 data.current_signers = fixtures.signers();
594 });
595
596 let can_sign_current_epoch = epoch_service
597 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
598 .unwrap();
599 assert!(!can_sign_current_epoch);
600 }
601
602 #[test]
603 fn cant_sign_if_stored_protocol_initializer_belong_to_another_party() {
604 let epoch = Epoch(12);
605 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
606
607 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
608 .set_data_to_default_or_fake(epoch)
609 .alter_data(|data| {
610 data.protocol_initializer =
611 Some(fixtures.signers_fixture()[2].protocol_initializer.clone());
612 data.current_signers = fixtures.signers();
613 });
614
615 let can_sign_current_epoch = epoch_service
616 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
617 .unwrap();
618 assert!(!can_sign_current_epoch);
619 }
620
621 #[test]
622 fn cant_sign_if_not_in_current_signers() {
623 let epoch = Epoch(12);
624 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
625
626 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
627 .set_data_to_default_or_fake(epoch)
628 .alter_data(|data| {
629 data.protocol_initializer =
630 Some(fixtures.signers_fixture()[0].protocol_initializer.clone());
631 data.current_signers = fixtures.signers()[2..].to_vec();
632 });
633
634 let can_sign_current_epoch = epoch_service
635 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
636 .unwrap();
637 assert!(!can_sign_current_epoch);
638 }
639
640 #[test]
641 fn can_sign_if_in_current_signers_and_use_the_stored_protocol_initializer() {
642 let epoch = Epoch(12);
643 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
644
645 let epoch_service = MithrilEpochService::new_with_dumb_dependencies()
646 .set_data_to_default_or_fake(epoch)
647 .alter_data(|data| {
648 data.protocol_initializer =
649 Some(fixtures.signers_fixture()[0].protocol_initializer.clone());
650 data.current_signers = fixtures.signers();
651 });
652
653 let can_sign_current_epoch = epoch_service
654 .can_signer_sign_current_epoch(fixtures.signers()[0].party_id.clone())
655 .unwrap();
656 assert!(can_sign_current_epoch);
657 }
658 }
659
660 #[tokio::test]
661 async fn test_retrieve_data_return_error_before_register_epoch_settings_was_call() {
662 let epoch = Epoch(12);
663 let signers = fake_data::signers(10);
665 let stake_distribution: StakeDistribution = signers
666 .iter()
667 .enumerate()
668 .map(|(i, signer)| (signer.party_id.clone(), (i + 1) as u64 * 100))
669 .collect();
670
671 let connection = Arc::new(main_db_connection().unwrap());
673 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
674 stake_store
675 .save_stakes(epoch, stake_distribution.clone())
676 .await
677 .expect("save_stakes should not fail");
678 let protocol_initializer_store =
679 Arc::new(ProtocolInitializerRepository::new(connection, None));
680
681 let service = MithrilEpochService::new(
683 stake_store,
684 protocol_initializer_store,
685 TestLogger::stdout(),
686 );
687 assert!(service.epoch_of_current_data().is_err());
688 assert!(service.registration_protocol_parameters().is_err());
689 assert!(service.protocol_initializer().is_err());
690 assert!(service.current_signers().is_err());
691 assert!(service.next_signers().is_err());
692 assert!(service.current_signers_with_stake().await.is_err());
693 assert!(service.next_signers_with_stake().await.is_err());
694 assert!(service.cardano_transactions_signing_config().is_err());
695 }
696
697 #[tokio::test]
698 async fn test_data_are_available_after_register_epoch_settings_call() {
699 let connection = Arc::new(main_db_connection().unwrap());
703 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
704 let protocol_initializer_store =
705 Arc::new(ProtocolInitializerRepository::new(connection, None));
706
707 let epoch = Epoch(12);
708 let mithril_network_configuration = MithrilNetworkConfiguration {
709 epoch,
710 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
711 enabled_signed_entity_types: BTreeSet::from([
712 SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
713 ]),
714 ..Dummy::dummy()
715 },
716 ..Dummy::dummy()
717 };
718
719 let signers = fake_data::signers(10);
720 let current_signers = signers[2..5].to_vec();
721 let next_signers = signers[3..7].to_vec();
722
723 let mut service = MithrilEpochService::new(
725 stake_store,
726 protocol_initializer_store,
727 TestLogger::stdout(),
728 );
729
730 service
731 .inform_epoch_settings(
732 epoch,
733 mithril_network_configuration.clone(),
734 current_signers.clone(),
735 next_signers.clone(),
736 )
737 .await
738 .unwrap();
739
740 {
742 let current_signers = service.current_signers().unwrap();
743 let expected_current_signers = current_signers.clone();
744 assert_eq!(expected_current_signers, *current_signers);
745 }
746 {
748 let next_signers = service.next_signers().unwrap();
749 let expected_next_signers = next_signers.clone();
750 assert_eq!(expected_next_signers, *next_signers);
751 }
752
753 assert_eq!(
755 mithril_network_configuration.epoch,
756 service.epoch_of_current_data().unwrap()
757 );
758 assert_eq!(
759 mithril_network_configuration
760 .configuration_for_registration
761 .protocol_parameters,
762 *service.registration_protocol_parameters().unwrap()
763 );
764 assert!(
765 service.protocol_initializer().unwrap().is_none(),
766 "protocol_initializer should be None since nothing was in store"
767 );
768
769 assert_eq!(
771 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]),
772 *service.allowed_discriminants().unwrap()
773 );
774
775 assert_eq!(
777 mithril_network_configuration
778 .configuration_for_aggregation
779 .signed_entity_types_config
780 .cardano_transactions,
781 *service.cardano_transactions_signing_config().unwrap()
782 );
783 }
784
785 #[tokio::test]
786 async fn test_signers_with_stake_are_available_after_register_epoch_settings_call() {
787 fn build_stake_distribution(signers: &[Signer], first_stake: u64) -> StakeDistribution {
788 signers
789 .iter()
790 .enumerate()
791 .map(|(i, signer)| (signer.party_id.clone(), first_stake + i as u64))
792 .collect()
793 }
794
795 let epoch = Epoch(12);
796
797 let signers = fake_data::signers(10);
799 let stake_distribution: StakeDistribution = build_stake_distribution(&signers, 100);
800 let next_stake_distribution: StakeDistribution = build_stake_distribution(&signers, 500);
801
802 let connection = Arc::new(main_db_connection().unwrap());
803 let stake_store = {
804 let store = Arc::new(StakePoolStore::new(connection.clone(), None));
805 store
806 .save_stakes(
807 epoch.offset_to_signer_retrieval_epoch().unwrap(),
808 stake_distribution.clone(),
809 )
810 .await
811 .unwrap();
812 store
813 .save_stakes(
814 epoch.offset_to_next_signer_retrieval_epoch(),
815 next_stake_distribution.clone(),
816 )
817 .await
818 .unwrap();
819 store
820 };
821 let protocol_initializer_store =
822 Arc::new(ProtocolInitializerRepository::new(connection, None));
823
824 let mithril_network_configuration = MithrilNetworkConfiguration {
826 epoch,
827 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
828 enabled_signed_entity_types: BTreeSet::new(),
829 ..Dummy::dummy()
830 },
831 ..Dummy::dummy()
832 };
833
834 let current_signers = signers[2..5].to_vec();
835 let next_signers = signers[3..7].to_vec();
836
837 let mut service = MithrilEpochService::new(
839 stake_store,
840 protocol_initializer_store,
841 TestLogger::stdout(),
842 );
843 service
844 .inform_epoch_settings(
845 epoch,
846 mithril_network_configuration,
847 current_signers.clone(),
848 next_signers.clone(),
849 )
850 .await
851 .unwrap();
852
853 {
855 let actual_current_signers = service.current_signers_with_stake().await.unwrap();
856
857 assert_eq!(current_signers.len(), actual_current_signers.len());
858 for signer in actual_current_signers {
859 let expected_stake = stake_distribution.get(&signer.party_id).unwrap();
860 assert_eq!(expected_stake, &signer.stake);
861 }
862 }
863
864 {
866 let actual_next_signers = service.next_signers_with_stake().await.unwrap();
867
868 assert_eq!(next_signers.len(), actual_next_signers.len());
869 for signer in actual_next_signers {
870 let expected_stake = next_stake_distribution.get(&signer.party_id).unwrap();
871 assert_eq!(expected_stake, &signer.stake);
872 }
873 }
874 }
875
876 #[tokio::test]
877 async fn test_protocol_initializer_is_available_after_register_epoch_settings_call_if_in_store()
878 {
879 let epoch = Epoch(12);
880 let connection = Arc::new(main_db_connection().unwrap());
881 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
882 let protocol_initializer_store =
883 Arc::new(ProtocolInitializerRepository::new(connection, None));
884 protocol_initializer_store
885 .save_protocol_initializer(
886 epoch.offset_to_signer_retrieval_epoch().unwrap(),
887 fake_data::protocol_initializer("seed", 1245),
888 )
889 .await
890 .unwrap();
891
892 let mut service = MithrilEpochService::new(
893 stake_store,
894 protocol_initializer_store,
895 TestLogger::stdout(),
896 );
897
898 let mithril_network_configuration = MithrilNetworkConfiguration {
899 epoch,
900 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
901 enabled_signed_entity_types: BTreeSet::new(),
902 ..Dummy::dummy()
903 },
904 ..Dummy::dummy()
905 };
906
907 service
908 .inform_epoch_settings(epoch, mithril_network_configuration, Vec::new(), Vec::new())
909 .await
910 .unwrap();
911
912 let protocol_initializer = service.protocol_initializer().unwrap();
913 assert_eq!(
914 Some(1245),
915 protocol_initializer.as_ref().map(|p| p.get_stake()),
916 );
917 }
918
919 #[tokio::test]
920 async fn is_source_of_signed_entity_config() {
921 let connection = Arc::new(main_db_connection().unwrap());
922 let stake_store = Arc::new(StakePoolStore::new(connection.clone(), None));
923 let protocol_initializer_store =
924 Arc::new(ProtocolInitializerRepository::new(connection, None));
925 let epoch_service = Arc::new(RwLock::new(MithrilEpochService::new(
926 stake_store,
927 protocol_initializer_store,
928 TestLogger::stdout(),
929 )));
930 let config_provider = SignerSignedEntityConfigProvider {
931 epoch_service: epoch_service.clone(),
932 };
933
934 {
936 config_provider.get().await.expect_err(
937 "Should fail since sources data are not set before the first inform_epoch_settings",
938 );
939 }
940 {
942 let signers = fake_data::signers(5);
943 let current_signers = signers[1..3].to_vec();
944 let next_signers = signers[2..5].to_vec();
945 let allowed_discriminants =
946 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoStakeDistribution]);
947
948 let configuration_for_aggregation = MithrilNetworkConfigurationForEpoch {
949 signed_entity_types_config: SignedEntityTypeConfiguration {
950 cardano_transactions: None,
951 cardano_blocks_transactions: None,
952 },
953 enabled_signed_entity_types: allowed_discriminants.clone(),
954 ..Dummy::dummy()
955 };
956 let configuration_for_next_aggregation = MithrilNetworkConfigurationForEpoch::dummy();
957
958 epoch_service
959 .write()
960 .await
961 .inform_epoch_settings(
962 fake_data::beacon().epoch,
963 MithrilNetworkConfiguration {
964 configuration_for_aggregation,
965 configuration_for_next_aggregation,
966 ..Dummy::dummy()
967 },
968 current_signers,
969 next_signers,
970 )
971 .await
972 .unwrap();
973
974 let config = config_provider.get().await.unwrap();
975
976 assert_eq!(
977 SignedEntityConfig {
978 allowed_discriminants,
979 cardano_transactions_signing_config: None,
980 cardano_blocks_transactions_signing_config: None,
981 },
982 config
983 );
984 }
985 {
987 let allowed_discriminants =
988 BTreeSet::from([SignedEntityTypeDiscriminants::CardanoImmutableFilesFull]);
989
990 let configuration_for_aggregation = MithrilNetworkConfigurationForEpoch {
991 enabled_signed_entity_types: allowed_discriminants.clone(),
992 ..Dummy::dummy()
993 };
994
995 let signers = fake_data::signers(5);
996 let current_signers = signers[1..3].to_vec();
997 let next_signers = signers[2..5].to_vec();
998
999 epoch_service
1000 .write()
1001 .await
1002 .inform_epoch_settings(
1003 fake_data::beacon().epoch,
1004 MithrilNetworkConfiguration {
1005 configuration_for_aggregation,
1006 ..Dummy::dummy()
1007 },
1008 current_signers,
1009 next_signers,
1010 )
1011 .await
1012 .unwrap();
1013
1014 let config = config_provider.get().await.unwrap();
1015
1016 assert_eq!(
1017 SignedEntityConfig {
1018 allowed_discriminants,
1019 cardano_transactions_signing_config: Some(
1020 CardanoTransactionsSigningConfig::dummy()
1021 ),
1022 cardano_blocks_transactions_signing_config: Some(
1023 CardanoBlocksTransactionsSigningConfig::dummy()
1024 ),
1025 },
1026 config
1027 );
1028 }
1029 }
1030}