1use anyhow::Context;
2use async_trait::async_trait;
3use slog::{Logger, debug};
4use std::collections::BTreeSet;
5use std::sync::Arc;
6use thiserror::Error;
7
8use mithril_cardano_node_chain::chain_observer::ChainObserver;
9use mithril_common::StdResult;
10use mithril_common::crypto_helper::ProtocolAggregateVerificationKey;
11use mithril_common::entities::{
12 CardanoEra, Epoch, ProtocolParameters, SignedEntityConfig, SignedEntityTypeDiscriminants,
13 Signer, SignerWithStake, Stake, SupportedEra, TotalSPOs,
14};
15use mithril_common::logging::LoggerExtensions;
16use mithril_common::protocol::{MultiSigner as ProtocolMultiSigner, SignerBuilder};
17use mithril_era::EraChecker;
18use mithril_persistence::store::StakeStorer;
19use mithril_protocol_config::interface::MithrilNetworkConfigurationProvider;
20use mithril_protocol_config::model::MithrilNetworkConfiguration;
21
22use crate::{EpochSettingsStorer, VerificationKeyStorer, entities::AggregatorEpochSettings};
23
24#[derive(Debug, Error)]
26pub enum EpochServiceError {
27 #[error("Epoch service could not obtain {1} for epoch {0}")]
29 UnavailableData(Epoch, String),
30
31 #[error("Epoch service was not initialized, the function `inform_epoch` must be called first")]
33 NotYetInitialized,
34
35 #[error(
37 "No data computed for epoch {0}, the function `precompute_epoch_data` must be called first"
38 )]
39 NotYetComputed(Epoch),
40}
41
42#[async_trait]
44pub trait EpochService: Sync + Send {
45 async fn inform_epoch(&mut self, epoch: Epoch) -> StdResult<()>;
48
49 async fn update_next_signers_with_stake(&mut self) -> StdResult<()>;
51
52 async fn precompute_epoch_data(&mut self) -> StdResult<()>;
56
57 fn cardano_era(&self) -> StdResult<CardanoEra>;
59
60 fn mithril_era(&self) -> StdResult<SupportedEra>;
62
63 fn epoch_of_current_data(&self) -> StdResult<Epoch>;
65
66 fn network_configuration(&self) -> StdResult<&MithrilNetworkConfiguration>;
68
69 fn current_protocol_parameters(&self) -> StdResult<&ProtocolParameters> {
71 Ok(&self
72 .network_configuration()?
73 .configuration_for_aggregation
74 .protocol_parameters)
75 }
76
77 fn next_protocol_parameters(&self) -> StdResult<&ProtocolParameters> {
79 Ok(&self
80 .network_configuration()?
81 .configuration_for_next_aggregation
82 .protocol_parameters)
83 }
84
85 fn signer_registration_protocol_parameters(&self) -> StdResult<&ProtocolParameters> {
87 Ok(&self
88 .network_configuration()?
89 .configuration_for_registration
90 .protocol_parameters)
91 }
92
93 fn current_aggregate_verification_key(&self) -> StdResult<&ProtocolAggregateVerificationKey>;
95
96 fn next_aggregate_verification_key(&self) -> StdResult<&ProtocolAggregateVerificationKey>;
98
99 fn current_signers_with_stake(&self) -> StdResult<&Vec<SignerWithStake>>;
101
102 fn next_signers_with_stake(&self) -> StdResult<&Vec<SignerWithStake>>;
104
105 fn current_signers(&self) -> StdResult<&Vec<Signer>>;
107
108 fn next_signers(&self) -> StdResult<&Vec<Signer>>;
110
111 fn total_stakes_signers(&self) -> StdResult<Stake>;
113
114 fn total_next_stakes_signers(&self) -> StdResult<Stake>;
116
117 fn protocol_multi_signer(&self) -> StdResult<&ProtocolMultiSigner>;
119
120 fn next_protocol_multi_signer(&self) -> StdResult<&ProtocolMultiSigner>;
122
123 fn signed_entity_config(&self) -> StdResult<&SignedEntityConfig>;
125
126 fn total_spo(&self) -> StdResult<Option<TotalSPOs>>;
130
131 fn total_stake(&self) -> StdResult<Option<Stake>>;
135}
136
137struct EpochData {
138 cardano_era: CardanoEra,
139 mithril_era: SupportedEra,
140 epoch: Epoch,
141 network_configuration: MithrilNetworkConfiguration,
142 current_signers_with_stake: Vec<SignerWithStake>,
143 next_signers_with_stake: Vec<SignerWithStake>,
144 current_signers: Vec<Signer>,
145 next_signers: Vec<Signer>,
146 total_stakes_signers: Stake,
147 total_next_stakes_signers: Stake,
148 signed_entity_config: SignedEntityConfig,
149 total_spo: Option<TotalSPOs>,
150 total_stake: Option<Stake>,
151}
152
153struct ComputedEpochData {
154 aggregate_verification_key: ProtocolAggregateVerificationKey,
155 next_aggregate_verification_key: ProtocolAggregateVerificationKey,
156 protocol_multi_signer: ProtocolMultiSigner,
157 next_protocol_multi_signer: ProtocolMultiSigner,
158}
159
160pub struct EpochServiceDependencies {
162 mithril_network_configuration_provider: Arc<dyn MithrilNetworkConfigurationProvider>,
163 epoch_settings_storer: Arc<dyn EpochSettingsStorer>,
164 verification_key_store: Arc<dyn VerificationKeyStorer>,
165 chain_observer: Arc<dyn ChainObserver>,
166 era_checker: Arc<EraChecker>,
167 stake_store: Arc<dyn StakeStorer>,
168}
169
170impl EpochServiceDependencies {
171 pub fn new(
173 mithril_network_configuration_provider: Arc<dyn MithrilNetworkConfigurationProvider>,
174 epoch_settings_storer: Arc<dyn EpochSettingsStorer>,
175 verification_key_store: Arc<dyn VerificationKeyStorer>,
176 chain_observer: Arc<dyn ChainObserver>,
177 era_checker: Arc<EraChecker>,
178 stake_store: Arc<dyn StakeStorer>,
179 ) -> Self {
180 Self {
181 mithril_network_configuration_provider,
182 epoch_settings_storer,
183 verification_key_store,
184 chain_observer,
185 era_checker,
186 stake_store,
187 }
188 }
189}
190
191pub struct MithrilEpochService {
193 epoch_data: Option<EpochData>,
194 computed_epoch_data: Option<ComputedEpochData>,
195 mithril_network_configuration_provider: Arc<dyn MithrilNetworkConfigurationProvider>,
196 epoch_settings_storer: Arc<dyn EpochSettingsStorer>,
197 verification_key_store: Arc<dyn VerificationKeyStorer>,
198 chain_observer: Arc<dyn ChainObserver>,
199 era_checker: Arc<EraChecker>,
200 stake_store: Arc<dyn StakeStorer>,
201 allowed_signed_entity_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
202 logger: Logger,
203}
204
205impl MithrilEpochService {
206 pub fn new(
208 dependencies: EpochServiceDependencies,
209 allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
210 logger: Logger,
211 ) -> Self {
212 Self {
213 epoch_data: None,
214 computed_epoch_data: None,
215 mithril_network_configuration_provider: dependencies
216 .mithril_network_configuration_provider,
217 epoch_settings_storer: dependencies.epoch_settings_storer,
218 verification_key_store: dependencies.verification_key_store,
219 chain_observer: dependencies.chain_observer,
220 era_checker: dependencies.era_checker,
221 stake_store: dependencies.stake_store,
222 allowed_signed_entity_discriminants: allowed_discriminants,
223 logger: logger.new_with_component_name::<Self>(),
224 }
225 }
226
227 async fn get_cardano_era(&self) -> StdResult<CardanoEra> {
228 let cardano_era = self
229 .chain_observer
230 .get_current_era()
231 .await?
232 .with_context(|| "No Cardano era returned by the chain observer")?;
233
234 Ok(cardano_era)
235 }
236
237 async fn get_total_spo_and_total_stake(
238 &self,
239 epoch: Epoch,
240 ) -> StdResult<(Option<TotalSPOs>, Option<Stake>)> {
241 match self.stake_store.get_stakes(epoch).await.with_context(|| {
242 format!("Epoch service failed to obtain the stake distribution for epoch: {epoch}")
243 })? {
244 None => Ok((None, None)),
245 Some(sd) => Ok((Some(sd.len() as TotalSPOs), Some(sd.values().sum()))),
246 }
247 }
248
249 async fn get_signers_with_stake_at_epoch(
250 &self,
251 signer_retrieval_epoch: Epoch,
252 ) -> StdResult<Vec<SignerWithStake>> {
253 let signers = self
254 .verification_key_store
255 .get_signers(signer_retrieval_epoch)
256 .await?
257 .unwrap_or_default();
258
259 Ok(signers)
260 }
261
262 async fn insert_epoch_settings(
263 &self,
264 recording_epoch: Epoch,
265 epoch_settings: &AggregatorEpochSettings,
266 ) -> StdResult<()> {
267 self.epoch_settings_storer
268 .save_epoch_settings(
269 recording_epoch,
270 epoch_settings.clone()
271 )
272 .await
273 .with_context(|| format!("Epoch service failed to insert future_epoch_settings to epoch {recording_epoch}"))
274 .map(|_| ())
275 }
276
277 fn unwrap_data(&self) -> Result<&EpochData, EpochServiceError> {
278 self.epoch_data.as_ref().ok_or(EpochServiceError::NotYetInitialized)
279 }
280
281 fn unwrap_computed_data(&self) -> Result<&ComputedEpochData, EpochServiceError> {
282 let epoch = self.unwrap_data()?.epoch;
283
284 self.computed_epoch_data
285 .as_ref()
286 .ok_or(EpochServiceError::NotYetComputed(epoch))
287 }
288}
289
290#[async_trait]
291impl EpochService for MithrilEpochService {
292 async fn inform_epoch(&mut self, epoch: Epoch) -> StdResult<()> {
293 debug!(self.logger, ">> inform_epoch(epoch: {epoch:?})");
294
295 let cardano_era = self.get_cardano_era().await?;
296
297 let mithril_era = self.era_checker.current_era();
298
299 let signer_retrieval_epoch =
300 epoch.offset_to_signer_retrieval_epoch().with_context(|| {
301 format!("EpochService could not compute signer retrieval epoch from epoch: {epoch}")
302 })?;
303 let next_signer_retrieval_epoch = epoch.offset_to_next_signer_retrieval_epoch();
304 let signer_registration_epoch = epoch.offset_to_recording_epoch();
305
306 let network_configuration = self
307 .mithril_network_configuration_provider
308 .get_network_configuration(epoch)
309 .await?;
310
311 let signer_registration_epoch_settings = AggregatorEpochSettings {
312 protocol_parameters: network_configuration
313 .configuration_for_registration
314 .protocol_parameters
315 .clone(),
316 cardano_transactions_signing_config: network_configuration
317 .configuration_for_registration
318 .signed_entity_types_config
319 .cardano_transactions
320 .clone(),
321 };
322 self.insert_epoch_settings(
323 signer_registration_epoch,
324 &signer_registration_epoch_settings,
325 )
326 .await?;
327
328 let current_signers_with_stake =
329 self.get_signers_with_stake_at_epoch(signer_retrieval_epoch).await?;
330 let next_signers_with_stake = self
331 .get_signers_with_stake_at_epoch(next_signer_retrieval_epoch)
332 .await?;
333 let current_signers = Signer::vec_from(current_signers_with_stake.clone());
334 let next_signers = Signer::vec_from(next_signers_with_stake.clone());
335 let total_stakes_signers = current_signers_with_stake.iter().map(|s| s.stake).sum();
336 let total_next_stakes_signers = next_signers_with_stake.iter().map(|s| s.stake).sum();
337
338 let signed_entity_config = SignedEntityConfig {
339 allowed_discriminants: self
340 .allowed_signed_entity_discriminants
341 .intersection(
342 &network_configuration
343 .configuration_for_aggregation
344 .enabled_signed_entity_types,
345 )
346 .cloned()
347 .collect(),
348 cardano_transactions_signing_config: network_configuration
349 .configuration_for_aggregation
350 .signed_entity_types_config
351 .cardano_transactions
352 .clone(),
353 };
354
355 let (total_spo, total_stake) =
356 self.get_total_spo_and_total_stake(signer_retrieval_epoch).await?;
357
358 self.epoch_data = Some(EpochData {
359 cardano_era,
360 mithril_era,
361 epoch,
362 network_configuration,
363 current_signers_with_stake,
364 next_signers_with_stake,
365 current_signers,
366 next_signers,
367 total_stakes_signers,
368 total_next_stakes_signers,
369 signed_entity_config,
370 total_spo,
371 total_stake,
372 });
373 self.computed_epoch_data = None;
374
375 Ok(())
376 }
377
378 async fn update_next_signers_with_stake(&mut self) -> StdResult<()> {
379 debug!(self.logger, ">> update_next_signers_with_stake");
380
381 let data = self.unwrap_data().with_context(
382 || "can't update next signers with stake if inform_epoch has not been called first",
383 )?;
384
385 let next_signer_retrieval_epoch = data.epoch.offset_to_next_signer_retrieval_epoch();
386 let next_signers_with_stake = self
387 .get_signers_with_stake_at_epoch(next_signer_retrieval_epoch)
388 .await?;
389
390 self.epoch_data.as_mut().unwrap().next_signers_with_stake = next_signers_with_stake;
391
392 self.precompute_epoch_data()
393 .await
394 .with_context(|| "Epoch service failed to precompute epoch data")?;
395
396 Ok(())
397 }
398
399 async fn precompute_epoch_data(&mut self) -> StdResult<()> {
400 debug!(self.logger, ">> precompute_epoch_data");
401
402 let data = self.unwrap_data().with_context(
403 || "can't precompute epoch data if inform_epoch has not been called first",
404 )?;
405
406 let protocol_multi_signer = SignerBuilder::new(
407 &data.current_signers_with_stake,
408 &data
409 .network_configuration
410 .configuration_for_aggregation
411 .protocol_parameters,
412 )
413 .with_context(|| "Epoch service failed to build protocol multi signer")?
414 .build_multi_signer();
415
416 let next_protocol_multi_signer = SignerBuilder::new(
417 &data.next_signers_with_stake,
418 &data
419 .network_configuration
420 .configuration_for_next_aggregation
421 .protocol_parameters,
422 )
423 .with_context(|| "Epoch service failed to build next protocol multi signer")?
424 .build_multi_signer();
425
426 self.computed_epoch_data = Some(ComputedEpochData {
427 aggregate_verification_key: protocol_multi_signer.compute_aggregate_verification_key(),
428 next_aggregate_verification_key: next_protocol_multi_signer
429 .compute_aggregate_verification_key(),
430 protocol_multi_signer,
431 next_protocol_multi_signer,
432 });
433
434 Ok(())
435 }
436
437 fn cardano_era(&self) -> StdResult<CardanoEra> {
438 Ok(self.unwrap_data()?.cardano_era.clone())
439 }
440
441 fn mithril_era(&self) -> StdResult<SupportedEra> {
442 Ok(self.unwrap_data()?.mithril_era)
443 }
444
445 fn epoch_of_current_data(&self) -> StdResult<Epoch> {
446 Ok(self.unwrap_data()?.epoch)
447 }
448
449 fn network_configuration(&self) -> StdResult<&MithrilNetworkConfiguration> {
450 Ok(&self.unwrap_data()?.network_configuration)
451 }
452
453 fn current_aggregate_verification_key(&self) -> StdResult<&ProtocolAggregateVerificationKey> {
454 Ok(&self.unwrap_computed_data()?.aggregate_verification_key)
455 }
456
457 fn next_aggregate_verification_key(&self) -> StdResult<&ProtocolAggregateVerificationKey> {
458 Ok(&self.unwrap_computed_data()?.next_aggregate_verification_key)
459 }
460
461 fn current_signers_with_stake(&self) -> StdResult<&Vec<SignerWithStake>> {
462 Ok(&self.unwrap_data()?.current_signers_with_stake)
463 }
464
465 fn next_signers_with_stake(&self) -> StdResult<&Vec<SignerWithStake>> {
466 Ok(&self.unwrap_data()?.next_signers_with_stake)
467 }
468
469 fn current_signers(&self) -> StdResult<&Vec<Signer>> {
470 Ok(&self.unwrap_data()?.current_signers)
471 }
472
473 fn next_signers(&self) -> StdResult<&Vec<Signer>> {
474 Ok(&self.unwrap_data()?.next_signers)
475 }
476
477 fn total_stakes_signers(&self) -> StdResult<Stake> {
478 Ok(self.unwrap_data()?.total_stakes_signers)
479 }
480
481 fn total_next_stakes_signers(&self) -> StdResult<Stake> {
482 Ok(self.unwrap_data()?.total_next_stakes_signers)
483 }
484
485 fn protocol_multi_signer(&self) -> StdResult<&ProtocolMultiSigner> {
486 Ok(&self.unwrap_computed_data()?.protocol_multi_signer)
487 }
488
489 fn next_protocol_multi_signer(&self) -> StdResult<&ProtocolMultiSigner> {
490 Ok(&self.unwrap_computed_data()?.next_protocol_multi_signer)
491 }
492
493 fn signed_entity_config(&self) -> StdResult<&SignedEntityConfig> {
494 Ok(&self.unwrap_data()?.signed_entity_config)
495 }
496
497 fn total_spo(&self) -> StdResult<Option<TotalSPOs>> {
498 Ok(self.unwrap_data()?.total_spo)
499 }
500
501 fn total_stake(&self) -> StdResult<Option<Stake>> {
502 Ok(self.unwrap_data()?.total_stake)
503 }
504}
505
506#[cfg(test)]
507pub(crate) struct FakeEpochService {
508 epoch_data: Option<EpochData>,
509 computed_epoch_data: Option<ComputedEpochData>,
510 inform_epoch_error: bool,
511 precompute_epoch_data_error: bool,
512 update_next_signers_with_stake_error: bool,
513}
514
515#[cfg(test)]
516pub(crate) struct FakeEpochServiceBuilder {
517 pub cardano_era: CardanoEra,
518 pub mithril_era: SupportedEra,
519 pub epoch: Epoch,
520 pub current_epoch_settings: AggregatorEpochSettings,
521 pub next_epoch_settings: AggregatorEpochSettings,
522 pub signer_registration_epoch_settings: AggregatorEpochSettings,
523 pub current_signers_with_stake: Vec<SignerWithStake>,
524 pub next_signers_with_stake: Vec<SignerWithStake>,
525 pub signed_entity_config: SignedEntityConfig,
526 pub total_spo: Option<TotalSPOs>,
527 pub total_stake: Option<Stake>,
528}
529
530#[cfg(test)]
531impl FakeEpochServiceBuilder {
532 pub fn dummy(epoch: Epoch) -> Self {
533 use mithril_common::test::double::{Dummy, fake_data};
534 let signers = fake_data::signers_with_stakes(3);
535
536 Self {
537 cardano_era: "DummyEra".to_string(),
538 mithril_era: SupportedEra::dummy(),
539 epoch,
540 current_epoch_settings: AggregatorEpochSettings::dummy(),
541 next_epoch_settings: AggregatorEpochSettings::dummy(),
542 signer_registration_epoch_settings: AggregatorEpochSettings::dummy(),
543 current_signers_with_stake: signers.clone(),
544 next_signers_with_stake: signers,
545 signed_entity_config: SignedEntityConfig::dummy(),
546 total_spo: None,
547 total_stake: None,
548 }
549 }
550
551 pub fn build(self) -> FakeEpochService {
552 let current_signers = Signer::vec_from(self.current_signers_with_stake.clone());
553 let next_signers = Signer::vec_from(self.next_signers_with_stake.clone());
554 let total_stakes_signers = self.current_signers_with_stake.iter().map(|s| s.stake).sum();
555 let total_next_stakes_signers = self.next_signers_with_stake.iter().map(|s| s.stake).sum();
556
557 let protocol_multi_signer = SignerBuilder::new(
558 &self.current_signers_with_stake,
559 &self.current_epoch_settings.protocol_parameters,
560 )
561 .with_context(|| "Could not build protocol_multi_signer for epoch service")
562 .unwrap()
563 .build_multi_signer();
564 let next_protocol_multi_signer = SignerBuilder::new(
565 &self.next_signers_with_stake,
566 &self.next_epoch_settings.protocol_parameters,
567 )
568 .with_context(|| "Could not build protocol_multi_signer for epoch service")
569 .unwrap()
570 .build_multi_signer();
571
572 let network_configuration = MithrilNetworkConfiguration {
573 epoch: self.epoch,
574 configuration_for_aggregation: self
575 .current_epoch_settings
576 .into_network_configuration_for_epoch(
577 self.signed_entity_config.allowed_discriminants.clone(),
578 ),
579 configuration_for_next_aggregation: self
580 .next_epoch_settings
581 .into_network_configuration_for_epoch(
582 self.signed_entity_config.allowed_discriminants.clone(),
583 ),
584 configuration_for_registration: self
585 .signer_registration_epoch_settings
586 .into_network_configuration_for_epoch(
587 self.signed_entity_config.allowed_discriminants.clone(),
588 ),
589 };
590
591 FakeEpochService {
592 epoch_data: Some(EpochData {
593 cardano_era: self.cardano_era,
594 mithril_era: self.mithril_era,
595 epoch: self.epoch,
596 network_configuration,
597 current_signers_with_stake: self.current_signers_with_stake,
598 next_signers_with_stake: self.next_signers_with_stake,
599 current_signers,
600 next_signers,
601 total_stakes_signers,
602 total_next_stakes_signers,
603 signed_entity_config: self.signed_entity_config,
604 total_spo: self.total_spo,
605 total_stake: self.total_stake,
606 }),
607 computed_epoch_data: Some(ComputedEpochData {
608 aggregate_verification_key: protocol_multi_signer
609 .compute_aggregate_verification_key(),
610 next_aggregate_verification_key: next_protocol_multi_signer
611 .compute_aggregate_verification_key(),
612 protocol_multi_signer,
613 next_protocol_multi_signer,
614 }),
615 inform_epoch_error: false,
616 precompute_epoch_data_error: false,
617 update_next_signers_with_stake_error: false,
618 }
619 }
620}
621
622#[cfg(test)]
623impl FakeEpochService {
624 pub fn from_fixture(
625 epoch: Epoch,
626 fixture: &mithril_common::test::builder::MithrilFixture,
627 ) -> Self {
628 use mithril_common::entities::CardanoTransactionsSigningConfig;
629 use mithril_common::test::double::Dummy;
630
631 let current_epoch_settings = AggregatorEpochSettings {
632 protocol_parameters: fixture.protocol_parameters(),
633 cardano_transactions_signing_config: Some(CardanoTransactionsSigningConfig::dummy()),
634 };
635 let next_epoch_settings = AggregatorEpochSettings {
636 protocol_parameters: fixture.protocol_parameters(),
637 cardano_transactions_signing_config: Some(CardanoTransactionsSigningConfig::dummy()),
638 };
639 let signer_registration_epoch_settings = AggregatorEpochSettings {
640 protocol_parameters: fixture.protocol_parameters(),
641 cardano_transactions_signing_config: Some(CardanoTransactionsSigningConfig::dummy()),
642 };
643
644 FakeEpochServiceBuilder {
645 current_epoch_settings,
646 next_epoch_settings,
647 signer_registration_epoch_settings,
648 current_signers_with_stake: fixture.signers_with_stake(),
649 next_signers_with_stake: fixture.signers_with_stake(),
650 ..FakeEpochServiceBuilder::dummy(epoch)
651 }
652 .build()
653 }
654
655 pub fn without_data() -> Self {
658 Self {
659 epoch_data: None,
660 computed_epoch_data: None,
661 inform_epoch_error: false,
662 precompute_epoch_data_error: false,
663 update_next_signers_with_stake_error: false,
664 }
665 }
666
667 pub fn toggle_errors(
668 &mut self,
669 inform_epoch: bool,
670 precompute_epoch: bool,
671 update_next_signers_with_stake: bool,
672 ) {
673 self.inform_epoch_error = inform_epoch;
674 self.precompute_epoch_data_error = precompute_epoch;
675 self.update_next_signers_with_stake_error = update_next_signers_with_stake;
676 }
677
678 fn unwrap_data(&self) -> Result<&EpochData, EpochServiceError> {
679 self.epoch_data.as_ref().ok_or(EpochServiceError::NotYetInitialized)
680 }
681
682 fn unwrap_computed_data(&self) -> Result<&ComputedEpochData, EpochServiceError> {
683 let epoch = self.unwrap_data()?.epoch;
684
685 self.computed_epoch_data
686 .as_ref()
687 .ok_or(EpochServiceError::NotYetComputed(epoch))
688 }
689}
690
691#[cfg(test)]
692#[async_trait]
693impl EpochService for FakeEpochService {
694 async fn inform_epoch(&mut self, epoch: Epoch) -> StdResult<()> {
695 if self.inform_epoch_error {
696 anyhow::bail!("inform_epoch fake error, given epoch: {epoch}");
697 }
698 Ok(())
699 }
700
701 async fn update_next_signers_with_stake(&mut self) -> StdResult<()> {
702 if self.update_next_signers_with_stake_error {
703 anyhow::bail!("update_next_signers_with_stake fake error");
704 }
705 Ok(())
706 }
707
708 async fn precompute_epoch_data(&mut self) -> StdResult<()> {
709 if self.precompute_epoch_data_error {
710 anyhow::bail!("precompute_epoch_data fake error");
711 }
712 Ok(())
713 }
714
715 fn cardano_era(&self) -> StdResult<CardanoEra> {
716 Ok(self.unwrap_data()?.cardano_era.clone())
717 }
718
719 fn mithril_era(&self) -> StdResult<SupportedEra> {
720 Ok(self.unwrap_data()?.mithril_era)
721 }
722
723 fn epoch_of_current_data(&self) -> StdResult<Epoch> {
724 Ok(self.unwrap_data()?.epoch)
725 }
726
727 fn network_configuration(&self) -> StdResult<&MithrilNetworkConfiguration> {
728 Ok(&self.unwrap_data()?.network_configuration)
729 }
730
731 fn current_aggregate_verification_key(&self) -> StdResult<&ProtocolAggregateVerificationKey> {
732 Ok(&self.unwrap_computed_data()?.aggregate_verification_key)
733 }
734
735 fn next_aggregate_verification_key(&self) -> StdResult<&ProtocolAggregateVerificationKey> {
736 Ok(&self.unwrap_computed_data()?.next_aggregate_verification_key)
737 }
738
739 fn current_signers_with_stake(&self) -> StdResult<&Vec<SignerWithStake>> {
740 Ok(&self.unwrap_data()?.current_signers_with_stake)
741 }
742
743 fn next_signers_with_stake(&self) -> StdResult<&Vec<SignerWithStake>> {
744 Ok(&self.unwrap_data()?.next_signers_with_stake)
745 }
746
747 fn current_signers(&self) -> StdResult<&Vec<Signer>> {
748 Ok(&self.unwrap_data()?.current_signers)
749 }
750
751 fn next_signers(&self) -> StdResult<&Vec<Signer>> {
752 Ok(&self.unwrap_data()?.next_signers)
753 }
754
755 fn total_stakes_signers(&self) -> StdResult<Stake> {
756 Ok(self.unwrap_data()?.total_stakes_signers)
757 }
758
759 fn total_next_stakes_signers(&self) -> StdResult<Stake> {
760 Ok(self.unwrap_data()?.total_next_stakes_signers)
761 }
762
763 fn protocol_multi_signer(&self) -> StdResult<&ProtocolMultiSigner> {
764 Ok(&self.unwrap_computed_data()?.protocol_multi_signer)
765 }
766
767 fn next_protocol_multi_signer(&self) -> StdResult<&ProtocolMultiSigner> {
768 Ok(&self.unwrap_computed_data()?.next_protocol_multi_signer)
769 }
770
771 fn signed_entity_config(&self) -> StdResult<&SignedEntityConfig> {
772 Ok(&self.unwrap_data()?.signed_entity_config)
773 }
774
775 fn total_spo(&self) -> StdResult<Option<u32>> {
776 Ok(self.unwrap_data()?.total_spo)
777 }
778
779 fn total_stake(&self) -> StdResult<Option<u64>> {
780 Ok(self.unwrap_data()?.total_stake)
781 }
782}
783
784#[cfg(test)]
785mod tests {
786 use mockall::predicate::eq;
787
788 use mithril_cardano_node_chain::test::double::FakeChainObserver;
789 use mithril_common::entities::{
790 BlockNumber, CardanoTransactionsSigningConfig, Stake, StakeDistribution, SupportedEra,
791 };
792 use mithril_common::test::{
793 builder::{MithrilFixture, MithrilFixtureBuilder, StakeDistributionGenerationMethod},
794 double::{Dummy, fake_data},
795 };
796 use mithril_protocol_config::{
797 model::{MithrilNetworkConfigurationForEpoch, SignedEntityTypeConfiguration},
798 test::double::configuration_provider::FakeMithrilNetworkConfigurationProvider,
799 };
800
801 use crate::store::{FakeEpochSettingsStorer, MockVerificationKeyStorer};
802 use crate::test::TestLogger;
803 use crate::test::double::mocks::MockStakeStore;
804
805 use super::*;
806
807 fn build_uniform_stake_distribution(
808 total_spo: TotalSPOs,
809 stake_by_spo: Stake,
810 ) -> StakeDistribution {
811 let fixture = MithrilFixtureBuilder::default()
812 .with_signers(total_spo as usize)
813 .with_stake_distribution(StakeDistributionGenerationMethod::Uniform(stake_by_spo))
814 .build();
815
816 fixture.stake_distribution()
817 }
818
819 #[derive(Debug, Clone, PartialEq)]
820 struct ExpectedEpochData {
821 cardano_era: CardanoEra,
822 mithril_era: SupportedEra,
823 epoch: Epoch,
824 protocol_parameters: ProtocolParameters,
825 next_protocol_parameters: ProtocolParameters,
826 signer_registration_protocol_parameters: ProtocolParameters,
827 current_signers_with_stake: BTreeSet<SignerWithStake>,
828 next_signers_with_stake: BTreeSet<SignerWithStake>,
829 current_signers: BTreeSet<Signer>,
830 next_signers: BTreeSet<Signer>,
831 signed_entity_config: SignedEntityConfig,
832 total_spo: Option<TotalSPOs>,
833 total_stake: Option<Stake>,
834 }
835
836 #[derive(Debug, Clone, PartialEq)]
837 struct ExpectedComputedEpochData {
838 aggregate_verification_key: ProtocolAggregateVerificationKey,
839 next_aggregate_verification_key: ProtocolAggregateVerificationKey,
840 }
841
842 impl ExpectedEpochData {
843 async fn from_service(service: &MithrilEpochService) -> StdResult<Self> {
844 Ok(Self {
845 cardano_era: service.cardano_era()?,
846 mithril_era: service.mithril_era()?,
847 epoch: service.epoch_of_current_data()?,
848 protocol_parameters: service.current_protocol_parameters()?.clone(),
849 next_protocol_parameters: service.next_protocol_parameters()?.clone(),
850 signer_registration_protocol_parameters: service
851 .signer_registration_protocol_parameters()?
852 .clone(),
853 current_signers_with_stake: service
854 .current_signers_with_stake()?
855 .clone()
856 .into_iter()
857 .collect(),
858 next_signers_with_stake: service
859 .next_signers_with_stake()?
860 .clone()
861 .into_iter()
862 .collect(),
863 current_signers: service.current_signers()?.clone().into_iter().collect(),
864 next_signers: service.next_signers()?.clone().into_iter().collect(),
865 signed_entity_config: service.signed_entity_config()?.clone(),
866 total_spo: service.total_spo()?,
867 total_stake: service.total_stake()?,
868 })
869 }
870 }
871
872 impl ExpectedComputedEpochData {
873 async fn from_service(service: &MithrilEpochService) -> StdResult<Self> {
874 Ok(Self {
875 aggregate_verification_key: service.current_aggregate_verification_key()?.clone(),
876 next_aggregate_verification_key: service.next_aggregate_verification_key()?.clone(),
877 })
878 }
879 }
880
881 struct EpochServiceBuilder {
882 allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
883 cardano_era: CardanoEra,
884 mithril_era: SupportedEra,
885 current_epoch: Epoch,
886 signers_with_stake: Vec<SignerWithStake>,
887 next_signers_with_stake: Vec<SignerWithStake>,
888 stored_current_epoch_settings: AggregatorEpochSettings,
889 stored_next_epoch_settings: AggregatorEpochSettings,
890 stored_signer_registration_epoch_settings: AggregatorEpochSettings,
891 total_spo: TotalSPOs,
892 total_stake: Stake,
893 }
894
895 impl EpochServiceBuilder {
896 fn new(epoch: Epoch, epoch_fixture: MithrilFixture) -> Self {
897 Self {
898 allowed_discriminants: BTreeSet::new(),
899 cardano_era: String::new(),
900 mithril_era: SupportedEra::dummy(),
901 current_epoch: epoch,
902 signers_with_stake: epoch_fixture.signers_with_stake(),
903 next_signers_with_stake: epoch_fixture.signers_with_stake(),
904 stored_current_epoch_settings: AggregatorEpochSettings {
905 protocol_parameters: epoch_fixture.protocol_parameters(),
906 cardano_transactions_signing_config: Some(
907 CardanoTransactionsSigningConfig::dummy(),
908 ),
909 },
910 stored_next_epoch_settings: AggregatorEpochSettings {
911 protocol_parameters: epoch_fixture.protocol_parameters(),
912 cardano_transactions_signing_config: Some(
913 CardanoTransactionsSigningConfig::dummy(),
914 ),
915 },
916 stored_signer_registration_epoch_settings: AggregatorEpochSettings {
917 protocol_parameters: epoch_fixture.protocol_parameters(),
918 cardano_transactions_signing_config: Some(
919 CardanoTransactionsSigningConfig::dummy(),
920 ),
921 },
922 total_spo: 1,
923 total_stake: 0,
924 }
925 }
926
927 async fn build(self) -> MithrilEpochService {
928 let signer_retrieval_epoch =
929 self.current_epoch.offset_to_signer_retrieval_epoch().unwrap();
930 let next_signer_retrieval_epoch =
931 self.current_epoch.offset_to_next_signer_retrieval_epoch();
932
933 let verification_key_store = {
934 let mut store = MockVerificationKeyStorer::new();
935 let signers_with_stake = self.signers_with_stake.clone();
936 store
937 .expect_get_signers()
938 .with(eq(signer_retrieval_epoch))
939 .returning(move |_| Ok(Some(signers_with_stake.clone())));
940
941 let next_signers_with_stake = self.next_signers_with_stake.clone();
942 store
943 .expect_get_signers()
944 .with(eq(next_signer_retrieval_epoch))
945 .returning(move |_| Ok(Some(next_signers_with_stake.clone())));
946 store
947 };
948
949 let chain_observer = FakeChainObserver::default();
950 chain_observer.set_current_era(self.cardano_era).await;
951 let era_checker = EraChecker::new(self.mithril_era, Epoch::default());
952
953 let stake_store = {
954 assert!(
955 self.total_stake.is_multiple_of(self.total_spo as u64),
956 "'total_stake' must be a multiple of 'total_spo' to create a uniform stake distribution"
957 );
958 let stake_per_spo = self.total_stake / self.total_spo as u64;
959
960 let stake_distribution =
961 build_uniform_stake_distribution(self.total_spo, stake_per_spo);
962
963 let mut stake_store = MockStakeStore::new();
964 stake_store
965 .expect_get_stakes()
966 .with(eq(signer_retrieval_epoch))
967 .returning(move |_| Ok(Some(stake_distribution.clone())));
968
969 stake_store
970 };
971
972 let configuration_for_aggregation = self
973 .stored_current_epoch_settings
974 .into_network_configuration_for_epoch(self.allowed_discriminants.clone());
975
976 let configuration_for_next_aggregation = self
977 .stored_next_epoch_settings
978 .into_network_configuration_for_epoch(self.allowed_discriminants.clone());
979
980 let configuration_for_registration = self
981 .stored_signer_registration_epoch_settings
982 .into_network_configuration_for_epoch(self.allowed_discriminants.clone());
983
984 let network_configuration_provider = FakeMithrilNetworkConfigurationProvider::new(
985 configuration_for_aggregation,
986 configuration_for_next_aggregation,
987 configuration_for_registration,
988 );
989
990 MithrilEpochService::new(
991 EpochServiceDependencies::new(
992 Arc::new(network_configuration_provider),
993 Arc::new(FakeEpochSettingsStorer::new(Vec::new())),
994 Arc::new(verification_key_store),
995 Arc::new(chain_observer),
996 Arc::new(era_checker),
997 Arc::new(stake_store),
998 ),
999 self.allowed_discriminants,
1000 TestLogger::stdout(),
1001 )
1002 }
1003 }
1004
1005 #[tokio::test]
1006 async fn inform_epoch_get_data_from_its_dependencies() {
1007 let current_epoch_fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1008 let next_epoch_fixture = MithrilFixtureBuilder::default()
1009 .with_protocol_parameters(ProtocolParameters::new(8, 80, 0.80))
1010 .with_signers(5)
1011 .build();
1012 let signer_registration_protocol_parameters = fake_data::protocol_parameters();
1013
1014 let epoch = Epoch(5);
1015 let builder = EpochServiceBuilder {
1016 next_signers_with_stake: next_epoch_fixture.signers_with_stake(),
1017 stored_next_epoch_settings: AggregatorEpochSettings {
1018 protocol_parameters: next_epoch_fixture.protocol_parameters(),
1019 ..AggregatorEpochSettings::dummy()
1020 },
1021 stored_signer_registration_epoch_settings: AggregatorEpochSettings {
1022 protocol_parameters: signer_registration_protocol_parameters.clone(),
1023 ..AggregatorEpochSettings::dummy()
1024 },
1025 allowed_discriminants: SignedEntityConfig::dummy().allowed_discriminants,
1026 cardano_era: "CardanoEra".to_string(),
1027 mithril_era: SupportedEra::eras()[0],
1028 total_spo: 10,
1029 total_stake: 20_000_000,
1030 ..EpochServiceBuilder::new(epoch, current_epoch_fixture.clone())
1031 };
1032
1033 let mut service = builder.build().await;
1034
1035 service
1036 .inform_epoch(epoch)
1037 .await
1038 .expect("inform_epoch should not fail");
1039
1040 let data = ExpectedEpochData::from_service(&service)
1041 .await
1042 .expect("extracting data from service should not fail");
1043
1044 assert_eq!(
1045 data.clone(),
1046 ExpectedEpochData {
1047 cardano_era: "CardanoEra".to_string(),
1048 mithril_era: SupportedEra::eras()[0],
1049 epoch,
1050 protocol_parameters: current_epoch_fixture.protocol_parameters(),
1051 next_protocol_parameters: next_epoch_fixture.protocol_parameters(),
1052 signer_registration_protocol_parameters,
1053 current_signers_with_stake: current_epoch_fixture
1054 .signers_with_stake()
1055 .into_iter()
1056 .collect(),
1057 next_signers_with_stake: next_epoch_fixture
1058 .signers_with_stake()
1059 .into_iter()
1060 .collect(),
1061 current_signers: current_epoch_fixture.signers().into_iter().collect(),
1062 next_signers: next_epoch_fixture.signers().into_iter().collect(),
1063 signed_entity_config: SignedEntityConfig::dummy(),
1064 total_spo: Some(10),
1065 total_stake: Some(20_000_000),
1066 }
1067 );
1068 }
1069
1070 #[tokio::test]
1071 async fn inform_epoch_get_signed_entity_config_from_its_dependencies_and_store() {
1072 let epoch = Epoch(5);
1073
1074 let cardano_transactions_signing_config = Some(CardanoTransactionsSigningConfig {
1075 security_parameter: BlockNumber(29),
1076 step: BlockNumber(986),
1077 });
1078 let allowed_discriminants = BTreeSet::from([
1079 SignedEntityTypeDiscriminants::CardanoTransactions,
1080 SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
1081 ]);
1082
1083 let mut service = EpochServiceBuilder {
1084 allowed_discriminants: allowed_discriminants.clone(),
1085 stored_current_epoch_settings: AggregatorEpochSettings {
1086 cardano_transactions_signing_config: cardano_transactions_signing_config.clone(),
1087 ..AggregatorEpochSettings::dummy()
1088 },
1089 ..EpochServiceBuilder::new(epoch, MithrilFixtureBuilder::default().build())
1090 }
1091 .build()
1092 .await;
1093
1094 service
1095 .inform_epoch(epoch)
1096 .await
1097 .expect("inform_epoch should not fail");
1098
1099 let signed_entity_config = service
1100 .signed_entity_config()
1101 .expect("extracting data from service should not fail");
1102
1103 assert_eq!(
1104 signed_entity_config.clone(),
1105 SignedEntityConfig {
1106 allowed_discriminants,
1107 cardano_transactions_signing_config,
1108 }
1109 );
1110 }
1111
1112 #[tokio::test]
1113 async fn inform_epoch_compute_allowed_discriminants_from_intersection_of_aggregation_network_config_and_configured_discriminants()
1114 {
1115 let epoch = Epoch(5);
1116 let allowed_discriminants = BTreeSet::from([
1117 SignedEntityTypeDiscriminants::CardanoStakeDistribution,
1118 SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
1119 SignedEntityTypeDiscriminants::CardanoTransactions,
1120 ]);
1121 let enabled_discriminants = BTreeSet::from([
1122 SignedEntityTypeDiscriminants::MithrilStakeDistribution,
1123 SignedEntityTypeDiscriminants::CardanoStakeDistribution,
1124 SignedEntityTypeDiscriminants::CardanoTransactions,
1125 ]);
1126
1127 let mut service = MithrilEpochService {
1128 mithril_network_configuration_provider: Arc::new(
1129 FakeMithrilNetworkConfigurationProvider::new(
1130 MithrilNetworkConfigurationForEpoch {
1131 enabled_signed_entity_types: enabled_discriminants,
1132 ..Dummy::dummy()
1133 },
1134 MithrilNetworkConfigurationForEpoch::dummy(),
1135 MithrilNetworkConfigurationForEpoch::dummy(),
1136 ),
1137 ),
1138 ..EpochServiceBuilder {
1139 allowed_discriminants: allowed_discriminants.clone(),
1140 ..EpochServiceBuilder::new(epoch, MithrilFixtureBuilder::default().build())
1141 }
1142 .build()
1143 .await
1144 };
1145
1146 service
1147 .inform_epoch(epoch)
1148 .await
1149 .expect("inform_epoch should not fail");
1150
1151 let signed_entity_config = service
1152 .signed_entity_config()
1153 .expect("extracting data from service should not fail");
1154
1155 assert_eq!(
1156 BTreeSet::from([
1157 SignedEntityTypeDiscriminants::CardanoTransactions,
1158 SignedEntityTypeDiscriminants::CardanoStakeDistribution,
1159 ]),
1160 signed_entity_config.allowed_discriminants
1161 );
1162 }
1163
1164 #[tokio::test]
1165 async fn compute_data_with_data_from_inform_epoch() {
1166 let current_epoch_fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1167 let next_epoch_fixture = MithrilFixtureBuilder::default()
1168 .with_protocol_parameters(ProtocolParameters::new(8, 80, 0.80))
1169 .with_signers(5)
1170 .build();
1171
1172 let epoch = Epoch(5);
1173 let mut service =
1174 EpochServiceBuilder {
1175 stored_next_epoch_settings: AggregatorEpochSettings {
1176 protocol_parameters: next_epoch_fixture.protocol_parameters(),
1177 cardano_transactions_signing_config: Some(
1178 CardanoTransactionsSigningConfig::dummy(),
1179 ),
1180 },
1181 next_signers_with_stake: next_epoch_fixture.signers_with_stake().clone(),
1182 ..EpochServiceBuilder::new(epoch, current_epoch_fixture.clone())
1183 }
1184 .build()
1185 .await;
1186
1187 service
1188 .inform_epoch(epoch)
1189 .await
1190 .expect("inform_epoch should not fail");
1191 service
1192 .precompute_epoch_data()
1193 .await
1194 .expect("precompute_epoch_data should not fail");
1195
1196 let data = ExpectedComputedEpochData::from_service(&service)
1197 .await
1198 .expect("extracting data from service should not fail");
1199
1200 assert_eq!(
1201 data,
1202 ExpectedComputedEpochData {
1203 aggregate_verification_key: current_epoch_fixture.compute_avk(),
1204 next_aggregate_verification_key: next_epoch_fixture.compute_avk(),
1205 }
1206 );
1207 }
1208
1209 #[tokio::test]
1210 async fn inform_epoch_reset_computed_data() {
1211 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1212 let avk = fixture.compute_avk();
1213 let epoch = Epoch(4);
1214 let mut service = EpochServiceBuilder::new(epoch, fixture.clone()).build().await;
1215 let signer_builder = SignerBuilder::new(
1216 &fixture.signers_with_stake(),
1217 &fixture.protocol_parameters(),
1218 )
1219 .unwrap();
1220 service.computed_epoch_data = Some(ComputedEpochData {
1221 aggregate_verification_key: avk.clone(),
1222 next_aggregate_verification_key: avk.clone(),
1223 protocol_multi_signer: signer_builder.build_multi_signer(),
1224 next_protocol_multi_signer: signer_builder.build_multi_signer(),
1225 });
1226
1227 service
1228 .inform_epoch(epoch)
1229 .await
1230 .expect("inform_epoch should not fail");
1231
1232 assert!(service.computed_epoch_data.is_none());
1233 }
1234
1235 #[tokio::test]
1236 async fn update_next_signers_with_stake_succeeds() {
1237 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1238 let next_fixture = MithrilFixtureBuilder::default().with_signers(5).build();
1239 let next_avk = next_fixture.compute_avk();
1240 let epoch = Epoch(4);
1241 let mut service = EpochServiceBuilder {
1242 next_signers_with_stake: next_fixture.signers_with_stake().clone(),
1243 ..EpochServiceBuilder::new(epoch, fixture.clone())
1244 }
1245 .build()
1246 .await;
1247 service
1248 .inform_epoch(epoch)
1249 .await
1250 .expect("inform_epoch should not fail");
1251 service.epoch_data = Some(EpochData {
1252 next_signers_with_stake: vec![],
1253 ..service.epoch_data.unwrap()
1254 });
1255 service.computed_epoch_data = None;
1256
1257 service
1258 .update_next_signers_with_stake()
1259 .await
1260 .expect("update_next_signers_with_stake should not fail");
1261
1262 let expected_next_signers_with_stake = next_fixture.signers_with_stake();
1263 assert_eq!(
1264 expected_next_signers_with_stake,
1265 service.epoch_data.unwrap().next_signers_with_stake
1266 );
1267
1268 assert_eq!(
1269 next_avk,
1270 service.computed_epoch_data.unwrap().next_aggregate_verification_key
1271 );
1272 }
1273
1274 #[tokio::test]
1275 async fn inform_epoch_insert_registration_epoch_settings_in_the_store() {
1276 let expected_epoch_settings = AggregatorEpochSettings {
1277 protocol_parameters: ProtocolParameters::new(6, 89, 0.124),
1278 cardano_transactions_signing_config: Some(CardanoTransactionsSigningConfig {
1279 security_parameter: BlockNumber(10),
1280 step: BlockNumber(15),
1281 }),
1282 };
1283
1284 let epoch = Epoch(4);
1285 let mut service = MithrilEpochService {
1286 mithril_network_configuration_provider: Arc::new(
1287 FakeMithrilNetworkConfigurationProvider::new(
1288 MithrilNetworkConfigurationForEpoch::dummy(),
1289 MithrilNetworkConfigurationForEpoch::dummy(),
1290 MithrilNetworkConfigurationForEpoch {
1291 protocol_parameters: expected_epoch_settings.protocol_parameters.clone(),
1292 signed_entity_types_config: SignedEntityTypeConfiguration {
1293 cardano_transactions: expected_epoch_settings
1294 .cardano_transactions_signing_config
1295 .clone(),
1296 },
1297 ..Dummy::dummy()
1298 },
1299 ),
1300 ),
1301 ..EpochServiceBuilder::new(epoch, MithrilFixtureBuilder::default().build())
1302 .build()
1303 .await
1304 };
1305
1306 service
1307 .inform_epoch(epoch)
1308 .await
1309 .expect("inform_epoch should not fail");
1310
1311 let inserted_epoch_settings = service
1312 .epoch_settings_storer
1313 .get_epoch_settings(epoch.offset_to_recording_epoch())
1314 .await
1315 .unwrap_or_else(|_| {
1316 panic!(
1317 "epoch settings should have been inserted for epoch {}",
1318 epoch.offset_to_recording_epoch()
1319 )
1320 })
1321 .unwrap();
1322
1323 assert_eq!(inserted_epoch_settings, expected_epoch_settings);
1324 }
1325
1326 #[tokio::test]
1327 async fn cant_get_data_if_inform_epoch_has_not_been_called() {
1328 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1329 let service = EpochServiceBuilder::new(Epoch(4), fixture.clone()).build().await;
1330
1331 for (name, res) in [
1332 ("cardano_era", service.cardano_era().err()),
1333 ("mithril_era", service.mithril_era().err()),
1334 (
1335 "epoch_of_current_data",
1336 service.epoch_of_current_data().err(),
1337 ),
1338 (
1339 "current_protocol_parameters",
1340 service.current_protocol_parameters().err(),
1341 ),
1342 (
1343 "next_protocol_parameters",
1344 service.next_protocol_parameters().err(),
1345 ),
1346 (
1347 "signer_registration_protocol_parameters",
1348 service.signer_registration_protocol_parameters().err(),
1349 ),
1350 (
1351 "current_signers_with_stake",
1352 service.current_signers_with_stake().err(),
1353 ),
1354 (
1355 "next_signers_with_stake",
1356 service.next_signers_with_stake().err(),
1357 ),
1358 ("current_signers", service.current_signers().err()),
1359 ("next_signers", service.next_signers().err()),
1360 (
1361 "current_aggregate_verification_key",
1362 service.current_aggregate_verification_key().err(),
1363 ),
1364 (
1365 "next_aggregate_verification_key",
1366 service.next_aggregate_verification_key().err(),
1367 ),
1368 (
1369 "protocol_multi_signer",
1370 service.protocol_multi_signer().err(),
1371 ),
1372 (
1373 "next_protocol_multi_signer",
1374 service.next_protocol_multi_signer().err(),
1375 ),
1376 ("signed_entity_config", service.signed_entity_config().err()),
1377 ("total_spo", service.total_spo().err()),
1378 ("total_stake", service.total_stake().err()),
1379 ] {
1380 let error =
1381 res.unwrap_or_else(|| panic!("getting {name} should have returned an error"));
1382
1383 match error.downcast_ref::<EpochServiceError>() {
1384 Some(EpochServiceError::NotYetInitialized) => (),
1385 _ => panic!("Expected an NotYetInitialized error, got: {error:?}"),
1386 }
1387 }
1388 }
1389
1390 #[tokio::test]
1391 async fn can_only_get_non_computed_data_if_inform_epoch_has_been_called_but_not_precompute_epoch_data()
1392 {
1393 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1394 let mut service = EpochServiceBuilder::new(Epoch(4), fixture.clone()).build().await;
1395 service.inform_epoch(Epoch(4)).await.unwrap();
1396
1397 assert!(service.cardano_era().is_ok());
1398 assert!(service.mithril_era().is_ok());
1399 assert!(service.epoch_of_current_data().is_ok());
1400 assert!(service.current_protocol_parameters().is_ok());
1401 assert!(service.next_protocol_parameters().is_ok());
1402 assert!(service.signer_registration_protocol_parameters().is_ok());
1403 assert!(service.current_signers_with_stake().is_ok());
1404 assert!(service.next_signers_with_stake().is_ok());
1405 assert!(service.current_signers().is_ok());
1406 assert!(service.next_signers().is_ok());
1407 assert!(service.signed_entity_config().is_ok());
1408 assert!(service.total_spo().is_ok());
1409 assert!(service.total_stake().is_ok());
1410
1411 for (name, res) in [
1412 (
1413 "current_aggregate_verification_key",
1414 service.current_aggregate_verification_key().err(),
1415 ),
1416 (
1417 "next_aggregate_verification_key",
1418 service.next_aggregate_verification_key().err(),
1419 ),
1420 (
1421 "protocol_multi_signer",
1422 service.protocol_multi_signer().err(),
1423 ),
1424 (
1425 "next_protocol_multi_signer",
1426 service.next_protocol_multi_signer().err(),
1427 ),
1428 ] {
1429 let error =
1430 res.unwrap_or_else(|| panic!("getting {name} should have returned an error"));
1431
1432 match error.downcast_ref::<EpochServiceError>() {
1433 Some(EpochServiceError::NotYetComputed(Epoch(4))) => (),
1434 _ => panic!("Expected an NotYetComputed error for epoch 4, got: {error:?}"),
1435 }
1436 }
1437 }
1438}