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