From 390ae762a9efd46e2ea6a6f868cb4577a8b501fc Mon Sep 17 00:00:00 2001 From: GheisMohammadi Date: Thu, 28 Nov 2024 19:45:55 +0800 Subject: [PATCH 1/4] Update Quorum Check to use GTE for consistency --- consensus/quorum/one-node-staked-vote.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/quorum/one-node-staked-vote.go b/consensus/quorum/one-node-staked-vote.go index 45f4289eab..179ccde2fb 100644 --- a/consensus/quorum/one-node-staked-vote.go +++ b/consensus/quorum/one-node-staked-vote.go @@ -160,7 +160,7 @@ func (v *stakedVoteWeight) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool { const msg = "[IsQuorumAchievedByMask] Voting power: need %+v, have %+v" utils.Logger().Debug(). Msgf(msg, threshold, currentTotalPower) - return (*currentTotalPower).GT(threshold) + return (*currentTotalPower).GTE(threshold) } func (v *stakedVoteWeight) ComputeTotalPowerByMask(mask *bls_cosi.Mask) numeric.Dec { From 5cef50c96530f59ccad581de686a5eb10fde9b2b Mon Sep 17 00:00:00 2001 From: GheisMohammadi Date: Mon, 27 Jan 2025 23:33:05 +0800 Subject: [PATCH 2/4] tweak uniformVoteWeight to match the logic in stakedVoteWeight by using GT to check Quorum --- consensus/quorum/one-node-one-vote.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/consensus/quorum/one-node-one-vote.go b/consensus/quorum/one-node-one-vote.go index 4962dfc86e..d4f8b2d73e 100644 --- a/consensus/quorum/one-node-one-vote.go +++ b/consensus/quorum/one-node-one-vote.go @@ -23,6 +23,8 @@ type uniformVoteWeight struct { lastPowerSignersCountCache map[Phase]int64 lastParticipantsCount int64 + + useGTforQuorumChecking bool } // Policy .. @@ -60,7 +62,11 @@ func (v *uniformVoteWeight) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool { } threshold := v.TwoThirdsSignersCount() currentTotalPower := utils.CountOneBits(mask.Bitmap) - if currentTotalPower < threshold { + enoughVotingPower := currentTotalPower >= threshold + if v.useGTforQuorumChecking { + enoughVotingPower = currentTotalPower > threshold + } + if !enoughVotingPower { const msg = "[IsQuorumAchievedByMask] Not enough voting power: need %+v, have %+v" utils.Logger().Warn().Msgf(msg, threshold, currentTotalPower) return false From 366fce08b937b1024f8ad23b16376b11558783df Mon Sep 17 00:00:00 2001 From: GheisMohammadi Date: Mon, 27 Jan 2025 23:34:05 +0800 Subject: [PATCH 3/4] add hardfork epoch to use GT for check Quorum in uniformVoteWeight --- cmd/harmony/main.go | 3 ++- consensus/consensus_service.go | 3 ++- consensus/consensus_service_test.go | 4 ++-- consensus/consensus_test.go | 2 +- consensus/construct_test.go | 10 +++++----- consensus/quorum/one-node-staked-vote.go | 2 +- consensus/quorum/one-node-staked-vote_test.go | 6 +++--- consensus/quorum/quorom_test.go | 12 ++++++------ consensus/quorum/quorum.go | 3 ++- core_test/shardchain_test.go | 2 +- hmy/staking.go | 4 ++-- 11 files changed, 27 insertions(+), 24 deletions(-) diff --git a/cmd/harmony/main.go b/cmd/harmony/main.go index c43d73b946..a816b7dff4 100644 --- a/cmd/harmony/main.go +++ b/cmd/harmony/main.go @@ -705,7 +705,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)) + useGT := registry.GetBlockchain().Config().IsLeaderRotationV2Epoch(registry.GetBlockchain().CurrentBlock().Epoch()) + decider := quorum.NewDecider(quorum.SuperMajorityVote, uint32(hc.General.ShardID), useGT) // Parse minPeers from harmonyconfig.HarmonyConfig var minPeers int diff --git a/consensus/consensus_service.go b/consensus/consensus_service.go index 9307aec36f..9a0a04ed3a 100644 --- a/consensus/consensus_service.go +++ b/consensus/consensus_service.go @@ -373,7 +373,8 @@ func (consensus *Consensus) updateConsensusInformation(reason string) Mode { // Only happens once, the flip-over to a new Decider policy if isFirstTimeStaking || haventUpdatedDecider { - decider := quorum.NewDecider(quorum.SuperMajorityStake, consensus.ShardID) + useGT := consensus.Blockchain().Config().IsLeaderRotationV2Epoch(consensus.Blockchain().CurrentBlock().Epoch()) + decider := quorum.NewDecider(quorum.SuperMajorityStake, consensus.ShardID, useGT) consensus.decider = decider } diff --git a/consensus/consensus_service_test.go b/consensus/consensus_service_test.go index b3e2e73ac9..5e883fa7f3 100644 --- a/consensus/consensus_service_test.go +++ b/consensus/consensus_service_test.go @@ -26,7 +26,7 @@ func TestSignAndMarshalConsensusMessage(t *testing.T) { if err != nil { t.Fatalf("newhost failure: %v", err) } - decider := quorum.NewDecider(quorum.SuperMajorityVote, shard.BeaconChainShardID) + decider := quorum.NewDecider(quorum.SuperMajorityVote, shard.BeaconChainShardID, false) blsPriKey := bls.RandPrivateKey() reg := registry.New() consensus, err := New(host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), reg, decider, 3, false) @@ -58,7 +58,7 @@ func TestSetViewID(t *testing.T) { t.Fatalf("newhost failure: %v", err) } decider := quorum.NewDecider( - quorum.SuperMajorityVote, shard.BeaconChainShardID, + quorum.SuperMajorityVote, shard.BeaconChainShardID, false, ) blsPriKey := bls.RandPrivateKey() reg := registry.New() diff --git a/consensus/consensus_test.go b/consensus/consensus_test.go index 794f8ecdb0..47e79b5a02 100644 --- a/consensus/consensus_test.go +++ b/consensus/consensus_test.go @@ -79,7 +79,7 @@ func GenerateConsensusForTesting() (p2p.Host, multibls.PrivateKeys, *Consensus, return nil, nil, nil, nil, err } - decider := quorum.NewDecider(quorum.SuperMajorityVote, shard.BeaconChainShardID) + decider := quorum.NewDecider(quorum.SuperMajorityVote, shard.BeaconChainShardID, false) multiBLSPrivateKey := multibls.GetPrivateKeys(bls.RandPrivateKey()) consensus, err := New(host, shard.BeaconChainShardID, multiBLSPrivateKey, registry.New(), decider, 3, false) diff --git a/consensus/construct_test.go b/consensus/construct_test.go index 24cd9fc3bc..09c96e7af9 100644 --- a/consensus/construct_test.go +++ b/consensus/construct_test.go @@ -37,7 +37,7 @@ func TestConstructAnnounceMessage(test *testing.T) { test.Fatalf("newhost failure: %v", err) } decider := quorum.NewDecider( - quorum.SuperMajorityVote, shard.BeaconChainShardID, + quorum.SuperMajorityVote, shard.BeaconChainShardID, false, ) blsPriKey := bls.RandPrivateKey() reg := registry.New() @@ -70,7 +70,7 @@ func TestConstructPreparedMessage(test *testing.T) { test.Fatalf("newhost failure: %v", err) } decider := quorum.NewDecider( - quorum.SuperMajorityVote, shard.BeaconChainShardID, + quorum.SuperMajorityVote, shard.BeaconChainShardID, false, ) blsPriKey := bls.RandPrivateKey() reg := registry.New() @@ -150,7 +150,7 @@ func TestConstructPrepareMessage(test *testing.T) { priKeyWrapper2 := bls.PrivateKeyWrapper{Pri: blsPriKey2, Pub: &pubKeyWrapper2} decider := quorum.NewDecider( - quorum.SuperMajorityStake, shard.BeaconChainShardID, + quorum.SuperMajorityStake, shard.BeaconChainShardID, false, ) consensus, err := New( @@ -242,7 +242,7 @@ func TestConstructCommitMessage(test *testing.T) { priKeyWrapper2 := bls.PrivateKeyWrapper{Pri: blsPriKey2, Pub: &pubKeyWrapper2} decider := quorum.NewDecider( - quorum.SuperMajorityStake, shard.BeaconChainShardID, + quorum.SuperMajorityStake, shard.BeaconChainShardID, false, ) consensus, err := New(host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey1), registry.New(), decider, 3, false) @@ -324,7 +324,7 @@ func TestPopulateMessageFields(t *testing.T) { } blsPriKey := bls.RandPrivateKey() decider := quorum.NewDecider( - quorum.SuperMajorityVote, shard.BeaconChainShardID, + quorum.SuperMajorityVote, shard.BeaconChainShardID, false, ) consensus, err := New( host, shard.BeaconChainShardID, multibls.GetPrivateKeys(blsPriKey), registry.New(), decider, 3, false, diff --git a/consensus/quorum/one-node-staked-vote.go b/consensus/quorum/one-node-staked-vote.go index 179ccde2fb..45f4289eab 100644 --- a/consensus/quorum/one-node-staked-vote.go +++ b/consensus/quorum/one-node-staked-vote.go @@ -160,7 +160,7 @@ func (v *stakedVoteWeight) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool { const msg = "[IsQuorumAchievedByMask] Voting power: need %+v, have %+v" utils.Logger().Debug(). Msgf(msg, threshold, currentTotalPower) - return (*currentTotalPower).GTE(threshold) + return (*currentTotalPower).GT(threshold) } func (v *stakedVoteWeight) ComputeTotalPowerByMask(mask *bls_cosi.Mask) numeric.Dec { diff --git a/consensus/quorum/one-node-staked-vote_test.go b/consensus/quorum/one-node-staked-vote_test.go index fcce3c61b0..f4a5f48df3 100644 --- a/consensus/quorum/one-node-staked-vote_test.go +++ b/consensus/quorum/one-node-staked-vote_test.go @@ -34,7 +34,7 @@ var ( type secretKeyMap map[bls.SerializedPublicKey]bls_core.SecretKey func init() { - basicDecider = NewDecider(SuperMajorityStake, shard.BeaconChainShardID) + basicDecider = NewDecider(SuperMajorityStake, shard.BeaconChainShardID, false) shard.Schedule = shardingconfig.LocalnetSchedule } @@ -71,7 +71,7 @@ func setupBaseCase() (Decider, *TallyResult, shard.SlotList, map[string]secretKe pubKeys = append(pubKeys, wrapper) } - decider := NewDecider(SuperMajorityStake, shard.BeaconChainShardID) + decider := NewDecider(SuperMajorityStake, shard.BeaconChainShardID, false) decider.UpdateParticipants(pubKeys, []bls.PublicKeyWrapper{}) tally, err := decider.SetVoters(&shard.Committee{ ShardID: shard.BeaconChainShardID, Slots: slotList, @@ -100,7 +100,7 @@ func setupEdgeCase() (Decider, *TallyResult, shard.SlotList, secretKeyMap) { pubKeys = append(pubKeys, wrapper) } - decider := NewDecider(SuperMajorityStake, shard.BeaconChainShardID) + decider := NewDecider(SuperMajorityStake, shard.BeaconChainShardID, false) decider.UpdateParticipants(pubKeys, []bls.PublicKeyWrapper{}) tally, err := decider.SetVoters(&shard.Committee{ ShardID: shard.BeaconChainShardID, Slots: slotList, diff --git a/consensus/quorum/quorom_test.go b/consensus/quorum/quorom_test.go index 7622f5aac3..98b099bae8 100644 --- a/consensus/quorum/quorom_test.go +++ b/consensus/quorum/quorom_test.go @@ -53,7 +53,7 @@ func TestPolicyStrings(t *testing.T) { } func TestAddingQuoromParticipants(t *testing.T) { - decider := NewDecider(SuperMajorityVote, shard.BeaconChainShardID) + decider := NewDecider(SuperMajorityVote, shard.BeaconChainShardID, false) assert.Equal(t, int64(0), decider.ParticipantsCount()) @@ -77,7 +77,7 @@ func TestSubmitVote(test *testing.T) { viewID := uint64(2) decider := NewDecider( - SuperMajorityStake, shard.BeaconChainShardID, + SuperMajorityStake, shard.BeaconChainShardID, false, ) message := "test string" @@ -131,7 +131,7 @@ func TestSubmitVoteAggregateSig(test *testing.T) { viewID := uint64(2) decider := NewDecider( - SuperMajorityStake, shard.BeaconChainShardID, + SuperMajorityStake, shard.BeaconChainShardID, false, ) blsPriKey1 := bls.RandPrivateKey() @@ -203,7 +203,7 @@ func TestAddNewVote(test *testing.T) { viewID := uint64(2) decider := NewDecider( - SuperMajorityStake, shard.BeaconChainShardID, + SuperMajorityStake, shard.BeaconChainShardID, false, ) slotList := shard.SlotList{} @@ -305,7 +305,7 @@ func TestAddNewVoteAggregateSig(test *testing.T) { viewID := uint64(2) decider := NewDecider( - SuperMajorityStake, shard.BeaconChainShardID, + SuperMajorityStake, shard.BeaconChainShardID, false, ) slotList := shard.SlotList{} @@ -386,7 +386,7 @@ func TestAddNewVoteInvalidAggregateSig(test *testing.T) { viewID := uint64(2) decider := NewDecider( - SuperMajorityStake, shard.BeaconChainShardID, + SuperMajorityStake, shard.BeaconChainShardID, false, ) slotList := shard.SlotList{} diff --git a/consensus/quorum/quorum.go b/consensus/quorum/quorum.go index e0feee4ec9..7ead38e0a1 100644 --- a/consensus/quorum/quorum.go +++ b/consensus/quorum/quorum.go @@ -483,12 +483,13 @@ func newBallotsBackedSignatureReader() *cIdentities { } // NewDecider .. -func NewDecider(p Policy, shardID uint32) Decider { +func NewDecider(p Policy, shardID uint32, useGTforQuorumChecking bool) Decider { switch p { case SuperMajorityVote: return &uniformVoteWeight{ SignatureReader: newBallotsBackedSignatureReader(), lastPowerSignersCountCache: make(map[Phase]int64), + useGTforQuorumChecking: useGTforQuorumChecking, } case SuperMajorityStake: return &stakedVoteWeight{ diff --git a/core_test/shardchain_test.go b/core_test/shardchain_test.go index ef4cc04cdb..e7f6492f1c 100644 --- a/core_test/shardchain_test.go +++ b/core_test/shardchain_test.go @@ -41,7 +41,7 @@ func TestAddNewBlock(t *testing.T) { nil, testDBFactory, &core.GenesisInitializer{NetworkType: nodeconfig.GetShardConfig(shard.BeaconChainShardID).GetNetworkType()}, engine, &chainconfig, ) decider := quorum.NewDecider( - quorum.SuperMajorityVote, shard.BeaconChainShardID, + quorum.SuperMajorityVote, shard.BeaconChainShardID, false, ) blockchain, err := collection.ShardChain(shard.BeaconChainShardID) if err != nil { diff --git a/hmy/staking.go b/hmy/staking.go index bab9c0adff..42754e0a7a 100644 --- a/hmy/staking.go +++ b/hmy/staking.go @@ -96,7 +96,7 @@ func (hmy *Harmony) getSuperCommittees() (*quorum.Transition, error) { rawStakes := []effective.SlotPurchase{} validatorSpreads := map[common.Address]numeric.Dec{} for _, comm := range prevCommittee.Shards { - decider := quorum.NewDecider(quorum.SuperMajorityStake, comm.ShardID) + decider := quorum.NewDecider(quorum.SuperMajorityStake, comm.ShardID, false) // before staking skip computing if hmy.BlockChain.Config().IsStaking(prevCommittee.Epoch) { if _, err := decider.SetVoters(&comm, prevCommittee.Epoch); err != nil { @@ -111,7 +111,7 @@ func (hmy *Harmony) getSuperCommittees() (*quorum.Transition, error) { rawStakes = []effective.SlotPurchase{} validatorSpreads = map[common.Address]numeric.Dec{} for _, comm := range nowCommittee.Shards { - decider := quorum.NewDecider(quorum.SuperMajorityStake, comm.ShardID) + decider := quorum.NewDecider(quorum.SuperMajorityStake, comm.ShardID, false) if _, err := decider.SetVoters(&comm, nowCommittee.Epoch); err != nil { return nil, errors.Wrapf( err, From 69cedcf3665bc32fe8160a69ce422e884c84999d Mon Sep 17 00:00:00 2001 From: GheisMohammadi Date: Tue, 28 Jan 2025 10:43:33 +0800 Subject: [PATCH 4/4] fix go-test missing parameters --- node/harmony/node_handler_test.go | 6 +++--- node/harmony/node_newblock_test.go | 2 +- node/harmony/node_test.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/node/harmony/node_handler_test.go b/node/harmony/node_handler_test.go index 65c960e028..a5c45e5b37 100644 --- a/node/harmony/node_handler_test.go +++ b/node/harmony/node_handler_test.go @@ -39,7 +39,7 @@ func TestAddNewBlock(t *testing.T) { nil, testDBFactory, &core.GenesisInitializer{NetworkType: nodeconfig.GetShardConfig(shard.BeaconChainShardID).GetNetworkType()}, engine, &chainconfig, ) decider := quorum.NewDecider( - quorum.SuperMajorityVote, shard.BeaconChainShardID, + quorum.SuperMajorityVote, shard.BeaconChainShardID, false, ) blockchain, err := collection.ShardChain(shard.BeaconChainShardID) if err != nil { @@ -97,7 +97,7 @@ func TestVerifyNewBlock(t *testing.T) { nil, testDBFactory, &core.GenesisInitializer{NetworkType: nodeconfig.GetShardConfig(shard.BeaconChainShardID).GetNetworkType()}, engine, &chainconfig, ) decider := quorum.NewDecider( - quorum.SuperMajorityVote, shard.BeaconChainShardID, + quorum.SuperMajorityVote, shard.BeaconChainShardID, false, ) blockchain, err := collection.ShardChain(shard.BeaconChainShardID) if err != nil { @@ -161,7 +161,7 @@ func TestVerifyVRF(t *testing.T) { t.Fatal("cannot get blockchain") } decider := quorum.NewDecider( - quorum.SuperMajorityVote, shard.BeaconChainShardID, + quorum.SuperMajorityVote, shard.BeaconChainShardID, false, ) reg := registry.New(). SetBlockchain(blockchain). diff --git a/node/harmony/node_newblock_test.go b/node/harmony/node_newblock_test.go index 5780b7cda0..ec12de2630 100644 --- a/node/harmony/node_newblock_test.go +++ b/node/harmony/node_newblock_test.go @@ -44,7 +44,7 @@ func TestFinalizeNewBlockAsync(t *testing.T) { require.NoError(t, err) decider := quorum.NewDecider( - quorum.SuperMajorityVote, shard.BeaconChainShardID, + quorum.SuperMajorityVote, shard.BeaconChainShardID, false, ) reg := registry.New(). SetBlockchain(blockchain). diff --git a/node/harmony/node_test.go b/node/harmony/node_test.go index e5a7d38be6..a646f24ea8 100644 --- a/node/harmony/node_test.go +++ b/node/harmony/node_test.go @@ -87,7 +87,7 @@ func TestNewNode(t *testing.T) { } engine := chain.NewEngine() decider := quorum.NewDecider( - quorum.SuperMajorityVote, shard.BeaconChainShardID, + quorum.SuperMajorityVote, shard.BeaconChainShardID, false, ) chainconfig := nodeconfig.GetShardConfig(shard.BeaconChainShardID).GetNetworkType().ChainConfig() collection := shardchain.NewCollection(