1use anyhow::Error;
2use chrono::Local;
3use slog::{Logger, debug, info};
4use std::{fmt::Display, ops::Deref, sync::Arc, time::Duration};
5use tokio::sync::Mutex;
6
7use mithril_common::{
8 crypto_helper::ProtocolInitializerError,
9 entities::{Epoch, Signer, TimePoint},
10 logging::LoggerExtensions,
11};
12
13use mithril_protocol_config::model::MithrilNetworkConfiguration;
14
15use crate::{MetricsService, entities::BeaconToSign, services::AggregatorClientError};
16
17use super::{Runner, RuntimeError};
18
19#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum SignerState {
22 Init,
24 Unregistered {
27 epoch: Epoch,
29 },
30
31 ReadyToSign {
33 epoch: Epoch,
35 },
36
37 RegisteredNotAbleToSign {
39 epoch: Epoch,
41 },
42}
43
44impl SignerState {
45 pub fn is_init(&self) -> bool {
47 matches!(*self, SignerState::Init)
48 }
49
50 pub fn is_unregistered(&self) -> bool {
52 matches!(*self, SignerState::Unregistered { .. })
53 }
54
55 pub fn is_ready_to_sign(&self) -> bool {
57 matches!(*self, SignerState::ReadyToSign { .. })
58 }
59
60 pub fn is_registered_not_able_to_sign(&self) -> bool {
62 matches!(*self, SignerState::RegisteredNotAbleToSign { .. })
63 }
64}
65
66impl Display for SignerState {
67 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68 match self {
69 Self::Init => write!(f, "Init"),
70 Self::Unregistered { epoch } => write!(f, "Unregistered - {epoch:?}"),
71 Self::RegisteredNotAbleToSign { epoch } => {
72 write!(f, "RegisteredNotAbleToSign - {epoch}")
73 }
74 Self::ReadyToSign { epoch } => {
75 write!(f, "ReadyToSign - {epoch}")
76 }
77 }
78 }
79}
80
81enum EpochStatus {
82 NewEpoch(Epoch),
83 Unchanged(TimePoint),
84}
85
86pub struct StateMachine {
88 state: Mutex<SignerState>,
89 runner: Box<dyn Runner>,
90 interval: Duration,
91 metrics_service: Arc<MetricsService>,
92 logger: Logger,
93}
94
95impl StateMachine {
96 pub fn new(
98 starting_state: SignerState,
99 runner: Box<dyn Runner>,
100 interval: Duration,
101 metrics_service: Arc<MetricsService>,
102 logger: Logger,
103 ) -> Self {
104 Self {
105 state: Mutex::new(starting_state),
106 runner,
107 interval,
108 metrics_service,
109 logger: logger.new_with_component_name::<Self>(),
110 }
111 }
112
113 pub async fn get_state(&self) -> SignerState {
115 self.state.lock().await.to_owned()
116 }
117
118 pub async fn run(&self) -> Result<(), RuntimeError> {
120 info!(self.logger, "Launching State Machine");
121 let mut interval = tokio::time::interval(self.interval);
122
123 loop {
124 interval.tick().await;
125 let approximate_next_cycle_time = Local::now() + self.interval;
128
129 if let Err(e) = self.cycle().await {
130 e.write_to_log(&self.logger);
131 if e.is_critical() {
132 return Err(e);
133 }
134 }
135
136 info!(
137 self.logger, "… Cycle finished";
138 "approximate_next_cycle_time" => %approximate_next_cycle_time.time().format("%H:%M:%S%.3f"),
139 "run_interval_in_ms" => self.interval.as_millis(),
140 );
141 }
142 }
143
144 pub async fn cycle(&self) -> Result<(), RuntimeError> {
146 let mut state = self.state.lock().await;
147 info!(
148 self.logger,
149 "================================================================================"
150 );
151 info!(self.logger, "New cycle: {}", *state);
152
153 self.metrics_service
154 .get_runtime_cycle_total_since_startup_counter()
155 .increment();
156
157 match state.deref() {
158 SignerState::Init => {
159 *state = self.transition_from_init_to_unregistered().await?;
160 }
161 SignerState::Unregistered { epoch } => {
162 if let EpochStatus::NewEpoch(new_epoch) = self.has_epoch_changed(*epoch).await? {
163 info!(
164 self.logger,
165 "→ Epoch has changed, transiting to Unregistered"
166 );
167 *state = self.transition_from_unregistered_to_unregistered(new_epoch).await?;
168 } else if let Some(signer_registrations) = self
169 .runner
170 .get_signer_registrations_from_aggregator()
171 .await
172 .map_err(|e| RuntimeError::KeepState {
173 message: format!("could not retrieve epoch settings at epoch {epoch:?}"),
174 nested_error: Some(e),
175 })?
176 {
177 info!(self.logger, "→ Epoch Signer registrations found");
178 let network_configuration: MithrilNetworkConfiguration =
179 self.runner.get_mithril_network_configuration(*epoch).await.map_err(
180 |e| RuntimeError::KeepState {
181 message: format!(
182 "could not retrieve Mithril network configuration for epoch {epoch:?}"
183 ),
184 nested_error: Some(e),
185 },
186 )?;
187 info!(self.logger, "→ Mithril network configuration found");
188
189 if signer_registrations.epoch >= *epoch {
190 info!(self.logger, "New Epoch found");
191 info!(self.logger, " ⋅ Transiting to Registered");
192 *state = self
193 .transition_from_unregistered_to_one_of_registered_states(
194 signer_registrations.epoch,
195 network_configuration,
196 signer_registrations.current_signers,
197 signer_registrations.next_signers,
198 )
199 .await?;
200 } else {
201 info!(
202 self.logger, " ⋅ Signer settings found, but its epoch is behind the known epoch, waiting…";
203 "network_configuration" => ?network_configuration,
204 "current_singer" => ?signer_registrations.current_signers,
205 "next_signer" => ?signer_registrations.next_signers,
206 "known_epoch" => ?epoch,
207 );
208 }
209 } else {
210 info!(self.logger, "→ No epoch settings found yet, waiting…");
211 }
212 }
213 SignerState::RegisteredNotAbleToSign { epoch } => {
214 if let EpochStatus::NewEpoch(new_epoch) = self.has_epoch_changed(*epoch).await? {
215 info!(
216 self.logger,
217 " → New Epoch detected, transiting to Unregistered"
218 );
219 *state = self
220 .transition_from_registered_not_able_to_sign_to_unregistered(new_epoch)
221 .await?;
222 } else {
223 info!(self.logger, " ⋅ Epoch has NOT changed, waiting…");
224 }
225 }
226
227 SignerState::ReadyToSign { epoch } => match self.has_epoch_changed(*epoch).await? {
228 EpochStatus::NewEpoch(new_epoch) => {
229 info!(
230 self.logger,
231 "→ Epoch has changed, transiting to Unregistered"
232 );
233 *state = self.transition_from_ready_to_sign_to_unregistered(new_epoch).await?;
234 }
235 EpochStatus::Unchanged(timepoint) => {
236 let beacon_to_sign =
237 self.runner.get_beacon_to_sign(timepoint).await.map_err(|e| {
238 RuntimeError::KeepState {
239 message: "could not fetch the beacon to sign".to_string(),
240 nested_error: Some(e),
241 }
242 })?;
243
244 match beacon_to_sign {
245 Some(beacon) => {
246 info!(
247 self.logger, "→ Epoch has NOT changed we can sign this beacon, transiting to ReadyToSign";
248 "beacon_to_sign" => ?beacon,
249 );
250 *state = self
251 .transition_from_ready_to_sign_to_ready_to_sign(*epoch, beacon)
252 .await?;
253 }
254 None => {
255 info!(self.logger, " ⋅ No beacon to sign, waiting…");
256 }
257 }
258 }
259 },
260 };
261
262 self.metrics_service
263 .get_runtime_cycle_success_since_startup_counter()
264 .increment();
265
266 Ok(())
267 }
268
269 async fn has_epoch_changed(&self, epoch: Epoch) -> Result<EpochStatus, RuntimeError> {
271 let current_time_point =
272 self.get_current_time_point("checking if epoch has changed").await?;
273
274 if current_time_point.epoch > epoch {
275 Ok(EpochStatus::NewEpoch(current_time_point.epoch))
276 } else {
277 Ok(EpochStatus::Unchanged(current_time_point))
278 }
279 }
280
281 async fn transition_from_unregistered_to_unregistered(
282 &self,
283 new_epoch: Epoch,
284 ) -> Result<SignerState, RuntimeError> {
285 self.update_era_checker(new_epoch, "unregistered → unregistered")
286 .await?;
287
288 Ok(SignerState::Unregistered { epoch: new_epoch })
289 }
290
291 async fn transition_from_init_to_unregistered(&self) -> Result<SignerState, RuntimeError> {
292 let current_epoch = self.get_current_time_point("init → unregistered").await?.epoch;
293 self.update_era_checker(current_epoch, "init → unregistered").await?;
294
295 Ok(SignerState::Unregistered {
296 epoch: current_epoch,
297 })
298 }
299
300 async fn transition_from_unregistered_to_one_of_registered_states(
302 &self,
303 aggregator_signer_registration_epoch: Epoch,
304 mithril_network_configuration: MithrilNetworkConfiguration,
305 current_signer: Vec<Signer>,
306 next_signer: Vec<Signer>,
307 ) -> Result<SignerState, RuntimeError> {
308 self.metrics_service
309 .get_signer_registration_total_since_startup_counter()
310 .increment();
311
312 let time_point = self.get_current_time_point("unregistered → registered").await?;
313 let epoch = time_point.epoch;
314 self.runner.update_stake_distribution(epoch)
315 .await
316 .map_err(|e| RuntimeError::KeepState {
317 message: format!("Could not update stake distribution in 'unregistered → registered' phase for epoch {epoch:?}."),
318 nested_error: Some(e),
319 })?;
320
321 self.runner
322 .inform_epoch_settings(aggregator_signer_registration_epoch, mithril_network_configuration, current_signer, next_signer)
323 .await
324 .map_err(|e| RuntimeError::KeepState {
325 message: format!(
326 "Could not register epoch information in 'unregistered → registered' phase for epoch {epoch:?}."
327 ),
328 nested_error: Some(e),
329 })?;
330
331 fn handle_registration_result(
332 register_result: Result<(), Error>,
333 epoch: Epoch,
334 ) -> Result<Option<SignerState>, RuntimeError> {
335 if let Err(e) = register_result {
336 if let Some(AggregatorClientError::RegistrationRoundNotYetOpened(_)) =
337 e.downcast_ref::<AggregatorClientError>()
338 {
339 Ok(Some(SignerState::Unregistered { epoch }))
340 } else if e.downcast_ref::<ProtocolInitializerError>().is_some() {
341 Err(RuntimeError::Critical {
342 message: format!(
343 "Could not register to aggregator in 'unregistered → registered' phase for epoch {epoch:?}."
344 ),
345 nested_error: Some(e),
346 })
347 } else {
348 Err(RuntimeError::KeepState {
349 message: format!(
350 "Could not register to aggregator in 'unregistered → registered' phase for epoch {epoch:?}."
351 ),
352 nested_error: Some(e),
353 })
354 }
355 } else {
356 Ok(None)
357 }
358 }
359
360 let register_result = self.runner.register_signer_to_aggregator().await;
361 let next_state_found = handle_registration_result(register_result, epoch)?;
362
363 self.metrics_service
364 .get_signer_registration_success_since_startup_counter()
365 .increment();
366
367 if let Some(state) = next_state_found {
368 return Ok(state);
369 }
370
371 self.metrics_service
372 .get_signer_registration_success_last_epoch_gauge()
373 .record(epoch);
374
375 self.runner.upkeep(epoch).await.map_err(|e| RuntimeError::KeepState {
376 message: "Failed to upkeep signer in 'unregistered → registered' phase".to_string(),
377 nested_error: Some(e),
378 })?;
379
380 match self
381 .runner
382 .can_sign_current_epoch()
383 .await
384 .map_err(|e| RuntimeError::KeepState {
385 message: "Failed to check if signer can sign in the current epoch in 'unregistered → ?' phase".to_string(),
386 nested_error: Some(e),
387 })? {
388 true => Ok(SignerState::ReadyToSign { epoch }),
389 false => Ok(SignerState::RegisteredNotAbleToSign { epoch }),
390 }
391 }
392
393 async fn transition_from_registered_not_able_to_sign_to_unregistered(
394 &self,
395 epoch: Epoch,
396 ) -> Result<SignerState, RuntimeError> {
397 self.update_era_checker(epoch, "registered not able to sign → unregistered")
398 .await?;
399
400 Ok(SignerState::Unregistered { epoch })
401 }
402
403 async fn transition_from_ready_to_sign_to_unregistered(
404 &self,
405 epoch: Epoch,
406 ) -> Result<SignerState, RuntimeError> {
407 self.update_era_checker(epoch, "ready to sign → unregistered").await?;
408
409 Ok(SignerState::Unregistered { epoch })
410 }
411
412 async fn transition_from_ready_to_sign_to_ready_to_sign(
414 &self,
415 current_epoch: Epoch,
416 beacon_to_sign: BeaconToSign,
417 ) -> Result<SignerState, RuntimeError> {
418 let (retrieval_epoch, next_retrieval_epoch) = (
419 current_epoch.offset_to_signer_retrieval_epoch()?,
420 current_epoch.offset_to_next_signer_retrieval_epoch(),
421 );
422
423 debug!(
424 self.logger, ">> transition_from_ready_to_sign_to_ready_to_sign";
425 "current_epoch" => ?current_epoch,
426 "retrieval_epoch" => ?retrieval_epoch,
427 "next_retrieval_epoch" => ?next_retrieval_epoch,
428 );
429
430 self.metrics_service
431 .get_signature_registration_total_since_startup_counter()
432 .increment();
433
434 let message = self
435 .runner
436 .compute_message(&beacon_to_sign.signed_entity_type)
437 .await
438 .map_err(|e| RuntimeError::KeepState {
439 message: format!("Could not compute message during 'ready to sign → ready to sign' phase (current epoch {current_epoch:?})"),
440 nested_error: Some(e)
441 })?;
442
443 self.runner.compute_publish_single_signature(&beacon_to_sign, &message)
444 .await
445 .map_err(|e| RuntimeError::KeepState {
446 message: format!("Could not compute and publish single signature during 'ready to sign → ready to sign' phase (current epoch {current_epoch:?})"),
447 nested_error: Some(e)
448 })?;
449
450 self.metrics_service
451 .get_signature_registration_success_since_startup_counter()
452 .increment();
453 self.metrics_service
454 .get_signature_registration_success_last_epoch_gauge()
455 .record(current_epoch);
456
457 Ok(SignerState::ReadyToSign {
458 epoch: current_epoch,
459 })
460 }
461
462 async fn get_current_time_point(&self, context: &str) -> Result<TimePoint, RuntimeError> {
463 let current_time_point =
464 self.runner
465 .get_current_time_point()
466 .await
467 .map_err(|e| RuntimeError::KeepState {
468 message: format!(
469 "Could not retrieve current time point in context '{context}'."
470 ),
471 nested_error: Some(e),
472 })?;
473
474 Ok(current_time_point)
475 }
476
477 async fn update_era_checker(&self, epoch: Epoch, context: &str) -> Result<(), RuntimeError> {
478 self.runner
479 .update_era_checker(epoch)
480 .await
481 .map_err(|e| RuntimeError::Critical {
482 message: format!(
483 "Could not update Era checker with context '{context}' for epoch {epoch:?}"
484 ),
485 nested_error: Some(e),
486 })
487 }
488}
489
490#[cfg(test)]
491mod tests {
492 use anyhow::anyhow;
493 use chrono::DateTime;
494
495 use mithril_common::entities::{ChainPoint, Epoch, ProtocolMessage, SignedEntityType};
496 use mithril_common::test::double::Dummy;
497
498 use crate::SignerEpochSettings;
499 use crate::runtime::runner::MockSignerRunner;
500 use crate::services::AggregatorClientError;
501 use crate::test_tools::TestLogger;
502
503 use super::*;
504
505 fn init_state_machine(init_state: SignerState, runner: MockSignerRunner) -> StateMachine {
506 let logger = TestLogger::stdout();
507 let metrics_service = Arc::new(MetricsService::new(logger.clone()).unwrap());
508 StateMachine {
509 state: init_state.into(),
510 runner: Box::new(runner),
511 interval: Duration::from_millis(100),
512 metrics_service,
513 logger,
514 }
515 }
516
517 #[tokio::test]
518 async fn unregistered_epoch_settings_not_found() {
519 let mut runner = MockSignerRunner::new();
520 runner
521 .expect_get_signer_registrations_from_aggregator()
522 .once()
523 .returning(|| Ok(None));
524 runner
525 .expect_get_current_time_point()
526 .once()
527 .returning(|| Ok(TimePoint::dummy()));
528 let state_machine = init_state_machine(
529 SignerState::Unregistered {
530 epoch: TimePoint::dummy().epoch,
531 },
532 runner,
533 );
534 state_machine
535 .cycle()
536 .await
537 .expect("Cycling the state machine should not fail");
538
539 assert_eq!(
540 SignerState::Unregistered {
541 epoch: TimePoint::dummy().epoch
542 },
543 state_machine.get_state().await
544 );
545 }
546
547 #[tokio::test]
548 async fn unregistered_epoch_settings_behind_known_epoch() {
549 let mut runner = MockSignerRunner::new();
550 let epoch_settings = SignerEpochSettings {
551 epoch: Epoch(3),
552 current_signers: vec![],
553 next_signers: vec![],
554 };
555 let known_epoch = Epoch(4);
556 runner
557 .expect_get_signer_registrations_from_aggregator()
558 .once()
559 .returning(move || Ok(Some(epoch_settings.to_owned())));
560 runner
561 .expect_get_mithril_network_configuration()
562 .once()
563 .returning(|_| {
564 Ok(MithrilNetworkConfiguration {
565 epoch: Epoch(999),
566 configuration_for_aggregation: Dummy::dummy(),
567 configuration_for_next_aggregation: Dummy::dummy(),
568 configuration_for_registration: Dummy::dummy(),
569 })
570 });
571 runner.expect_get_current_time_point().once().returning(|| {
572 Ok(TimePoint {
573 epoch: Epoch(4),
574 ..TimePoint::dummy()
575 })
576 });
577 let state_machine =
578 init_state_machine(SignerState::Unregistered { epoch: known_epoch }, runner);
579 state_machine
580 .cycle()
581 .await
582 .expect("Cycling the state machine should not fail");
583
584 assert_eq!(
585 SignerState::Unregistered { epoch: known_epoch },
586 state_machine.get_state().await
587 );
588 }
589
590 #[tokio::test]
591 async fn unregistered_to_registered_not_able_to_sign() {
592 let mut runner = MockSignerRunner::new();
593 runner.expect_upkeep().returning(|_| Ok(())).once();
594 runner
595 .expect_get_signer_registrations_from_aggregator()
596 .once()
597 .returning(|| Ok(Some(SignerEpochSettings::dummy())));
598
599 runner
600 .expect_get_mithril_network_configuration()
601 .once()
602 .returning(|_| Ok(MithrilNetworkConfiguration::dummy()));
603
604 runner
605 .expect_inform_epoch_settings()
606 .once()
607 .returning(|_, _, _, _| Ok(()));
608
609 runner
610 .expect_get_current_time_point()
611 .times(2)
612 .returning(|| Ok(TimePoint::dummy()));
613 runner.expect_update_stake_distribution().once().returning(|_| Ok(()));
614 runner
615 .expect_register_signer_to_aggregator()
616 .once()
617 .returning(|| Ok(()));
618
619 runner.expect_can_sign_current_epoch().once().returning(|| Ok(false));
620
621 let state_machine = init_state_machine(
622 SignerState::Unregistered {
623 epoch: TimePoint::dummy().epoch,
624 },
625 runner,
626 );
627
628 state_machine
629 .cycle()
630 .await
631 .expect("Cycling the state machine should not fail");
632
633 if let SignerState::RegisteredNotAbleToSign { epoch: _ } = state_machine.get_state().await {
634 } else {
635 panic!(
636 "state machine did not return a RegisteredNotAbleToSign state but {:?}",
637 state_machine.get_state().await
638 );
639 }
640 }
641
642 #[tokio::test]
643 async fn unregistered_to_ready_to_sign() {
644 let mut runner = MockSignerRunner::new();
645 runner.expect_upkeep().returning(|_| Ok(())).once();
646 runner
647 .expect_get_signer_registrations_from_aggregator()
648 .once()
649 .returning(|| Ok(Some(SignerEpochSettings::dummy())));
650
651 runner
652 .expect_get_mithril_network_configuration()
653 .once()
654 .returning(|_| Ok(MithrilNetworkConfiguration::dummy()));
655
656 runner
657 .expect_inform_epoch_settings()
658 .once()
659 .returning(|_, _, _, _| Ok(()));
660
661 runner
662 .expect_get_current_time_point()
663 .times(2)
664 .returning(|| Ok(TimePoint::dummy()));
665 runner.expect_update_stake_distribution().once().returning(|_| Ok(()));
666 runner
667 .expect_register_signer_to_aggregator()
668 .once()
669 .returning(|| Ok(()));
670
671 runner.expect_can_sign_current_epoch().once().returning(|| Ok(true));
672
673 let state_machine = init_state_machine(
674 SignerState::Unregistered {
675 epoch: TimePoint::dummy().epoch,
676 },
677 runner,
678 );
679
680 state_machine
681 .cycle()
682 .await
683 .expect("Cycling the state machine should not fail");
684
685 assert_eq!(
686 SignerState::ReadyToSign {
687 epoch: TimePoint::dummy().epoch,
688 },
689 state_machine.get_state().await
690 );
691
692 let metrics_service = state_machine.metrics_service;
693 let success_since_startup =
694 metrics_service.get_runtime_cycle_success_since_startup_counter();
695 assert_eq!(1, success_since_startup.get());
696 }
697
698 #[tokio::test]
699 async fn unregistered_to_ready_to_sign_counter() {
700 let mut runner = MockSignerRunner::new();
701
702 runner
703 .expect_get_signer_registrations_from_aggregator()
704 .once()
705 .returning(|| Ok(Some(SignerEpochSettings::dummy())));
706
707 runner
708 .expect_get_mithril_network_configuration()
709 .once()
710 .returning(|_| Ok(MithrilNetworkConfiguration::dummy()));
711
712 runner
713 .expect_inform_epoch_settings()
714 .once()
715 .returning(|_, _, _, _| Ok(()));
716
717 runner
718 .expect_get_current_time_point()
719 .times(2)
720 .returning(|| Ok(TimePoint::dummy()));
721 runner.expect_update_stake_distribution().once().returning(|_| Ok(()));
722 runner.expect_register_signer_to_aggregator().once().returning(|| {
723 Err(AggregatorClientError::RegistrationRoundNotYetOpened(
724 anyhow!("Not yet opened"),
725 ))?
726 });
727
728 runner.expect_upkeep().never();
729 runner.expect_can_sign_current_epoch().never();
730
731 let state_machine = init_state_machine(
732 SignerState::Unregistered {
733 epoch: TimePoint::dummy().epoch,
734 },
735 runner,
736 );
737
738 state_machine
739 .cycle()
740 .await
741 .expect("Cycling the state machine should not fail");
742
743 assert_eq!(
744 SignerState::Unregistered {
745 epoch: TimePoint::dummy().epoch,
746 },
747 state_machine.get_state().await
748 );
749
750 let metrics_service = state_machine.metrics_service;
751 assert_eq!(
752 1,
753 metrics_service
754 .get_signer_registration_success_since_startup_counter()
755 .get()
756 );
757
758 assert_eq!(
759 0 as f64,
760 metrics_service
761 .get_signer_registration_success_last_epoch_gauge()
762 .get()
763 );
764
765 assert_eq!(
766 1,
767 metrics_service.get_runtime_cycle_total_since_startup_counter().get()
768 );
769 }
770
771 #[tokio::test]
772 async fn registered_not_able_to_sign_to_unregistered() {
773 let mut runner = MockSignerRunner::new();
774 runner
775 .expect_get_current_time_point()
776 .once()
777 .returning(|| Ok(TimePoint::new(10, 100, ChainPoint::dummy())));
778 runner
779 .expect_update_era_checker()
780 .once()
781 .returning(|_e: Epoch| Ok(()));
782
783 let state_machine = init_state_machine(
784 SignerState::RegisteredNotAbleToSign { epoch: Epoch(0) },
785 runner,
786 );
787
788 state_machine
789 .cycle()
790 .await
791 .expect("Cycling the state machine should not fail");
792 assert_eq!(
793 SignerState::Unregistered { epoch: Epoch(10) },
794 state_machine.get_state().await
795 );
796 }
797
798 #[tokio::test]
799 async fn registered_not_able_to_sign_to_registered_not_able_to_sign() {
800 let mut runner = MockSignerRunner::new();
801 runner
802 .expect_get_current_time_point()
803 .once()
804 .returning(|| Ok(TimePoint::new(10, 100, ChainPoint::dummy())));
805
806 let state_machine = init_state_machine(
807 SignerState::RegisteredNotAbleToSign { epoch: Epoch(10) },
808 runner,
809 );
810
811 state_machine
812 .cycle()
813 .await
814 .expect("Cycling the state machine should not fail");
815 assert_eq!(
816 SignerState::RegisteredNotAbleToSign { epoch: Epoch(10) },
817 state_machine.get_state().await
818 );
819 }
820
821 #[tokio::test]
822 async fn ready_to_sign_to_unregistered() {
823 let mut runner = MockSignerRunner::new();
824 runner
825 .expect_get_current_time_point()
826 .once()
827 .returning(|| Ok(TimePoint::new(10, 100, ChainPoint::dummy())));
828 runner
829 .expect_update_era_checker()
830 .once()
831 .returning(|_e: Epoch| Ok(()));
832
833 let state_machine =
834 init_state_machine(SignerState::ReadyToSign { epoch: Epoch(0) }, runner);
835
836 state_machine
837 .cycle()
838 .await
839 .expect("Cycling the state machine should not fail");
840 assert_eq!(
841 SignerState::Unregistered { epoch: Epoch(10) },
842 state_machine.get_state().await
843 );
844 }
845
846 #[tokio::test]
847 async fn ready_to_sign_to_ready_to_sign_when_there_is_a_beacon_to_sign() {
848 let time_point = TimePoint::dummy();
849 let beacon_to_sign = BeaconToSign {
850 epoch: time_point.epoch,
851 signed_entity_type: SignedEntityType::MithrilStakeDistribution(time_point.epoch),
852 initiated_at: DateTime::default(),
853 };
854 let beacon_to_sign_clone = beacon_to_sign.clone();
855 let current_epoch = time_point.epoch;
856
857 let mut runner = MockSignerRunner::new();
858 runner
859 .expect_get_current_time_point()
860 .once()
861 .returning(move || Ok(time_point.to_owned()));
862 runner
863 .expect_get_beacon_to_sign()
864 .once()
865 .returning(move |_| Ok(Some(beacon_to_sign_clone.clone())));
866 runner
867 .expect_compute_message()
868 .once()
869 .returning(|_| Ok(ProtocolMessage::new()));
870 runner
871 .expect_compute_publish_single_signature()
872 .once()
873 .returning(|_, _| Ok(()));
874
875 let state_machine = init_state_machine(
876 SignerState::ReadyToSign {
877 epoch: current_epoch,
878 },
879 runner,
880 );
881 state_machine
882 .cycle()
883 .await
884 .expect("Cycling the state machine should not fail");
885
886 assert_eq!(
887 SignerState::ReadyToSign {
888 epoch: current_epoch
889 },
890 state_machine.get_state().await,
891 "state machine did not return a ReadyToSign state but {:?}",
892 state_machine.get_state().await
893 );
894 }
895
896 #[tokio::test]
897 async fn ready_to_sign_to_ready_to_sign_when_there_no_beacon_to_sign() {
898 let time_point = TimePoint::dummy();
899 let current_epoch = time_point.epoch;
900
901 let mut runner = MockSignerRunner::new();
902 runner
903 .expect_get_current_time_point()
904 .once()
905 .returning(move || Ok(time_point.to_owned()));
906 runner.expect_get_beacon_to_sign().once().returning(move |_| Ok(None));
907
908 let state_machine = init_state_machine(
909 SignerState::ReadyToSign {
910 epoch: current_epoch,
911 },
912 runner,
913 );
914 state_machine
915 .cycle()
916 .await
917 .expect("Cycling the state machine should not fail");
918
919 assert_eq!(
920 SignerState::ReadyToSign {
921 epoch: current_epoch
922 },
923 state_machine.get_state().await,
924 "state machine did not return a ReadyToSign state but {:?}",
925 state_machine.get_state().await
926 );
927 }
928}