From e124173a81785916600250561b2ea94983e08992 Mon Sep 17 00:00:00 2001 From: Konstantin <355847+Frozen@users.noreply.github.com> Date: Sun, 29 Oct 2023 17:48:30 -0800 Subject: [PATCH 1/2] Cleanup. (#4547) * Cleanup * Cleanup --- Makefile | 3 --- core/blockchain_impl.go | 2 -- core/state_processor.go | 10 +++++++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 6fc8f2607..906e8c06a 100644 --- a/Makefile +++ b/Makefile @@ -180,6 +180,3 @@ debug_external: clean build_localnet_validator: bash test/build-localnet-validator.sh - -tt: - go test -v -test.run OnDisconnectCheck ./p2p/security \ No newline at end of file diff --git a/core/blockchain_impl.go b/core/blockchain_impl.go index b12de5637..e9eca1f4c 100644 --- a/core/blockchain_impl.go +++ b/core/blockchain_impl.go @@ -1682,8 +1682,6 @@ func (bc *BlockChainImpl) insertChain(chain types.Blocks, verifyHeaders bool) (i if len(chain) == 0 { return 0, nil, nil, ErrEmptyChain } - first := chain[0] - fmt.Println("insertChain", utils.GetPort(), first.ShardID(), first.Epoch().Uint64(), first.NumberU64()) // Do a sanity check that the provided chain is actually ordered and linked for i := 1; i < len(chain); i++ { if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() { diff --git a/core/state_processor.go b/core/state_processor.go index 6ea9e244a..9ccb256a7 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -310,7 +310,15 @@ func ApplyTransaction(bc ChainContext, author *common.Address, gp *GasPool, stat // Apply the transaction to the current state (included in the env) result, err := ApplyMessage(vmenv, msg, gp) if err != nil { - return nil, nil, nil, 0, errors.Wrapf(err, "apply failed from='%s' to='%s' balance='%s'", msg.From().Hex(), msg.To().Hex(), statedb.GetBalance(msg.From()).String()) + to := "" + if m := msg.To(); m != nil { + to = m.Hex() + } + balance := "" + if a := statedb.GetBalance(msg.From()); a != nil { + balance = a.String() + } + return nil, nil, nil, 0, errors.Wrapf(err, "apply failed from='%s' to='%s' balance='%s'", msg.From().Hex(), to, balance) } // Update the state with pending changes var root []byte From 4b8cf56055c5a69e199836283aa88a6724fa90fb Mon Sep 17 00:00:00 2001 From: Konstantin <355847+Frozen@users.noreply.github.com> Date: Tue, 31 Oct 2023 14:20:41 -0800 Subject: [PATCH 2/2] Leader rotation. Check next leader aliveness. (#4359) * Cleanup and fix update pub keys. * Skip the next leader if it doesn't sign blocks. * Comment & constant. * Updated with dev. * Updated with latest dev. * Cleanup --- cmd/harmony/main.go | 3 +- consensus/consensus_v2.go | 70 +++++++++++++++++++++++++++++++------- consensus/quorum/quorum.go | 2 +- internal/utils/math.go | 17 +++++++++ 4 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 internal/utils/math.go diff --git a/cmd/harmony/main.go b/cmd/harmony/main.go index 9fc89d45d..021061c75 100644 --- a/cmd/harmony/main.go +++ b/cmd/harmony/main.go @@ -788,6 +788,8 @@ func setupChain(hc harmonyconfig.HarmonyConfig, nodeConfig *nodeconfig.ConfigTyp } func setupConsensusAndNode(hc harmonyconfig.HarmonyConfig, nodeConfig *nodeconfig.ConfigType, registry *registry.Registry) *node.Node { + decider := quorum.NewDecider(quorum.SuperMajorityVote, uint32(hc.General.ShardID)) + // Parse minPeers from harmonyconfig.HarmonyConfig var minPeers int var aggregateSig bool @@ -821,7 +823,6 @@ func setupConsensusAndNode(hc harmonyconfig.HarmonyConfig, nodeConfig *nodeconfi registry.SetCxPool(cxPool) // Consensus object. - decider := quorum.NewDecider(quorum.SuperMajorityVote, nodeConfig.ShardID) registry.SetIsBackup(isBackup(hc)) currentConsensus, err := consensus.New( myHost, nodeConfig.ShardID, nodeConfig.ConsensusPriKey, registry, decider, minPeers, aggregateSig) diff --git a/consensus/consensus_v2.go b/consensus/consensus_v2.go index 6d3ef5b47..b3c94a77f 100644 --- a/consensus/consensus_v2.go +++ b/consensus/consensus_v2.go @@ -690,10 +690,15 @@ func (consensus *Consensus) commitBlock(blk *types.Block, committedMsg *FBFTMess // This function must be called with enabled leader rotation. func (consensus *Consensus) rotateLeader(epoch *big.Int) { var ( - bc = consensus.Blockchain() - prev = consensus.getLeaderPubKey() - leader = consensus.getLeaderPubKey() + bc = consensus.Blockchain() + prev = consensus.getLeaderPubKey() + leader = consensus.getLeaderPubKey() + curBlock = bc.CurrentBlock() + curNumber = curBlock.NumberU64() + curEpoch = curBlock.Epoch().Uint64() ) + const blocksCountAliveness = 10 + 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 { @@ -741,18 +746,59 @@ func (consensus *Consensus) rotateLeader(epoch *big.Int) { var ( wasFound bool next *bls.PublicKeyWrapper + offset = 1 ) - if bc.Config().IsLeaderRotationExternalValidatorsAllowed(epoch) { - wasFound, next = consensus.Decider.NthNextValidator(committee.Slots, leader, 1) - } else { - wasFound, next = consensus.Decider.NthNextHmy(shard.Schedule.InstanceForEpoch(epoch), leader, 1) - } - if !wasFound { - utils.Logger().Error().Msg("Failed to get next leader") - return - } else { + + for { + if bc.Config().IsLeaderRotationExternalValidatorsAllowed(epoch) { + wasFound, next = consensus.Decider.NthNextValidator(committee.Slots, leader, offset) + } else { + wasFound, next = consensus.Decider.NthNextHmy(shard.Schedule.InstanceForEpoch(epoch), leader, offset) + } + if !wasFound { + utils.Logger().Error().Msg("Failed to get next leader") + // Seems like nothing we can do here. + return + } + members := consensus.Decider.Participants() + mask := bls.NewMask(members) + skipped := 0 + for i := 0; i < blocksCountAliveness; i++ { + header := bc.GetHeaderByNumber(curNumber - uint64(i)) + if header == nil { + utils.Logger().Error().Msgf("Failed to get header by number %d", curNumber-uint64(i)) + return + } + // if epoch is different, we should not check this block. + if header.Epoch().Uint64() != curEpoch { + break + } + // Populate the mask with the bitmap. + err = mask.SetMask(header.LastCommitBitmap()) + if err != nil { + utils.Logger().Err(err).Msg("Failed to set mask") + return + } + ok, err := mask.KeyEnabled(next.Bytes) + if err != nil { + utils.Logger().Err(err).Msg("Failed to get key enabled") + return + } + if !ok { + skipped++ + } + } + + // no signature from the next leader at all, we should skip it. + if skipped >= blocksCountAliveness { + // Next leader is not signing blocks, we should skip it. + offset++ + continue + } consensus.setLeaderPubKey(next) + break } + if consensus.isLeader() && !consensus.getLeaderPubKey().Object.IsEqual(prev.Object) { // leader changed go func() { diff --git a/consensus/quorum/quorum.go b/consensus/quorum/quorum.go index aaeaab236..3930abef1 100644 --- a/consensus/quorum/quorum.go +++ b/consensus/quorum/quorum.go @@ -77,7 +77,7 @@ type ParticipantTracker interface { ParticipantsCount() int64 // NthNextValidator returns key for next validator. It assumes external validators and leader rotation. NthNextValidator(slotList shard.SlotList, pubKey *bls.PublicKeyWrapper, next int) (bool, *bls.PublicKeyWrapper) - NthNextHmy(shardingconfig.Instance, *bls.PublicKeyWrapper, int) (bool, *bls.PublicKeyWrapper) + NthNextHmy(instance shardingconfig.Instance, pubkey *bls.PublicKeyWrapper, next int) (bool, *bls.PublicKeyWrapper) NthNextHmyExt(shardingconfig.Instance, *bls.PublicKeyWrapper, int) (bool, *bls.PublicKeyWrapper) FirstParticipant(shardingconfig.Instance) *bls.PublicKeyWrapper UpdateParticipants(pubKeys, allowlist []bls.PublicKeyWrapper) diff --git a/internal/utils/math.go b/internal/utils/math.go new file mode 100644 index 000000000..6dceec5eb --- /dev/null +++ b/internal/utils/math.go @@ -0,0 +1,17 @@ +package utils + +import "golang.org/x/exp/constraints" + +func Min[T constraints.Ordered](a, b T) T { + if a < b { + return a + } + return b +} + +func Max[T constraints.Ordered](a, b T) T { + if a > b { + return a + } + return b +}