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