Removed outdated flag, additional checks and simplified logic. (#4621)

* Removed outdated flag and simplified logic.

* Removed outdated flag and simplified logic.

* Added additional logs.
feature/updated-libp2p-version
Konstantin 10 months ago committed by GitHub
parent ae4ffeb09a
commit 8d5f20f998
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 41
      consensus/consensus_v2.go
  2. 32
      core/blockchain_leader_rotation.go
  3. 43
      core/blockchain_leader_rotation_test.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. // rotateLeader rotates the leader to the next leader in the committee.
// This function must be called with enabled leader rotation. // 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 ( var (
bc = consensus.Blockchain() bc = consensus.Blockchain()
leader = consensus.getLeaderPubKey() leader = consensus.getLeaderPubKey()
@ -687,31 +687,32 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper {
curNumber = curBlock.NumberU64() curNumber = curBlock.NumberU64()
curEpoch = curBlock.Epoch().Uint64() curEpoch = curBlock.Epoch().Uint64()
) )
if epoch.Uint64() != curEpoch {
return defaultKey
}
const blocksCountAliveness = 4 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)) 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) ss, err := bc.ReadShardState(epoch)
if err != nil { if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to read shard state") utils.Logger().Error().Err(err).Msg("Failed to read shard state")
return nil return defaultKey
} }
committee, err := ss.FindCommitteeByID(consensus.ShardID) committee, err := ss.FindCommitteeByID(consensus.ShardID)
if err != nil { if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to find committee") utils.Logger().Error().Err(err).Msg("Failed to find committee")
return nil return defaultKey
} }
slotsCount := len(committee.Slots) slotsCount := len(committee.Slots)
blocksPerEpoch := shard.Schedule.InstanceForEpoch(epoch).BlocksPerEpoch() blocksPerEpoch := shard.Schedule.InstanceForEpoch(epoch).BlocksPerEpoch()
if blocksPerEpoch == 0 { if blocksPerEpoch == 0 {
utils.Logger().Error().Msg("[Rotating leader] blocks per epoch is 0") utils.Logger().Error().Msg("[Rotating leader] blocks per epoch is 0")
return nil return defaultKey
} }
if slotsCount == 0 { if slotsCount == 0 {
utils.Logger().Error().Msg("[Rotating leader] slots count is 0") utils.Logger().Error().Msg("[Rotating leader] slots count is 0")
return nil return defaultKey
} }
numBlocksProducedByLeader := blocksPerEpoch / uint64(slotsCount) numBlocksProducedByLeader := blocksPerEpoch / uint64(slotsCount)
rest := blocksPerEpoch % uint64(slotsCount)
const minimumBlocksForLeaderInRow = blocksCountAliveness const minimumBlocksForLeaderInRow = blocksCountAliveness
if numBlocksProducedByLeader < minimumBlocksForLeaderInRow { if numBlocksProducedByLeader < minimumBlocksForLeaderInRow {
// mine no less than 3 blocks in a row // 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() s := bc.LeaderRotationMeta()
if !bytes.Equal(leader.Bytes[:], s.Pub) { if !bytes.Equal(leader.Bytes[:], s.Pub) {
// Another leader. // Another leader.
return nil return defaultKey
}
// If it is the first validator producing blocks, it should also produce the remaining 'rest' of the blocks.
if s.Shifts == 0 {
numBlocksProducedByLeader += rest
} }
if s.Count < numBlocksProducedByLeader { if s.Count < numBlocksProducedByLeader {
// Not enough blocks produced by the leader, continue producing by the same leader. // Not enough blocks produced by the leader, continue producing by the same leader.
return nil return defaultKey
} }
// Passed all checks, we can change leader. // Passed all checks, we can change leader.
// NthNext will move the leader to the next leader in the committee. // 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 { if !wasFound {
utils.Logger().Error().Msg("Failed to get next leader") utils.Logger().Error().Msg("Failed to get next leader")
// Seems like nothing we can do here. // Seems like nothing we can do here.
return nil return defaultKey
} }
members := consensus.decider.Participants() members := consensus.decider.Participants()
mask := bls.NewMask(members) mask := bls.NewMask(members)
@ -757,7 +754,7 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper {
header := bc.GetHeaderByNumber(curNumber - uint64(i)) header := bc.GetHeaderByNumber(curNumber - uint64(i))
if header == nil { if header == nil {
utils.Logger().Error().Msgf("Failed to get header by number %d", curNumber-uint64(i)) 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 epoch is different, we should not check this block.
if header.Epoch().Uint64() != curEpoch { if header.Epoch().Uint64() != curEpoch {
@ -767,12 +764,12 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper {
err = mask.SetMask(header.LastCommitBitmap()) err = mask.SetMask(header.LastCommitBitmap())
if err != nil { if err != nil {
utils.Logger().Err(err).Msg("Failed to set mask") utils.Logger().Err(err).Msg("Failed to set mask")
return nil return defaultKey
} }
ok, err := mask.KeyEnabled(next.Bytes) ok, err := mask.KeyEnabled(next.Bytes)
if err != nil { if err != nil {
utils.Logger().Err(err).Msg("Failed to get key enabled") utils.Logger().Err(err).Msg("Failed to get key enabled")
return nil return defaultKey
} }
if !ok { if !ok {
skipped++ skipped++
@ -787,14 +784,13 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) *bls.PublicKeyWrapper {
} }
return next return next
} }
return nil return defaultKey
} }
// SetupForNewConsensus sets the state for new consensus // SetupForNewConsensus sets the state for new consensus
func (consensus *Consensus) setupForNewConsensus(blk *types.Block, committedMsg *FBFTMessage) { func (consensus *Consensus) setupForNewConsensus(blk *types.Block, committedMsg *FBFTMessage) {
atomic.StoreUint64(&consensus.blockNum, blk.NumberU64()+1) atomic.StoreUint64(&consensus.blockNum, blk.NumberU64()+1)
consensus.setCurBlockViewID(committedMsg.ViewID + 1) consensus.setCurBlockViewID(committedMsg.ViewID + 1)
consensus.LeaderPubKey = committedMsg.SenderPubkeys[0]
var epoch *big.Int var epoch *big.Int
if blk.IsLastBlockInEpoch() { if blk.IsLastBlockInEpoch() {
epoch = new(big.Int).Add(blk.Epoch(), common.Big1) epoch = new(big.Int).Add(blk.Epoch(), common.Big1)
@ -802,9 +798,14 @@ func (consensus *Consensus) setupForNewConsensus(blk *types.Block, committedMsg
epoch = blk.Epoch() epoch = blk.Epoch()
} }
if consensus.Blockchain().Config().IsLeaderRotationInternalValidators(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() prev := consensus.getLeaderPubKey()
consensus.setLeaderPubKey(next) 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) { if consensus.isLeader() && !consensus.getLeaderPubKey().Object.IsEqual(prev.Object) {
// leader changed // leader changed
blockPeriod := consensus.BlockPeriod blockPeriod := consensus.BlockPeriod

@ -14,10 +14,9 @@ import (
// LeaderRotationMeta contains information about leader rotation // LeaderRotationMeta contains information about leader rotation
type LeaderRotationMeta struct { type LeaderRotationMeta struct {
Pub []byte // bls public key of previous block miner Pub []byte // bls public key of previous block miner
Epoch uint64 // epoch number of previously inserted block Epoch uint64 // epoch number of previously inserted block
Count uint64 // quantity of continuous blocks inserted by the same leader Count uint64 // quantity of continuous blocks inserted by the same leader
Shifts uint64 // number of leader shifts, shift happens when leader changes
} }
// ShortString returns string representation of the struct // 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(strconv.FormatUint(a.Epoch, 10))
s.WriteString(" ") s.WriteString(" ")
s.WriteString(strconv.FormatUint(a.Count, 10)) s.WriteString(strconv.FormatUint(a.Count, 10))
s.WriteString(" ")
s.WriteString(strconv.FormatUint(a.Shifts, 10))
return s.String() return s.String()
} }
@ -39,17 +36,15 @@ func (a LeaderRotationMeta) Hash() []byte {
c.Write(a.Pub) c.Write(a.Pub)
c.Write([]byte(strconv.FormatUint(a.Epoch, 10))) c.Write([]byte(strconv.FormatUint(a.Epoch, 10)))
c.Write([]byte(strconv.FormatUint(a.Count, 10))) c.Write([]byte(strconv.FormatUint(a.Count, 10)))
c.Write([]byte(strconv.FormatUint(a.Shifts, 10)))
return c.Sum(nil) return c.Sum(nil)
} }
// Clone returns a copy of the struct // Clone returns a copy of the struct
func (a LeaderRotationMeta) Clone() LeaderRotationMeta { func (a LeaderRotationMeta) Clone() LeaderRotationMeta {
return LeaderRotationMeta{ return LeaderRotationMeta{
Pub: append([]byte{}, a.Pub...), Pub: append([]byte{}, a.Pub...),
Epoch: a.Epoch, Epoch: a.Epoch,
Count: a.Count, Count: a.Count,
Shifts: a.Shifts,
} }
} }
@ -109,19 +104,10 @@ func processRotationMeta(epoch uint64, blockPubKey bls.SerializedPublicKey, s Le
} else { } else {
s.Count = 1 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 s.Epoch = epoch
return LeaderRotationMeta{ return LeaderRotationMeta{
Pub: blockPubKey[:], Pub: blockPubKey[:],
Epoch: s.Epoch, Epoch: s.Epoch,
Count: s.Count, Count: s.Count,
Shifts: s.Shifts,
} }
} }

@ -12,46 +12,27 @@ var k1 = bls.SerializedPublicKey{1, 2, 3}
func TestRotationMetaProcess(t *testing.T) { func TestRotationMetaProcess(t *testing.T) {
t.Run("same_leader_increase_count", func(t *testing.T) { t.Run("same_leader_increase_count", func(t *testing.T) {
rs := processRotationMeta(1, bls.SerializedPublicKey{}, LeaderRotationMeta{ rs := processRotationMeta(1, bls.SerializedPublicKey{}, LeaderRotationMeta{
Pub: bls.SerializedPublicKey{}.Bytes(), Pub: bls.SerializedPublicKey{}.Bytes(),
Epoch: 1, Epoch: 1,
Count: 1, Count: 1,
Shifts: 1,
}) })
require.Equal(t, LeaderRotationMeta{ require.Equal(t, LeaderRotationMeta{
Pub: bls.SerializedPublicKey{}.Bytes(), Pub: bls.SerializedPublicKey{}.Bytes(),
Epoch: 1, Epoch: 1,
Count: 2, 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,
}, rs) }, rs)
}) })
t.Run("new_epoch_reset_count", func(t *testing.T) { t.Run("new_epoch_reset_count", func(t *testing.T) {
rs := processRotationMeta(2, k1, LeaderRotationMeta{ rs := processRotationMeta(2, k1, LeaderRotationMeta{
Pub: bls.SerializedPublicKey{}.Bytes(), Pub: bls.SerializedPublicKey{}.Bytes(),
Epoch: 1, Epoch: 1,
Count: 1, Count: 1,
Shifts: 1,
}) })
require.Equal(t, LeaderRotationMeta{ require.Equal(t, LeaderRotationMeta{
Pub: k1.Bytes(), Pub: k1.Bytes(),
Epoch: 2, Epoch: 2,
Count: 1, Count: 1,
Shifts: 0,
}, rs) }, rs)
}) })
} }

Loading…
Cancel
Save