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 std::collections::BTreeSet;
371 use std::{path::Path, sync::Arc};
372
373 use mockall::mock;
374 use mockall::predicate::eq;
375 use tokio::sync::RwLock;
376
377 use mithril_cardano_node_chain::chain_importer::CardanoChainDataImporter;
378 use mithril_cardano_node_chain::test::double::{
379 DumbBlockScanner, FakeChainObserver, InMemoryChainDataStore,
380 };
381 use mithril_cardano_node_internal_database::{
382 signable_builder::{
383 CardanoDatabaseSignableBuilder, CardanoImmutableFilesFullSignableBuilder,
384 },
385 test::double::{DumbImmutableDigester, DumbImmutableFileObserver},
386 };
387 use mithril_common::{
388 api_version::APIVersionProvider,
389 crypto_helper::{MKMap, MKMapNode, MKTreeNode, MKTreeStoreInMemory, MKTreeStorer},
390 entities::{BlockNumber, BlockRange, Epoch, SignedEntityTypeDiscriminants},
391 signable_builder::{
392 BlockRangeRootRetriever, CardanoBlocksTransactionsSignableBuilder,
393 CardanoStakeDistributionSignableBuilder, CardanoTransactionsSignableBuilder,
394 LegacyBlockRangeRootRetriever, MithrilSignableBuilderService,
395 MithrilStakeDistributionSignableBuilder, SignableBuilderServiceDependencies,
396 },
397 test::{
398 builder::MithrilFixtureBuilder,
399 double::{Dummy, fake_data},
400 },
401 };
402 use mithril_era::{EraChecker, EraReader, adapters::EraReaderBootstrapAdapter};
403 use mithril_protocol_config::model::MithrilNetworkConfigurationForEpoch;
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 MithrilEpochService, MithrilSingleSigner, MockUpkeepService, SignaturePublisherNoop,
418 SignerCertifierService, SignerChainDataImporter, SignerSignableSeedBuilder,
419 SignerSignedEntityConfigProvider,
420 };
421 use crate::test::TestLogger;
422 use crate::test::double::{DumbSignersRegistrationRetriever, SpySignerRegistrationPublisher};
423
424 use super::*;
425
426 const DIGESTER_RESULT: &str = "a digest";
427
428 mock! {
429 pub FakeTimePointProvider { }
430
431 #[async_trait]
432 impl TickerService for FakeTimePointProvider {
433 async fn get_current_time_point(&self) -> StdResult<TimePoint>;
434 }
435 }
436
437 mock! {
438 pub BlockRangeRootRetriever<S: MKTreeStorer> { }
439
440 #[async_trait]
441 impl<S: MKTreeStorer> BlockRangeRootRetriever<S> for BlockRangeRootRetriever<S> {
442 async fn retrieve_block_range_roots<'a>(
443 &'a self,
444 up_to_beacon: BlockNumber,
445 ) -> StdResult<Box<dyn Iterator<Item = (BlockRange, MKTreeNode)> + 'a>>;
446
447 async fn compute_merkle_map_from_block_range_roots(
448 &self,
449 up_to_beacon: BlockNumber,
450 ) -> StdResult<MKMap<BlockRange, MKMapNode<BlockRange,S>, S>>;
451 }
452 }
453
454 mock! {
455 pub LegacyBlockRangeRootRetriever<S: MKTreeStorer> { }
456
457 #[async_trait]
458 impl<S: MKTreeStorer> LegacyBlockRangeRootRetriever<S> for LegacyBlockRangeRootRetriever<S> {
459 async fn retrieve_block_range_roots<'a>(
460 &'a self,
461 up_to_beacon: BlockNumber,
462 ) -> StdResult<Box<dyn Iterator<Item = (BlockRange, MKTreeNode)> + 'a>>;
463
464 async fn compute_merkle_map_from_block_range_roots(
465 &self,
466 up_to_beacon: BlockNumber,
467 ) -> StdResult<MKMap<BlockRange, MKMapNode<BlockRange,S>, S>>;
468 }
469 }
470
471 async fn init_services() -> SignerDependencyContainer {
472 let logger = TestLogger::stdout();
473 let sqlite_connection = Arc::new(main_db_connection().unwrap());
474 let stake_distribution_signers = fake_data::signers_with_stakes(2);
475 let party_id = stake_distribution_signers[1].party_id.clone();
476 let fake_observer = FakeChainObserver::default();
477 fake_observer.set_signers(stake_distribution_signers).await;
478 let chain_observer = Arc::new(fake_observer);
479 let ticker_service = Arc::new(MithrilTickerService::new(
480 chain_observer.clone(),
481 Arc::new(DumbImmutableFileObserver::default()),
482 ));
483 let era_reader = Arc::new(EraReader::new(Arc::new(EraReaderBootstrapAdapter)));
484 let era_epoch_token = era_reader
485 .read_era_epoch_token(ticker_service.get_current_epoch().await.unwrap())
486 .await
487 .unwrap();
488 let era_checker = Arc::new(EraChecker::new(
489 era_epoch_token.get_current_supported_era().unwrap(),
490 era_epoch_token.get_current_epoch(),
491 ));
492
493 let api_version_provider = Arc::new(APIVersionProvider::new(era_checker.clone()));
494 let digester = Arc::new(DumbImmutableDigester::default().with_digest(DIGESTER_RESULT));
495 let cardano_immutable_signable_builder =
496 Arc::new(CardanoImmutableFilesFullSignableBuilder::new(
497 digester.clone(),
498 Path::new(""),
499 logger.clone(),
500 ));
501 let mithril_stake_distribution_signable_builder =
502 Arc::new(MithrilStakeDistributionSignableBuilder::default());
503 let transaction_parser = Arc::new(DumbBlockScanner::new());
504 let transaction_store = Arc::new(InMemoryChainDataStore::default());
505 let transactions_importer = Arc::new(SignerChainDataImporter::new(Arc::new(
506 CardanoChainDataImporter::new(
507 transaction_parser.clone(),
508 transaction_store.clone(),
509 logger.clone(),
510 ),
511 )));
512 let legacy_block_range_root_retriever =
513 Arc::new(MockLegacyBlockRangeRootRetriever::<MKTreeStoreInMemory>::new());
514 let cardano_transactions_builder = Arc::new(CardanoTransactionsSignableBuilder::new(
515 transactions_importer.clone(),
516 legacy_block_range_root_retriever,
517 ));
518 let block_range_root_retriever =
519 Arc::new(MockBlockRangeRootRetriever::<MKTreeStoreInMemory>::new());
520 let cardano_blocks_transactions_builder =
521 Arc::new(CardanoBlocksTransactionsSignableBuilder::new(
522 transactions_importer.clone(),
523 block_range_root_retriever,
524 ));
525 let stake_store = Arc::new(StakePoolStore::new(sqlite_connection.clone(), None));
526 let cardano_stake_distribution_builder = Arc::new(
527 CardanoStakeDistributionSignableBuilder::new(stake_store.clone()),
528 );
529 let cardano_database_signable_builder = Arc::new(CardanoDatabaseSignableBuilder::new(
530 digester.clone(),
531 Path::new(""),
532 logger.clone(),
533 ));
534 let protocol_initializer_store = Arc::new(ProtocolInitializerRepository::new(
535 sqlite_connection.clone(),
536 None,
537 ));
538 let epoch_service = Arc::new(RwLock::new(MithrilEpochService::new(
539 stake_store.clone(),
540 protocol_initializer_store.clone(),
541 logger.clone(),
542 )));
543 let single_signer = Arc::new(MithrilSingleSigner::new(
544 party_id,
545 epoch_service.clone(),
546 logger.clone(),
547 ));
548 let signable_seed_builder_service = Arc::new(SignerSignableSeedBuilder::new(
549 epoch_service.clone(),
550 protocol_initializer_store.clone(),
551 ));
552 let signable_builders_dependencies = SignableBuilderServiceDependencies::new(
553 mithril_stake_distribution_signable_builder,
554 cardano_immutable_signable_builder,
555 cardano_transactions_builder,
556 cardano_blocks_transactions_builder,
557 cardano_stake_distribution_builder,
558 cardano_database_signable_builder,
559 );
560 let signable_builder_service = Arc::new(MithrilSignableBuilderService::new(
561 signable_seed_builder_service,
562 signable_builders_dependencies,
563 logger.clone(),
564 ));
565 let metrics_service = Arc::new(MetricsService::new(logger.clone()).unwrap());
566 let signed_entity_type_lock = Arc::new(SignedEntityTypeLock::default());
567 let security_parameter = BlockNumber(0);
568 let cardano_transactions_preloader = Arc::new(CardanoTransactionsPreloader::new(
569 signed_entity_type_lock.clone(),
570 transactions_importer.clone(),
571 security_parameter,
572 chain_observer.clone(),
573 logger.clone(),
574 Arc::new(CardanoTransactionsPreloaderActivation::new(true)),
575 ));
576 let upkeep_service = Arc::new(MockUpkeepService::new());
577 let certifier = Arc::new(SignerCertifierService::new(
578 Arc::new(SignedBeaconRepository::new(sqlite_connection.clone(), None)),
579 Arc::new(SignerSignedEntityConfigProvider::new(epoch_service.clone())),
580 signed_entity_type_lock.clone(),
581 single_signer.clone(),
582 Arc::new(SignaturePublisherNoop),
583 logger.clone(),
584 ));
585 let kes_signer = None;
586
587 let configuration_for_aggregation = MithrilNetworkConfigurationForEpoch::dummy();
588 let configuration_for_next_aggregation = MithrilNetworkConfigurationForEpoch::dummy();
589 let configuration_for_registration = MithrilNetworkConfigurationForEpoch::dummy();
590
591 let network_configuration_service = Arc::new(FakeMithrilNetworkConfigurationProvider::new(
592 configuration_for_aggregation,
593 configuration_for_next_aggregation,
594 configuration_for_registration,
595 ));
596
597 SignerDependencyContainer {
598 stake_store,
599 chain_observer,
600 digester,
601 single_signer,
602 ticker_service,
603 protocol_initializer_store,
604 era_checker,
605 era_reader,
606 api_version_provider,
607 signable_builder_service,
608 metrics_service,
609 signed_entity_type_lock,
610 cardano_transactions_preloader,
611 upkeep_service,
612 epoch_service,
613 certifier,
614 signer_registration_publisher: Arc::new(SpySignerRegistrationPublisher::default()),
615 signers_registration_retriever: Arc::new(DumbSignersRegistrationRetriever::default()),
616 kes_signer,
617 network_configuration_service,
618 }
619 }
620
621 async fn init_runner(
622 maybe_services: Option<SignerDependencyContainer>,
623 maybe_config: Option<Configuration>,
624 ) -> SignerRunner {
625 SignerRunner::new(
626 maybe_config.unwrap_or(Configuration::new_sample("1")),
627 maybe_services.unwrap_or(init_services().await),
628 TestLogger::stdout(),
629 )
630 }
631
632 #[tokio::test]
633 async fn test_get_current_time_point() {
634 let mut services = init_services().await;
635 let expected = TimePoint::dummy();
636 let mut ticker_service = MockFakeTimePointProvider::new();
637 ticker_service
638 .expect_get_current_time_point()
639 .once()
640 .returning(move || Ok(TimePoint::dummy()));
641 services.ticker_service = Arc::new(ticker_service);
642 let runner = init_runner(Some(services), None).await;
643
644 assert_eq!(
645 expected,
646 runner
647 .get_current_time_point()
648 .await
649 .expect("Get current time point should not fail.")
650 );
651 }
652
653 #[tokio::test]
654 async fn test_update_stake_distribution() {
655 let services = init_services().await;
656 let stake_store = services.stake_store.clone();
657 let current_epoch = services
658 .chain_observer
659 .get_current_epoch()
660 .await
661 .expect("chain observer should not fail")
662 .expect("the observer should return an epoch");
663 let runner = init_runner(Some(services), None).await;
664 assert!(
665 stake_store
666 .get_stakes(current_epoch)
667 .await
668 .expect("getting stakes from store should not fail")
669 .is_none()
670 );
671
672 runner
673 .update_stake_distribution(current_epoch)
674 .await
675 .expect("update_stake_distribution should not fail.");
676
677 let stake_distribution = stake_store
678 .get_stakes(current_epoch.offset_to_recording_epoch())
679 .await
680 .expect("getting stakes from store should not fail")
681 .expect("there should be stakes for this epoch");
682
683 assert_eq!(2, stake_distribution.len());
684 }
685
686 #[tokio::test]
687 async fn test_register_signer_to_aggregator() {
688 let mut services = init_services().await;
689 let fixture = MithrilFixtureBuilder::default().with_signers(5).build();
690 let registration_publisher_spy = Arc::new(SpySignerRegistrationPublisher::default());
691 services.signer_registration_publisher = registration_publisher_spy.clone();
692 let protocol_initializer_store = services.protocol_initializer_store.clone();
693 let current_epoch = services.ticker_service.get_current_epoch().await.unwrap();
694
695 let stakes = services
696 .chain_observer
697 .get_current_stake_distribution()
698 .await
699 .unwrap()
700 .unwrap();
701 services
702 .stake_store
703 .save_stakes(current_epoch.offset_to_recording_epoch(), stakes)
704 .await
705 .unwrap();
706
707 let runner = init_runner(Some(services), None).await;
708
709 let mithril_network_configuration = MithrilNetworkConfiguration {
710 epoch: current_epoch,
711 ..MithrilNetworkConfiguration::dummy()
712 };
713
714 runner
715 .inform_epoch_settings(
716 current_epoch,
717 mithril_network_configuration,
718 fixture.signers(),
719 fixture.signers(),
720 )
721 .await
722 .unwrap();
723
724 runner
725 .register_signer_to_aggregator()
726 .await
727 .expect("registering a signer to the aggregator should not fail");
728
729 let last_registered_signer_first_registration =
730 registration_publisher_spy.get_last_registered_signer().await.unwrap();
731 let maybe_protocol_initializer_first_registration = protocol_initializer_store
732 .get_protocol_initializer(current_epoch.offset_to_recording_epoch())
733 .await
734 .expect("get_protocol_initializer should not fail");
735 assert!(
736 maybe_protocol_initializer_first_registration.is_some(),
737 "A protocol initializer should have been registered at the 'Recording' epoch"
738 );
739
740 let total_registered_signers =
741 registration_publisher_spy.get_total_registered_signers().await;
742 assert_eq!(1, total_registered_signers);
743
744 runner
745 .register_signer_to_aggregator()
746 .await
747 .expect("registering a signer to the aggregator should not fail");
748
749 let last_registered_signer_second_registration =
750 registration_publisher_spy.get_last_registered_signer().await.unwrap();
751 let maybe_protocol_initializer_second_registration = protocol_initializer_store
752 .get_protocol_initializer(current_epoch.offset_to_recording_epoch())
753 .await
754 .expect("get_protocol_initializer should not fail");
755 assert!(
756 maybe_protocol_initializer_second_registration.is_some(),
757 "A protocol initializer should have been registered at the 'Recording' epoch"
758 );
759 assert_eq!(
760 serde_json::to_string(&last_registered_signer_first_registration).unwrap(),
761 serde_json::to_string(&last_registered_signer_second_registration).unwrap(),
762 "The signer registration should be the same and should have been registered twice"
763 );
764
765 let total_registered_signers =
766 registration_publisher_spy.get_total_registered_signers().await;
767 assert_eq!(1, total_registered_signers);
768 }
769
770 #[tokio::test]
771 async fn test_update_era_checker() {
772 let services = init_services().await;
773 let ticker_service = services.ticker_service.clone();
774 let era_checker = services.era_checker.clone();
775 let mut time_point = ticker_service.get_current_time_point().await.unwrap();
776
777 assert_eq!(time_point.epoch, era_checker.current_epoch());
778 let runner = init_runner(Some(services), None).await;
779 time_point.epoch += 1;
780 runner.update_era_checker(time_point.epoch).await.unwrap();
781
782 assert_eq!(time_point.epoch, era_checker.current_epoch());
783 }
784
785 #[tokio::test]
786 async fn test_upkeep() {
787 let mut services = init_services().await;
788 let mut upkeep_service_mock = MockUpkeepService::new();
789 upkeep_service_mock
790 .expect_run()
791 .with(eq(Epoch(17)))
792 .returning(|_| Ok(()))
793 .once();
794 services.upkeep_service = Arc::new(upkeep_service_mock);
795
796 let runner = init_runner(Some(services), None).await;
797 runner.upkeep(Epoch(17)).await.expect("upkeep should not fail");
798 }
799
800 #[tokio::test]
801 async fn test_inform_epoch_setting_pass_available_signed_entity_types_to_epoch_service() {
802 let services = init_services().await;
803 let runner = init_runner(Some(services), None).await;
804
805 let epoch = Epoch(1);
806 let signers = fake_data::signers(5);
807 let current_signers = signers[1..3].to_vec();
808 let next_signers = signers[2..5].to_vec();
809
810 let mithril_network_configuration = MithrilNetworkConfiguration {
811 epoch,
812 configuration_for_aggregation: MithrilNetworkConfigurationForEpoch {
813 enabled_signed_entity_types: BTreeSet::from([
814 SignedEntityTypeDiscriminants::MithrilStakeDistribution,
815 SignedEntityTypeDiscriminants::CardanoTransactions,
816 ]),
817 ..Dummy::dummy()
818 },
819 ..Dummy::dummy()
820 };
821
822 runner
823 .inform_epoch_settings(
824 epoch,
825 mithril_network_configuration,
826 current_signers,
827 next_signers,
828 )
829 .await
830 .unwrap();
831
832 let epoch_service = runner.services.epoch_service.read().await;
833 let recorded_allowed_discriminants = epoch_service.allowed_discriminants().unwrap();
834
835 assert_eq!(
836 &BTreeSet::from([
837 SignedEntityTypeDiscriminants::MithrilStakeDistribution,
838 SignedEntityTypeDiscriminants::CardanoTransactions,
839 ]),
840 recorded_allowed_discriminants
841 );
842 }
843}