hotmint_types/
certificate.rs1use serde::{Deserialize, Serialize};
2
3use crate::block::BlockHash;
4use crate::crypto::AggregateSignature;
5use crate::epoch::EpochNumber;
6use crate::view::ViewNumber;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct QuorumCertificate {
11 pub block_hash: BlockHash,
12 pub view: ViewNumber,
13 pub aggregate_signature: AggregateSignature,
14 #[serde(default)]
17 pub epoch: EpochNumber,
18}
19
20impl QuorumCertificate {
21 pub fn rank(&self) -> ViewNumber {
23 self.view
24 }
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct DoubleCertificate {
30 pub inner_qc: QuorumCertificate,
31 pub outer_qc: QuorumCertificate,
32 #[serde(default)]
36 pub vote_extensions: Vec<(crate::ValidatorId, Vec<u8>)>,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct TimeoutCertificate {
42 pub view: ViewNumber,
43 pub aggregate_signature: AggregateSignature,
44 pub highest_qcs: Vec<Option<QuorumCertificate>>,
46}
47
48impl TimeoutCertificate {
49 pub fn highest_qc(&self) -> Option<&QuorumCertificate> {
51 self.highest_qcs
52 .iter()
53 .filter_map(|qc| qc.as_ref())
54 .max_by_key(|qc| qc.view)
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 fn make_qc(view: u64, hash: [u8; 32]) -> QuorumCertificate {
63 QuorumCertificate {
64 block_hash: BlockHash(hash),
65 view: ViewNumber(view),
66 aggregate_signature: AggregateSignature::new(4),
67 epoch: EpochNumber(0),
68 }
69 }
70
71 #[test]
72 fn test_qc_rank() {
73 let qc = make_qc(5, [1u8; 32]);
74 assert_eq!(qc.rank(), ViewNumber(5));
75 }
76
77 #[test]
78 fn test_tc_highest_qc_some() {
79 let qc1 = make_qc(3, [1u8; 32]);
80 let qc2 = make_qc(7, [2u8; 32]);
81 let tc = TimeoutCertificate {
82 view: ViewNumber(8),
83 aggregate_signature: AggregateSignature::new(4),
84 highest_qcs: vec![Some(qc1), None, Some(qc2), None],
85 };
86 let highest = tc.highest_qc().unwrap();
87 assert_eq!(highest.view, ViewNumber(7));
88 }
89
90 #[test]
91 fn test_tc_highest_qc_all_none() {
92 let tc = TimeoutCertificate {
93 view: ViewNumber(5),
94 aggregate_signature: AggregateSignature::new(4),
95 highest_qcs: vec![None, None, None, None],
96 };
97 assert!(tc.highest_qc().is_none());
98 }
99
100 #[test]
101 fn test_tc_highest_qc_empty() {
102 let tc = TimeoutCertificate {
103 view: ViewNumber(5),
104 aggregate_signature: AggregateSignature::new(4),
105 highest_qcs: vec![],
106 };
107 assert!(tc.highest_qc().is_none());
108 }
109}