cfxcore/pos/consensus/liveness/
vrf_proposer_election.rs1use crate::pos::consensus::liveness::proposer_election::ProposerElection;
9use consensus_types::common::{Author, Round};
10
11use cfx_types::U256;
12use consensus_types::{block::Block, block_data::BlockData};
13use diem_crypto::{vrf_number_with_nonce, HashValue, VRFPrivateKey, VRFProof};
14use diem_logger::debug as diem_debug;
15use diem_types::{
16 epoch_state::EpochState,
17 validator_config::{ConsensusVRFPrivateKey, ConsensusVRFProof},
18};
19use parking_lot::Mutex;
20
21pub struct VrfProposer {
23 author: Author,
24 vrf_private_key: ConsensusVRFPrivateKey,
25
26 proposal_threshold: HashValue,
27
28 current_round: Mutex<Round>,
29 current_seed: Mutex<Vec<u8>>,
30 proposal_candidates: Mutex<Option<Block>>,
31
32 epoch_state: EpochState,
34}
35
36impl VrfProposer {
37 pub fn new(
38 author: Author, vrf_private_key: ConsensusVRFPrivateKey,
39 proposal_threshold_u256: U256, epoch_state: EpochState,
40 ) -> Self {
41 let proposal_threshold = proposal_threshold_u256.to_big_endian();
42 Self {
43 author,
44 vrf_private_key,
45 proposal_threshold: HashValue::new(proposal_threshold),
46 current_round: Mutex::new(0),
49 current_seed: Mutex::new(vec![]),
50 proposal_candidates: Default::default(),
51 epoch_state,
52 }
53 }
54
55 pub fn get_vrf_number(&self, block: &Block) -> Option<HashValue> {
56 Some(vrf_number_with_nonce(
57 &block.vrf_proof()?.to_hash().ok()?,
58 block.vrf_nonce()?,
59 ))
60 }
61}
62
63impl ProposerElection for VrfProposer {
64 fn get_valid_proposer(&self, _round: Round) -> Author {
65 unreachable!(
66 "We will never get valid proposer based on round for VRF election"
67 )
68 }
69
70 fn is_valid_proposer(&self, author: Author, round: Round) -> bool {
71 assert_eq!(
72 author, self.author,
73 "VRF election can not check proposer validity without vrf_proof"
74 );
75 assert_eq!(
76 round,
77 *self.current_round.lock(),
78 "VRF election can not generate vrf_proof for other rounds"
79 );
80 let voting_power =
81 match self.epoch_state.verifier().get_voting_power(&author) {
82 None => return false,
83 Some(p) => p,
84 };
85 let mut round_seed = self.current_seed.lock().clone();
88 let leader_round = (round + 1) / 3;
89 round_seed.extend_from_slice(&leader_round.to_be_bytes());
90 let vrf_output = self
91 .vrf_private_key
92 .compute(round_seed.as_slice())
93 .expect("vrf compute fail")
94 .to_hash()
95 .expect("to hash error");
96 for nonce in 0..=voting_power {
97 let vrf_number = vrf_number_with_nonce(&vrf_output, nonce);
98 if vrf_number <= self.proposal_threshold {
99 return true;
100 }
101 }
102 false
103 }
104
105 fn is_valid_proposal(&self, block: &Block) -> bool {
106 let author = match block.author() {
107 Some(author) => author,
108 None => return false,
109 };
110 let voting_power =
111 match self.epoch_state.verifier().get_voting_power(&author) {
112 None => return false,
113 Some(p) => p,
114 };
115 let (nonce, vrf_proof) = match (block.vrf_nonce(), block.vrf_proof()) {
116 (Some(nonce), Some(vrf_proof)) => (nonce, vrf_proof),
117 _ => return false,
118 };
119 if nonce > voting_power || *self.current_round.lock() != block.round() {
120 return false;
121 }
122 let seed = block
123 .block_data()
124 .vrf_round_seed(self.current_seed.lock().as_slice());
125 let vrf_hash = match self
126 .epoch_state
127 .verifier()
128 .get_vrf_public_key(&author)
129 {
130 Some(Some(vrf_public_key)) => {
131 match vrf_proof.verify(seed.as_slice(), &vrf_public_key) {
132 Ok(vrf_hash) => vrf_hash,
133 Err(e) => {
134 diem_debug!("is_valid_proposal: invalid proposal err={:?}, block={:?}", e, block);
135 return false;
136 }
137 }
138 }
139 _ => {
140 diem_debug!(
141 "Receive block from non-validator: author={:?}",
142 block.author()
143 );
144 return false;
145 }
146 };
147 vrf_number_with_nonce(&vrf_hash, nonce) <= self.proposal_threshold
148 }
149
150 fn is_random_election(&self) -> bool { true }
151
152 fn receive_proposal_candidate(
157 &self, block: &Block,
158 ) -> anyhow::Result<bool> {
159 let current_round = *self.current_round.lock();
160 if block.round() < current_round {
161 anyhow::bail!("Incorrect round");
162 } else if block.round() > current_round {
163 return Ok(true);
167 }
168 let block_vrf_number = self.get_vrf_number(block).ok_or_else(|| {
170 anyhow::anyhow!("proposal missing vrf proof/nonce")
171 })?;
172 let old_proposal = self.proposal_candidates.lock();
173 match old_proposal.as_ref().and_then(|b| self.get_vrf_number(b)) {
174 Some(old_vrf_number) => Ok(old_vrf_number > block_vrf_number),
175 None => Ok(true),
176 }
177 }
178
179 fn set_proposal_candidate(&self, block: Block) {
180 *self.proposal_candidates.lock() = Some(block);
181 }
182
183 fn choose_proposal_to_vote(&self) -> Option<Block> {
185 let chosen_proposal = self.proposal_candidates.lock().clone();
186 diem_debug!(
187 "choose_proposal_to_vote: {:?}, data={:?}",
188 chosen_proposal,
189 chosen_proposal.as_ref().map(|b| b.block_data())
190 );
191 chosen_proposal
192 }
193
194 fn next_round(&self, round: Round, new_seed: Vec<u8>) {
195 *self.current_round.lock() = round;
196 self.proposal_candidates.lock().take();
197 *self.current_seed.lock() = new_seed;
198 }
199
200 fn gen_vrf_nonce_and_proof(
201 &self, block_data: &BlockData,
202 ) -> Option<(u64, ConsensusVRFProof)> {
203 let mut min_vrf_number = self.proposal_threshold;
204 let mut best_nonce = None;
205 let voting_power = self
206 .epoch_state
207 .verifier()
208 .get_voting_power(&block_data.author()?)?;
209
210 let vrf_proof = self
211 .vrf_private_key
212 .compute(
213 block_data
214 .vrf_round_seed(self.current_seed.lock().as_slice())
215 .as_slice(),
216 )
217 .ok()?;
218 let vrf_output = vrf_proof.to_hash().ok()?;
219 for nonce in 0..=voting_power {
220 let vrf_number = vrf_number_with_nonce(&vrf_output, nonce);
221 if vrf_number <= min_vrf_number {
222 min_vrf_number = vrf_number;
223 best_nonce = Some(nonce);
224 }
225 }
226 best_nonce.map(|nonce| (nonce, vrf_proof))
227 }
228}