@@ -137,8 +137,6 @@ pub(crate) struct SingleHeightConsensus {
137137 timeouts : TimeoutsConfig ,
138138 state_machine : StateMachine ,
139139 proposals : HashMap < Round , Option < ProposalCommitment > > ,
140- prevotes : HashMap < ( Round , ValidatorId ) , Vote > ,
141- precommits : HashMap < ( Round , ValidatorId ) , Vote > ,
142140 last_prevote : Option < Vote > ,
143141 last_precommit : Option < Vote > ,
144142}
@@ -161,8 +159,6 @@ impl SingleHeightConsensus {
161159 timeouts,
162160 state_machine,
163161 proposals : HashMap :: new ( ) ,
164- prevotes : HashMap :: new ( ) ,
165- precommits : HashMap :: new ( ) ,
166162 last_prevote : None ,
167163 last_precommit : None ,
168164 }
@@ -254,7 +250,7 @@ impl SingleHeightConsensus {
254250 context. broadcast ( last_vote. clone ( ) ) . await ?;
255251 Ok ( ShcReturn :: Tasks ( vec ! [ ShcTask :: Prevote (
256252 self . timeouts. get_prevote_timeout( 0 ) ,
257- StateMachineEvent :: Prevote ( last_vote . clone ( ) ) ,
253+ StateMachineEvent :: Prevote ( vote ) ,
258254 ) ] ) )
259255 }
260256 StateMachineEvent :: Precommit ( vote) => {
@@ -271,7 +267,7 @@ impl SingleHeightConsensus {
271267 context. broadcast ( last_vote. clone ( ) ) . await ?;
272268 Ok ( ShcReturn :: Tasks ( vec ! [ ShcTask :: Precommit (
273269 self . timeouts. get_precommit_timeout( 0 ) ,
274- StateMachineEvent :: Precommit ( last_vote . clone ( ) ) ,
270+ StateMachineEvent :: Precommit ( vote ) ,
275271 ) ] ) )
276272 }
277273 StateMachineEvent :: Proposal ( proposal_id, round, valid_round) => {
@@ -349,29 +345,27 @@ impl SingleHeightConsensus {
349345 return Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) ) ;
350346 }
351347
352- let ( votes, sm_vote) = match vote. vote_type {
353- VoteType :: Prevote => ( & mut self . prevotes , StateMachineEvent :: Prevote ( vote. clone ( ) ) ) ,
348+ // Check duplicates/conflicts from SM stored votes.
349+ let ( votes_map, sm_vote) = match vote. vote_type {
350+ VoteType :: Prevote => {
351+ ( self . state_machine . prevotes_ref ( ) , StateMachineEvent :: Prevote ( vote. clone ( ) ) )
352+ }
354353 VoteType :: Precommit => {
355- ( & mut self . precommits , StateMachineEvent :: Precommit ( vote. clone ( ) ) )
354+ ( self . state_machine . precommits_ref ( ) , StateMachineEvent :: Precommit ( vote. clone ( ) ) )
356355 }
357356 } ;
358-
359- match votes. entry ( ( vote. round , vote. voter ) ) {
360- Entry :: Vacant ( entry) => {
361- entry. insert ( vote. clone ( ) ) ;
362- }
363- Entry :: Occupied ( entry) => {
364- let old = entry. get ( ) ;
365- if old. proposal_commitment != vote. proposal_commitment {
366- warn ! ( "Conflicting votes: old={:?}, new={:?}" , old, vote) ;
367- CONSENSUS_CONFLICTING_VOTES . increment ( 1 ) ;
368- return Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) ) ;
369- } else {
370- // Replay, ignore.
371- return Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) ) ;
372- }
357+ if let Some ( ( old_vote, _) ) = votes_map. get ( & ( vote. round , vote. voter ) ) {
358+ if old_vote. proposal_commitment == vote. proposal_commitment {
359+ // Duplicate - ignore.
360+ return Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) ) ;
361+ } else {
362+ // Conflict - ignore and record.
363+ warn ! ( "Conflicting votes: old={old_vote:?}, new={vote:?}" ) ;
364+ CONSENSUS_CONFLICTING_VOTES . increment ( 1 ) ;
365+ return Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) ) ;
373366 }
374367 }
368+
375369 info ! ( "Accepting {:?}" , vote) ;
376370 let height = self . state_machine . height ( ) ;
377371 let leader_fn = |round : Round | -> ValidatorId { context. proposer ( height, round) } ;
@@ -502,29 +496,24 @@ impl SingleHeightConsensus {
502496 context : & mut ContextT ,
503497 vote : Vote ,
504498 ) -> Result < Vec < ShcTask > , ConsensusError > {
505- let prevote_timeout = self . timeouts . get_prevote_timeout ( vote. round ) ;
506- let precommit_timeout = self . timeouts . get_precommit_timeout ( vote. round ) ;
507- let ( votes, last_vote, task) = match vote. vote_type {
499+ let ( last_vote, task) = match vote. vote_type {
508500 VoteType :: Prevote => (
509- & mut self . prevotes ,
510501 & mut self . last_prevote ,
511- ShcTask :: Prevote ( prevote_timeout, StateMachineEvent :: Prevote ( vote. clone ( ) ) ) ,
502+ ShcTask :: Prevote (
503+ self . timeouts . get_prevote_timeout ( 0 ) ,
504+ StateMachineEvent :: Prevote ( vote. clone ( ) ) ,
505+ ) ,
512506 ) ,
513507 VoteType :: Precommit => (
514- & mut self . precommits ,
515508 & mut self . last_precommit ,
516- ShcTask :: Precommit ( precommit_timeout, StateMachineEvent :: Precommit ( vote. clone ( ) ) ) ,
509+ ShcTask :: Precommit (
510+ self . timeouts . get_precommit_timeout ( 0 ) ,
511+ StateMachineEvent :: Precommit ( vote. clone ( ) ) ,
512+ ) ,
517513 ) ,
518514 } ;
519515 // Ensure the voter matches this node.
520516 assert_eq ! ( vote. voter, self . state_machine. validator_id( ) ) ;
521- if let Some ( old) =
522- votes. insert ( ( vote. round , self . state_machine . validator_id ( ) ) , vote. clone ( ) )
523- {
524- return Err ( ConsensusError :: InternalInconsistency ( format ! (
525- "State machine should not send repeat votes: old={old:?}, new={vote:?}"
526- ) ) ) ;
527- }
528517 * last_vote = match last_vote {
529518 None => Some ( vote. clone ( ) ) ,
530519 Some ( last_vote) if vote. round > last_vote. round => Some ( vote. clone ( ) ) ,
@@ -569,18 +558,7 @@ impl SingleHeightConsensus {
569558 {block}"
570559 ) ) ) ;
571560 }
572- let supporting_precommits: Vec < Vote > = self
573- . validators
574- . iter ( )
575- . filter_map ( |v| {
576- let vote = self . precommits . get ( & ( round, * v) ) ?;
577- if vote. proposal_commitment == Some ( proposal_id) {
578- Some ( vote. clone ( ) )
579- } else {
580- None
581- }
582- } )
583- . collect ( ) ;
561+ let supporting_precommits = self . precommit_votes_for_value ( round, Some ( proposal_id) ) ;
584562
585563 // TODO(matan): Check actual weights.
586564 let vote_weight = u64:: try_from ( supporting_precommits. len ( ) )
@@ -596,4 +574,18 @@ impl SingleHeightConsensus {
596574 }
597575 Ok ( ShcReturn :: Decision ( Decision { precommits : supporting_precommits, block } ) )
598576 }
577+
578+ fn precommit_votes_for_value (
579+ & self ,
580+ round : Round ,
581+ value : Option < ProposalCommitment > ,
582+ ) -> Vec < Vote > {
583+ self . state_machine
584+ . precommits_ref ( )
585+ . iter ( )
586+ . filter_map ( |( & ( r, _voter) , ( v, _w) ) | {
587+ if r == round && v. proposal_commitment == value { Some ( v. clone ( ) ) } else { None }
588+ } )
589+ . collect ( )
590+ }
599591}
0 commit comments