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 mut proposal_threshold = [0 as u8; HashValue::LENGTH];
42 proposal_threshold_u256.to_big_endian(&mut proposal_threshold);
43 Self {
44 author,
45 vrf_private_key,
46 proposal_threshold: HashValue::new(proposal_threshold),
47 current_round: Mutex::new(0),
50 current_seed: Mutex::new(vec![]),
51 proposal_candidates: Default::default(),
52 epoch_state,
53 }
54 }
55
56 pub fn get_vrf_number(&self, block: &Block) -> Option<HashValue> {
57 Some(vrf_number_with_nonce(
58 &block.vrf_proof()?.to_hash().ok()?,
59 block.vrf_nonce()?,
60 ))
61 }
62}
63
64impl ProposerElection for VrfProposer {
65 fn get_valid_proposer(&self, _round: Round) -> Author {
66 unreachable!(
67 "We will never get valid proposer based on round for VRF election"
68 )
69 }
70
71 fn is_valid_proposer(&self, author: Author, round: Round) -> bool {
72 assert_eq!(
73 author, self.author,
74 "VRF election can not check proposer validity without vrf_proof"
75 );
76 assert_eq!(
77 round,
78 *self.current_round.lock(),
79 "VRF election can not generate vrf_proof for other rounds"
80 );
81 let voting_power =
82 match self.epoch_state.verifier().get_voting_power(&author) {
83 None => return false,
84 Some(p) => p,
85 };
86 let mut round_seed = self.current_seed.lock().clone();
89 let leader_round = (round + 1) / 3;
90 round_seed.extend_from_slice(&leader_round.to_be_bytes());
91 let vrf_output = self
92 .vrf_private_key
93 .compute(round_seed.as_slice())
94 .expect("vrf compute fail")
95 .to_hash()
96 .expect("to hash error");
97 for nonce in 0..=voting_power {
98 let vrf_number = vrf_number_with_nonce(&vrf_output, nonce);
99 if vrf_number <= self.proposal_threshold {
100 return true;
101 }
102 }
103 false
104 }
105
106 fn is_valid_proposal(&self, block: &Block) -> bool {
107 let voting_power = match self
108 .epoch_state
109 .verifier()
110 .get_voting_power(&block.author().expect("checked"))
111 {
112 None => return false,
113 Some(p) => p,
114 };
115 let nonce = block.vrf_nonce().expect("checked");
116 if nonce > voting_power || *self.current_round.lock() != block.round() {
117 return false;
118 }
119 let seed = block
120 .block_data()
121 .vrf_round_seed(self.current_seed.lock().as_slice());
122 let vrf_hash = match self
123 .epoch_state
124 .verifier()
125 .get_vrf_public_key(&block.author().expect("checked"))
126 {
127 Some(Some(vrf_public_key)) => {
128 match block
129 .vrf_proof()
130 .unwrap()
131 .verify(seed.as_slice(), &vrf_public_key)
132 {
133 Ok(vrf_hash) => vrf_hash,
134 Err(e) => {
135 diem_debug!("is_valid_proposal: invalid proposal err={:?}, block={:?}", e, block);
136 return false;
137 }
138 }
139 }
140 _ => {
141 diem_debug!(
142 "Receive block from non-validator: author={:?}",
143 block.author()
144 );
145 return false;
146 }
147 };
148 vrf_number_with_nonce(&vrf_hash, nonce) <= self.proposal_threshold
149 }
150
151 fn is_random_election(&self) -> bool { true }
152
153 fn receive_proposal_candidate(
158 &self, block: &Block,
159 ) -> anyhow::Result<bool> {
160 let current_round = *self.current_round.lock();
162 if block.round() < current_round {
163 anyhow::bail!("Incorrect round");
164 } else if block.round() > current_round {
165 return Ok(true);
169 }
170 let old_proposal = self.proposal_candidates.lock();
171 if old_proposal.is_none()
172 || self.get_vrf_number(old_proposal.as_ref().unwrap()).unwrap()
173 > self.get_vrf_number(block).unwrap()
174 {
175 Ok(true)
176 } else {
177 Ok(false)
178 }
179 }
180
181 fn set_proposal_candidate(&self, block: Block) {
182 *self.proposal_candidates.lock() = Some(block);
183 }
184
185 fn choose_proposal_to_vote(&self) -> Option<Block> {
187 let chosen_proposal = self.proposal_candidates.lock().clone();
188 diem_debug!(
189 "choose_proposal_to_vote: {:?}, data={:?}",
190 chosen_proposal,
191 chosen_proposal.as_ref().map(|b| b.block_data())
192 );
193 chosen_proposal
194 }
195
196 fn next_round(&self, round: Round, new_seed: Vec<u8>) {
197 *self.current_round.lock() = round;
198 self.proposal_candidates.lock().take();
199 *self.current_seed.lock() = new_seed;
200 }
201
202 fn gen_vrf_nonce_and_proof(
203 &self, block_data: &BlockData,
204 ) -> Option<(u64, ConsensusVRFProof)> {
205 let mut min_vrf_number = self.proposal_threshold;
206 let mut best_nonce = None;
207 let voting_power = self
208 .epoch_state
209 .verifier()
210 .get_voting_power(&block_data.author()?)?;
211
212 let vrf_proof = self
213 .vrf_private_key
214 .compute(
215 block_data
216 .vrf_round_seed(self.current_seed.lock().as_slice())
217 .as_slice(),
218 )
219 .ok()?;
220 let vrf_output = vrf_proof.to_hash().ok()?;
221 for nonce in 0..=voting_power {
222 let vrf_number = vrf_number_with_nonce(&vrf_output, nonce);
223 if vrf_number <= min_vrf_number {
224 min_vrf_number = vrf_number;
225 best_nonce = Some(nonce);
226 }
227 }
228 best_nonce.map(|nonce| (nonce, vrf_proof))
229 }
230}