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