[viewchange] fix getNextLeader

next leader can be any leader depending on the gap of the view ID

do not change current pubkey unless leader change succeeded

Signed-off-by: Leo Chen <leo@harmony.one>
pull/3365/head
Leo Chen 4 years ago
parent 7d24f05f79
commit 9dc8f43288
  1. 4
      consensus/consensus_viewchange_msg.go
  2. 6
      consensus/quorum/quorum.go
  3. 16
      consensus/view_change.go
  4. 4
      consensus/view_change_test.go

@ -13,7 +13,7 @@ import (
) )
// construct the view change message // construct the view change message
func (consensus *Consensus) constructViewChangeMessage(priKey *bls.PrivateKeyWrapper) []byte { func (consensus *Consensus) constructViewChangeMessage(priKey *bls.PrivateKeyWrapper, nextLeaderPubKey *bls.PublicKeyWrapper) []byte {
message := &msg_pb.Message{ message := &msg_pb.Message{
ServiceType: msg_pb.ServiceType_CONSENSUS, ServiceType: msg_pb.ServiceType_CONSENSUS,
Type: msg_pb.MessageType_VIEWCHANGE, Type: msg_pb.MessageType_VIEWCHANGE,
@ -23,7 +23,7 @@ func (consensus *Consensus) constructViewChangeMessage(priKey *bls.PrivateKeyWra
BlockNum: consensus.blockNum, BlockNum: consensus.blockNum,
ShardId: consensus.ShardID, ShardId: consensus.ShardID,
SenderPubkey: priKey.Pub.Bytes[:], SenderPubkey: priKey.Pub.Bytes[:],
LeaderPubkey: consensus.LeaderPubKey.Bytes[:], LeaderPubkey: nextLeaderPubKey.Bytes[:],
}, },
}, },
} }

@ -72,7 +72,7 @@ type ParticipantTracker interface {
Participants() multibls.PublicKeys Participants() multibls.PublicKeys
IndexOf(bls.SerializedPublicKey) int IndexOf(bls.SerializedPublicKey) int
ParticipantsCount() int64 ParticipantsCount() int64
NextAfter(*bls.PublicKeyWrapper) (bool, *bls.PublicKeyWrapper) NextAfter(*bls.PublicKeyWrapper, int) (bool, *bls.PublicKeyWrapper)
UpdateParticipants(pubKeys []bls.PublicKeyWrapper) UpdateParticipants(pubKeys []bls.PublicKeyWrapper)
} }
@ -187,14 +187,14 @@ func (s *cIdentities) IndexOf(pubKey bls.SerializedPublicKey) int {
return -1 return -1
} }
func (s *cIdentities) NextAfter(pubKey *bls.PublicKeyWrapper) (bool, *bls.PublicKeyWrapper) { func (s *cIdentities) NextAfter(pubKey *bls.PublicKeyWrapper, next int) (bool, *bls.PublicKeyWrapper) {
found := false found := false
idx := s.IndexOf(pubKey.Bytes) idx := s.IndexOf(pubKey.Bytes)
if idx != -1 { if idx != -1 {
found = true found = true
} }
idx = (idx + 1) % int(s.ParticipantsCount()) idx = (idx + next) % int(s.ParticipantsCount())
return found, &s.publicKeys[idx] return found, &s.publicKeys[idx]
} }

