Skip to main content

dig_epoch/types/
epoch_phase.rs

1//! # `types::epoch_phase` — `EpochPhase` enum and `PhaseTransition` struct
2//!
3//! **Implemented by:** `TYP-001` — SPEC §3.2-3.3.
4
5use serde::{Deserialize, Serialize};
6
7/// Sentinel marker proving the module exists and is reachable at
8/// `dig_epoch::types::epoch_phase::STR_002_MODULE_PRESENT`.
9#[doc(hidden)]
10pub const STR_002_MODULE_PRESENT: () = ();
11
12/// The lifecycle phase of a DIG L2 epoch, driven by L1 block-height progress.
13///
14/// Phase progress is `(l1_now - epoch_start_l1) * 100 / EPOCH_L1_BLOCKS`:
15///
16/// | Range | Phase |
17/// |-------|-------|
18/// | 0 – 49 % | `BlockProduction` |
19/// | 50 – 74 % | `Checkpoint` |
20/// | 75 – 99 % | `Finalization` |
21/// | ≥ 100 % | `Complete` |
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub enum EpochPhase {
24    /// Block production (0–50 % of L1 window).
25    BlockProduction,
26    /// Checkpoint submission (50–75 % of L1 window).
27    Checkpoint,
28    /// Finalization (75–100 % of L1 window).
29    Finalization,
30    /// Epoch complete (≥ 100 % of L1 window).
31    Complete,
32}
33
34impl EpochPhase {
35    /// Ordinal index: `BlockProduction=0`, `Checkpoint=1`, `Finalization=2`, `Complete=3`.
36    pub fn index(&self) -> usize {
37        match self {
38            Self::BlockProduction => 0,
39            Self::Checkpoint => 1,
40            Self::Finalization => 2,
41            Self::Complete => 3,
42        }
43    }
44
45    /// Successor phase, or `None` if already `Complete`.
46    pub fn next(&self) -> Option<EpochPhase> {
47        match self {
48            Self::BlockProduction => Some(Self::Checkpoint),
49            Self::Checkpoint => Some(Self::Finalization),
50            Self::Finalization => Some(Self::Complete),
51            Self::Complete => None,
52        }
53    }
54
55    /// Predecessor phase, or `None` if already `BlockProduction`.
56    pub fn previous(&self) -> Option<EpochPhase> {
57        match self {
58            Self::Complete => Some(Self::Finalization),
59            Self::Finalization => Some(Self::Checkpoint),
60            Self::Checkpoint => Some(Self::BlockProduction),
61            Self::BlockProduction => None,
62        }
63    }
64
65    /// Canonical string name used in Display and logging.
66    pub fn name(&self) -> &'static str {
67        match self {
68            Self::BlockProduction => "BlockProduction",
69            Self::Checkpoint => "Checkpoint",
70            Self::Finalization => "Finalization",
71            Self::Complete => "Complete",
72        }
73    }
74
75    /// Returns `true` only during `BlockProduction`.
76    pub fn allows_block_production(&self) -> bool {
77        matches!(self, Self::BlockProduction)
78    }
79
80    /// Returns `true` only during `Checkpoint`.
81    pub fn allows_checkpoint_submission(&self) -> bool {
82        matches!(self, Self::Checkpoint)
83    }
84
85    /// Returns `true` only during `Finalization`.
86    pub fn allows_finalization(&self) -> bool {
87        matches!(self, Self::Finalization)
88    }
89}
90
91impl std::fmt::Display for EpochPhase {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        f.write_str(self.name())
94    }
95}
96
97/// Records the details of a phase transition event.
98#[derive(Debug, Clone)]
99pub struct PhaseTransition {
100    /// Epoch number in which the transition occurred.
101    pub epoch: u64,
102    /// Phase before the transition.
103    pub from: EpochPhase,
104    /// Phase after the transition.
105    pub to: EpochPhase,
106    /// L1 block height at which the transition was observed.
107    pub l1_height: u32,
108}