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