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