consensus_types/
sync_info.rs1use crate::{
9 common::Round, quorum_cert::QuorumCert,
10 timeout_certificate::TimeoutCertificate,
11};
12use anyhow::{ensure, Context};
13use diem_types::{
14 block_info::BlockInfo, validator_verifier::ValidatorVerifier,
15};
16use serde::{Deserialize, Serialize};
17use std::fmt::{Debug, Display, Formatter};
18
19#[derive(Deserialize, Serialize, Clone, Eq, PartialEq)]
20pub struct SyncInfo {
22 highest_quorum_cert: QuorumCert,
24 highest_commit_cert: Option<QuorumCert>,
26 highest_timeout_cert: Option<TimeoutCertificate>,
28}
29
30impl Debug for SyncInfo {
32 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
33 write!(f, "{}", self)
34 }
35}
36
37impl Display for SyncInfo {
38 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
39 let htc_repr = match self.highest_timeout_certificate() {
40 Some(tc) => format!("{}", tc.round()),
41 None => "None".to_string(),
42 };
43 write!(
44 f,
45 "SyncInfo[HQC: {}, HCC: {}, HTC: {}]",
46 self.highest_certified_round(),
47 self.highest_commit_round(),
48 htc_repr,
49 )
50 }
51}
52
53impl SyncInfo {
54 pub fn new(
55 highest_quorum_cert: QuorumCert, highest_commit_cert: QuorumCert,
56 highest_timeout_cert: Option<TimeoutCertificate>,
57 ) -> Self {
58 let commit_cert = if highest_quorum_cert == highest_commit_cert {
59 None
60 } else {
61 Some(highest_commit_cert)
62 };
63 let highest_timeout_cert = highest_timeout_cert.filter(|tc| {
65 tc.round() > highest_quorum_cert.certified_block().round()
66 });
67 Self {
68 highest_quorum_cert,
69 highest_commit_cert: commit_cert,
70 highest_timeout_cert,
71 }
72 }
73
74 pub fn highest_quorum_cert(&self) -> &QuorumCert {
76 &self.highest_quorum_cert
77 }
78
79 pub fn highest_commit_cert(&self) -> &QuorumCert {
81 self.highest_commit_cert
82 .as_ref()
83 .unwrap_or(&self.highest_quorum_cert)
84 }
85
86 pub fn highest_timeout_certificate(&self) -> Option<&TimeoutCertificate> {
88 self.highest_timeout_cert.as_ref()
89 }
90
91 pub fn highest_certified_round(&self) -> Round {
92 self.highest_quorum_cert.certified_block().round()
93 }
94
95 pub fn highest_timeout_round(&self) -> Round {
96 self.highest_timeout_certificate()
97 .map_or(0, |tc| tc.round())
98 }
99
100 pub fn highest_commit_round(&self) -> Round {
101 self.highest_commit_cert().commit_info().round()
102 }
103
104 pub fn highest_round(&self) -> Round {
106 std::cmp::max(
107 self.highest_certified_round(),
108 self.highest_timeout_round(),
109 )
110 }
111
112 pub fn verify(&self, validator: &ValidatorVerifier) -> anyhow::Result<()> {
113 let epoch = self.highest_quorum_cert.certified_block().epoch();
114 ensure!(
115 epoch == self.highest_commit_cert().certified_block().epoch(),
116 "Multi epoch in SyncInfo - HCC and HQC"
117 );
118 if let Some(tc) = &self.highest_timeout_cert {
119 ensure!(
120 epoch == tc.epoch(),
121 "Multi epoch in SyncInfo - TC and HQC"
122 );
123 }
124
125 ensure!(
126 self.highest_quorum_cert.certified_block().round()
127 >= self.highest_commit_cert().certified_block().round(),
128 "HQC has lower round than HCC"
129 );
130 ensure!(
131 *self.highest_commit_cert().commit_info() != BlockInfo::empty(),
132 "HCC has no committed block"
133 );
134 self.highest_quorum_cert
135 .verify(validator)
136 .and_then(|_| {
137 self.highest_commit_cert
138 .as_ref()
139 .map_or(Ok(()), |cert| cert.verify(validator))
140 })
141 .and_then(|_| {
142 if let Some(tc) = &self.highest_timeout_cert {
143 tc.verify(validator)?;
144 }
145 Ok(())
146 })
147 .context("Fail to verify SyncInfo")?;
148 Ok(())
149 }
150
151 pub fn epoch(&self) -> u64 {
152 self.highest_quorum_cert.certified_block().epoch()
153 }
154
155 pub fn has_newer_certificates(&self, other: &SyncInfo) -> bool {
156 self.highest_certified_round() > other.highest_certified_round()
157 || self.highest_timeout_round() > other.highest_timeout_round()
158 || self.highest_commit_round() > other.highest_commit_round()
159 }
160}