hotmint_consensus/
state.rs1use hotmint_types::{
2 BlockHash, DoubleCertificate, Epoch, Height, QuorumCertificate, ValidatorId, ValidatorSet,
3 ViewNumber,
4};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum ViewRole {
9 Leader,
10 Replica,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum ViewStep {
16 Entered,
17 WaitingForStatus,
18 Proposed,
19 WaitingForProposal,
20 Voted,
21 CollectingVotes,
22 Prepared,
23 SentVote2,
24 Done,
25}
26
27pub struct ConsensusState {
29 pub validator_id: ValidatorId,
30 pub validator_set: ValidatorSet,
31 pub chain_id_hash: [u8; 32],
34 pub current_view: ViewNumber,
35 pub role: ViewRole,
36 pub step: ViewStep,
37 pub locked_qc: Option<QuorumCertificate>,
38 pub highest_double_cert: Option<DoubleCertificate>,
39 pub highest_qc: Option<QuorumCertificate>,
40 pub last_committed_height: Height,
41 pub last_app_hash: BlockHash,
44 pub current_epoch: Epoch,
45 pub pending_vote_extensions: Vec<(ValidatorId, Vec<u8>)>,
48}
49
50impl ConsensusState {
51 pub fn new(validator_id: ValidatorId, validator_set: ValidatorSet) -> Self {
52 Self::with_chain_id(validator_id, validator_set, "")
53 }
54
55 pub fn with_chain_id(
56 validator_id: ValidatorId,
57 validator_set: ValidatorSet,
58 chain_id: &str,
59 ) -> Self {
60 let current_epoch = Epoch::genesis(validator_set.clone());
61 let chain_id_hash = *blake3::hash(chain_id.as_bytes()).as_bytes();
62 Self {
63 validator_id,
64 validator_set,
65 chain_id_hash,
66 current_view: ViewNumber::GENESIS,
67 role: ViewRole::Replica,
68 step: ViewStep::Entered,
69 locked_qc: None,
70 highest_double_cert: None,
71 highest_qc: None,
72 last_committed_height: Height::GENESIS,
73 last_app_hash: BlockHash::GENESIS,
74 current_epoch,
75 pending_vote_extensions: vec![],
76 }
77 }
78
79 pub fn is_leader(&self) -> bool {
80 self.role == ViewRole::Leader
81 }
82
83 pub fn update_highest_qc(&mut self, qc: &QuorumCertificate) {
84 let dominated = self.highest_qc.as_ref().is_none_or(|h| qc.view > h.view);
85 if dominated {
86 self.highest_qc = Some(qc.clone());
87 }
88 }
89
90 pub fn update_locked_qc(&mut self, qc: &QuorumCertificate) {
91 let dominated = self.locked_qc.as_ref().is_none_or(|h| qc.view > h.view);
92 if dominated {
93 self.locked_qc = Some(qc.clone());
94 }
95 }
96}