diff --git a/consensus/quorum/quorum.go b/consensus/quorum/quorum.go index 6f9c68678..f41d47ec1 100644 --- a/consensus/quorum/quorum.go +++ b/consensus/quorum/quorum.go @@ -10,6 +10,7 @@ import ( bls_core "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/consensus/votepower" bls_cosi "github.com/harmony-one/harmony/crypto/bls" + shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding" "github.com/harmony-one/harmony/multibls" "github.com/harmony-one/harmony/numeric" "github.com/harmony-one/harmony/shard" @@ -73,6 +74,7 @@ type ParticipantTracker interface { IndexOf(bls.SerializedPublicKey) int ParticipantsCount() int64 NthNext(*bls.PublicKeyWrapper, int) (bool, *bls.PublicKeyWrapper) + NthNextHmy(shardingconfig.Instance, *bls.PublicKeyWrapper, int) (bool, *bls.PublicKeyWrapper) UpdateParticipants(pubKeys []bls.PublicKeyWrapper) } @@ -214,7 +216,29 @@ func (s *cIdentities) NthNext(pubKey *bls.PublicKeyWrapper, next int) (bool, *bl if idx != -1 { found = true } - idx = (idx + next) % int(s.ParticipantsCount()) + numNodes := int(s.ParticipantsCount()) + // sanity check to avoid out of bound access + if numNodes <= 0 || numNodes > len(s.publicKeys) { + numNodes = len(s.publicKeys) + } + idx = (idx + next) % numNodes + return found, &s.publicKeys[idx] +} + +// NthNextHmy return the Nth next pubkey of Harmony nodes, next can be negative number +func (s *cIdentities) NthNextHmy(instance shardingconfig.Instance, pubKey *bls.PublicKeyWrapper, next int) (bool, *bls.PublicKeyWrapper) { + found := false + + idx := s.IndexOf(pubKey.Bytes) + if idx != -1 { + found = true + } + numNodes := instance.NumHarmonyOperatedNodesPerShard() + // sanity check to avoid out of bound access + if numNodes <= 0 || numNodes > len(s.publicKeys) { + numNodes = len(s.publicKeys) + } + idx = (idx + next) % numNodes return found, &s.publicKeys[idx] } diff --git a/consensus/view_change.go b/consensus/view_change.go index 8c41cb4b6..1167d1870 100644 --- a/consensus/view_change.go +++ b/consensus/view_change.go @@ -1,6 +1,7 @@ package consensus import ( + "math/big" "sync" "time" @@ -13,6 +14,7 @@ import ( nodeconfig "github.com/harmony-one/harmony/internal/configs/node" "github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/p2p" + "github.com/harmony-one/harmony/shard" "github.com/pkg/errors" ) @@ -159,6 +161,7 @@ func (consensus *Consensus) getNextLeaderKey(viewID uint64) *bls.PublicKeyWrappe } var lastLeaderPubKey *bls.PublicKeyWrapper var err error + epoch := big.NewInt(0) if consensus.ChainReader == nil { consensus.getLogger().Error().Msg("[getNextLeaderKey] ChainReader is nil. Use consensus.LeaderPubKey") lastLeaderPubKey = consensus.LeaderPubKey @@ -175,6 +178,7 @@ func (consensus *Consensus) getNextLeaderKey(viewID uint64) *bls.PublicKeyWrappe Msg("[getNextLeaderKey] Unable to get leaderPubKey from coinbase. Set it to consensus.LeaderPubKey") lastLeaderPubKey = consensus.LeaderPubKey } + epoch = curHeader.Epoch() // viewchange happened at the first block of new epoch // use the LeaderPubKey as the base of the next leader // as we shouldn't use lastLeader from coinbase as the base. @@ -192,7 +196,12 @@ func (consensus *Consensus) getNextLeaderKey(viewID uint64) *bls.PublicKeyWrappe Uint64("newViewID", viewID). Uint64("myCurBlockViewID", consensus.GetCurBlockViewID()). Msg("[getNextLeaderKey] got leaderPubKey from coinbase") - wasFound, next := consensus.Decider.NthNext(lastLeaderPubKey, gap) + // wasFound, next := consensus.Decider.NthNext(lastLeaderPubKey, gap) + // FIXME: rotate leader on harmony nodes only before fully externalization + wasFound, next := consensus.Decider.NthNextHmy( + shard.Schedule.InstanceForEpoch(epoch), + lastLeaderPubKey, + gap) if !wasFound { consensus.getLogger().Warn(). Str("key", consensus.LeaderPubKey.Bytes.Hex()).