Skip to content

Commit 128c952

Browse files
committed
Replace request_proposal_to_any to request_proposal_to_superiors
1 parent 2beb9b3 commit 128c952

File tree

6 files changed

+119
-44
lines changed

6 files changed

+119
-44
lines changed

core/src/consensus/sortition/vrf_sortition.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub struct VRFSortition {
3535
pub vrf_inst: ECVRF,
3636
}
3737

38-
#[derive(Eq, PartialEq, Clone, Debug, RlpEncodable, RlpDecodable)]
38+
#[derive(Eq, PartialEq, Clone, Default, Debug, RlpEncodable, RlpDecodable)]
3939
pub struct PriorityInfo {
4040
signer_idx: usize,
4141
priority: Priority,

core/src/consensus/tendermint/message.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use snap;
2525

2626
use super::super::BitSet;
2727
use super::{Height, Step, View};
28-
use crate::consensus::Priority;
28+
use crate::consensus::{Priority, PriorityInfo};
2929

3030
/// Step for the sortition round.
3131
/// FIXME: It has a large overlap with the previous VoteStep.
@@ -123,10 +123,16 @@ const MESSAGE_ID_COMMIT: u8 = 0x07;
123123
#[derive(Clone, Debug, PartialEq, RlpEncodable, RlpDecodable)]
124124
#[cfg_attr(test, derive(Default))]
125125
pub struct ProposalSummary {
126-
pub priority: Priority,
126+
pub priority_info: PriorityInfo,
127127
pub block_hash: BlockHash,
128128
}
129129

130+
impl ProposalSummary {
131+
pub fn priority(&self) -> Priority {
132+
self.priority_info.priority()
133+
}
134+
}
135+
130136
#[derive(Debug, PartialEq)]
131137
pub enum TendermintMessage {
132138
ConsensusMessage(Vec<Bytes>),
@@ -442,7 +448,7 @@ mod tests {
442448
bit_set.set(2);
443449
rlp_encode_and_decode_test!(TendermintMessage::StepState {
444450
vote_step: VoteStep::new(10, 123, Step::Prevote),
445-
proposal: Some(Default::default()),
451+
proposal: Box::new(Some(Default::default())),
446452
lock_view: Some(2),
447453
known_votes: bit_set
448454
});

core/src/consensus/tendermint/network.rs

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use super::message::*;
3434
use super::params::TimeoutParams;
3535
use super::types::{PeerState, Step, View};
3636
use super::worker;
37-
use crate::consensus::{EngineError, PriorityInfo};
37+
use crate::consensus::{EngineError, Priority, PriorityInfo};
3838

3939
use super::{
4040
ENGINE_TIMEOUT_BROADCAST_STEP_STATE, ENGINE_TIMEOUT_BROADCAT_STEP_STATE_INTERVAL, ENGINE_TIMEOUT_TOKEN_NONCE_BASE,
@@ -154,21 +154,25 @@ impl TendermintExtension {
154154
}
155155
}
156156

157-
fn request_proposal_to_any(&self, round: SortitionRound) {
158-
for (token, peer) in &self.peers {
159-
let is_future_height_and_view = round < peer.vote_step.into();
160-
161-
if is_future_height_and_view {
162-
self.request_proposal(token, round);
163-
continue
164-
}
165-
166-
let is_same_height_and_view = round == peer.vote_step.into();
167-
168-
if is_same_height_and_view && peer.proposal.is_some() {
169-
self.request_proposal(token, round);
170-
}
171-
}
157+
fn request_proposal_to_superiors(&self, round: SortitionRound, my_highest: Option<Priority>) {
158+
// Request to future round peers
159+
self.peers
160+
.iter()
161+
.filter(|(_, peer)| round < peer.vote_step.into())
162+
.for_each(|(token, _)| self.request_proposal(token, round));
163+
164+
let current_round_peers = self.peers.iter().filter(|(_, peer)| round == peer.vote_step.into());
165+
// Request to current round higher peers
166+
if let Some(current_round_highest_priority) = current_round_peers
167+
.clone()
168+
.map(|(_id, peer)| peer.priority())
169+
.max()
170+
.filter(|highest_priority| *highest_priority > my_highest)
171+
{
172+
current_round_peers
173+
.filter(|(_id, peer)| peer.priority() == current_round_highest_priority)
174+
.for_each(|(token, _)| self.request_proposal(token, round))
175+
};
172176
}
173177

174178
fn request_proposal(&self, token: &NodeId, round: SortitionRound) {
@@ -301,21 +305,44 @@ impl NetworkExtension<Event> for TendermintExtension {
301305
lock_view,
302306
known_votes,
303307
);
304-
self.update_peer_state(token, vote_step, (*proposal).clone(), known_votes);
305-
let (result, receiver) = crossbeam::unbounded();
306-
self.inner
307-
.send(worker::Event::StepState {
308-
token: *token,
309-
vote_step,
310-
proposal: *proposal,
311-
lock_view,
312-
known_votes: Box::from(known_votes),
313-
result,
314-
})
315-
.unwrap();
316-
317-
while let Ok(message) = receiver.recv() {
318-
self.api.send(token, Arc::new(message));
308+
let unchanged = match self.peers.get(token) {
309+
Some(peer_state) => *proposal == peer_state.proposal,
310+
None => false,
311+
};
312+
let verified = unchanged || {
313+
(*proposal)
314+
.clone()
315+
.map(|summary| {
316+
let (result, receiver) = crossbeam::bounded(1);
317+
self.inner
318+
.send(worker::Event::VerifyPriorityInfo {
319+
height: vote_step.height,
320+
view: vote_step.view,
321+
priority_info: summary.priority_info,
322+
result,
323+
})
324+
.unwrap();
325+
receiver.recv().unwrap().unwrap_or(false)
326+
})
327+
.unwrap_or(true)
328+
};
329+
if verified {
330+
self.update_peer_state(token, vote_step, (*proposal).clone(), known_votes);
331+
let (result, receiver) = crossbeam::unbounded();
332+
self.inner
333+
.send(worker::Event::StepState {
334+
token: *token,
335+
vote_step,
336+
proposal: *proposal,
337+
lock_view,
338+
known_votes: Box::from(known_votes),
339+
result,
340+
})
341+
.unwrap();
342+
343+
while let Ok(message) = receiver.recv() {
344+
self.api.send(token, Arc::new(message));
345+
}
319346
}
320347
}
321348
Ok(TendermintMessage::RequestProposal {
@@ -420,10 +447,11 @@ impl NetworkExtension<Event> for TendermintExtension {
420447
} => {
421448
self.request_messages_to_all(vote_step, requested_votes);
422449
}
423-
Event::RequestProposalToAny {
450+
Event::RequestProposalToSuperiors {
424451
round,
452+
current_highest,
425453
} => {
426-
self.request_proposal_to_any(round);
454+
self.request_proposal_to_superiors(round, current_highest);
427455
}
428456
Event::SetTimerStep {
429457
step,
@@ -456,8 +484,9 @@ pub enum Event {
456484
vote_step: VoteStep,
457485
requested_votes: BitSet,
458486
},
459-
RequestProposalToAny {
487+
RequestProposalToSuperiors {
460488
round: SortitionRound,
489+
current_highest: Option<Priority>,
461490
},
462491
SetTimerStep {
463492
step: Step,

core/src/consensus/tendermint/types.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ impl PeerState {
191191
messages: BitSet::new(),
192192
}
193193
}
194+
195+
pub fn priority(&self) -> Option<Priority> {
196+
self.proposal.as_ref().map(|summary| summary.priority())
197+
}
194198
}
195199

196200
pub struct TendermintSealView<'a> {

core/src/consensus/tendermint/vote_collector.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use ckey::SchnorrSignature;
2121
use ctypes::BlockHash;
2222
use rlp::{Encodable, RlpStream};
2323

24-
use super::super::PriorityInfo;
24+
use super::super::{Priority, PriorityInfo};
2525
use super::stake::Action;
2626
use super::{ConsensusMessage, ProposalSummary, SortitionRound, Step, VoteStep};
2727
use crate::consensus::BitSet;
@@ -335,6 +335,10 @@ impl VoteCollector {
335335
.and_then(|step_collector| step_collector.priority_collector().get_highest())
336336
}
337337

338+
pub fn get_highest_priority(&self, sortition_round: SortitionRound) -> Option<Priority> {
339+
self.get_highest_priority_info(sortition_round).map(|priority_info| priority_info.priority())
340+
}
341+
338342
pub fn get_highest_proposal_hash(&self, sortition_round: SortitionRound) -> Option<BlockHash> {
339343
self.votes.get(&sortition_round.into()).and_then(|step_collector| {
340344
let highest_priority_idx =

core/src/consensus/tendermint/worker.rs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use crate::consensus::signer::EngineSigner;
4848
use crate::consensus::validator_set::{DynamicValidator, ValidatorSet};
4949
use crate::consensus::{
5050
sortition::seed::{SeedInfo, VRFSeed},
51-
EngineError, PriorityInfo, Seal, VRFSortition,
51+
EngineError, Priority, PriorityInfo, Seal, VRFSortition,
5252
};
5353
use crate::encoded;
5454
use crate::error::{BlockError, Error};
@@ -147,6 +147,12 @@ pub enum Event {
147147
message: Bytes,
148148
result: crossbeam::Sender<Option<Arc<dyn ConsensusClient>>>,
149149
},
150+
VerifyPriorityInfo {
151+
height: Height,
152+
view: View,
153+
priority_info: PriorityInfo,
154+
result: crossbeam::Sender<Option<bool>>,
155+
},
150156
StepState {
151157
token: NodeId,
152158
vote_step: VoteStep,
@@ -362,6 +368,14 @@ impl Worker {
362368
let client = inner.on_commit_message(block, votes);
363369
result.send(client).unwrap();
364370
}
371+
Ok(Event::VerifyPriorityInfo {
372+
height,
373+
view,
374+
priority_info,
375+
result
376+
}) => {
377+
result.send(inner.verify_priority_info(height, view, priority_info)).unwrap();
378+
}
365379
Err(crossbeam::RecvError) => {
366380
cerror!(ENGINE, "The event channel for tendermint thread had been closed.");
367381
break
@@ -592,10 +606,11 @@ impl Worker {
592606
.unwrap();
593607
}
594608

595-
fn request_proposal_to_any(&self, round: SortitionRound) {
609+
fn request_proposal_to_superiors(&self, round: SortitionRound, current_highest: Option<Priority>) {
596610
self.extension
597-
.send(network::Event::RequestProposalToAny {
611+
.send(network::Event::RequestProposalToSuperiors {
598612
round,
613+
current_highest,
599614
})
600615
.unwrap();
601616
}
@@ -707,7 +722,10 @@ impl Worker {
707722
};
708723
}
709724
} else {
710-
self.request_proposal_to_any(vote_step.into());
725+
let sortition_round = vote_step.into();
726+
let round_highest_priority = self.votes.get_highest_priority(sortition_round);
727+
cinfo!(ENGINE, "I am not eligible to be a proposer, I'll request a proposal");
728+
self.request_proposal_to_superiors(sortition_round, round_highest_priority);
711729
}
712730
}
713731
Step::Prevote => {
@@ -829,7 +847,9 @@ impl Worker {
829847
let received_locked_block = self.votes.has_votes_for(&vote_step, locked_proposal_hash);
830848

831849
if !received_locked_block {
832-
self.request_proposal_to_any(vote_step.into());
850+
let sortition_round = vote_step.into();
851+
let round_highest_priority = self.votes.get_highest_priority(sortition_round);
852+
self.request_proposal_to_superiors(sortition_round, round_highest_priority);
833853
return Err(format!("Have a lock on {}-{}, but do not received a locked proposal", self.height, locked_view))
834854
}
835855

@@ -1140,6 +1160,18 @@ impl Worker {
11401160
Ok(())
11411161
}
11421162

1163+
fn verify_priority_info(&mut self, height: Height, view: View, priority_info: PriorityInfo) -> Option<bool> {
1164+
let parent_seed = self.prev_vrf_seed_of_height(height)?;
1165+
let parent_hash = self.client().block_hash(&(height - 1).into())?;
1166+
let signer_idx = priority_info.signer_idx();
1167+
let signer_public = self.validators.get(&parent_hash, signer_idx);
1168+
let voting_power = self.get_voting_power(height - 1, &parent_hash, signer_idx);
1169+
1170+
priority_info
1171+
.verify(&parent_seed.round_msg(view), &signer_public, voting_power, &mut self.sortition_scheme)
1172+
.ok()
1173+
}
1174+
11431175
fn verify_seed(&mut self, header: &Header, parent: &Header) -> Result<(), Error> {
11441176
let current_seal_view = TendermintSealView::new(&header.seal());
11451177
let current_seed_signer_idx = current_seal_view.vrf_seed_info().expect("Seal field verified").signer_idx();

0 commit comments

Comments
 (0)