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 short_hex_str::AsShortHexStr;
13use std::fmt;
14
15#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
18pub struct ProposalMsg {
19 proposal: Block,
20 sync_info: SyncInfo,
21}
22
23impl ProposalMsg {
24 pub fn new(proposal: Block, sync_info: SyncInfo) -> Self {
26 Self {
27 proposal,
28 sync_info,
29 }
30 }
31
32 pub fn epoch(&self) -> u64 { self.proposal.epoch() }
33
34 pub fn verify_well_formed(&self) -> Result<()> {
36 ensure!(
37 !self.proposal.is_nil_block(),
38 "Proposal {} for a NIL block",
39 self.proposal
40 );
41 self.proposal
42 .verify_well_formed()
43 .context("Fail to verify ProposalMsg's block")?;
44 ensure!(
45 self.proposal.round() > 0,
46 "Proposal for {} has an incorrect round of 0",
47 self.proposal,
48 );
49 ensure!(
50 self.proposal.epoch() == self.sync_info.epoch(),
51 "ProposalMsg has different epoch number from SyncInfo"
52 );
53 ensure!(
54 self.proposal.parent_id()
55 == self.sync_info.highest_quorum_cert().certified_block().id(),
56 "Proposal HQC in SyncInfo certifies {}, but block parent id is {}",
57 self.sync_info.highest_quorum_cert().certified_block().id(),
58 self.proposal.parent_id(),
59 );
60 let previous_round = self
61 .proposal
62 .round()
63 .checked_sub(1)
64 .ok_or_else(|| anyhow!("proposal round overflowed!"))?;
65
66 let highest_certified_round = std::cmp::max(
67 self.proposal.quorum_cert().certified_block().round(),
68 self.sync_info
69 .highest_timeout_certificate()
70 .map_or(0, |tc| tc.round()),
71 );
72 ensure!(
73 previous_round == highest_certified_round,
74 "Proposal {} does not have a certified round {}",
75 self.proposal,
76 previous_round
77 );
78 ensure!(
79 self.proposal.author().is_some(),
80 "Proposal {} does not define an author",
81 self.proposal
82 );
83 Ok(())
84 }
85
86 pub fn verify(
87 &self, validator: &ValidatorVerifier, epoch_vrf_seed: &[u8],
88 ) -> Result<()> {
89 self.proposal
90 .validate_signature(validator)
91 .map_err(|e| format_err!("{:?}", e))?;
92
93 if let Some(vrf_proof) = self.proposal.vrf_proof() {
94 validator.verify_vrf(
95 self.proposal.author().unwrap(),
96 &self.proposal.block_data().vrf_round_seed(epoch_vrf_seed),
97 vrf_proof,
98 )?;
99 }
100 if let Some(tc) = self.sync_info.highest_timeout_certificate() {
102 tc.verify(validator).map_err(|e| format_err!("{:?}", e))?;
103 }
104 self.verify_well_formed()
107 }
108
109 pub fn proposal(&self) -> &Block { &self.proposal }
110
111 pub fn take_proposal(self) -> Block { self.proposal }
112
113 pub fn sync_info(&self) -> &SyncInfo { &self.sync_info }
114
115 pub fn proposer(&self) -> Author {
116 self.proposal
117 .author()
118 .expect("Proposal should be verified having an author")
119 }
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, "{}]", author.short_str()),
127 None => write!(f, "NIL]"),
128 }
129 }
130}