1use anyhow::{anyhow, Context};
2use async_trait::async_trait;
3use slog::{debug, Logger};
4use std::collections::BTreeSet;
5use std::sync::Arc;
6use thiserror::Error;
7
8use mithril_cardano_node_chain::chain_observer::ChainObserver;
9use mithril_common::crypto_helper::ProtocolAggregateVerificationKey;
10use mithril_common::entities::{
11 CardanoEra, CardanoTransactionsSigningConfig, Epoch, ProtocolParameters, SignedEntityConfig,
12 SignedEntityTypeDiscriminants, Signer, SignerWithStake, Stake, SupportedEra, TotalSPOs,
13};
14use mithril_common::logging::LoggerExtensions;
15use mithril_common::protocol::{MultiSigner as ProtocolMultiSigner, SignerBuilder};
16use mithril_common::StdResult;
17use mithril_era::EraChecker;
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_cardano_node_chain::test::double::FakeChainObserver;
856 use mithril_common::entities::{
857 BlockNumber, CardanoTransactionsSigningConfig, Stake, StakeDistribution, SupportedEra,
858 };
859 use mithril_common::test_utils::{
860 fake_data, MithrilFixture, MithrilFixtureBuilder, StakeDistributionGenerationMethod,
861 };
862 use mockall::predicate::eq;
863
864 use crate::store::{FakeEpochSettingsStorer, MockVerificationKeyStorer};
865 use crate::test_tools::TestLogger;
866 use crate::tools::mocks::MockStakeStore;
867
868 use super::*;
869
870 fn build_uniform_stake_distribution(
871 total_spo: TotalSPOs,
872 stake_by_spo: Stake,
873 ) -> StakeDistribution {
874 let fixture = MithrilFixtureBuilder::default()
875 .with_signers(total_spo as usize)
876 .with_stake_distribution(StakeDistributionGenerationMethod::Uniform(stake_by_spo))
877 .build();
878
879 fixture.stake_distribution()
880 }
881
882 #[derive(Debug, Clone, PartialEq)]
883 struct ExpectedEpochData {
884 cardano_era: CardanoEra,
885 mithril_era: SupportedEra,
886 epoch: Epoch,
887 protocol_parameters: ProtocolParameters,
888 next_protocol_parameters: ProtocolParameters,
889 cardano_signing_config: CardanoTransactionsSigningConfig,
890 next_cardano_signing_config: CardanoTransactionsSigningConfig,
891 signer_registration_protocol_parameters: ProtocolParameters,
892 current_signers_with_stake: BTreeSet<SignerWithStake>,
893 next_signers_with_stake: BTreeSet<SignerWithStake>,
894 current_signers: BTreeSet<Signer>,
895 next_signers: BTreeSet<Signer>,
896 signed_entity_config: SignedEntityConfig,
897 total_spo: Option<TotalSPOs>,
898 total_stake: Option<Stake>,
899 }
900
901 #[derive(Debug, Clone, PartialEq)]
902 struct ExpectedComputedEpochData {
903 aggregate_verification_key: ProtocolAggregateVerificationKey,
904 next_aggregate_verification_key: ProtocolAggregateVerificationKey,
905 }
906
907 impl ExpectedEpochData {
908 async fn from_service(service: &MithrilEpochService) -> StdResult<Self> {
909 Ok(Self {
910 cardano_era: service.cardano_era()?,
911 mithril_era: service.mithril_era()?,
912 epoch: service.epoch_of_current_data()?,
913 protocol_parameters: service.current_protocol_parameters()?.clone(),
914 next_protocol_parameters: service.next_protocol_parameters()?.clone(),
915 signer_registration_protocol_parameters: service
916 .signer_registration_protocol_parameters()?
917 .clone(),
918 cardano_signing_config: service
919 .current_cardano_transactions_signing_config()?
920 .clone(),
921 next_cardano_signing_config: service
922 .next_cardano_transactions_signing_config()?
923 .clone(),
924 current_signers_with_stake: service
925 .current_signers_with_stake()?
926 .clone()
927 .into_iter()
928 .collect(),
929 next_signers_with_stake: service
930 .next_signers_with_stake()?
931 .clone()
932 .into_iter()
933 .collect(),
934 current_signers: service.current_signers()?.clone().into_iter().collect(),
935 next_signers: service.next_signers()?.clone().into_iter().collect(),
936 signed_entity_config: service.signed_entity_config()?.clone(),
937 total_spo: service.total_spo()?,
938 total_stake: service.total_stake()?,
939 })
940 }
941 }
942
943 impl ExpectedComputedEpochData {
944 async fn from_service(service: &MithrilEpochService) -> StdResult<Self> {
945 Ok(Self {
946 aggregate_verification_key: service.current_aggregate_verification_key()?.clone(),
947 next_aggregate_verification_key: service.next_aggregate_verification_key()?.clone(),
948 })
949 }
950 }
951
952 struct EpochServiceBuilder {
953 cardano_transactions_signing_config: CardanoTransactionsSigningConfig,
954 future_protocol_parameters: ProtocolParameters,
955 allowed_discriminants: BTreeSet<SignedEntityTypeDiscriminants>,
956 cardano_era: CardanoEra,
957 mithril_era: SupportedEra,
958 current_epoch: Epoch,
959 signers_with_stake: Vec<SignerWithStake>,
960 next_signers_with_stake: Vec<SignerWithStake>,
961 stored_current_epoch_settings: AggregatorEpochSettings,
962 stored_next_epoch_settings: AggregatorEpochSettings,
963 stored_signer_registration_epoch_settings: AggregatorEpochSettings,
964 total_spo: TotalSPOs,
965 total_stake: Stake,
966 }
967
968 impl EpochServiceBuilder {
969 fn new(epoch: Epoch, epoch_fixture: MithrilFixture) -> Self {
970 Self {
971 cardano_transactions_signing_config: CardanoTransactionsSigningConfig::dummy(),
972 future_protocol_parameters: epoch_fixture.protocol_parameters(),
973 allowed_discriminants: BTreeSet::new(),
974 cardano_era: String::new(),
975 mithril_era: SupportedEra::dummy(),
976 current_epoch: epoch,
977 signers_with_stake: epoch_fixture.signers_with_stake(),
978 next_signers_with_stake: epoch_fixture.signers_with_stake(),
979 stored_current_epoch_settings: AggregatorEpochSettings {
980 protocol_parameters: epoch_fixture.protocol_parameters(),
981 cardano_transactions_signing_config: CardanoTransactionsSigningConfig::dummy(),
982 },
983 stored_next_epoch_settings: AggregatorEpochSettings {
984 protocol_parameters: epoch_fixture.protocol_parameters(),
985 cardano_transactions_signing_config: CardanoTransactionsSigningConfig::dummy(),
986 },
987 stored_signer_registration_epoch_settings: AggregatorEpochSettings {
988 protocol_parameters: epoch_fixture.protocol_parameters(),
989 cardano_transactions_signing_config: CardanoTransactionsSigningConfig::dummy(),
990 },
991 total_spo: 1,
992 total_stake: 0,
993 }
994 }
995
996 async fn build(self) -> MithrilEpochService {
997 let signer_retrieval_epoch = self
998 .current_epoch
999 .offset_to_signer_retrieval_epoch()
1000 .unwrap();
1001 let next_signer_retrieval_epoch =
1002 self.current_epoch.offset_to_next_signer_retrieval_epoch();
1003
1004 let epoch_settings_storer = FakeEpochSettingsStorer::new(vec![
1005 (signer_retrieval_epoch, self.stored_current_epoch_settings),
1006 (
1007 next_signer_retrieval_epoch,
1008 self.stored_next_epoch_settings.clone(),
1009 ),
1010 (
1011 next_signer_retrieval_epoch.next(),
1012 self.stored_signer_registration_epoch_settings.clone(),
1013 ),
1014 ]);
1015
1016 let verification_key_store = {
1017 let mut store = MockVerificationKeyStorer::new();
1018 let signers_with_stake = self.signers_with_stake.clone();
1019 store
1020 .expect_get_signers()
1021 .with(eq(signer_retrieval_epoch))
1022 .returning(move |_| Ok(Some(signers_with_stake.clone())));
1023
1024 let next_signers_with_stake = self.next_signers_with_stake.clone();
1025 store
1026 .expect_get_signers()
1027 .with(eq(next_signer_retrieval_epoch))
1028 .returning(move |_| Ok(Some(next_signers_with_stake.clone())));
1029 store
1030 };
1031
1032 let chain_observer = FakeChainObserver::default();
1033 chain_observer.set_current_era(self.cardano_era).await;
1034 let era_checker = EraChecker::new(self.mithril_era, Epoch::default());
1035
1036 let stake_store = {
1037 assert!(
1038 self.total_stake % self.total_spo as u64 == 0,
1039 "'total_stake' must be a multiple of 'total_spo' to create a uniform stake distribution"
1040 );
1041 let stake_per_spo = self.total_stake / self.total_spo as u64;
1042
1043 let stake_distribution =
1044 build_uniform_stake_distribution(self.total_spo, stake_per_spo);
1045
1046 let mut stake_store = MockStakeStore::new();
1047 stake_store
1048 .expect_get_stakes()
1049 .with(eq(signer_retrieval_epoch))
1050 .returning(move |_| Ok(Some(stake_distribution.clone())));
1051
1052 stake_store
1053 };
1054
1055 MithrilEpochService::new(
1056 AggregatorEpochSettings {
1057 protocol_parameters: self.future_protocol_parameters,
1058 cardano_transactions_signing_config: self.cardano_transactions_signing_config,
1059 },
1060 EpochServiceDependencies::new(
1061 Arc::new(epoch_settings_storer),
1062 Arc::new(verification_key_store),
1063 Arc::new(chain_observer),
1064 Arc::new(era_checker),
1065 Arc::new(stake_store),
1066 ),
1067 self.allowed_discriminants,
1068 TestLogger::stdout(),
1069 )
1070 }
1071 }
1072
1073 #[tokio::test]
1074 async fn inform_epoch_get_data_from_its_dependencies() {
1075 let current_epoch_fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1076 let next_epoch_fixture = MithrilFixtureBuilder::default()
1077 .with_protocol_parameters(ProtocolParameters::new(8, 80, 0.80))
1078 .with_signers(5)
1079 .build();
1080 let signer_registration_protocol_parameters = fake_data::protocol_parameters();
1081
1082 let epoch = Epoch(5);
1083 let builder = EpochServiceBuilder {
1084 next_signers_with_stake: next_epoch_fixture.signers_with_stake(),
1085 stored_next_epoch_settings: AggregatorEpochSettings {
1086 protocol_parameters: next_epoch_fixture.protocol_parameters(),
1087 ..AggregatorEpochSettings::dummy()
1088 },
1089 stored_signer_registration_epoch_settings: AggregatorEpochSettings {
1090 protocol_parameters: signer_registration_protocol_parameters.clone(),
1091 ..AggregatorEpochSettings::dummy()
1092 },
1093 allowed_discriminants: SignedEntityConfig::dummy().allowed_discriminants,
1094 cardano_era: "CardanoEra".to_string(),
1095 mithril_era: SupportedEra::eras()[0],
1096 total_spo: 10,
1097 total_stake: 20_000_000,
1098 ..EpochServiceBuilder::new(epoch, current_epoch_fixture.clone())
1099 };
1100
1101 let mut service = builder.build().await;
1102
1103 service
1104 .inform_epoch(epoch)
1105 .await
1106 .expect("inform_epoch should not fail");
1107
1108 let data = ExpectedEpochData::from_service(&service)
1109 .await
1110 .expect("extracting data from service should not fail");
1111
1112 assert_eq!(
1113 data.clone(),
1114 ExpectedEpochData {
1115 cardano_era: "CardanoEra".to_string(),
1116 mithril_era: SupportedEra::eras()[0],
1117 epoch,
1118 protocol_parameters: current_epoch_fixture.protocol_parameters(),
1119 next_protocol_parameters: next_epoch_fixture.protocol_parameters(),
1120 signer_registration_protocol_parameters,
1121 cardano_signing_config: CardanoTransactionsSigningConfig::dummy(),
1122 next_cardano_signing_config: CardanoTransactionsSigningConfig::dummy(),
1123 current_signers_with_stake: current_epoch_fixture
1124 .signers_with_stake()
1125 .into_iter()
1126 .collect(),
1127 next_signers_with_stake: next_epoch_fixture
1128 .signers_with_stake()
1129 .into_iter()
1130 .collect(),
1131 current_signers: current_epoch_fixture.signers().into_iter().collect(),
1132 next_signers: next_epoch_fixture.signers().into_iter().collect(),
1133 signed_entity_config: SignedEntityConfig::dummy(),
1134 total_spo: Some(10),
1135 total_stake: Some(20_000_000),
1136 }
1137 );
1138 }
1139
1140 #[tokio::test]
1141 async fn inform_epoch_get_signed_entity_config_from_its_dependencies_and_store() {
1142 let epoch = Epoch(5);
1143
1144 let cardano_transactions_signing_config =
1145 CardanoTransactionsSigningConfig::new(BlockNumber(29), BlockNumber(986));
1146 let allowed_discriminants = BTreeSet::from([
1147 SignedEntityTypeDiscriminants::CardanoTransactions,
1148 SignedEntityTypeDiscriminants::CardanoImmutableFilesFull,
1149 ]);
1150
1151 let mut service = EpochServiceBuilder {
1152 allowed_discriminants: allowed_discriminants.clone(),
1153 stored_current_epoch_settings: AggregatorEpochSettings {
1154 cardano_transactions_signing_config: cardano_transactions_signing_config.clone(),
1155 ..AggregatorEpochSettings::dummy()
1156 },
1157 ..EpochServiceBuilder::new(epoch, MithrilFixtureBuilder::default().build())
1158 }
1159 .build()
1160 .await;
1161
1162 service
1163 .inform_epoch(epoch)
1164 .await
1165 .expect("inform_epoch should not fail");
1166
1167 let signed_entity_config = service
1168 .signed_entity_config()
1169 .expect("extracting data from service should not fail");
1170
1171 assert_eq!(
1172 signed_entity_config.clone(),
1173 SignedEntityConfig {
1174 allowed_discriminants,
1175 cardano_transactions_signing_config,
1176 }
1177 );
1178 }
1179
1180 #[tokio::test]
1181 async fn compute_data_with_data_from_inform_epoch() {
1182 let current_epoch_fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1183 let next_epoch_fixture = MithrilFixtureBuilder::default()
1184 .with_protocol_parameters(ProtocolParameters::new(8, 80, 0.80))
1185 .with_signers(5)
1186 .build();
1187
1188 let epoch = Epoch(5);
1189 let mut service = EpochServiceBuilder {
1190 stored_next_epoch_settings: AggregatorEpochSettings {
1191 protocol_parameters: next_epoch_fixture.protocol_parameters(),
1192 cardano_transactions_signing_config: CardanoTransactionsSigningConfig::dummy(),
1193 },
1194 next_signers_with_stake: next_epoch_fixture.signers_with_stake().clone(),
1195 ..EpochServiceBuilder::new(epoch, current_epoch_fixture.clone())
1196 }
1197 .build()
1198 .await;
1199
1200 service
1201 .inform_epoch(epoch)
1202 .await
1203 .expect("inform_epoch should not fail");
1204 service
1205 .precompute_epoch_data()
1206 .await
1207 .expect("precompute_epoch_data should not fail");
1208
1209 let data = ExpectedComputedEpochData::from_service(&service)
1210 .await
1211 .expect("extracting data from service should not fail");
1212
1213 assert_eq!(
1214 data,
1215 ExpectedComputedEpochData {
1216 aggregate_verification_key: current_epoch_fixture.compute_avk(),
1217 next_aggregate_verification_key: next_epoch_fixture.compute_avk(),
1218 }
1219 );
1220 }
1221
1222 #[tokio::test]
1223 async fn inform_epoch_reset_computed_data() {
1224 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1225 let avk = fixture.compute_avk();
1226 let epoch = Epoch(4);
1227 let mut service = EpochServiceBuilder::new(epoch, fixture.clone())
1228 .build()
1229 .await;
1230 let signer_builder = SignerBuilder::new(
1231 &fixture.signers_with_stake(),
1232 &fixture.protocol_parameters(),
1233 )
1234 .unwrap();
1235 service.computed_epoch_data = Some(ComputedEpochData {
1236 aggregate_verification_key: avk.clone(),
1237 next_aggregate_verification_key: avk.clone(),
1238 protocol_multi_signer: signer_builder.build_multi_signer(),
1239 next_protocol_multi_signer: signer_builder.build_multi_signer(),
1240 });
1241
1242 service
1243 .inform_epoch(epoch)
1244 .await
1245 .expect("inform_epoch should not fail");
1246
1247 assert!(service.computed_epoch_data.is_none());
1248 }
1249
1250 #[tokio::test]
1251 async fn update_next_signers_with_stake_succeeds() {
1252 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1253 let next_fixture = MithrilFixtureBuilder::default().with_signers(5).build();
1254 let next_avk = next_fixture.compute_avk();
1255 let epoch = Epoch(4);
1256 let mut service = EpochServiceBuilder {
1257 next_signers_with_stake: next_fixture.signers_with_stake().clone(),
1258 ..EpochServiceBuilder::new(epoch, fixture.clone())
1259 }
1260 .build()
1261 .await;
1262 service
1263 .inform_epoch(epoch)
1264 .await
1265 .expect("inform_epoch should not fail");
1266 service.epoch_data = Some(EpochData {
1267 next_signers_with_stake: vec![],
1268 ..service.epoch_data.unwrap()
1269 });
1270 service.computed_epoch_data = None;
1271
1272 service
1273 .update_next_signers_with_stake()
1274 .await
1275 .expect("update_next_signers_with_stake should not fail");
1276
1277 let expected_next_signers_with_stake = next_fixture.signers_with_stake();
1278 assert_eq!(
1279 expected_next_signers_with_stake,
1280 service.epoch_data.unwrap().next_signers_with_stake
1281 );
1282
1283 assert_eq!(
1284 next_avk,
1285 service
1286 .computed_epoch_data
1287 .unwrap()
1288 .next_aggregate_verification_key
1289 );
1290 }
1291
1292 #[tokio::test]
1293 async fn update_epoch_settings_insert_future_epoch_settings_in_the_store() {
1294 let future_protocol_parameters = ProtocolParameters::new(6, 89, 0.124);
1295 let epoch = Epoch(4);
1296 let mut service = EpochServiceBuilder {
1297 future_protocol_parameters: future_protocol_parameters.clone(),
1298 ..EpochServiceBuilder::new(epoch, MithrilFixtureBuilder::default().build())
1299 }
1300 .build()
1301 .await;
1302
1303 service
1304 .inform_epoch(epoch)
1305 .await
1306 .expect("inform_epoch should not fail");
1307 service
1308 .update_epoch_settings()
1309 .await
1310 .expect("update_epoch_settings should not fail");
1311
1312 let inserted_epoch_settings = service
1313 .epoch_settings_storer
1314 .get_epoch_settings(epoch.offset_to_epoch_settings_recording_epoch())
1315 .await
1316 .unwrap_or_else(|_| {
1317 panic!(
1318 "epoch settings should have been inserted for epoch {}",
1319 epoch.offset_to_epoch_settings_recording_epoch()
1320 )
1321 })
1322 .unwrap();
1323
1324 assert_eq!(
1325 inserted_epoch_settings.protocol_parameters,
1326 future_protocol_parameters
1327 );
1328 }
1329
1330 #[tokio::test]
1331 async fn cant_get_data_if_inform_epoch_has_not_been_called() {
1332 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1333 let service = EpochServiceBuilder::new(Epoch(4), fixture.clone())
1334 .build()
1335 .await;
1336
1337 for (name, res) in [
1338 ("cardano_era", service.cardano_era().err()),
1339 ("mithril_era", service.mithril_era().err()),
1340 (
1341 "epoch_of_current_data",
1342 service.epoch_of_current_data().err(),
1343 ),
1344 (
1345 "current_protocol_parameters",
1346 service.current_protocol_parameters().err(),
1347 ),
1348 (
1349 "next_protocol_parameters",
1350 service.next_protocol_parameters().err(),
1351 ),
1352 (
1353 "signer_registration_protocol_parameters",
1354 service.signer_registration_protocol_parameters().err(),
1355 ),
1356 (
1357 "current_cardano_transactions_signing_config",
1358 service.current_cardano_transactions_signing_config().err(),
1359 ),
1360 (
1361 "next_cardano_transactions_signing_config",
1362 service.next_cardano_transactions_signing_config().err(),
1363 ),
1364 (
1365 "current_signers_with_stake",
1366 service.current_signers_with_stake().err(),
1367 ),
1368 (
1369 "next_signers_with_stake",
1370 service.next_signers_with_stake().err(),
1371 ),
1372 ("current_signers", service.current_signers().err()),
1373 ("next_signers", service.next_signers().err()),
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 ("signed_entity_config", service.signed_entity_config().err()),
1391 ("total_spo", service.total_spo().err()),
1392 ("total_stake", service.total_stake().err()),
1393 ] {
1394 let error =
1395 res.unwrap_or_else(|| panic!("getting {name} should have returned an error"));
1396
1397 match error.downcast_ref::<EpochServiceError>() {
1398 Some(EpochServiceError::NotYetInitialized) => (),
1399 _ => panic!("Expected an NotYetInitialized error, got: {error:?}"),
1400 }
1401 }
1402 }
1403
1404 #[tokio::test]
1405 async fn can_only_get_non_computed_data_if_inform_epoch_has_been_called_but_not_precompute_epoch_data(
1406 ) {
1407 let fixture = MithrilFixtureBuilder::default().with_signers(3).build();
1408 let mut service = EpochServiceBuilder::new(Epoch(4), fixture.clone())
1409 .build()
1410 .await;
1411 service.inform_epoch(Epoch(4)).await.unwrap();
1412
1413 assert!(service.cardano_era().is_ok());
1414 assert!(service.mithril_era().is_ok());
1415 assert!(service.epoch_of_current_data().is_ok());
1416 assert!(service.current_protocol_parameters().is_ok());
1417 assert!(service.next_protocol_parameters().is_ok());
1418 assert!(service.signer_registration_protocol_parameters().is_ok());
1419 assert!(service
1420 .current_cardano_transactions_signing_config()
1421 .is_ok());
1422 assert!(service.next_cardano_transactions_signing_config().is_ok());
1423 assert!(service.current_signers_with_stake().is_ok());
1424 assert!(service.next_signers_with_stake().is_ok());
1425 assert!(service.current_signers().is_ok());
1426 assert!(service.next_signers().is_ok());
1427 assert!(service.signed_entity_config().is_ok());
1428 assert!(service.total_spo().is_ok());
1429 assert!(service.total_stake().is_ok());
1430
1431 for (name, res) in [
1432 (
1433 "current_aggregate_verification_key",
1434 service.current_aggregate_verification_key().err(),
1435 ),
1436 (
1437 "next_aggregate_verification_key",
1438 service.next_aggregate_verification_key().err(),
1439 ),
1440 (
1441 "protocol_multi_signer",
1442 service.protocol_multi_signer().err(),
1443 ),
1444 (
1445 "next_protocol_multi_signer",
1446 service.next_protocol_multi_signer().err(),
1447 ),
1448 ] {
1449 let error =
1450 res.unwrap_or_else(|| panic!("getting {name} should have returned an error"));
1451
1452 match error.downcast_ref::<EpochServiceError>() {
1453 Some(EpochServiceError::NotYetComputed(Epoch(4))) => (),
1454 _ => panic!("Expected an NotYetComputed error for epoch 4, got: {error:?}"),
1455 }
1456 }
1457 }
1458}