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.proposal
89 .validate_signature(validator)
90 .map_err(|e| format_err!("{:?}", e))?;
91
92 if let Some(vrf_proof) = self.proposal.vrf_proof() {
93 validator.verify_vrf(
94 self.proposal.author().unwrap(),
95 &self.proposal.block_data().vrf_round_seed(epoch_vrf_seed),
96 vrf_proof,
97 )?;
98 }
99 if let Some(tc) = self.sync_info.highest_timeout_certificate() {
101 tc.verify(validator).map_err(|e| format_err!("{:?}", e))?;
102 }
103 self.verify_well_formed()
106 }
107
108 pub fn proposal(&self) -> &Block { &self.proposal }
109
110 pub fn take_proposal(self) -> Block { self.proposal }
111
112 pub fn sync_info(&self) -> &SyncInfo { &self.sync_info }
113
114 pub fn proposer(&self) -> Author {
115 self.proposal
116 .author()
117 .expect("Proposal should be verified having an author")
118 }
119}
120
121impl fmt::Display for ProposalMsg {
122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 write!(f, "[proposal {} from ", self.proposal)?;
124 match self.proposal.author() {
125 Some(author) => write!(f, "{}]", hex::encode(&author[..4])),
126 None => write!(f, "NIL]"),
127 }
128 }
129}