@@ -25,6 +25,7 @@ import (
2525
2626 "github.com/ethereum/go-ethereum/common"
2727 "github.com/ethereum/go-ethereum/consensus/istanbul"
28+ "github.com/ethereum/go-ethereum/core/types"
2829 "github.com/ethereum/go-ethereum/event"
2930 "github.com/ethereum/go-ethereum/log"
3031 metrics "github.com/ethereum/go-ethereum/metrics"
@@ -171,6 +172,7 @@ func (c *core) commit() {
171172 }
172173
173174 if err := c .backend .Commit (proposal , committedSeals ); err != nil {
175+ c .current .UnlockHash () //Unlock block when insertion fails
174176 c .sendNextRoundChange ()
175177 return
176178 }
@@ -203,13 +205,21 @@ func (c *core) startNewRound(newView *istanbul.View, lastProposal istanbul.Propo
203205 // Clear invalid ROUND CHANGE messages
204206 c .roundChangeSet = newRoundChangeSet (c .valSet )
205207 // New snapshot for new round
206- c .current = newRoundState (newView , c .valSet )
208+ c .updateRoundState (newView , c .valSet , roundChange )
207209 // Calculate new proposer
208210 c .valSet .CalcProposer (c .lastProposer , newView .Round .Uint64 ())
209211 c .waitingForRoundChange = false
210212 c .setState (StateAcceptRequest )
211213 if roundChange && c .isProposer () {
212- c .backend .NextRound ()
214+ // If it is locked, propose the old proposal
215+ if c .current != nil && c .current .IsHashLocked () {
216+ r := & istanbul.Request {
217+ Proposal : c .current .Proposal (), //c.current.Proposal would be the locked proposal by previous proposer, see updateRoundState
218+ }
219+ c .sendPreprepare (r )
220+ } else {
221+ c .backend .NextRound ()
222+ }
213223 }
214224 c .newRoundChangeTimer ()
215225
@@ -223,13 +233,25 @@ func (c *core) catchUpRound(view *istanbul.View) {
223233 c .roundMeter .Mark (new (big.Int ).Sub (view .Round , c .current .Round ()).Int64 ())
224234 }
225235 c .waitingForRoundChange = true
226- c .current = newRoundState (view , c .valSet )
236+
237+ // Need to keep block locked for round catching up
238+ c .updateRoundState (view , c .valSet , true )
227239 c .roundChangeSet .Clear (view .Round )
228240 c .newRoundChangeTimer ()
229241
230242 logger .Trace ("Catch up round" , "new_round" , view .Round , "new_seq" , view .Sequence , "new_proposer" , c .valSet )
231243}
232244
245+ // updateRoundState updates round state by checking if locking block is necessary
246+ func (c * core ) updateRoundState (view * istanbul.View , validatorSet istanbul.ValidatorSet , roundChange bool ) {
247+ // Lock only if both roundChange is true and it is locked
248+ if roundChange && c .current != nil && c .current .IsHashLocked () {
249+ c .current = newRoundState (view , validatorSet , c .current .GetLockedHash (), c .current .Preprepare )
250+ } else {
251+ c .current = newRoundState (view , validatorSet , common.Hash {}, nil )
252+ }
253+ }
254+
233255func (c * core ) setState (state State ) {
234256 if c .state != state {
235257 c .state = state
0 commit comments