diff --git a/consensus/consensus_v2.go b/consensus/consensus_v2.go index b0f8a966a..85b1851e9 100644 --- a/consensus/consensus_v2.go +++ b/consensus/consensus_v2.go @@ -505,14 +505,13 @@ func (consensus *Consensus) onPrepared(msg *msg_pb.Message) { utils.Logger().Error().Err(err).Msg("ReadSignatureBitmapPayload failed!!") return } - prepareCount := consensus.Decider.SignersCount(quorum.Prepare) - if count := utils.CountOneBits(mask.Bitmap); count < prepareCount { - utils.Logger().Debug(). - Int64("Need", prepareCount). - Int64("Got", count). - Msg("Not enough signatures in the Prepared msg") + + if !consensus.Decider.IsQuorumAchievedByMask(mask) { + utils.Logger().Warn(). + Msgf("[OnPrepared] Quorum Not achieved") return } + if !aggSig.VerifyHash(mask.AggregatePublic, blockHash[:]) { myBlockHash := common.Hash{} myBlockHash.SetBytes(consensus.blockHash[:]) @@ -892,22 +891,12 @@ func (consensus *Consensus) onCommitted(msg *msg_pb.Message) { return } - switch consensus.Decider.Policy() { - case quorum.SuperMajorityVote: - threshold := consensus.Decider.TwoThirdsSignersCount() - if count := utils.CountOneBits(mask.Bitmap); int64(count) < threshold { - utils.Logger().Warn(). - Int64("need", threshold). - Int64("got", count). - Msg("[OnCommitted] Not enough signature in committed msg") - return - } - case quorum.SuperMajorityStake: - // Come back to thinking about this situation for Bitmap + if !consensus.Decider.IsQuorumAchievedByMask(mask) { + utils.Logger().Warn(). + Msgf("[OnCommitted] Quorum Not achieved") + return } - // check has 2f+1 signatures - blockNumBytes := make([]byte, 8) binary.LittleEndian.PutUint64(blockNumBytes, recvMsg.BlockNum) commitPayload := append(blockNumBytes, recvMsg.BlockHash[:]...) diff --git a/consensus/quorum/one-node-one-vote.go b/consensus/quorum/one-node-one-vote.go index 749908b02..e2d067487 100644 --- a/consensus/quorum/one-node-one-vote.go +++ b/consensus/quorum/one-node-one-vote.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/harmony-one/bls/ffi/go/bls" + bls_cosi "github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/numeric" "github.com/harmony-one/harmony/shard" @@ -33,6 +34,20 @@ func (v *uniformVoteWeight) IsQuorumAchieved(p Phase) bool { return r } +// IsQuorumAchivedByMask .. +func (v *uniformVoteWeight) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool { + threshold := v.TwoThirdsSignersCount() + currentTotalPower := utils.CountOneBits(mask.Bitmap) + if currentTotalPower < threshold { + utils.Logger().Warn(). + Msgf("[IsQuorumAchievedByMask] Not enough voting power: need %+v, have %+v", threshold, currentTotalPower) + return false + } + utils.Logger().Debug(). + Msgf("[IsQuorumAchievedByMask] have enough voting power: need %+v, have %+v", threshold, currentTotalPower) + return true +} + // QuorumThreshold .. func (v *uniformVoteWeight) QuorumThreshold() numeric.Dec { return numeric.NewDec(v.TwoThirdsSignersCount()) diff --git a/consensus/quorum/one-node-staked-vote.go b/consensus/quorum/one-node-staked-vote.go index 440a5ccc1..590d7242d 100644 --- a/consensus/quorum/one-node-staked-vote.go +++ b/consensus/quorum/one-node-staked-vote.go @@ -5,6 +5,7 @@ import ( "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/consensus/votepower" + bls_cosi "github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/internal/utils" "github.com/harmony-one/harmony/numeric" "github.com/harmony-one/harmony/shard" @@ -62,6 +63,25 @@ func (v *stakedVoteWeight) IsQuorumAchieved(p Phase) bool { return currentTotalPower.GT(t) } +// IsQuorumAchivedByMask .. +func (v *stakedVoteWeight) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool { + threshold := v.QuorumThreshold() + currentTotalPower := v.computeTotalPowerByMask(mask) + if currentTotalPower == nil { + utils.Logger().Warn(). + Msgf("[IsQuorumAchievedByMask] currentTotalPower is nil") + return false + } + if (*currentTotalPower).LT(threshold) { + utils.Logger().Warn(). + Msgf("[IsQuorumAchievedByMask] Not enough voting power: need %+v, have %+v", threshold, currentTotalPower) + return false + } + utils.Logger().Debug(). + Msgf("[IsQuorumAchievedByMask] have enough voting power: need %+v, have %+v", threshold, currentTotalPower) + return true +} + func (v *stakedVoteWeight) computeCurrentTotalPower(p Phase) (*numeric.Dec, error) { w := shard.BlsPublicKey{} members := v.Participants() @@ -78,10 +98,26 @@ func (v *stakedVoteWeight) computeCurrentTotalPower(p Phase) (*numeric.Dec, erro ) } } - return ¤tTotalPower, nil } +// ComputeTotalPowerByMask computes the total power indicated by bitmap mask +func (v *stakedVoteWeight) computeTotalPowerByMask(mask *bls_cosi.Mask) *numeric.Dec { + currentTotalPower := numeric.ZeroDec() + pubKeys := mask.GetPubKeyFromMask(true) + for _, key := range pubKeys { + w := shard.BlsPublicKey{} + err := w.FromLibBLSPublicKey(key) + if err != nil { + return nil + } + currentTotalPower = currentTotalPower.Add( + v.roster.Voters[w].EffectivePercent, + ) + } + return ¤tTotalPower +} + // QuorumThreshold .. func (v *stakedVoteWeight) QuorumThreshold() numeric.Dec { return twoThird diff --git a/consensus/quorum/quorum.go b/consensus/quorum/quorum.go index 16d9c4b41..dd5177af7 100644 --- a/consensus/quorum/quorum.go +++ b/consensus/quorum/quorum.go @@ -5,6 +5,7 @@ import ( "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/consensus/votepower" + bls_cosi "github.com/harmony-one/harmony/crypto/bls" "github.com/harmony-one/harmony/numeric" "github.com/harmony-one/harmony/shard" "github.com/harmony-one/harmony/staking/slash" @@ -113,6 +114,7 @@ type Decider interface { SetVoters(shard.SlotList) (*TallyResult, error) Policy() Policy IsQuorumAchieved(Phase) bool + IsQuorumAchievedByMask(*bls_cosi.Mask) bool QuorumThreshold() numeric.Dec AmIMemberOfCommitee() bool IsRewardThresholdAchieved() bool diff --git a/consensus/view_change.go b/consensus/view_change.go index 147f02a52..cb9443ec5 100644 --- a/consensus/view_change.go +++ b/consensus/view_change.go @@ -281,11 +281,10 @@ func (consensus *Consensus) onViewChange(msg *msg_pb.Message) { utils.Logger().Error().Err(err).Msg("[onViewChange] M1 RecvMsg Payload Read Error") return } - // check has 2f+1 signature in m1 type message - need := consensus.Decider.TwoThirdsSignersCount() - if count := utils.CountOneBits(mask.Bitmap); count < need { - utils.Logger().Debug().Int64("need", need).Int64("have", count). - Msg("[onViewChange] M1 Payload Not Have Enough Signature") + + if !consensus.Decider.IsQuorumAchievedByMask(mask) { + utils.Logger().Warn(). + Msgf("[onViewChange] Quorum Not achieved") return } @@ -445,11 +444,10 @@ func (consensus *Consensus) onNewView(msg *msg_pb.Message) { viewIDBytes := make([]byte, 8) binary.LittleEndian.PutUint64(viewIDBytes, recvMsg.ViewID) - // check total number of sigs >= 2f+1 - need := consensus.Decider.TwoThirdsSignersCount() - if count := utils.CountOneBits(m3Mask.Bitmap); count < need { - utils.Logger().Debug().Int64("need", need).Int64("have", count). - Msg("[onNewView] Not Have Enough M3 (ViewID) Signature") + + if !consensus.Decider.IsQuorumAchievedByMask(m3Mask) { + utils.Logger().Warn(). + Msgf("[onNewView] Quorum Not achieved") return }