@ -120,8 +120,12 @@ func (consensus *Consensus) switchPhase(desired FBFTPhase, override bool) {
} }
// GetNextLeaderKey uniquely determine who is the leader for given viewID // GetNextLeaderKey uniquely determine who is the leader for given viewID
func (consensus *Consensus) GetNextLeaderKey() *bls.PublicKeyWrapper { func (consensus *Consensus) GetNextLeaderKey(viewID uint64) *bls.PublicKeyWrapper {
wasFound, next := consensus.Decider.NextAfter(consensus.LeaderPubKey) gap := 1
if viewID > consensus.GetCurViewID() {
gap = int(viewID - consensus.GetCurViewID())
}
wasFound, next := consensus.Decider.NextAfter(consensus.LeaderPubKey, gap)
if !wasFound { if !wasFound {
consensus.getLogger().Warn(). consensus.getLogger().Warn().
Str("key", consensus.LeaderPubKey.Bytes.Hex()). Str("key", consensus.LeaderPubKey.Bytes.Hex()).
@ -163,20 +167,20 @@ func (consensus *Consensus) startViewChange(viewID uint64) {
consensus.consensusTimeout[timeoutBootstrap].Stop() consensus.consensusTimeout[timeoutBootstrap].Stop()
consensus.current.SetMode(ViewChanging) consensus.current.SetMode(ViewChanging)
consensus.SetViewChangingID(viewID) consensus.SetViewChangingID(viewID)
consensus.LeaderPubKey = consensus.GetNextLeaderKey() nextLeaderPubKey := consensus.GetNextLeaderKey(viewID)
duration := consensus.current.GetViewChangeDuraion() duration := consensus.current.GetViewChangeDuraion()
consensus.getLogger().Warn(). consensus.getLogger().Warn().
Uint64("viewChangingID", consensus.GetViewChangingID()). Uint64("viewChangingID", consensus.GetViewChangingID()).
Dur("timeoutDuration", duration). Dur("timeoutDuration", duration).
Str("NextLeader", consensus.LeaderPubKey.Bytes.Hex()). Str("NextLeader", nextLeaderPubKey.Bytes.Hex()).
Msg("[startViewChange]") Msg("[startViewChange]")
for _, key := range consensus.priKey { for _, key := range consensus.priKey {
if !consensus.IsValidatorInCommittee(key.Pub.Bytes) { if !consensus.IsValidatorInCommittee(key.Pub.Bytes) {
continue continue
} }
msgToSend := consensus.constructViewChangeMessage(&key) msgToSend := consensus.constructViewChangeMessage(&key, nextLeaderPubKey)
consensus.host.SendMessageToGroups([]nodeconfig.GroupID{ consensus.host.SendMessageToGroups([]nodeconfig.GroupID{
nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID)), nodeconfig.NewGroupIDByShardID(nodeconfig.ShardID(consensus.ShardID)),
}, },
@ -680,8 +684,6 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) {
consensus.getLogger().Info(). consensus.getLogger().Info().
Str("newLeaderKey", consensus.LeaderPubKey.Bytes.Hex()). Str("newLeaderKey", consensus.LeaderPubKey.Bytes.Hex()).
Msg("new leader changed") Msg("new leader changed")
consensus.getLogger().Info().
Msg("validator start consensus timer and stop view change timer")
consensus.consensusTimeout[timeoutConsensus].Start() consensus.consensusTimeout[timeoutConsensus].Start()
consensus.consensusTimeout[timeoutViewChange].Stop() consensus.consensusTimeout[timeoutViewChange].Stop()
} }

@ -111,7 +111,7 @@ func TestGetNextLeaderKeyShouldFailForStandardGeneratedConsensus(t *testing.T) {
// The below results in: "panic: runtime error: integer divide by zero" // The below results in: "panic: runtime error: integer divide by zero"
// This happens because there's no check for if there are any participants or not in https://github.com/harmony-one/harmony/blob/main/consensus/quorum/quorum.go#L188-L197 // This happens because there's no check for if there are any participants or not in https://github.com/harmony-one/harmony/blob/main/consensus/quorum/quorum.go#L188-L197
assert.Panics(t, func() { consensus.GetNextLeaderKey() }) assert.Panics(t, func() { consensus.GetNextLeaderKey(uint64(1)) })
} }
func TestGetNextLeaderKeyShouldSucceed(t *testing.T) { func TestGetNextLeaderKeyShouldSucceed(t *testing.T) {
@ -139,7 +139,7 @@ func TestGetNextLeaderKeyShouldSucceed(t *testing.T) {
assert.Equal(t, keyCount, consensus.Decider.ParticipantsCount()) assert.Equal(t, keyCount, consensus.Decider.ParticipantsCount())
consensus.LeaderPubKey = &wrappedBLSKeys[0] consensus.LeaderPubKey = &wrappedBLSKeys[0]
nextKey := consensus.GetNextLeaderKey() nextKey := consensus.GetNextLeaderKey(uint64(1))
assert.Equal(t, nextKey, &wrappedBLSKeys[1]) assert.Equal(t, nextKey, &wrappedBLSKeys[1])
} }

Loading…
Cancel
Save