@@ -99,6 +99,9 @@ pub(crate) struct StateMachine {
9999 prevote_quorum : HashSet < Round > ,
100100 mixed_prevote_quorum : HashSet < Round > ,
101101 mixed_precommit_quorum : HashSet < Round > ,
102+ // Tracks the latest self votes for efficient rebroadcasts.
103+ last_self_prevote : Option < Vote > ,
104+ last_self_precommit : Option < Vote > ,
102105}
103106
104107impl StateMachine {
@@ -131,6 +134,8 @@ impl StateMachine {
131134 prevote_quorum : HashSet :: new ( ) ,
132135 mixed_prevote_quorum : HashSet :: new ( ) ,
133136 mixed_precommit_quorum : HashSet :: new ( ) ,
137+ last_self_prevote : None ,
138+ last_self_precommit : None ,
134139 }
135140 }
136141
@@ -170,13 +175,37 @@ impl StateMachine {
170175 self . proposals . get ( & round) . and_then ( |( id, _) | * id)
171176 }
172177
178+ pub ( crate ) fn last_self_prevote ( & self ) -> Option < Vote > {
179+ self . last_self_prevote . clone ( )
180+ }
181+
182+ pub ( crate ) fn last_self_precommit ( & self ) -> Option < Vote > {
183+ self . last_self_precommit . clone ( )
184+ }
185+
173186 fn make_self_vote (
174- & self ,
187+ & mut self ,
175188 vote_type : VoteType ,
176- round : Round ,
177189 proposal_commitment : Option < ProposalCommitment > ,
178190 ) -> Vote {
179- Vote { vote_type, height : self . height . 0 , round, proposal_commitment, voter : self . id }
191+ let vote = Vote {
192+ vote_type,
193+ height : self . height . 0 ,
194+ round : self . round ,
195+ proposal_commitment,
196+ voter : self . id ,
197+ } ;
198+ // update the latest self vote.
199+ let last_self_vote = match vote_type {
200+ VoteType :: Prevote => & mut self . last_self_prevote ,
201+ VoteType :: Precommit => & mut self . last_self_precommit ,
202+ } ;
203+ assert ! (
204+ last_self_vote. as_ref( ) . is_none_or( |last| self . round > last. round) ,
205+ "State machine must progress in time: last_vote: {last_self_vote:?} new_vote: {vote:?}"
206+ ) ;
207+ * last_self_vote = Some ( vote. clone ( ) ) ;
208+ vote
180209 }
181210
182211 /// Starts the state machine, effectively calling `StartRound(0)` from the paper. This is
@@ -338,7 +367,7 @@ impl StateMachine {
338367 round={round}."
339368 ) ;
340369 CONSENSUS_TIMEOUTS . increment ( 1 , & [ ( LABEL_NAME_TIMEOUT_TYPE , TimeoutType :: Propose . into ( ) ) ] ) ;
341- let vote = self . make_self_vote ( VoteType :: Prevote , round , None ) ;
370+ let vote = self . make_self_vote ( VoteType :: Prevote , None ) ;
342371 let mut output = VecDeque :: from ( [ StateMachineEvent :: Prevote ( vote) ] ) ;
343372 output. append ( & mut self . advance_to_step ( Step :: Prevote ) ) ;
344373 output
@@ -370,7 +399,7 @@ impl StateMachine {
370399 } ;
371400 debug ! ( "Applying TimeoutPrevote for round={round}." ) ;
372401 CONSENSUS_TIMEOUTS . increment ( 1 , & [ ( LABEL_NAME_TIMEOUT_TYPE , TimeoutType :: Prevote . into ( ) ) ] ) ;
373- let vote = self . make_self_vote ( VoteType :: Precommit , round , None ) ;
402+ let vote = self . make_self_vote ( VoteType :: Precommit , None ) ;
374403 let mut output = VecDeque :: from ( [ StateMachineEvent :: Precommit ( vote) ] ) ;
375404 output. append ( & mut self . advance_to_step ( Step :: Precommit ) ) ;
376405 output
@@ -518,7 +547,7 @@ impl StateMachine {
518547 } else {
519548 None
520549 } ;
521- let vote = self . make_self_vote ( VoteType :: Prevote , self . round , vote_commitment) ;
550+ let vote = self . make_self_vote ( VoteType :: Prevote , vote_commitment) ;
522551 let mut output = VecDeque :: from ( [ StateMachineEvent :: Prevote ( vote) ] ) ;
523552 output. append ( & mut self . advance_to_step ( Step :: Prevote ) ) ;
524553 output
@@ -550,7 +579,7 @@ impl StateMachine {
550579 } else {
551580 None
552581 } ;
553- let vote = self . make_self_vote ( VoteType :: Prevote , self . round , vote_commitment) ;
582+ let vote = self . make_self_vote ( VoteType :: Prevote , vote_commitment) ;
554583 let mut output = VecDeque :: from ( [ StateMachineEvent :: Prevote ( vote) ] ) ;
555584 output. append ( & mut self . advance_to_step ( Step :: Prevote ) ) ;
556585 output
@@ -600,7 +629,7 @@ impl StateMachine {
600629 CONSENSUS_NEW_VALUE_LOCKS . increment ( 1 ) ;
601630 }
602631 self . locked_value_round = new_value;
603- let vote = self . make_self_vote ( VoteType :: Precommit , self . round , Some ( * proposal_id) ) ;
632+ let vote = self . make_self_vote ( VoteType :: Precommit , Some ( * proposal_id) ) ;
604633 let mut output = VecDeque :: from ( [ StateMachineEvent :: Precommit ( vote) ] ) ;
605634 output. append ( & mut self . advance_to_step ( Step :: Precommit ) ) ;
606635 output
@@ -614,7 +643,7 @@ impl StateMachine {
614643 if !self . value_has_enough_votes ( & self . prevotes , self . round , & None , & self . quorum ) {
615644 return VecDeque :: new ( ) ;
616645 }
617- let vote = self . make_self_vote ( VoteType :: Precommit , self . round , None ) ;
646+ let vote = self . make_self_vote ( VoteType :: Precommit , None ) ;
618647 let mut output = VecDeque :: from ( [ StateMachineEvent :: Precommit ( vote) ] ) ;
619648 output. append ( & mut self . advance_to_step ( Step :: Precommit ) ) ;
620649 output
0 commit comments