1use anyhow::Context;
2use async_trait::async_trait;
3use slog::{Logger, debug, warn};
4use thiserror::Error;
5use tokio::sync::RwLockReadGuard;
6
7use mithril_common::StdResult;
8use mithril_common::crypto_helper::{KesPeriod, OpCert, ProtocolOpCert, SerDeShelleyFileFormat};
9use mithril_common::entities::{
10 Epoch, PartyId, ProtocolMessage, SignedEntityType, Signer, TimePoint,
11};
12use mithril_common::logging::LoggerExtensions;
13use mithril_protocol_config::model::MithrilNetworkConfiguration;
14
15use crate::Configuration;
16use crate::dependency_injection::SignerDependencyContainer;
17use crate::entities::{BeaconToSign, SignerEpochSettings};
18use crate::services::{EpochService, MithrilProtocolInitializerBuilder};
19
20#[async_trait]
22pub trait Runner: Send + Sync {
23 async fn get_mithril_network_configuration(
25 &self,
26 epoch: Epoch,
27 ) -> StdResult<MithrilNetworkConfiguration>;
28
29 async fn get_signer_registrations_from_aggregator(
31 &self,
32 ) -> StdResult<Option<SignerEpochSettings>>;
33
34 async fn get_beacon_to_sign(&self, time_point: TimePoint) -> StdResult<Option<BeaconToSign>>;
36
37 async fn get_current_time_point(&self) -> StdResult<TimePoint>;
39
40 async fn register_signer_to_aggregator(&self) -> StdResult<()>;
42
43 async fn update_stake_distribution(&self, epoch: Epoch) -> StdResult<()>;
45
46 async fn can_sign_current_epoch(&self) -> StdResult<bool>;
48
49 async fn inform_epoch_settings(
51 &self,
52 aggregator_signer_registration_epoch: Epoch,
53 mithril_network_configuration: MithrilNetworkConfiguration,
54 current_signer: Vec<Signer>,
55 next_signer: Vec<Signer>,
56 ) -> StdResult<()>;
57
58 async fn compute_message(
60 &self,
61 signed_entity_type: &SignedEntityType,
62 ) -> StdResult<ProtocolMessage>;
63
64 async fn compute_publish_single_signature(
66 &self,
67 beacon_to_sign: &BeaconToSign,
68 message: &ProtocolMessage,
69 ) -> StdResult<()>;
70
71 async fn update_era_checker(&self, epoch: Epoch) -> StdResult<()>;
73
74 async fn upkeep(&self, current_epoch: Epoch) -> StdResult<()>;
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, Error)]
80pub enum RunnerError {
81 #[error("No value returned by the subsystem for `{0}`.")]
83 NoValueError(String),
84 #[error("No stake associated with myself.")]
86 NoStakeForSelf(),
87 #[error("No stake associated with this signer, party_id: {0}.")]
89 NoStakeForSigner(PartyId),
90 #[error("File parse failed: {0}.")]
92 FileParse(String),
93}
94
95pub struct SignerRunner {
97 config: Configuration,
98 services: SignerDependencyContainer,
99 logger: Logger,
100}
101
102impl SignerRunner {
103 pub fn new(config: Configuration, services: SignerDependencyContainer, logger: Logger) -> Self {
105 Self {
106 services,
107 config,
108 logger: logger.new_with_component_name::<Self>(),
109 }
110 }
111
112 async fn epoch_service_read(&self) -> RwLockReadGuard<'_, dyn EpochService> {
113 self.services.epoch_service.read().await
114 }
115}
116
117#[cfg_attr(test, mockall::automock)]
118#[async_trait]
119impl Runner for SignerRunner {
120 async fn get_mithril_network_configuration(
121 &self,
122 epoch: Epoch,
123 ) -> StdResult<MithrilNetworkConfiguration> {
124 debug!(self.logger, ">> get_mithril_network_configuration");
125
126 self.services
127 .network_configuration_service
128 .get_network_configuration(epoch)
129 .await
130 }
131
132 async fn get_signer_registrations_from_aggregator(
133 &self,
134 ) -> StdResult<Option<SignerEpochSettings>> {
135 debug!(self.logger, ">> get_epoch_settings");
136
137 self.services
138 .certificate_handler
139 .retrieve_epoch_settings()
140 .await
141 .map_err(|e| e.into())
142 }
143
144 async fn get_beacon_to_sign(&self, time_point: TimePoint) -> StdResult<Option<BeaconToSign>> {
145 debug!(
146 self.logger,
147 ">> get_beacon_to_sign(time_point: {time_point})"
148 );
149
150 self.services.certifier.get_beacon_to_sign(time_point).await
151 }
152
153 async fn get_current_time_point(&self) -> StdResult<TimePoint> {
154 debug!(self.logger, ">> get_current_time_point");
155
156 self.services
157 .ticker_service
158 .get_current_time_point()
159 .await
160 .with_context(|| "Runner can not get current time point")
161 }
162
163 async fn register_signer_to_aggregator(&self) -> StdResult<()> {
164 debug!(self.logger, ">> register_signer_to_aggregator");
165
166 let (epoch, protocol_parameters) = {
167 let epoch_service = self.services.epoch_service.read().await;
168 let epoch = epoch_service.epoch_of_current_data()?;
169 let protocol_parameters = epoch_service.registration_protocol_parameters()?;
170
171 (epoch, protocol_parameters.clone())
172 };
173
174 let epoch_offset_to_recording_epoch = epoch.offset_to_recording_epoch();
175 let stake_distribution = self
176 .services
177 .stake_store
178 .get_stakes(epoch_offset_to_recording_epoch)
179 .await?
180 .ok_or_else(|| {
181 RunnerError::NoValueError(format!(
182 "stakes at epoch {epoch_offset_to_recording_epoch}"
183 ))
184 })?;
185 let stake = stake_distribution
186 .get(&self.services.single_signer.get_party_id())
187 .ok_or_else(RunnerError::NoStakeForSelf)?;
188 let (operational_certificate, protocol_operational_certificate) = match &self
189 .config
190 .operational_certificate_path
191 {
192 Some(operational_certificate_path) => {
193 let opcert: OpCert = OpCert::from_file(operational_certificate_path)
194 .map_err(|_| RunnerError::FileParse("operational_certificate_path".to_string()))
195 .with_context(
196 || "register_signer_to_aggregator can not decode OpCert from file",
197 )?;
198 (Some(opcert.clone()), Some(ProtocolOpCert::new(opcert)))
199 }
200 _ => (None, None),
201 };
202
203 let kes_period = match operational_certificate {
204 Some(operational_certificate) => Some(
205 self.services
206 .chain_observer
207 .get_current_kes_period()
208 .await?
209 .unwrap_or_default()
210 - operational_certificate.get_start_kes_period() as KesPeriod,
211 ),
212 None => None,
213 };
214 let protocol_initializer = MithrilProtocolInitializerBuilder::build(
215 stake,
216 &protocol_parameters,
217 self.services.kes_signer.clone(),
218 kes_period,
219 )?;
220 self.services
221 .protocol_initializer_store
222 .save_protocol_initializer(epoch_offset_to_recording_epoch, protocol_initializer)
223 .await?;
224
225 let protocol_initializer = self
226 .services
227 .protocol_initializer_store
228 .get_protocol_initializer(epoch_offset_to_recording_epoch)
229 .await?.ok_or(RunnerError::NoValueError(
230 format!("no protocol_initializer available in store for epoch {epoch_offset_to_recording_epoch}"),
231 )).with_context(
232 || "register_signer_to_aggregator can not retrieve protocol initializer from store",
233 )?;
234 let signer = Signer::new(
235 self.services.single_signer.get_party_id(),
236 protocol_initializer.verification_key().into(),
237 protocol_initializer.verification_key_signature(),
238 protocol_operational_certificate,
239 kes_period,
240 );
241 self.services
242 .certificate_handler
243 .register_signer(epoch_offset_to_recording_epoch, &signer)
244 .await?;
245
246 Ok(())
247 }
248
249 async fn update_stake_distribution(&self, epoch: Epoch) -> StdResult<()> {
250 debug!(self.logger, ">> update_stake_distribution(epoch: {epoch})");
251
252 let exists_stake_distribution = !self
253 .services
254 .stake_store
255 .get_stakes(epoch.offset_to_recording_epoch())
256 .await?
257 .unwrap_or_default()
258 .is_empty();
259 if exists_stake_distribution {
260 return Ok(());
261 }
262
263 let stake_distribution = self
264 .services
265 .chain_observer
266 .get_current_stake_distribution()
267 .await?
268 .ok_or_else(|| RunnerError::NoValueError("current_stake_distribution".to_string()))?;
269 self.services
270 .stake_store
271 .save_stakes(epoch.offset_to_recording_epoch(), stake_distribution)
272 .await?;
273
274 Ok(())
275 }
276
277 async fn can_sign_current_epoch(&self) -> StdResult<bool> {
278 let epoch_service = self.epoch_service_read().await;
279 epoch_service.can_signer_sign_current_epoch(self.services.single_signer.get_party_id())
280 }
281
282 async fn inform_epoch_settings(
283 &self,
284 aggregator_signer_registration_epoch: Epoch,
285 mithril_network_configuration: MithrilNetworkConfiguration,
286 current_signer: Vec<Signer>,
287 next_signer: Vec<Signer>,
288 ) -> StdResult<()> {
289 debug!(
290 self.logger,
291 ">> inform_epoch_settings(epoch:{})", aggregator_signer_registration_epoch
292 );
293
294 self.services
295 .epoch_service
296 .write()
297 .await
298 .inform_epoch_settings(
299 aggregator_signer_registration_epoch,
300 mithril_network_configuration,
301 current_signer,
302 next_signer,
303 )
304 .await
305 }
306
307 async fn compute_message(
308 &self,
309 signed_entity_type: &SignedEntityType,
310 ) -> StdResult<ProtocolMessage> {
311 debug!(self.logger, ">> compute_message({signed_entity_type:?})");
312
313 let protocol_message = self
314 .services
315 .signable_builder_service
316 .compute_protocol_message(signed_entity_type.to_owned())
317 .await
318 .with_context(|| format!("Runner can not compute protocol message for signed entity type: '{signed_entity_type}'"))?;
319
320 Ok(protocol_message)
321 }
322
323 async fn compute_publish_single_signature(
324 &self,
325 beacon_to_sign: &BeaconToSign,
326 message: &ProtocolMessage,
327 ) -> StdResult<()> {
328 debug!(self.logger, ">> compute_publish_single_signature"; "beacon_to_sign" => ?beacon_to_sign);
329 self.services
330 .certifier
331 .compute_publish_single_signature(beacon_to_sign, message)
332 .await
333 }
334
335 async fn update_era_checker(&self, epoch: Epoch) -> StdResult<()> {
336 debug!(self.logger, ">> update_era_checker(epoch:{epoch})");
337
338 let era_token = self
339 .services
340 .era_reader
341 .read_era_epoch_token(epoch)
342 .await
343 .map_err(Box::new)?;
344 let current_era = era_token.get_current_supported_era()?;
345 self.services
346 .era_checker
347 .change_era(current_era, era_token.get_current_epoch());
348 debug!(
349 self.logger,
350 "Current Era is {} (Epoch {}).",
351 current_era,
352 era_token.get_current_epoch()
353 );
354
355 if era_token.get_next_supported_era().is_err() {
356 let era_name = &era_token.get_next_era_marker().unwrap().name;
357 warn!(
358 self.logger,
359 "Upcoming Era '{era_name}' is not supported by this version of the software. Please update!"
360 );
361 }
362
363 Ok(())
364 }
365
366 async fn upkeep(&self, current_epoch: Epoch) -> StdResult<()> {
367 debug!(self.logger, ">> upkeep(current_epoch:{current_epoch})");
368 self.services.upkeep_service.run(current_epoch).await?;
369 Ok(())
370 }
371}
372
373#[cfg(test)]
374mod tests {
375 use mithril_protocol_config::model::MithrilNetworkConfigurationForEpoch;
376 use mockall::mock;
377 use mockall::predicate::eq;
378 use std::collections::BTreeSet;
379 use std::{path::Path, sync::Arc};
380 use tokio::sync::RwLock;
381
382 use mithril_cardano_node_chain::test::double::{DumbBlockScanner, FakeChainObserver};
383 use mithril_cardano_node_internal_database::{
384 signable_builder::{
385 CardanoDatabaseSignableBuilder, CardanoImmutableFilesFullSignableBuilder,
386 },
387 test::double::{DumbImmutableDigester, DumbImmutableFileObserver},
388 };
389 use mithril_common::{
390 api_version::APIVersionProvider,
391 crypto_helper::{MKMap, MKMapNode, MKTreeNode, MKTreeStoreInMemory, MKTreeStorer},
392 entities::{BlockNumber, BlockRange, Epoch, SignedEntityTypeDiscriminants},
393 signable_builder::{
394 BlockRangeRootRetriever, CardanoStakeDistributionSignableBuilder,
395 CardanoTransactionsSignableBuilder, MithrilSignableBuilderService,
396 MithrilStakeDistributionSignableBuilder, SignableBuilderServiceDependencies,
397 },
398 test::{
399 builder::MithrilFixtureBuilder,
400 double::{Dummy, fake_data},
401 },
402 };
403 use mithril_era::{EraChecker, EraReader, adapters::EraReaderBootstrapAdapter};
404 use mithril_protocol_config::test::double::configuration_provider::FakeMithrilNetworkConfigurationProvider;
405 use mithril_signed_entity_lock::SignedEntityTypeLock;
406 use mithril_signed_entity_preloader::{
407 CardanoTransactionsPreloader, CardanoTransactionsPreloaderActivation,
408 };
409 use mithril_ticker::{MithrilTickerService, TickerService};
410
411 use crate::database::repository::{
412 ProtocolInitializerRepository, SignedBeaconRepository, StakePoolStore,
413 };
414 use crate::database::test_helper::main_db_connection;
415 use crate::metrics::MetricsService;
416 use crate::services::{
417 CardanoTransactionsImporter, DumbAggregatorClient, MithrilEpochService,
418 MithrilSingleSigner, MockTransactionStore, MockUpkeepService, SignerCertifierService,
419 SignerSignableSeedBuilder, SignerSignedEntityConfigProvider,
420 };
421 use crate::test_tools::TestLogger;
422
423 use super::*;
424
425 const DIGESTER_RESULT: &str = "a digest";
426
427 mock! {
428 pub FakeTimePointProvider { }
429
430 #[async_trait]
431 impl TickerService for FakeTimePointProvider {
432 async fn get_current_time_point(&self) -> StdResult<TimePoint>;
433 }
434 }
435
436 mock! {
437 pub BlockRangeRootRetrieverImpl<S: MKTreeStorer> { }
438
439 #[async_trait]
440 impl<S: MKTreeStorer> BlockRangeRootRetriever<S> for BlockRangeRootRetrieverImpl<S> {
441 async fn retrieve_block_range_roots<'a>(
442 &'a self,
443 up_to_beacon: BlockNumber,
444 ) -> StdResult<Box<dyn Iterator<Item = (BlockRange, MKTreeNode)> + 'a>>;
445
446 async fn compute_merkle_map_from_block_range_roots(
447 &self,
448 up_to_beacon: BlockNumber,
449 ) -> StdResult<MKMap<BlockRange, MKMapNode<BlockRange,S>, S>>;
450 }
451 }
452
453 async fn init_services() -> SignerDependencyContainer {
454 let logger = TestLogger::stdout();
455 let sqlite_connection = Arc::new(main_db_connection().unwrap());
456 let stake_distribution_signers = fake_data::signers_with_stakes(2);
457 let party_id = stake_distribution_signers[1].party_id.clone();
458 let fake_observer = FakeChainObserver::default();
459 fake_observer.set_signers(stake_distribution_signers).await;
460 let chain_observer = Arc::new(fake_observer);
461 let ticker_service = Arc::new(MithrilTickerService::new(
462 chain_observer.clone(),
463 Arc::new(DumbImmutableFileObserver::default()),
464 ));
465 let era_reader = Arc::new(EraReader::new(Arc::new(EraReaderBootstrapAdapter)));
466 let era_epoch_token = era_reader
467 .read_era_epoch_token(ticker_service.get_current_epoch().await.unwrap())
468 .await
469 .unwrap();
470 let era_checker = Arc::new(EraChecker::new(
471 era_epoch_token.get_current_supported_era().unwrap(),
472 era_epoch_token.get_current_epoch(),
473 ));
474
475 let api_version_provider = Arc::new(APIVersionProvider::new(era_checker.clone()));
476 let digester = Arc::new(DumbImmutableDigester::default().with_digest(DIGESTER_RESULT));
477 let cardano_immutable_signable_builder =
478 Arc::new(CardanoImmutableFilesFullSignableBuilder::new(
479 digester.clone(),
480 Path::new(""),
481 logger.clone(),
482 ));
483 let mithril_stake_distribution_signable_builder =
484 Arc::new(MithrilStakeDistributionSignableBuilder::default());
485 let transaction_parser = Arc::new(DumbBlockScanner::new());
486 let transaction_store = Arc::new(MockTransactionStore::new());
487 let transactions_importer = Arc::new(CardanoTransactionsImporter::new(
488 transaction_parser.clone(),
489 transaction_store.clone(),
490 logger.clone(),
491 ));
492 let block_range_root_retriever =
493 Arc::new(MockBlockRangeRootRetrieverImpl::<MKTreeStoreInMemory>::new());
494 let cardano_transactions_builder = Arc::new(CardanoTransactionsSignableBuilder::new(
495 transactions_importer.clone(),
496 block_range_root_retriever,
497 ));
498 let stake_store = Arc::new(StakePoolStore::new(sqlite_connection.clone(), None));
499 let cardano_stake_distribution_builder = Arc::new(
500 CardanoStakeDistributionSignableBuilder::new(stake_store.clone()),
501 );
502 let cardano_database_signable_builder = Arc::new(CardanoDatabaseSignableBuilder::new(
503 digester.clone(),
504 Path::new(""),
505 logger.clone(),
506 ));
507 let protocol_initializer_store = Arc::new(ProtocolInitializerRepository::new(
508 sqlite_connection.clone(),
509 None,
510 ));
511 let epoch_service = Arc::new(RwLock::new(MithrilEpochService::new(
512 stake_store.clone(),
513 protocol_initializer_store.clone(),
514 logger.clone(),
515 )));
516 let single_signer = Arc::new(MithrilSingleSigner::new(
517 party_id,
518 epoch_service.clone(),
519 logger.clone(),
520 ));
521 let signable_seed_builder_service = Arc::new(SignerSignableSeedBuilder::new(
522 epoch_service.clone(),
523 protocol_initializer_store.clone(),
524 ));
525 let signable_builders_dependencies = SignableBuilderServiceDependencies::new(
526 mithril_stake_distribution_signable_builder,
527 cardano_immutable_signable_builder,
528 cardano_transactions_builder,
529 cardano_stake_distribution_builder,
530 cardano_database_signable_builder,
531 );
532 let signable_builder_service = Arc::new(MithrilSignableBuilderService::new(
533 signable_seed_builder_service,
534 signable_builders_dependencies,
535 logger.clone(),
536 ));
537 let metrics_service = Arc::new(MetricsService::new(logger.clone()).unwrap());
538 let signed_entity_type_lock = Arc::new(SignedEntityTypeLock::default());
539 let security_parameter = BlockNumber(0);
540 let cardano_transactions_preloader = Arc::new(CardanoTransactionsPreloader::new(
541 signed_entity_type_lock.clone(),
542 transactions_importer.clone(),
543 security_parameter,
544 chain_observer.clone(),
545 logger.clone(),
546 Arc::new(CardanoTransactionsPreloaderActivation::new(true)),
547 ));
548 let upkeep_service = Arc::new(MockUpkeepService::new());
549 let aggregator_client = Arc::new(DumbAggregatorClient::default());
550 let certifier = Arc::new(SignerCertifierService::new(
551 Arc::new(SignedBeaconRepository::new(sqlite_connection.clone(), None)),
552 Arc::new(SignerSignedEntityConfigProvider::new(epoch_service.clone())),
553 signed_entity_type_lock.clone(),
554 single_signer.clone(),
555 aggregator_client.clone(),
556 logger.clone(),
557 ));
558 let kes_signer = None;
559
560 let configuration_for_aggregation = MithrilNetworkConfigurationForEpoch::dummy();
561 let configuration_for_next_aggregation = MithrilNetworkConfigurationForEpoch::dummy();
562 let configuration_for_registration = MithrilNetworkConfigurationForEpoch::dummy();
563
564 let network_configuration_service = Arc::new(FakeMithrilNetworkConfigurationProvider::new(
565 configuration_for_aggregation,
566 configuration_for_next_aggregation,
567 configuration_for_registration,
568 ));
569
570 SignerDependencyContainer {
571 stake_store,
572 certificate_handler: aggregator_client,
573 chain_observer,
574 digester,
575 single_signer,
576 ticker_service,
577 protocol_initializer_store,
578 era_checker,
579 era_reader,
580 api_version_provider,
581 signable_builder_service,
582 metrics_service,
583 signed_entity_type_lock,
584 cardano_transactions_preloader,
585 upkeep_service,
586 epoch_service,
587 certifier,
588 kes_signer,
589 network_configuration_service,
590 }
591 }
592
593 async fn init_runner(
594 maybe_services: Option<SignerDependencyContainer>,
595 maybe_config: Option<Configuration>,
596 ) -> SignerRunner {
597 SignerRunner::new(
598 maybe_config.unwrap_or(Configuration::new_sample("1")),
599 maybe_services.unwrap_or(init_services().await),
600 TestLogger::stdout(),
601 )
602 }
603
604 #[tokio::test]
605 async fn test_get_current_time_point() {
606 let mut services = init_services().await;
607 let expected = TimePoint::dummy();
608 let mut ticker_service = MockFakeTimePointProvider::new();
609 ticker_service
610 .expect_get_current_time_point()
611 .once()
612 .returning(move || Ok(TimePoint::dummy()));
613 services.ticker_service = Arc::new(ticker_service);
614 let runner = init_runner(Some(services), None).await;
615
616 assert_eq!(
617 expected,
618 runner
619 .get_current_time_point()
620 .await
621 .expect("Get current time point should not fail.")
622 );
623 }
624
625 #[tokio::test]
626 async fn test_update_stake_distribution() {
627 let services = init_services().await;
628 let stake_store = services.stake_store.clone();
629 let current_epoch = services
630 .chain_observer
631 .get_current_epoch()
632 .await
633 .expect("chain observer should not fail")
634 .expect("the observer should return an epoch");
635 let runner = init_runner(Some(services), None).await;
636 assert!(
637 stake_store
638 .get_stakes(current_epoch)
639 .await
640 .expect("getting stakes from store should not fail")
641 .is_none()
642 );
643
644 runner
645 .update_stake_distribution(current_epoch)
646 .await
647 .expect("update_stake_distribution should not fail.");
648
649 let stake_distribution = stake_store
650 .get_stakes(current_epoch.offset_to_recording_epoch())
651 .await
652 .expect("getting stakes from store should not fail")
653 .expect("there should be stakes for this epoch");
654
655 assert_eq!(2, stake_distribution.len());
656 }
657
658 #[tokio::test]
659 async fn test_register_signer_to_aggregator() {
660 let mut services = init_services().await;
661 let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
662 let certificate_handler = Arc::new(DumbAggregatorClient::default());
663 services.certificate_handler = certificate_handler.clone();
664 let protocol_initializer_store = services.protocol_initializer_store.clone();
665 let current_epoch = services.ticker_service.get_current_epoch().await.unwrap();
666
667 let stakes = services
668 .chain_observer
669 .get_current_stake_distribution()
670 .await
671 .unwrap()
672 .unwrap();
673 services
674 .stake_store
675 .save_stakes(current_epoch.offset_to_recording_epoch(), stakes)
676 .await
677 .unwrap();
678
679 let runner = init_runner(Some(services), None).await;
680
681 let mithril_network_configuration = MithrilNetworkConfiguration {
682 epoch: current_epoch,
683 ..MithrilNetworkConfiguration::dummy()
684 };
685
686 runner
687 .inform_epoch_settings(
688 current_epoch,
689 mithril_network_configuration,
690 fixture.signers(),
691 fixture.signers(),
692 )
693 .await
694 .unwrap();
695
696 runner
697 .register_signer_to_aggregator()
698 .await
699 .expect("registering a signer to the aggregator should not fail");
700
701 let last_registered_signer_first_registration =
702 certificate_handler.get_last_registered_signer().await.unwrap();
703 let maybe_protocol_initializer_first_registration = protocol_initializer_store
704 .get_protocol_initializer(current_epoch.offset_to_recording_epoch())
705 .await
706 .expect("get_protocol_initializer should not fail");
707 assert!(
708 maybe_protocol_initializer_first_registration.is_some(),
709 "A protocol initializer should have been registered at the 'Recording' epoch"
710 );
711
712 runner
713 .register_signer_to_aggregator()
714 .await
715 .expect("registering a signer to the aggregator should not fail");
716
717 let last_registered_signer_second_registration =
718 certificate_handler.get_last_registered_signer().await.unwrap();
719 let maybe_protocol_initializer_second_registration = protocol_initializer_store
720 .get_protocol_initializer(current_epoch.offset_to_recording_epoch())
721 .await
722 .expect("get_protocol_initializer should not fail");
723 assert!(
724 maybe_protocol_initializer_second_registration.is_some(),
725 "A protocol initializer should have been registered at the 'Recording' epoch"
726 );
727 assert_eq!(
728 serde_json::to_string(&last_registered_signer_first_registration).unwrap(),
729 serde_json::to_string(&last_registered_signer_second_registration).unwrap(),
730 "The signer registration should be the same and should have been registered twice"
731 );
732 }
733
734 #[tokio::test]
735 async fn test_update_era_checker() {
736 let services = init_services().await;
737 let ticker_service = services.ticker_service.clone();
738 let era_checker = services.era_checker.clone();
739 let mut time_point = ticker_service.get_current_time_point().await.unwrap();
740
741 assert_eq!(time_point.epoch, era_checker.current_epoch());
742 let runner = init_runner(Some(services), None).await;
743 time_point.epoch += 1;
744 runner.update_era_checker(time_point.epoch).await.unwrap();
745
746 assert_eq!(time_point.epoch, era_checker.current_epoch());
747 }
748
749 #[tokio::test]
750 async fn test_upkeep() {
751 let mut services = init_services().await;
752 let mut upkeep_service_mock = MockUpkeepService::new();
753 upkeep_service_mock
754 .expect_run()
755 .with(eq(Epoch(17)))
756 .returning(|_| Ok(()))
757 .once();
758 services.upkeep_service = Arc::new(upkeep_service_mock);
759
760 let runner = init_runner(Some(services), None).await;
761 runner.upkeep(Epoch(17)).await.expect("upkeep should not fail");
762 }
763
764 #[tokio::test]
765 async fn test_inform_epoch_setting_pass_available_signed_entity_types_to_epoch_service() {
766 let mut services = init_services().await;
767 let certificate_handler = Arc::new(DumbAggregatorClient::default());
768
769 services.certificate_handler = certificate_handler;
770 let runner = init_runner(Some(services), None).await;
771
772 let epoch = Epoch(1);
773 let signers = fake_data::signers(5);
774 let current_signers = signers[1..3].to_vec();
775 let next_signers = signers[2..5].to_vec();
776
777 let mithril_network_configuration = MithrilNetworkConfiguration {
778 epoch,
779 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
780 enabled_signed_entity_types: BTreeSet::from([
781 SignedEntityTypeDiscriminants::MithrilStakeDistribution,
782 SignedEntityTypeDiscriminants::CardanoTransactions,
783 ]),
784 ..Dummy::dummy()
785 },
786 ..Dummy::dummy()
787 };
788
789 runner
790 .inform_epoch_settings(
791 epoch,
792 mithril_network_configuration,
793 current_signers,
794 next_signers,
795 )
796 .await
797 .unwrap();
798
799 let epoch_service = runner.services.epoch_service.read().await;
800 let recorded_allowed_discriminants = epoch_service.allowed_discriminants().unwrap();
801
802 assert_eq!(
803 &BTreeSet::from([
804 SignedEntityTypeDiscriminants::MithrilStakeDistribution,
805 SignedEntityTypeDiscriminants::CardanoTransactions,
806 ]),
807 recorded_allowed_discriminants
808 );
809 }
810}