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_aggregator_client::AggregatorHttpClientError;
14use mithril_protocol_config::model::MithrilNetworkConfiguration;
15
16use crate::{MetricsService, entities::BeaconToSign};
17
18use super::{Runner, RuntimeError};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum SignerState {
23 Init,
25 Unregistered {
28 epoch: Epoch,
30 },
31
32 ReadyToSign {
34 epoch: Epoch,
36 },
37
38 RegisteredNotAbleToSign {
40 epoch: Epoch,
42 },
43}
44
45impl SignerState {
46 pub fn is_init(&self) -> bool {
48 matches!(*self, SignerState::Init)
49 }
50
51 pub fn is_unregistered(&self) -> bool {
53 matches!(*self, SignerState::Unregistered { .. })
54 }
55
56 pub fn is_ready_to_sign(&self) -> bool {
58 matches!(*self, SignerState::ReadyToSign { .. })
59 }
60
61 pub fn is_registered_not_able_to_sign(&self) -> bool {
63 matches!(*self, SignerState::RegisteredNotAbleToSign { .. })
64 }
65}
66
67impl Display for SignerState {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 match self {
70 Self::Init => write!(f, "Init"),
71 Self::Unregistered { epoch } => write!(f, "Unregistered - {epoch:?}"),
72 Self::RegisteredNotAbleToSign { epoch } => {
73 write!(f, "RegisteredNotAbleToSign - {epoch}")
74 }
75 Self::ReadyToSign { epoch } => {
76 write!(f, "ReadyToSign - {epoch}")
77 }
78 }
79 }
80}
81
82enum EpochStatus {
83 NewEpoch(Epoch),
84 Unchanged(TimePoint),
85}
86
87pub struct StateMachine {
89 state: Mutex<SignerState>,
90 runner: Box<dyn Runner>,
91 interval: Duration,
92 metrics_service: Arc<MetricsService>,
93 logger: Logger,
94}
95
96impl StateMachine {
97 pub fn new(
99 starting_state: SignerState,
100 runner: Box<dyn Runner>,
101 interval: Duration,
102 metrics_service: Arc<MetricsService>,
103 logger: Logger,
104 ) -> Self {
105 Self {
106 state: Mutex::new(starting_state),
107 runner,
108 interval,
109 metrics_service,
110 logger: logger.new_with_component_name::<Self>(),
111 }
112 }
113
114 pub async fn get_state(&self) -> SignerState {
116 self.state.lock().await.to_owned()
117 }
118
119 pub async fn run(&self) -> Result<(), RuntimeError> {
121 info!(self.logger, "Launching State Machine");
122 let mut interval = tokio::time::interval(self.interval);
123
124 loop {
125 interval.tick().await;
126 let approximate_next_cycle_time = Local::now() + self.interval;
129
130 if let Err(e) = self.cycle().await {
131 e.write_to_log(&self.logger);
132 if e.is_critical() {
133 return Err(e);
134 }
135 }
136
137 info!(
138 self.logger, "… Cycle finished";
139 "approximate_next_cycle_time" => %approximate_next_cycle_time.time().format("%H:%M:%S%.3f"),
140 "run_interval_in_ms" => self.interval.as_millis(),
141 );
142 }
143 }
144
145 pub async fn cycle(&self) -> Result<(), RuntimeError> {
147 let mut state = self.state.lock().await;
148 info!(
149 self.logger,
150 "================================================================================"
151 );
152 info!(self.logger, "New cycle: {}", *state);
153
154 self.metrics_service
155 .get_runtime_cycle_total_since_startup_counter()
156 .increment();
157
158 match state.deref() {
159 SignerState::Init => {
160 *state = self.transition_from_init_to_unregistered().await?;
161 }
162 SignerState::Unregistered { epoch } => {
163 if let EpochStatus::NewEpoch(new_epoch) = self.has_epoch_changed(*epoch).await? {
164 info!(
165 self.logger,
166 "→ Epoch has changed, transiting to Unregistered"
167 );
168 *state = self.transition_from_unregistered_to_unregistered(new_epoch).await?;
169 } else if let Some(signer_registrations) = self
170 .runner
171 .get_signer_registrations_from_aggregator()
172 .await
173 .map_err(|e| RuntimeError::KeepState {
174 message: format!("could not retrieve epoch settings at epoch {epoch:?}"),
175 nested_error: Some(e),
176 })?
177 {
178 info!(self.logger, "→ Epoch Signer registrations found");
179 let network_configuration: MithrilNetworkConfiguration =
180 self.runner.get_mithril_network_configuration(*epoch).await.map_err(
181 |e| RuntimeError::KeepState {
182 message: format!(
183 "could not retrieve Mithril network configuration for epoch {epoch:?}"
184 ),
185 nested_error: Some(e),
186 },
187 )?;
188 info!(self.logger, "→ Mithril network configuration found");
189
190 if signer_registrations.epoch >= *epoch {
191 info!(self.logger, "New Epoch found");
192 info!(self.logger, " ⋅ Transiting to Registered");
193 *state = self
194 .transition_from_unregistered_to_one_of_registered_states(
195 signer_registrations.epoch,
196 network_configuration,
197 signer_registrations.current_signers,
198 signer_registrations.next_signers,
199 )
200 .await?;
201 } else {
202 info!(
203 self.logger, " ⋅ Signer settings found, but its epoch is behind the known epoch, waiting…";
204 "network_configuration" => ?network_configuration,
205 "current_singer" => ?signer_registrations.current_signers,
206 "next_signer" => ?signer_registrations.next_signers,
207 "known_epoch" => ?epoch,
208 );
209 }
210 } else {
211 info!(self.logger, "→ No epoch settings found yet, waiting…");
212 }
213 }
214 SignerState::RegisteredNotAbleToSign { epoch } => {
215 if let EpochStatus::NewEpoch(new_epoch) = self.has_epoch_changed(*epoch).await? {
216 info!(
217 self.logger,
218 " → New Epoch detected, transiting to Unregistered"
219 );
220 *state = self
221 .transition_from_registered_not_able_to_sign_to_unregistered(new_epoch)
222 .await?;
223 } else {
224 info!(self.logger, " ⋅ Epoch has NOT changed, waiting…");
225 }
226 }
227
228 SignerState::ReadyToSign { epoch } => match self.has_epoch_changed(*epoch).await? {
229 EpochStatus::NewEpoch(new_epoch) => {
230 info!(
231 self.logger,
232 "→ Epoch has changed, transiting to Unregistered"
233 );
234 *state = self.transition_from_ready_to_sign_to_unregistered(new_epoch).await?;
235 }
236 EpochStatus::Unchanged(timepoint) => {
237 let beacon_to_sign =
238 self.runner.get_beacon_to_sign(timepoint).await.map_err(|e| {
239 RuntimeError::KeepState {
240 message: "could not fetch the beacon to sign".to_string(),
241 nested_error: Some(e),
242 }
243 })?;
244
245 match beacon_to_sign {
246 Some(beacon) => {
247 info!(
248 self.logger, "→ Epoch has NOT changed we can sign this beacon, transiting to ReadyToSign";
249 "beacon_to_sign" => ?beacon,
250 );
251 *state = self
252 .transition_from_ready_to_sign_to_ready_to_sign(*epoch, beacon)
253 .await?;
254 }
255 None => {
256 info!(self.logger, " ⋅ No beacon to sign, waiting…");
257 }
258 }
259 }
260 },
261 };
262
263 self.metrics_service
264 .get_runtime_cycle_success_since_startup_counter()
265 .increment();
266
267 Ok(())
268 }
269
270 async fn has_epoch_changed(&self, epoch: Epoch) -> Result<EpochStatus, RuntimeError> {
272 let current_time_point =
273 self.get_current_time_point("checking if epoch has changed").await?;
274
275 if current_time_point.epoch > epoch {
276 Ok(EpochStatus::NewEpoch(current_time_point.epoch))
277 } else {
278 Ok(EpochStatus::Unchanged(current_time_point))
279 }
280 }
281
282 async fn transition_from_unregistered_to_unregistered(
283 &self,
284 new_epoch: Epoch,
285 ) -> Result<SignerState, RuntimeError> {
286 self.update_era_checker(new_epoch, "unregistered → unregistered")
287 .await?;
288
289 Ok(SignerState::Unregistered { epoch: new_epoch })
290 }
291
292 async fn transition_from_init_to_unregistered(&self) -> Result<SignerState, RuntimeError> {
293 let current_epoch = self.get_current_time_point("init → unregistered").await?.epoch;
294 self.update_era_checker(current_epoch, "init → unregistered").await?;
295
296 Ok(SignerState::Unregistered {
297 epoch: current_epoch,
298 })
299 }
300
301 async fn transition_from_unregistered_to_one_of_registered_states(
303 &self,
304 aggregator_signer_registration_epoch: Epoch,
305 mithril_network_configuration: MithrilNetworkConfiguration,
306 current_signer: Vec<Signer>,
307 next_signer: Vec<Signer>,
308 ) -> Result<SignerState, RuntimeError> {
309 self.metrics_service
310 .get_signer_registration_total_since_startup_counter()
311 .increment();
312
313 let time_point = self.get_current_time_point("unregistered → registered").await?;
314 let epoch = time_point.epoch;
315 self.runner.update_stake_distribution(epoch)
316 .await
317 .map_err(|e| RuntimeError::KeepState {
318 message: format!("Could not update stake distribution in 'unregistered → registered' phase for epoch {epoch:?}."),
319 nested_error: Some(e),
320 })?;
321
322 self.runner
323 .inform_epoch_settings(aggregator_signer_registration_epoch, mithril_network_configuration, current_signer, next_signer)
324 .await
325 .map_err(|e| RuntimeError::KeepState {
326 message: format!(
327 "Could not register epoch information in 'unregistered → registered' phase for epoch {epoch:?}."
328 ),
329 nested_error: Some(e),
330 })?;
331
332 fn handle_registration_result(
333 register_result: Result<(), Error>,
334 epoch: Epoch,
335 ) -> Result<Option<SignerState>, RuntimeError> {
336 if let Err(e) = register_result {
337 if let Some(AggregatorHttpClientError::RegistrationRoundNotYetOpened(_)) =
338 e.downcast_ref::<AggregatorHttpClientError>()
339 {
340 Ok(Some(SignerState::Unregistered { epoch }))
341 } else if e.downcast_ref::<ProtocolInitializerError>().is_some() {
342 Err(RuntimeError::Critical {
343 message: format!(
344 "Could not register to aggregator in 'unregistered → registered' phase for epoch {epoch:?}."
345 ),
346 nested_error: Some(e),
347 })
348 } else {
349 Err(RuntimeError::KeepState {
350 message: format!(
351 "Could not register to aggregator in 'unregistered → registered' phase for epoch {epoch:?}."
352 ),
353 nested_error: Some(e),
354 })
355 }
356 } else {
357 Ok(None)
358 }
359 }
360
361 let register_result = self.runner.register_signer_to_aggregator().await;
362 let next_state_found = handle_registration_result(register_result, epoch)?;
363
364 self.metrics_service
365 .get_signer_registration_success_since_startup_counter()
366 .increment();
367
368 if let Some(state) = next_state_found {
369 return Ok(state);
370 }
371
372 self.metrics_service
373 .get_signer_registration_success_last_epoch_gauge()
374 .record(epoch);
375
376 self.runner.upkeep(epoch).await.map_err(|e| RuntimeError::KeepState {
377 message: "Failed to upkeep signer in 'unregistered → registered' phase".to_string(),
378 nested_error: Some(e),
379 })?;
380
381 match self
382 .runner
383 .can_sign_current_epoch()
384 .await
385 .map_err(|e| RuntimeError::KeepState {
386 message: "Failed to check if signer can sign in the current epoch in 'unregistered → ?' phase".to_string(),
387 nested_error: Some(e),
388 })? {
389 true => Ok(SignerState::ReadyToSign { epoch }),
390 false => Ok(SignerState::RegisteredNotAbleToSign { epoch }),
391 }
392 }
393
394 async fn transition_from_registered_not_able_to_sign_to_unregistered(
395 &self,
396 epoch: Epoch,
397 ) -> Result<SignerState, RuntimeError> {
398 self.update_era_checker(epoch, "registered not able to sign → unregistered")
399 .await?;
400
401 Ok(SignerState::Unregistered { epoch })
402 }
403
404 async fn transition_from_ready_to_sign_to_unregistered(
405 &self,
406 epoch: Epoch,
407 ) -> Result<SignerState, RuntimeError> {
408 self.update_era_checker(epoch, "ready to sign → unregistered").await?;
409
410 Ok(SignerState::Unregistered { epoch })
411 }
412
413 async fn transition_from_ready_to_sign_to_ready_to_sign(
415 &self,
416 current_epoch: Epoch,
417 beacon_to_sign: BeaconToSign,
418 ) -> Result<SignerState, RuntimeError> {
419 let (retrieval_epoch, next_retrieval_epoch) = (
420 current_epoch.offset_to_signer_retrieval_epoch()?,
421 current_epoch.offset_to_next_signer_retrieval_epoch(),
422 );
423
424 debug!(
425 self.logger, ">> transition_from_ready_to_sign_to_ready_to_sign";
426 "current_epoch" => ?current_epoch,
427 "retrieval_epoch" => ?retrieval_epoch,
428 "next_retrieval_epoch" => ?next_retrieval_epoch,
429 );
430
431 self.metrics_service
432 .get_signature_registration_total_since_startup_counter()
433 .increment();
434
435 let message = self
436 .runner
437 .compute_message(&beacon_to_sign.signed_entity_type)
438 .await
439 .map_err(|e| RuntimeError::KeepState {
440 message: format!("Could not compute message during 'ready to sign → ready to sign' phase (current epoch {current_epoch:?})"),
441 nested_error: Some(e)
442 })?;
443
444 self.runner.compute_publish_single_signature(&beacon_to_sign, &message)
445 .await
446 .map_err(|e| RuntimeError::KeepState {
447 message: format!("Could not compute and publish single signature during 'ready to sign → ready to sign' phase (current epoch {current_epoch:?})"),
448 nested_error: Some(e)
449 })?;
450
451 self.metrics_service
452 .get_signature_registration_success_since_startup_counter()
453 .increment();
454 self.metrics_service
455 .get_signature_registration_success_last_epoch_gauge()
456 .record(current_epoch);
457
458 Ok(SignerState::ReadyToSign {
459 epoch: current_epoch,
460 })
461 }
462
463 async fn get_current_time_point(&self, context: &str) -> Result<TimePoint, RuntimeError> {
464 let current_time_point =
465 self.runner
466 .get_current_time_point()
467 .await
468 .map_err(|e| RuntimeError::KeepState {
469 message: format!(
470 "Could not retrieve current time point in context '{context}'."
471 ),
472 nested_error: Some(e),
473 })?;
474
475 Ok(current_time_point)
476 }
477
478 async fn update_era_checker(&self, epoch: Epoch, context: &str) -> Result<(), RuntimeError> {
479 self.runner
480 .update_era_checker(epoch)
481 .await
482 .map_err(|e| RuntimeError::Critical {
483 message: format!(
484 "Could not update Era checker with context '{context}' for epoch {epoch:?}"
485 ),
486 nested_error: Some(e),
487 })
488 }
489}
490
491#[cfg(test)]
492mod tests {
493 use anyhow::anyhow;
494 use chrono::DateTime;
495
496 use mithril_common::entities::{ChainPoint, Epoch, ProtocolMessage, SignedEntityType};
497 use mithril_common::test::double::Dummy;
498
499 use crate::RegisteredSigners;
500 use crate::runtime::runner::MockSignerRunner;
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 = RegisteredSigners {
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(RegisteredSigners::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(RegisteredSigners::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(RegisteredSigners::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(AggregatorHttpClientError::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}