diff --git a/consensus/consensus_v2.go b/consensus/consensus_v2.go index f4b8c56f0..9780accb7 100644 --- a/consensus/consensus_v2.go +++ b/consensus/consensus_v2.go @@ -679,7 +679,7 @@ func (consensus *Consensus) commitBlock(blk *types.Block, committedMsg *FBFTMess // rotateLeader rotates the leader to the next leader in the committee. // This function must be called with enabled leader rotation. -func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper { +func (consensus *Consensus) rotateLeader(epoch *big.Int, defaultKey *bls.PublicKeyWrapper) *bls.PublicKeyWrapper { var ( bc = consensus.Blockchain() leader = consensus.getLeaderPubKey() @@ -687,31 +687,32 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper { curNumber = curBlock.NumberU64() curEpoch = curBlock.Epoch().Uint64() ) + if epoch.Uint64() != curEpoch { + return defaultKey + } const blocksCountAliveness = 4 - utils.Logger().Info().Msgf("[Rotating leader] epoch: %v rotation:%v external rotation %v", epoch.Uint64(), bc.Config().IsLeaderRotationInternalValidators(epoch), bc.Config().IsLeaderRotationExternalValidatorsAllowed(epoch)) ss, err := bc.ReadShardState(epoch) if err != nil { utils.Logger().Error().Err(err).Msg("Failed to read shard state") - return nil + return defaultKey } committee, err := ss.FindCommitteeByID(consensus.ShardID) if err != nil { utils.Logger().Error().Err(err).Msg("Failed to find committee") - return nil + return defaultKey } slotsCount := len(committee.Slots) blocksPerEpoch := shard.Schedule.InstanceForEpoch(epoch).BlocksPerEpoch() if blocksPerEpoch == 0 { utils.Logger().Error().Msg("[Rotating leader] blocks per epoch is 0") - return nil + return defaultKey } if slotsCount == 0 { utils.Logger().Error().Msg("[Rotating leader] slots count is 0") - return nil + return defaultKey } numBlocksProducedByLeader := blocksPerEpoch / uint64(slotsCount) - rest := blocksPerEpoch % uint64(slotsCount) const minimumBlocksForLeaderInRow = blocksCountAliveness if numBlocksProducedByLeader < minimumBlocksForLeaderInRow { // mine no less than 3 blocks in a row @@ -720,15 +721,11 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper { s := bc.LeaderRotationMeta() if !bytes.Equal(leader.Bytes[:], s.Pub) { // Another leader. - return nil - } - // If it is the first validator producing blocks, it should also produce the remaining 'rest' of the blocks. - if s.Shifts == 0 { - numBlocksProducedByLeader += rest + return defaultKey } if s.Count < numBlocksProducedByLeader { // Not enough blocks produced by the leader, continue producing by the same leader. - return nil + return defaultKey } // Passed all checks, we can change leader. // NthNext will move the leader to the next leader in the committee. @@ -748,7 +745,7 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper { if !wasFound { utils.Logger().Error().Msg("Failed to get next leader") // Seems like nothing we can do here. - return nil + return defaultKey } members := consensus.decider.Participants() mask := bls.NewMask(members) @@ -757,7 +754,7 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper { header := bc.GetHeaderByNumber(curNumber - uint64(i)) if header == nil { utils.Logger().Error().Msgf("Failed to get header by number %d", curNumber-uint64(i)) - return nil + return defaultKey } // if epoch is different, we should not check this block. if header.Epoch().Uint64() != curEpoch { @@ -767,12 +764,12 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper { err = mask.SetMask(header.LastCommitBitmap()) if err != nil { utils.Logger().Err(err).Msg("Failed to set mask") - return nil + return defaultKey } ok, err := mask.KeyEnabled(next.Bytes) if err != nil { utils.Logger().Err(err).Msg("Failed to get key enabled") - return nil + return defaultKey } if !ok { skipped++ @@ -787,14 +784,13 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper { } return next } - return nil + return defaultKey } // SetupForNewConsensus sets the state for new consensus func (consensus *Consensus) setupForNewConsensus(blk *types.Block, committedMsg *FBFTMessage) { atomic.StoreUint64(&consensus.blockNum, blk.NumberU64()+1) consensus.setCurBlockViewID(committedMsg.ViewID + 1) - consensus.LeaderPubKey = committedMsg.SenderPubkeys[0] var epoch *big.Int if blk.IsLastBlockInEpoch() { epoch = new(big.Int).Add(blk.Epoch(), common.Big1) @@ -802,9 +798,14 @@ func (consensus *Consensus) setupForNewConsensus(blk *types.Block, committedMsg epoch = blk.Epoch() } if consensus.Blockchain().Config().IsLeaderRotationInternalValidators(epoch) { - if next := consensus.rotateLeader(epoch); next != nil { + if next := consensus.rotateLeader(epoch, committedMsg.SenderPubkeys[0]); next != nil { prev := consensus.getLeaderPubKey() consensus.setLeaderPubKey(next) + if consensus.isLeader() { + utils.Logger().Info().Msgf("We are block %d, I am the new leader %s", blk.NumberU64(), next.Bytes.Hex()) + } else { + utils.Logger().Info().Msgf("We are block %d, the leader is %s", blk.NumberU64(), next.Bytes.Hex()) + } if consensus.isLeader() && !consensus.getLeaderPubKey().Object.IsEqual(prev.Object) { // leader changed blockPeriod := consensus.BlockPeriod diff --git a/core/blockchain_leader_rotation.go b/core/blockchain_leader_rotation.go index b7cdef519..8b2683780 100644 --- a/core/blockchain_leader_rotation.go +++ b/core/blockchain_leader_rotation.go @@ -14,10 +14,9 @@ import ( // LeaderRotationMeta contains information about leader rotation type LeaderRotationMeta struct { - Pub []byte // bls public key of previous block miner - Epoch uint64 // epoch number of previously inserted block - Count uint64 // quantity of continuous blocks inserted by the same leader - Shifts uint64 // number of leader shifts, shift happens when leader changes + Pub []byte // bls public key of previous block miner + Epoch uint64 // epoch number of previously inserted block + Count uint64 // quantity of continuous blocks inserted by the same leader } // ShortString returns string representation of the struct @@ -28,8 +27,6 @@ func (a LeaderRotationMeta) ShortString() string { s.WriteString(strconv.FormatUint(a.Epoch, 10)) s.WriteString(" ") s.WriteString(strconv.FormatUint(a.Count, 10)) - s.WriteString(" ") - s.WriteString(strconv.FormatUint(a.Shifts, 10)) return s.String() } @@ -39,17 +36,15 @@ func (a LeaderRotationMeta) Hash() []byte { c.Write(a.Pub) c.Write([]byte(strconv.FormatUint(a.Epoch, 10))) c.Write([]byte(strconv.FormatUint(a.Count, 10))) - c.Write([]byte(strconv.FormatUint(a.Shifts, 10))) return c.Sum(nil) } // Clone returns a copy of the struct func (a LeaderRotationMeta) Clone() LeaderRotationMeta { return LeaderRotationMeta{ - Pub: append([]byte{}, a.Pub...), - Epoch: a.Epoch, - Count: a.Count, - Shifts: a.Shifts, + Pub: append([]byte{}, a.Pub...), + Epoch: a.Epoch, + Count: a.Count, } } @@ -109,19 +104,10 @@ func processRotationMeta(epoch uint64, blockPubKey bls.SerializedPublicKey, s Le } else { s.Count = 1 } - // we should increase shifts if the leader has changed. - if !bytes.Equal(s.Pub, blockPubKey[:]) { - s.Shifts++ - } - // but set to zero if new - if s.Epoch != epoch { - s.Shifts = 0 - } s.Epoch = epoch return LeaderRotationMeta{ - Pub: blockPubKey[:], - Epoch: s.Epoch, - Count: s.Count, - Shifts: s.Shifts, + Pub: blockPubKey[:], + Epoch: s.Epoch, + Count: s.Count, } } diff --git a/core/blockchain_leader_rotation_test.go b/core/blockchain_leader_rotation_test.go index 047dbdd63..e964d39d7 100644 --- a/core/blockchain_leader_rotation_test.go +++ b/core/blockchain_leader_rotation_test.go @@ -12,46 +12,27 @@ var k1 = bls.SerializedPublicKey{1, 2, 3} func TestRotationMetaProcess(t *testing.T) { t.Run("same_leader_increase_count", func(t *testing.T) { rs := processRotationMeta(1, bls.SerializedPublicKey{}, LeaderRotationMeta{ - Pub: bls.SerializedPublicKey{}.Bytes(), - Epoch: 1, - Count: 1, - Shifts: 1, + Pub: bls.SerializedPublicKey{}.Bytes(), + Epoch: 1, + Count: 1, }) require.Equal(t, LeaderRotationMeta{ - Pub: bls.SerializedPublicKey{}.Bytes(), - Epoch: 1, - Count: 2, - Shifts: 1, - }, rs) - }) - - t.Run("new_leader_increase_shifts", func(t *testing.T) { - rs := processRotationMeta(1, k1, LeaderRotationMeta{ - Pub: bls.SerializedPublicKey{}.Bytes(), - Epoch: 1, - Count: 1, - Shifts: 1, - }) - require.Equal(t, LeaderRotationMeta{ - Pub: k1.Bytes(), - Epoch: 1, - Count: 1, - Shifts: 2, + Pub: bls.SerializedPublicKey{}.Bytes(), + Epoch: 1, + Count: 2, }, rs) }) t.Run("new_epoch_reset_count", func(t *testing.T) { rs := processRotationMeta(2, k1, LeaderRotationMeta{ - Pub: bls.SerializedPublicKey{}.Bytes(), - Epoch: 1, - Count: 1, - Shifts: 1, + Pub: bls.SerializedPublicKey{}.Bytes(), + Epoch: 1, + Count: 1, }) require.Equal(t, LeaderRotationMeta{ - Pub: k1.Bytes(), - Epoch: 2, - Count: 1, - Shifts: 0, + Pub: k1.Bytes(), + Epoch: 2, + Count: 1, }, rs) }) }