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