consensus_types/
quorum_cert.rs1use crate::vote_data::VoteData;
9use anyhow::{ensure, Context};
10use diem_crypto::{hash::CryptoHash, HashValue};
11use diem_types::{
12 block_info::BlockInfo,
13 ledger_info::{
14 LedgerInfo, LedgerInfoWithSignatures, LedgerInfoWithSignaturesUnchecked,
15 },
16 validator_verifier::ValidatorVerifier,
17};
18use serde::{Deserialize, Serialize};
19use std::{
20 collections::BTreeMap,
21 fmt::{Display, Formatter},
22};
23
24#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)]
25pub struct QuorumCert {
26 vote_data: VoteData,
28 signed_ledger_info: LedgerInfoWithSignatures,
31}
32
33#[derive(Deserialize)]
34pub struct QuorumCertUnchecked {
35 vote_data: VoteData,
36 signed_ledger_info: LedgerInfoWithSignaturesUnchecked,
37}
38
39impl From<QuorumCertUnchecked> for QuorumCert {
40 fn from(q: QuorumCertUnchecked) -> Self {
41 Self {
42 vote_data: q.vote_data,
43 signed_ledger_info: q.signed_ledger_info.into(),
44 }
45 }
46}
47
48impl Display for QuorumCert {
49 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
50 write!(
51 f,
52 "QuorumCert: [{}, {}]",
53 self.vote_data, self.signed_ledger_info
54 )
55 }
56}
57
58impl QuorumCert {
59 pub fn new(
60 vote_data: VoteData, signed_ledger_info: LedgerInfoWithSignatures,
61 ) -> Self {
62 QuorumCert {
63 vote_data,
64 signed_ledger_info,
65 }
66 }
67
68 pub fn vote_data(&self) -> &VoteData { &self.vote_data }
69
70 pub fn certified_block(&self) -> &BlockInfo { self.vote_data().proposed() }
71
72 pub fn parent_block(&self) -> &BlockInfo { self.vote_data().parent() }
73
74 pub fn ledger_info(&self) -> &LedgerInfoWithSignatures {
75 &self.signed_ledger_info
76 }
77
78 pub fn commit_info(&self) -> &BlockInfo {
79 self.ledger_info().ledger_info().commit_info()
80 }
81
82 pub fn ends_epoch(&self) -> bool {
84 self.signed_ledger_info.ledger_info().ends_epoch()
85 }
86
87 pub fn certificate_for_genesis_from_ledger_info(
95 ledger_info: &LedgerInfo, genesis_id: HashValue,
96 ) -> QuorumCert {
97 let ancestor = BlockInfo::new(
98 ledger_info
99 .epoch()
100 .checked_add(1)
101 .expect("Integer overflow when creating cert for genesis from ledger info"),
102 0,
103 genesis_id,
104 ledger_info.transaction_accumulator_hash(),
105 ledger_info.version(),
106 ledger_info.timestamp_usecs(),
107 None,
108 ledger_info.pivot_decision().cloned(),
109 );
110 let vote_data = VoteData::new(ancestor.clone(), ancestor.clone());
111 let li = LedgerInfo::new(ancestor, vote_data.hash());
112
113 QuorumCert::new(
114 vote_data,
115 LedgerInfoWithSignatures::new(li, BTreeMap::new()),
116 )
117 }
118
119 pub fn verify(&self, validator: &ValidatorVerifier) -> anyhow::Result<()> {
120 let vote_hash = self.vote_data.hash();
121 ensure!(
122 self.ledger_info().ledger_info().consensus_data_hash() == vote_hash,
123 "Quorum Cert's hash mismatch LedgerInfo"
124 );
125 if self.certified_block().round() == 0 {
130 ensure!(
131 self.parent_block() == self.certified_block(),
132 "Genesis QC has inconsistent parent block with certified block"
133 );
134 ensure!(
135 self.certified_block()
136 == self.ledger_info().ledger_info().commit_info(),
137 "Genesis QC has inconsistent commit block with certified block"
138 );
139 ensure!(
140 self.ledger_info().signatures().is_empty(),
141 "Genesis QC should not carry signatures"
142 );
143 return Ok(());
144 }
145 self.ledger_info()
146 .verify_signatures(validator)
147 .context("Fail to verify QuorumCert")?;
148 self.vote_data.verify()?;
149 Ok(())
150 }
151}