Skip to main content

hotmint_consensus/
state.rs

1use hotmint_types::{
2    DoubleCertificate, Epoch, Height, QuorumCertificate, ValidatorId, ValidatorSet, ViewNumber,
3};
4
5/// Role of the validator in the current view
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum ViewRole {
8    Leader,
9    Replica,
10}
11
12/// Step within a view (state machine progression)
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ViewStep {
15    Entered,
16    WaitingForStatus,
17    Proposed,
18    WaitingForProposal,
19    Voted,
20    CollectingVotes,
21    Prepared,
22    SentVote2,
23    Done,
24}
25
26/// Mutable consensus state for a single validator
27pub struct ConsensusState {
28    pub validator_id: ValidatorId,
29    pub validator_set: ValidatorSet,
30    pub current_view: ViewNumber,
31    pub role: ViewRole,
32    pub step: ViewStep,
33    pub locked_qc: Option<QuorumCertificate>,
34    pub highest_double_cert: Option<DoubleCertificate>,
35    pub highest_qc: Option<QuorumCertificate>,
36    pub last_committed_height: Height,
37    pub current_epoch: Epoch,
38}
39
40impl ConsensusState {
41    pub fn new(validator_id: ValidatorId, validator_set: ValidatorSet) -> Self {
42        let current_epoch = Epoch::genesis(validator_set.clone());
43        Self {
44            validator_id,
45            validator_set,
46            current_view: ViewNumber::GENESIS,
47            role: ViewRole::Replica,
48            step: ViewStep::Entered,
49            locked_qc: None,
50            highest_double_cert: None,
51            highest_qc: None,
52            last_committed_height: Height::GENESIS,
53            current_epoch,
54        }
55    }
56
57    pub fn is_leader(&self) -> bool {
58        self.role == ViewRole::Leader
59    }
60
61    pub fn update_highest_qc(&mut self, qc: &QuorumCertificate) {
62        let dominated = self.highest_qc.as_ref().is_none_or(|h| qc.view > h.view);
63        if dominated {
64            self.highest_qc = Some(qc.clone());
65        }
66    }
67
68    pub fn update_locked_qc(&mut self, qc: &QuorumCertificate) {
69        let dominated = self.locked_qc.as_ref().is_none_or(|h| qc.view > h.view);
70        if dominated {
71            self.locked_qc = Some(qc.clone());
72        }
73    }
74}