Skip to content

Commit 91feaa1

Browse files
committed
Get rid of the state variable "proposal"
Proposal information is now managed only by vote_collector
1 parent 17f983b commit 91feaa1

File tree

3 files changed

+112
-102
lines changed

3 files changed

+112
-102
lines changed

core/src/consensus/tendermint/types.rs

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -284,43 +284,3 @@ impl TwoThirdsMajority {
284284
}
285285
}
286286
}
287-
288-
#[derive(Debug, PartialEq)]
289-
pub enum Proposal {
290-
ProposalReceived(BlockHash, Bytes, SchnorrSignature),
291-
ProposalImported(BlockHash),
292-
None,
293-
}
294-
295-
impl Proposal {
296-
pub fn new_received(hash: BlockHash, block: Bytes, signature: SchnorrSignature) -> Self {
297-
Proposal::ProposalReceived(hash, block, signature)
298-
}
299-
300-
pub fn new_imported(hash: BlockHash) -> Self {
301-
Proposal::ProposalImported(hash)
302-
}
303-
304-
pub fn block_hash(&self) -> Option<BlockHash> {
305-
match self {
306-
Proposal::ProposalReceived(hash, ..) => Some(*hash),
307-
Proposal::ProposalImported(hash) => Some(*hash),
308-
Proposal::None => None,
309-
}
310-
}
311-
312-
pub fn imported_block_hash(&self) -> Option<BlockHash> {
313-
match self {
314-
Proposal::ProposalReceived(..) => None,
315-
Proposal::ProposalImported(hash) => Some(*hash),
316-
Proposal::None => None,
317-
}
318-
}
319-
320-
pub fn is_none(&self) -> bool {
321-
match self {
322-
Proposal::None => true,
323-
_ => false,
324-
}
325-
}
326-
}

core/src/consensus/tendermint/vote_collector.rs

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@
1414
// You should have received a copy of the GNU Affero General Public License
1515
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1616

17-
use std::collections::{BTreeMap, BTreeSet, HashMap};
18-
use std::iter::Iterator;
17+
use std::collections::{btree_set::Iter, BTreeMap, BTreeSet, HashMap};
18+
use std::iter::{Iterator, Rev};
1919

2020
use ckey::SchnorrSignature;
2121
use ctypes::BlockHash;
2222
use rlp::{Encodable, RlpStream};
2323

2424
use super::super::PriorityInfo;
2525
use super::stake::Action;
26-
use super::{ConsensusMessage, SortitionRound, Step, VoteStep};
26+
use super::{ConsensusMessage, ProposalSummary, SortitionRound, Step, VoteStep};
2727
use crate::consensus::BitSet;
2828

2929
/// Storing all Proposals, Prevotes and Precommits.
@@ -130,6 +130,14 @@ impl PriorityCollector {
130130
fn insert(&mut self, info: PriorityInfo) -> bool {
131131
self.priorities.insert(info)
132132
}
133+
134+
fn get_highest(&self) -> Option<PriorityInfo> {
135+
self.priorities.iter().rev().next().cloned()
136+
}
137+
138+
fn iter_from_highest(&self) -> Rev<Iter<'_, PriorityInfo>> {
139+
self.priorities.iter().rev()
140+
}
133141
}
134142

135143
impl MessageCollector {
@@ -317,3 +325,54 @@ impl VoteCollector {
317325
.unwrap_or_default()
318326
}
319327
}
328+
329+
impl VoteCollector {
330+
pub fn collect_priority(&mut self, sortition_round: SortitionRound, info: PriorityInfo) -> bool {
331+
self.votes.entry(sortition_round.into()).or_insert_with(StepCollector::new_pp).insert_priority(info)
332+
}
333+
334+
pub fn get_highest_priority_info(&self, sortition_round: SortitionRound) -> Option<PriorityInfo> {
335+
self.votes
336+
.get(&sortition_round.into())
337+
.and_then(|step_collector| step_collector.priority_collector().get_highest())
338+
}
339+
340+
pub fn get_highest_proposal_hash(&self, sortition_round: SortitionRound) -> Option<BlockHash> {
341+
self.votes.get(&sortition_round.into()).and_then(|step_collector| {
342+
let highest_priority_idx =
343+
step_collector.priority_collector().get_highest().map(|priority_info| priority_info.signer_idx())?;
344+
step_collector
345+
.message_collector()
346+
.fetch_by_idx(highest_priority_idx)
347+
.and_then(|priority_message| priority_message.block_hash())
348+
})
349+
}
350+
351+
pub fn get_highest_proposal_summary(&self, sortition_round: SortitionRound) -> Option<ProposalSummary> {
352+
let block_hash = self.get_highest_proposal_hash(sortition_round)?;
353+
let priority_info = self.get_highest_priority_info(sortition_round)?;
354+
Some(ProposalSummary {
355+
priority_info,
356+
block_hash,
357+
})
358+
}
359+
360+
pub fn block_hashes_from_highest(&self, sortition_round: SortitionRound) -> Vec<BlockHash> {
361+
match self.votes.get(&sortition_round.into()) {
362+
Some(step_collector) => {
363+
let message_collector = step_collector.message_collector();
364+
let priority_iter_from_highest = step_collector.priority_collector().iter_from_highest();
365+
priority_iter_from_highest
366+
.map(|priority_info| {
367+
message_collector
368+
.fetch_by_idx(priority_info.signer_idx())
369+
.expect("Signer index was verified")
370+
.block_hash()
371+
.expect("Proposal vote always have BlockHash")
372+
})
373+
.collect()
374+
}
375+
None => vec![],
376+
}
377+
}
378+
}

