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