@@ -139,8 +139,6 @@ pub(crate) struct SingleHeightConsensus {
139139 timeouts : TimeoutsConfig ,
140140 state_machine : StateMachine ,
141141 proposals : HashMap < Round , Option < ProposalCommitment > > ,
142- prevotes : HashMap < ( Round , ValidatorId ) , Vote > ,
143- precommits : HashMap < ( Round , ValidatorId ) , Vote > ,
144142 last_prevote : Option < Vote > ,
145143 last_precommit : Option < Vote > ,
146144 height_voted_storage : Arc < Mutex < dyn HeightVotedStorageTrait > > ,
@@ -165,8 +163,6 @@ impl SingleHeightConsensus {
165163 timeouts,
166164 state_machine,
167165 proposals : HashMap :: new ( ) ,
168- prevotes : HashMap :: new ( ) ,
169- precommits : HashMap :: new ( ) ,
170166 last_prevote : None ,
171167 last_precommit : None ,
172168 height_voted_storage,
@@ -259,7 +255,7 @@ impl SingleHeightConsensus {
259255 context. broadcast ( last_vote. clone ( ) ) . await ?;
260256 Ok ( ShcReturn :: Tasks ( vec ! [ ShcTask :: Prevote (
261257 self . timeouts. get_prevote_timeout( 0 ) ,
262- StateMachineEvent :: Prevote ( last_vote . clone ( ) ) ,
258+ StateMachineEvent :: Prevote ( vote ) ,
263259 ) ] ) )
264260 }
265261 StateMachineEvent :: Precommit ( vote) => {
@@ -276,7 +272,7 @@ impl SingleHeightConsensus {
276272 context. broadcast ( last_vote. clone ( ) ) . await ?;
277273 Ok ( ShcReturn :: Tasks ( vec ! [ ShcTask :: Precommit (
278274 self . timeouts. get_precommit_timeout( 0 ) ,
279- StateMachineEvent :: Precommit ( last_vote . clone ( ) ) ,
275+ StateMachineEvent :: Precommit ( vote ) ,
280276 ) ] ) )
281277 }
282278 StateMachineEvent :: Proposal ( proposal_id, round, valid_round) => {
@@ -354,29 +350,27 @@ impl SingleHeightConsensus {
354350 return Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) ) ;
355351 }
356352
357- let ( votes, sm_vote) = match vote. vote_type {
358- VoteType :: Prevote => ( & mut self . prevotes , StateMachineEvent :: Prevote ( vote. clone ( ) ) ) ,
353+ // Check duplicates/conflicts from SM stored votes.
354+ let ( votes_map, sm_vote) = match vote. vote_type {
355+ VoteType :: Prevote => {
356+ ( self . state_machine . prevotes_ref ( ) , StateMachineEvent :: Prevote ( vote. clone ( ) ) )
357+ }
359358 VoteType :: Precommit => {
360- ( & mut self . precommits , StateMachineEvent :: Precommit ( vote. clone ( ) ) )
359+ ( self . state_machine . precommits_ref ( ) , StateMachineEvent :: Precommit ( vote. clone ( ) ) )
361360 }
362361 } ;
363-
364- match votes. entry ( ( vote. round , vote. voter ) ) {
365- Entry :: Vacant ( entry) => {
366- entry. insert ( vote. clone ( ) ) ;
367- }
368- Entry :: Occupied ( entry) => {
369- let old = entry. get ( ) ;
370- if old. proposal_commitment != vote. proposal_commitment {
371- warn ! ( "Conflicting votes: old={:?}, new={:?}" , old, vote) ;
372- CONSENSUS_CONFLICTING_VOTES . increment ( 1 ) ;
373- return Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) ) ;
374- } else {
375- // Replay, ignore.
376- return Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) ) ;
377- }
362+ if let Some ( ( old_vote, _) ) = votes_map. get ( & ( vote. round , vote. voter ) ) {
363+ if old_vote. proposal_commitment == vote. proposal_commitment {
364+ // Duplicate - ignore.
365+ return Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) ) ;
366+ } else {
367+ // Conflict - ignore and record.
368+ warn ! ( "Conflicting votes: old={old_vote:?}, new={vote:?}" ) ;
369+ CONSENSUS_CONFLICTING_VOTES . increment ( 1 ) ;
370+ return Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) ) ;
378371 }
379372 }
373+
380374 info ! ( "Accepting {:?}" , vote) ;
381375 let height = self . state_machine . height ( ) ;
382376 let leader_fn = |round : Round | -> ValidatorId { context. proposer ( height, round) } ;
@@ -507,29 +501,24 @@ impl SingleHeightConsensus {
507501 context : & mut ContextT ,
508502 vote : Vote ,
509503 ) -> Result < Vec < ShcTask > , ConsensusError > {
510- let prevote_timeout = self . timeouts . get_prevote_timeout ( vote. round ) ;
511- let precommit_timeout = self . timeouts . get_precommit_timeout ( vote. round ) ;
512- let ( votes, last_vote, task) = match vote. vote_type {
504+ let ( last_vote, task) = match vote. vote_type {
513505 VoteType :: Prevote => (
514- & mut self . prevotes ,
515506 & mut self . last_prevote ,
516- ShcTask :: Prevote ( prevote_timeout, StateMachineEvent :: Prevote ( vote. clone ( ) ) ) ,
507+ ShcTask :: Prevote (
508+ self . timeouts . get_prevote_timeout ( 0 ) ,
509+ StateMachineEvent :: Prevote ( vote. clone ( ) ) ,
510+ ) ,
517511 ) ,
518512 VoteType :: Precommit => (
519- & mut self . precommits ,
520513 & mut self . last_precommit ,
521- ShcTask :: Precommit ( precommit_timeout, StateMachineEvent :: Precommit ( vote. clone ( ) ) ) ,
514+ ShcTask :: Precommit (
515+ self . timeouts . get_precommit_timeout ( 0 ) ,
516+ StateMachineEvent :: Precommit ( vote. clone ( ) ) ,
517+ ) ,
522518 ) ,
523519 } ;
524520 // Ensure the voter matches this node.
525521 assert_eq ! ( vote. voter, self . state_machine. validator_id( ) ) ;
526- if let Some ( old) =
527- votes. insert ( ( vote. round , self . state_machine . validator_id ( ) ) , vote. clone ( ) )
528- {
529- return Err ( ConsensusError :: InternalInconsistency ( format ! (
530- "State machine should not send repeat votes: old={old:?}, new={vote:?}"
531- ) ) ) ;
532- }
533522 * last_vote = match last_vote {
534523 None => Some ( vote. clone ( ) ) ,
535524 Some ( last_vote) if vote. round > last_vote. round => Some ( vote. clone ( ) ) ,
@@ -583,18 +572,7 @@ impl SingleHeightConsensus {
583572 {block}"
584573 ) ) ) ;
585574 }
586- let supporting_precommits: Vec < Vote > = self
587- . validators
588- . iter ( )
589- . filter_map ( |v| {
590- let vote = self . precommits . get ( & ( round, * v) ) ?;
591- if vote. proposal_commitment == Some ( proposal_id) {
592- Some ( vote. clone ( ) )
593- } else {
594- None
595- }
596- } )
597- . collect ( ) ;
575+ let supporting_precommits = self . precommit_votes_for_value ( round, Some ( proposal_id) ) ;
598576
599577 // TODO(matan): Check actual weights.
600578 let vote_weight = u64:: try_from ( supporting_precommits. len ( ) )
@@ -610,4 +588,18 @@ impl SingleHeightConsensus {
610588 }
611589 Ok ( ShcReturn :: Decision ( Decision { precommits : supporting_precommits, block } ) )
612590 }
591+
592+ fn precommit_votes_for_value (
593+ & self ,
594+ round : Round ,
595+ value : Option < ProposalCommitment > ,
596+ ) -> Vec < Vote > {
597+ self . state_machine
598+ . precommits_ref ( )
599+ . iter ( )
600+ . filter_map ( |( & ( r, _voter) , ( v, _w) ) | {
601+ if r == round && v. proposal_commitment == value { Some ( v. clone ( ) ) } else { None }
602+ } )
603+ . collect ( )
604+ }
613605}
0 commit comments