consensus_types/
proposal_msg.rs1use crate::{block::Block, common::Author, sync_info::SyncInfo};
9use anyhow::{anyhow, ensure, format_err, Context, Result};
10use diem_types::validator_verifier::ValidatorVerifier;
11use serde::{Deserialize, Serialize};
12use std::fmt;
13
14#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
17pub struct ProposalMsg {
18 proposal: Block,
19 sync_info: SyncInfo,
20}
21
22impl ProposalMsg {
23 pub fn new(proposal: Block, sync_info: SyncInfo) -> Self {
25 Self {
26 proposal,
27 sync_info,
28 }
29 }
30
31 pub fn epoch(&self) -> u64 { self.proposal.epoch() }
32
33 pub fn verify_well_formed(&self) -> Result<()> {
35 ensure!(
36 !self.proposal.is_nil_block(),
37 "Proposal {} for a NIL block",
38 self.proposal
39 );
40 self.proposal
41 .verify_well_formed()
42 .context("Fail to verify ProposalMsg's block")?;
43 ensure!(
44 self.proposal.round() > 0,
45 "Proposal for {} has an incorrect round of 0",
46 self.proposal,
47 );
48 ensure!(
49 self.proposal.epoch() == self.sync_info.epoch(),
50 "ProposalMsg has different epoch number from SyncInfo"
51 );
52 ensure!(
53 self.proposal.parent_id()
54 == self.sync_info.highest_quorum_cert().certified_block().id(),
55 "Proposal HQC in SyncInfo certifies {}, but block parent id is {}",
56 self.sync_info.highest_quorum_cert().certified_block().id(),
57 self.proposal.parent_id(),
58 );
59 let previous_round = self
60 .proposal
61 .round()
62 .checked_sub(1)
63 .ok_or_else(|| anyhow!("proposal round overflowed!"))?;
64
65 let highest_certified_round = std::cmp::max(
66 self.proposal.quorum_cert().certified_block().round(),
67 self.sync_info
68 .highest_timeout_certificate()
69 .map_or(0, |tc| tc.round()),
70 );
71 ensure!(
72 previous_round == highest_certified_round,
73 "Proposal {} does not have a certified round {}",
74 self.proposal,
75 previous_round
76 );
77 ensure!(
78 self.proposal.author().is_some(),
79 "Proposal {} does not define an author",
80 self.proposal
81 );
82 Ok(())
83 }
84
85 pub fn verify(
86 &self, validator: &ValidatorVerifier, epoch_vrf_seed: &[u8],
87 ) -> Result<()> {
88 self.verify_well_formed()?;
91 self.proposal
92 .validate_signature(validator)
93 .map_err(|e| format_err!("{:?}", e))?;
94
95 if let Some(vrf_proof) = self.proposal.vrf_proof() {
96 let author = self.proposal.author().ok_or_else(|| {
97 format_err!("VRF proof present but block has no author")
98 })?;
99 validator.verify_vrf(
100 author,
101 &self.proposal.block_data().vrf_round_seed(epoch_vrf_seed),
102 vrf_proof,
103 )?;
104 }
105 if let Some(tc) = self.sync_info.highest_timeout_certificate() {
106 tc.verify(validator).map_err(|e| format_err!("{:?}", e))?;
107 }
108 Ok(())
109 }
110
111 pub fn proposal(&self) -> &Block { &self.proposal }
112
113 pub fn take_proposal(self) -> Block { self.proposal }
114
115 pub fn sync_info(&self) -> &SyncInfo { &self.sync_info }
116
117 pub fn proposer(&self) -> Option<Author> { self.proposal.author() }
120}
121
122impl fmt::Display for ProposalMsg {
123 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124 write!(f, "[proposal {} from ", self.proposal)?;
125 match self.proposal.author() {
126 Some(author) => write!(f, "{}]", hex::encode(&author[..4])),
127 None => write!(f, "NIL]"),
128 }
129 }
130}