Skip to content

Commit

Permalink
Unlock proposed block after bulk sync (#581)
Browse files Browse the repository at this point in the history
* Add unlock after sync and reject the proposed block at incorrect height

* Fixed failing test

* Add comment and improve code readability

* Add IBFT Tests for catch up sequence

* Add comment

* Fix sequence check in AcceptState and unlock during SyncState

* Fix lint error

* Move startNewSequence from insertBlock method to runValidateState to improve code readability

* Add comment

* Fix comment
  • Loading branch information
Kourin1996 authored Jun 14, 2022
1 parent 542a840 commit 6da0978
Show file tree
Hide file tree
Showing 2 changed files with 434 additions and 31 deletions.
77 changes: 56 additions & 21 deletions consensus/ibft/ibft.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,11 +464,6 @@ func (i *Ibft) isValidSnapshot() bool {
}

if snap.Set.Includes(i.validatorKeyAddr) {
i.state.view = &proto.View{
Sequence: header.Number + 1,
Round: 0,
}

return true
}

Expand All @@ -487,6 +482,12 @@ func (i *Ibft) runSyncState() {
}
}

// save current height in order to check new blocks are added or not during sync
beginningHeight := uint64(0)
if header := i.blockchain.Header(); header != nil {
beginningHeight = header.Number
}

for i.isState(SyncState) {
// try to sync with the best-suited peer
p := i.syncer.BestPeer()
Expand All @@ -496,11 +497,8 @@ func (i *Ibft) runSyncState() {
// reverted later
if i.isValidSnapshot() {
// initialize the round and sequence
header := i.blockchain.Header()
i.state.view = &proto.View{
Round: 0,
Sequence: header.Number + 1,
}
i.startNewSequence()

//Set the round metric
i.metrics.Rounds.Set(float64(i.state.view.Round))

Expand All @@ -524,6 +522,7 @@ func (i *Ibft) runSyncState() {
// if we are a validator we do not even want to wait here
// we can just move ahead
if i.isValidSnapshot() {
i.startNewSequence()
i.setState(AcceptState)

continue
Expand All @@ -548,9 +547,21 @@ func (i *Ibft) runSyncState() {
// at this point, we are in sync with the latest chain we know of
// and we are a validator of that chain so we need to change to AcceptState
// so that we can start to do some stuff there
i.startNewSequence()
i.setState(AcceptState)
}
}

// check that new blocks are added during sync
endingHeight := uint64(0)
if header := i.blockchain.Header(); header != nil {
endingHeight = header.Number
}

// if new blocks are added, validator will unlock current block
if endingHeight > beginningHeight {
i.state.unlock()
}
}

// shouldWriteTransactions checks if each consensus mechanism accepts a block with transactions at given height
Expand Down Expand Up @@ -847,6 +858,14 @@ func (i *Ibft) runAcceptState() { // start new round
return
}

// Make sure the proposing block height match the current sequence
if block.Number() != i.state.view.Sequence {
i.logger.Error("sequence not correct", "block", block.Number, "sequence", i.state.view.Sequence)
i.handleStateErr(errIncorrectBlockHeight)

return
}

if i.state.locked {
// the state is locked, we need to receive the same block
if block.Hash() == i.state.block.Hash() {
Expand Down Expand Up @@ -964,6 +983,9 @@ func (i *Ibft) runValidateState() {
// update metrics
i.updateMetrics(block)

// increase the sequence number and reset the round if any
i.startNewSequence()

// move ahead to the next block
i.setState(AcceptState)
}
Expand Down Expand Up @@ -1041,12 +1063,6 @@ func (i *Ibft) insertBlock(block *types.Block) error {
"committed", i.state.numCommitted(),
)

// increase the sequence number and reset the round if any
i.state.view = &proto.View{
Sequence: header.Number + 1,
Round: 0,
}

// broadcast the new block
i.syncer.Broadcast(block)

Expand All @@ -1058,9 +1074,10 @@ func (i *Ibft) insertBlock(block *types.Block) error {
}

var (
errIncorrectBlockLocked = fmt.Errorf("block locked is incorrect")
errBlockVerificationFailed = fmt.Errorf("block verification failed")
errFailedToInsertBlock = fmt.Errorf("failed to insert block")
errIncorrectBlockLocked = errors.New("block locked is incorrect")
errIncorrectBlockHeight = errors.New("proposed block number is incorrect")
errBlockVerificationFailed = errors.New("block verification failed")
errFailedToInsertBlock = errors.New("failed to insert block")
)

func (i *Ibft) handleStateErr(err error) {
Expand All @@ -1072,7 +1089,7 @@ func (i *Ibft) runRoundChangeState() {
sendRoundChange := func(round uint64) {
i.logger.Debug("local round change", "round", round+1)
// set the new round and update the round metric
i.state.view.Round = round
i.startNewRound(round)
i.metrics.Rounds.Set(float64(round))
// clean the round
i.state.cleanRound(round)
Expand Down Expand Up @@ -1149,7 +1166,7 @@ func (i *Ibft) runRoundChangeState() {
sendRoundChange(msg.View.Round)
} else if num == i.quorumSize(i.state.view.Sequence)(i.state.validators) {
// start a new round immediately
i.state.view.Round = msg.View.Round
i.startNewRound(msg.View.Round)
i.setState(AcceptState)
}
}
Expand Down Expand Up @@ -1411,3 +1428,21 @@ func (i *Ibft) pushMessage(msg *proto.MessageReq) {
default:
}
}

// startNewSequence changes the sequence and resets the round in the view of state
func (i *Ibft) startNewSequence() {
header := i.blockchain.Header()

i.state.view = &proto.View{
Sequence: header.Number + 1,
Round: 0,
}
}

// startNewRound changes the round in the view of state
func (i *Ibft) startNewRound(newRound uint64) {
i.state.view = &proto.View{
Sequence: i.state.view.Sequence,
Round: newRound,
}
}
Loading

0 comments on commit 6da0978

Please sign in to comment.