1use std::cmp::{Ord, Ordering, PartialOrd};
2use std::convert::TryFrom;
3
4use bytes::Bytes;
5use derive_more::Display;
6use serde::{Deserialize, Serialize};
7
8use crate::error::ConsensusError;
9use crate::smr::smr_types::{SMRStatus, Step, TriggerType};
10use crate::{Codec, DurationConfig};
11
12pub type Address = Bytes;
14pub type Hash = Bytes;
16pub type Signature = Bytes;
18
19#[derive(Serialize, Deserialize, Clone, Debug, Display, PartialEq, Eq, Hash)]
22pub enum VoteType {
23 #[display(fmt = "Prevote")]
25 Prevote,
26 #[display(fmt = "Precommit")]
28 Precommit,
29}
30
31impl From<VoteType> for u8 {
32 fn from(v: VoteType) -> u8 {
33 match v {
34 VoteType::Prevote => 1,
35 VoteType::Precommit => 2,
36 }
37 }
38}
39
40impl From<VoteType> for TriggerType {
41 fn from(v: VoteType) -> TriggerType {
42 match v {
43 VoteType::Prevote => TriggerType::PrevoteQC,
44 VoteType::Precommit => TriggerType::PrecommitQC,
45 }
46 }
47}
48
49impl From<VoteType> for Step {
50 fn from(v: VoteType) -> Step {
51 match v {
52 VoteType::Prevote => Step::Prevote,
53 VoteType::Precommit => Step::Precommit,
54 }
55 }
56}
57
58impl TryFrom<u8> for VoteType {
59 type Error = ConsensusError;
60
61 fn try_from(s: u8) -> Result<Self, Self::Error> {
62 match s {
63 1 => Ok(VoteType::Prevote),
64 2 => Ok(VoteType::Precommit),
65 _ => Err(ConsensusError::Other("".to_string())),
66 }
67 }
68}
69
70#[allow(clippy::large_enum_variant)]
72#[derive(Clone, Debug, Display, PartialEq, Eq)]
73pub enum OverlordMsg<T: Codec> {
74 #[display(fmt = "Signed Proposal")]
76 SignedProposal(SignedProposal<T>),
77 #[display(fmt = "Signed Vote")]
79 SignedVote(SignedVote),
80 #[display(fmt = "Aggregated Vote")]
82 AggregatedVote(AggregatedVote),
83 #[display(fmt = "Rich Status")]
85 RichStatus(Status),
86 #[display(fmt = "Choke Message")]
88 SignedChoke(SignedChoke),
89 #[display(fmt = "Stop Overlord")]
91 Stop,
92
93 #[cfg(test)]
95 Commit(Commit<T>),
96}
97
98impl<T: Codec> OverlordMsg<T> {
99 pub(crate) fn is_rich_status(&self) -> bool {
100 matches!(self, OverlordMsg::RichStatus(_))
101 }
102
103 pub(crate) fn get_height(&self) -> u64 {
104 match self {
105 OverlordMsg::SignedProposal(sp) => sp.proposal.height,
106 OverlordMsg::SignedVote(sv) => sv.get_height(),
107 OverlordMsg::AggregatedVote(av) => av.get_height(),
108 OverlordMsg::RichStatus(s) => s.height,
109 OverlordMsg::SignedChoke(sc) => sc.choke.height,
110 _ => unreachable!(),
111 }
112 }
113}
114
115#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
117pub enum UpdateFrom {
118 PrevoteQC(AggregatedVote),
120 PrecommitQC(AggregatedVote),
122 ChokeQC(AggregatedChoke),
124}
125
126#[derive(Serialize, Deserialize, Clone, Debug, Display)]
128pub enum ViewChangeReason {
129 #[display(fmt = "Do not receive proposal from network")]
131 NoProposalFromNetwork,
132
133 #[display(fmt = "Do not receive Prevote QC from network")]
135 NoPrevoteQCFromNetwork,
136
137 #[display(fmt = "Do not receive precommit QC from network")]
139 NoPrecommitQCFromNetwork,
140
141 #[display(fmt = "Check the block not pass")]
143 CheckBlockNotPass,
144
145 #[display(fmt = "Update from a higher round prevote QC from {} to {}", _0, _1)]
147 UpdateFromHigherPrevoteQC(u64, u64),
148
149 #[display(fmt = "Update from a higher round precommit QC from {} to {}", _0, _1)]
151 UpdateFromHigherPrecommitQC(u64, u64),
152
153 #[display(fmt = "Update from a higher round choke QC from {} to {}", _0, _1)]
155 UpdateFromHigherChokeQC(u64, u64),
156
157 #[display(fmt = "{:?} votes count is below threshold", _0)]
159 LeaderReceivedVoteBelowThreshold(VoteType),
160
161 #[display(fmt = "other reasons")]
163 Others,
164}
165
166#[derive(Clone, Debug, Display, PartialEq, Eq)]
168#[display(fmt = "Signed Proposal {:?}", proposal)]
169pub struct SignedProposal<T: Codec> {
170 pub signature: Bytes,
172 pub proposal: Proposal<T>,
174}
175
176#[derive(Clone, Debug, Display, PartialEq, Eq)]
178#[display(fmt = "Proposal height {}, round {}", height, round)]
179pub struct Proposal<T: Codec> {
180 pub height: u64,
182 pub round: u64,
184 pub content: T,
186 pub block_hash: Hash,
188 pub lock: Option<PoLC>,
190 pub proposer: Address,
192}
193
194#[derive(Clone, Debug, PartialEq, Eq)]
196pub struct PoLC {
197 pub lock_round: u64,
199 pub lock_votes: AggregatedVote,
201}
202
203#[derive(Clone, Debug, Display, PartialEq, Eq, Hash)]
205#[display(fmt = "Signed vote {:?}", vote)]
206pub struct SignedVote {
207 pub signature: Bytes,
209 pub vote: Vote,
211 pub voter: Address,
213}
214
215impl PartialOrd for SignedVote {
216 fn partial_cmp(&self, other: &SignedVote) -> Option<Ordering> {
217 Some(self.voter.cmp(&other.voter))
218 }
219}
220
221impl Ord for SignedVote {
222 fn cmp(&self, other: &SignedVote) -> Ordering {
223 self.voter.cmp(&other.voter)
224 }
225}
226
227impl SignedVote {
228 pub fn get_height(&self) -> u64 {
230 self.vote.height
231 }
232
233 pub fn get_round(&self) -> u64 {
235 self.vote.round
236 }
237
238 pub fn get_hash(&self) -> Hash {
240 self.vote.block_hash.clone()
241 }
242
243 pub fn is_prevote(&self) -> bool {
245 self.vote.vote_type == VoteType::Prevote
246 }
247}
248
249#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
251pub struct AggregatedSignature {
252 #[serde(with = "super::serde_hex")]
254 pub signature: Signature,
255 #[serde(with = "super::serde_hex")]
257 pub address_bitmap: Bytes,
258}
259
260#[derive(Serialize, Deserialize, Clone, Debug, Display, PartialEq, Eq, Hash)]
262#[rustfmt::skip]
263#[display(fmt = "{:?} aggregated vote height {}, round {}", vote_type, height, round)]
264pub struct AggregatedVote {
265 pub signature: AggregatedSignature,
267 pub vote_type: VoteType,
269 pub height: u64,
271 pub round: u64,
273 #[serde(with = "super::serde_hex")]
275 pub block_hash: Hash,
276 #[serde(with = "super::serde_hex")]
278 pub leader: Address,
279}
280
281impl AggregatedVote {
282 pub fn get_height(&self) -> u64 {
284 self.height
285 }
286
287 pub fn get_round(&self) -> u64 {
289 self.round
290 }
291
292 pub fn is_prevote_qc(&self) -> bool {
294 self.vote_type == VoteType::Prevote
295 }
296
297 pub fn to_vote(&self) -> Vote {
299 Vote {
300 height: self.height,
301 round: self.round,
302 vote_type: self.vote_type.clone(),
303 block_hash: self.block_hash.clone(),
304 }
305 }
306}
307
308#[derive(Clone, Debug, Display, PartialEq, Eq, Hash)]
310#[display(fmt = "{:?} vote height {}, round {}", vote_type, height, round)]
311pub struct Vote {
312 pub height: u64,
314 pub round: u64,
316 pub vote_type: VoteType,
318 pub block_hash: Hash,
320}
321
322#[derive(Clone, Debug, Display, PartialEq, Eq)]
324#[display(fmt = "Commit height {}", height)]
325pub struct Commit<T: Codec> {
326 pub height: u64,
328 pub content: T,
330 pub proof: Proof,
332}
333
334#[derive(Clone, Debug, PartialEq, Eq)]
336pub struct Proof {
337 pub height: u64,
339 pub round: u64,
341 pub block_hash: Hash,
343 pub signature: AggregatedSignature,
345}
346
347#[derive(Clone, Debug, Display, PartialEq, Eq)]
349#[display(fmt = "Rich status height {}", height)]
350pub struct Status {
351 pub height: u64,
353 pub interval: Option<u64>,
355 pub timer_config: Option<DurationConfig>,
357 pub authority_list: Vec<Node>,
359}
360
361impl From<Status> for SMRStatus {
362 fn from(s: Status) -> SMRStatus {
363 SMRStatus {
364 height: s.height,
365 new_interval: s.interval,
366 new_config: s.timer_config,
367 }
368 }
369}
370
371impl Status {
372 pub(crate) fn is_consensus_node(&self, address: &Address) -> bool {
373 self.authority_list
374 .iter()
375 .any(|node| node.address == address)
376 }
377}
378
379#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
381pub struct Node {
382 #[serde(with = "super::serde_hex")]
384 pub address: Address,
385 pub propose_weight: u32,
388 pub vote_weight: u32,
390}
391
392impl PartialOrd for Node {
393 fn partial_cmp(&self, other: &Node) -> Option<Ordering> {
394 Some(self.address.cmp(&other.address))
395 }
396}
397
398impl Ord for Node {
399 fn cmp(&self, other: &Node) -> Ordering {
400 self.address.cmp(&other.address)
401 }
402}
403
404impl Node {
405 pub fn new(addr: Address) -> Self {
407 Node {
408 address: addr,
409 propose_weight: 1u32,
410 vote_weight: 1u32,
411 }
412 }
413
414 pub fn set_propose_weight(&mut self, propose_weight: u32) {
417 self.propose_weight = propose_weight;
418 }
419
420 pub fn set_vote_weight(&mut self, vote_weight: u32) {
422 self.vote_weight = vote_weight;
423 }
424}
425
426#[derive(Clone, Debug, PartialEq, Eq)]
428pub(crate) struct VerifyResp {
429 pub(crate) height: u64,
431 pub(crate) round: u64,
433 pub(crate) block_hash: Hash,
435 pub(crate) is_pass: bool,
437}
438
439#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
441pub struct AggregatedChoke {
442 pub height: u64,
444 pub round: u64,
446 #[serde(with = "super::serde_hex")]
448 pub signature: Signature,
449 #[serde(with = "super::serde_multi_hex")]
451 pub voters: Vec<Address>,
452}
453
454#[allow(clippy::len_without_is_empty)]
455impl AggregatedChoke {
456 pub(crate) fn len(&self) -> usize {
457 self.voters.len()
458 }
459
460 pub(crate) fn to_hash(&self) -> HashChoke {
461 HashChoke {
462 height: self.height,
463 round: self.round,
464 }
465 }
466}
467
468#[derive(Clone, Debug, Hash, PartialEq, Eq)]
470pub struct SignedChoke {
471 pub signature: Signature,
473 pub choke: Choke,
475 pub address: Address,
477}
478
479#[derive(Clone, Debug, Hash, PartialEq, Eq)]
481pub struct Choke {
482 pub height: u64,
484 pub round: u64,
486 pub from: UpdateFrom,
488}
489
490impl Choke {
491 pub(crate) fn to_hash(&self) -> HashChoke {
492 HashChoke {
493 height: self.height,
494 round: self.round,
495 }
496 }
497}
498
499#[derive(Clone, Debug)]
500pub(crate) struct HashChoke {
501 pub(crate) height: u64,
502 pub(crate) round: u64,
503}
504
505#[cfg(test)]
506mod test {
507 use super::*;
508 use rand::random;
509
510 fn gen_address() -> Address {
511 Address::from((0..32).map(|_| random::<u8>()).collect::<Vec<_>>())
512 }
513
514 fn mock_node() -> Node {
515 Node::new(gen_address())
516 }
517
518 fn mock_status() -> Status {
519 Status {
520 height: random::<u64>(),
521 interval: None,
522 timer_config: None,
523 authority_list: vec![mock_node(), mock_node()],
524 }
525 }
526
527 #[test]
528 fn test_consensus_power() {
529 let status = mock_status();
530 let consensus_node = status.authority_list[0].address.clone();
531 let sync_node = gen_address();
532
533 assert!(status.is_consensus_node(&consensus_node));
534 assert!(!status.is_consensus_node(&sync_node));
535 }
536}