core/src/consensus/tendermint/worker.rs

Lines changed: 50 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use super::message::*;
3636
use super::network;
3737
use super::params::TimeGapParams;
3838
use super::stake::CUSTOM_ACTION_HANDLER_ID;
39-
use super::types::{Height, Proposal, Step, TendermintSealView, TendermintState, TwoThirdsMajority, View};
39+
use super::types::{Height, Step, TendermintSealView, TendermintState, TwoThirdsMajority, View};
4040
use super::vote_collector::{DoubleVote, VoteCollector};
4141
use super::vote_regression_checker::VoteRegressionChecker;
4242
use super::{ENGINE_TIMEOUT_BROADCAST_STEP_STATE, ENGINE_TIMEOUT_TOKEN_NONCE_BASE, SEAL_FIELDS};
@@ -52,6 +52,7 @@ use crate::consensus::{
5252
use crate::encoded;
5353
use crate::error::{BlockError, Error};
5454
use crate::transaction::{SignedTransaction, UnverifiedTransaction};
55+
use crate::types::BlockStatus;
5556
use crate::views::BlockView;
5657
use crate::BlockId;
5758
use std::cell::Cell;
@@ -84,8 +85,6 @@ struct Worker {
8485
signer: EngineSigner,
8586
/// Last majority
8687
last_two_thirds_majority: TwoThirdsMajority,
87-
/// hash of the proposed block, used for seal submission.
88-
proposal: Proposal,
8988
/// The finalized view of the previous height's block.
9089
/// The signatures for the previous block is signed for the view below.
9190
finalized_view_of_previous_block: View,
@@ -192,7 +191,6 @@ impl Worker {
192191
votes: Default::default(),
193192
signer: Default::default(),
194193
last_two_thirds_majority: TwoThirdsMajority::Empty,
195-
proposal: Proposal::None,
196194
finalized_view_of_previous_block: 0,
197195
finalized_view_of_current_block: None,
198196
validators,
@@ -637,7 +635,6 @@ impl Worker {
637635
fn increment_view(&mut self, n: View) {
638636
cinfo!(ENGINE, "increment_view: New view.");
639637
self.view += n;
640-
self.proposal = Proposal::None;
641638
self.votes_received = MutTrigger::new(BitSet::new());
642639
}
643640

@@ -654,7 +651,6 @@ impl Worker {
654651
self.last_two_thirds_majority = TwoThirdsMajority::Empty;
655652
self.height += 1;
656653
self.view = 0;
657-
self.proposal = Proposal::None;
658654
self.votes_received = MutTrigger::new(BitSet::new());
659655
self.finalized_view_of_previous_block =
660656
self.finalized_view_of_current_block.expect("self.step == Step::Commit");
@@ -672,7 +668,6 @@ impl Worker {
672668
self.last_two_thirds_majority = TwoThirdsMajority::Empty;
673669
self.height = height;
674670
self.view = 0;
675-
self.proposal = Proposal::None;
676671
self.votes_received = MutTrigger::new(BitSet::new());
677672
self.finalized_view_of_previous_block = finalized_view_of_previous_height;
678673
self.finalized_view_of_current_block = None;
@@ -708,7 +703,7 @@ impl Worker {
708703
// need to reset vote
709704
self.broadcast_state(
710705
vote_step,
711-
self.proposal.block_hash(),
706+
self.votes.get_highest_proposal_summary(self.current_sortition_round()),
712707
self.last_two_thirds_majority.view(),
713708
self.votes_received.borrow_anyway(),
714709
);
@@ -723,9 +718,6 @@ impl Worker {
723718
// Wait for verification.
724719
return
725720
}
726-
self.proposal = Proposal::new_imported(*hash);
727-
self.move_to_step(TendermintState::Prevote, is_restoring);
728-
return
729721
}
730722
let parent_block_hash = self.prev_block_hash();
731723
if !self.is_signer_proposer(&parent_block_hash) {
@@ -754,8 +746,8 @@ impl Worker {
754746
self.request_messages_to_all(vote_step, &BitSet::all_set() - &self.votes_received);
755747
if !self.already_generated_message() {
756748
let block_hash_candidate = match &self.last_two_thirds_majority {
757-
TwoThirdsMajority::Empty => self.proposal.imported_block_hash(),
758-
TwoThirdsMajority::Unlock(_) => self.proposal.imported_block_hash(),
749+
TwoThirdsMajority::Empty => self.highest_imported_block_hash(),
750+
TwoThirdsMajority::Unlock(_) => self.highest_imported_block_hash(),
759751
TwoThirdsMajority::Lock(_, block_hash) => Some(*block_hash),
760752
};
761753
let block_hash = block_hash_candidate.filter(|hash| {
@@ -826,6 +818,21 @@ impl Worker {
826818
}
827819
}
828820

821+
fn highest_imported_block_hash(&self) -> Option<BlockHash> {
822+
match self.step {
823+
TendermintState::Prevote => {
824+
self.votes.block_hashes_from_highest(self.current_sortition_round()).into_iter().find(|block_hash| {
825+
if let BlockStatus::InChain = self.client().block_status(&(*block_hash).into()) {
826+
true
827+
} else {
828+
false
829+
}
830+
})
831+
}
832+
_ => panic!(),
833+
}
834+
}
835+
829836
fn is_generation_time_relevant(&self, block_header: &Header) -> bool {
830837
let acceptable_past_gap = self.time_gap_params.allowed_past_gap;
831838
let acceptable_future_gap = self.time_gap_params.allowed_future_gap;
@@ -988,7 +995,6 @@ impl Worker {
988995
let current_vote_step = VoteStep::new(self.height, self.view, self.step.to_step());
989996
let proposal_is_for_current = self.votes.has_votes_for(&current_vote_step, proposal.hash());
990997
if proposal_is_for_current {
991-
self.proposal = Proposal::new_imported(proposal.hash());
992998
let current_step = self.step.clone();
993999
match current_step {
9941000
TendermintState::Propose => {
@@ -1008,19 +1014,7 @@ impl Worker {
10081014
TendermintSealView::new(proposal.seal()).parent_block_finalized_view().unwrap();
10091015

10101016
self.jump_to_height(height, finalized_view_of_previous_height);
1011-
1012-
let proposal_is_for_view0 = self.votes.has_votes_for(
1013-
&VoteStep {
1014-
height,
1015-
view: 0,
1016-
step: Step::Propose,
1017-
},
1018-
proposal.hash(),
1019-
);
1020-
if proposal_is_for_view0 {
1021-
self.proposal = Proposal::new_imported(proposal.hash())
1022-
}
1023-
self.move_to_step(TendermintState::Prevote, false);
1017+
self.move_to_step(TendermintState::new_propose_step(), false);
10241018
}
10251019
}
10261020

@@ -1054,12 +1048,6 @@ impl Worker {
10541048
self.finalized_view_of_previous_block = backup.finalized_view_of_previous_block;
10551049
self.finalized_view_of_current_block = backup.finalized_view_of_current_block;
10561050

1057-
if let Some(proposal) = backup.proposal {
1058-
if client.block(&BlockId::Hash(proposal)).is_some() {
1059-
self.proposal = Proposal::ProposalImported(proposal);
1060-
}
1061-
}
1062-
10631051
for vote in backup.votes {
10641052
let bytes = rlp::encode(&vote);
10651053
if let Err(err) = self.handle_message(&bytes, true) {
@@ -1086,7 +1074,6 @@ impl Worker {
10861074
return Seal::None
10871075
}
10881076

1089-
assert_eq!(Proposal::None, self.proposal);
10901077
assert_eq!(height, self.height);
10911078

10921079
let view = self.view;
@@ -1274,7 +1261,7 @@ impl Worker {
12741261
if let Some(votes_received) = self.votes_received.borrow_if_mutated() {
12751262
self.broadcast_state(
12761263
self.vote_step(),
1277-
self.proposal.block_hash(),
1264+
self.votes.get_highest_proposal_summary(self.current_sortition_round()),
12781265
self.last_two_thirds_majority.view(),
12791266
votes_received,
12801267
);
@@ -1490,7 +1477,7 @@ impl Worker {
14901477
fn repropose_block(&mut self, block: encoded::Block) {
14911478
let header = block.decode_header();
14921479
self.vote_on_header_for_proposal(&header).expect("I am proposer");
1493-
self.proposal = Proposal::new_imported(header.hash());
1480+
debug_assert_eq!(self.client().block_status(&header.hash().into()), BlockStatus::InChain);
14941481
self.broadcast_proposal_block(self.view, block);
14951482
}
14961483

@@ -1799,13 +1786,21 @@ impl Worker {
17991786
proposed_view,
18001787
author_view
18011788
);
1802-
self.proposal = Proposal::new_imported(header_view.hash());
1803-
} else {
1804-
self.proposal = Proposal::new_received(header_view.hash(), bytes.clone(), signature);
1789+
} else if Some(priority_info.priority())
1790+
>= self
1791+
.votes
1792+
.get_highest_priority_info(self.current_sortition_round())
1793+
.map(|priority_info| priority_info.priority())
1794+
{
1795+
cdebug!(
1796+
ENGINE,
1797+
"Received a proposal with the priority {}. Replace the highest proposal",
1798+
priority_info.priority()
1799+
);
18051800
}
18061801
self.broadcast_state(
18071802
VoteStep::new(self.height, self.view, self.step.to_step()),
1808-
self.proposal.block_hash(),
1803+
self.votes.get_highest_proposal_summary(self.current_sortition_round()),
18091804
self.last_two_thirds_majority.view(),
18101805
self.votes_received.borrow_anyway(),
18111806
);
@@ -1862,9 +1857,12 @@ impl Worker {
18621857
|| self.view < peer_vote_step.view
18631858
|| self.height < peer_vote_step.height;
18641859

1865-
let need_proposal = self.need_proposal();
1866-
if need_proposal && peer_has_proposal {
1867-
self.send_request_proposal(token, self.height, self.view, &result);
1860+
let is_not_commit_step = !self.step.is_commit();
1861+
let peer_has_higher =
1862+
self.votes.get_highest_priority(peer_vote_step.into()) < peer_proposal.map(|summary| summary.priority());
1863+
1864+
if is_not_commit_step && peer_has_proposal && peer_has_higher {
1865+
self.send_request_proposal(token, self.current_sortition_round(), &result);
18681866
}
18691867

18701868
let current_step = current_vote_step.step;
@@ -1945,20 +1943,15 @@ impl Worker {
19451943
return
19461944
}
19471945

1948-
if request_height == self.height && request_view > self.view {
1949-
return
1950-
}
1951-
1952-
if let Some((signature, _signer_index, block)) = self.first_proposal_at(request_height, request_view) {
1953-
ctrace!(ENGINE, "Send proposal {}-{} to {:?}", request_height, request_view, token);
1954-
self.send_proposal_block(signature, request_view, block, result);
1955-
return
1956-
}
1957-
1958-
if request_height == self.height && request_view == self.view {
1959-
if let Proposal::ProposalReceived(_hash, block, signature) = &self.proposal {
1960-
self.send_proposal_block(*signature, request_view, block.clone(), result);
1961-
}
1946+
if let Some((signature, highest_priority_info, block)) = self.highest_proposal_at(requested_round) {
1947+
ctrace!(
1948+
ENGINE,
1949+
"Send proposal of priority {:?} in a round {:?} to {:?}",
1950+
highest_priority_info.priority(),
1951+
requested_round,
1952+
token
1953+
);
1954+
self.send_proposal_block(signature, highest_priority_info, requested_round.view, block, result);
19621955
}
19631956
}
19641957

@@ -2155,8 +2148,6 @@ impl Worker {
21552148
}
21562149
}
21572150

2158-
// Since we don't have proposal vote, set proposal = None
2159-
self.proposal = Proposal::None;
21602151
self.view = commit_view;
21612152
self.votes_received = MutTrigger::new(vote_bitset);
21622153
self.last_two_thirds_majority = TwoThirdsMajority::Empty;

0 commit comments

Comments
 (0)