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