From f17e76fe1bd825cfa8034a30c52dd53dc3e967d8 Mon Sep 17 00:00:00 2001 From: Edgar Aroutiounian Date: Tue, 10 Dec 2019 13:40:08 -0800 Subject: [PATCH] [engine] Verify quorum achieved by mask in VerifySeal (#2003) * [engine] Verify quorum achieved by mask in VerifySeal * [engine] Use RJs PR comment on how to pull slotList, move parentQuorum inside else * [node] Use votingpower logic check in node explorer message handler * [explorer][node] Simplify explorer quorum by mask * [engine] Additional check for quorum voting power in VerifyHeaderWithSignature --- internal/chain/engine.go | 71 +++++++++++++++++++++++++++++----------- node/node_explorer.go | 7 ++-- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/internal/chain/engine.go b/internal/chain/engine.go index 466421308..1aa5d9650 100644 --- a/internal/chain/engine.go +++ b/internal/chain/engine.go @@ -11,6 +11,7 @@ import ( "github.com/harmony-one/bls/ffi/go/bls" "github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/consensus/engine" + "github.com/harmony-one/harmony/consensus/quorum" "github.com/harmony-one/harmony/consensus/reward" "github.com/harmony-one/harmony/core/state" "github.com/harmony-one/harmony/core/types" @@ -206,18 +207,37 @@ func (e *engineImpl) VerifySeal(chain engine.ChainReader, header *block.Header) payload := append(sig[:], header.LastCommitBitmap()...) aggSig, mask, err := ReadSignatureBitmapByPublicKeys(payload, publicKeys) if err != nil { - return ctxerror.New("[VerifySeal] Unable to deserialize the LastCommitSignature and LastCommitBitmap in Block Header").WithCause(err) + return ctxerror.New( + "[VerifySeal] Unable to deserialize the LastCommitSignature" + + " and LastCommitBitmap in Block Header", + ).WithCause(err) } parentHash := header.ParentHash() parentHeader := chain.GetHeader(parentHash, header.Number().Uint64()-1) - parentQuorum, err := QuorumForBlock(chain, parentHeader, false) - if err != nil { - return errors.Wrapf(err, - "cannot calculate quorum for block %s", header.Number()) - } - if count := utils.CountOneBits(mask.Bitmap); count < int64(parentQuorum) { - return ctxerror.New("[VerifySeal] Not enough signature in LastCommitSignature from Block Header", - "need", parentQuorum, "got", count) + if e := parentHeader.Epoch(); chain.Config().IsStaking(e) { + slotList, err := chain.ReadShardState(e) + if err != nil { + return errors.Wrapf(err, "cannot read shard state") + } + d := quorum.NewDecider(quorum.SuperMajorityStake) + d.SetVoters(slotList.FindCommitteeByID(parentHeader.ShardID()).Slots) + if !d.IsQuorumAchievedByMask(mask) { + return ctxerror.New( + "[VerifySeal] Not enough voting power in LastCommitSignature from Block Header", + ) + } + } else { + parentQuorum, err := QuorumForBlock(chain, parentHeader, false) + if err != nil { + return errors.Wrapf(err, + "cannot calculate quorum for block %s", header.Number()) + } + if count := utils.CountOneBits(mask.Bitmap); count < int64(parentQuorum) { + return ctxerror.New( + "[VerifySeal] Not enough signature in LastCommitSignature from Block Header", + "need", parentQuorum, "got", count, + ) + } } blockNumHash := make([]byte, 8) @@ -318,18 +338,31 @@ func (e *engineImpl) VerifyHeaderWithSignature(chain engine.ChainReader, header if err != nil { return ctxerror.New("[VerifyHeaderWithSignature] Unable to deserialize the commitSignature and commitBitmap in Block Header").WithCause(err) } - hash := header.Hash() - quorum, err := QuorumForBlock(chain, header, reCalculate) - if err != nil { - return errors.Wrapf(err, - "cannot calculate quorum for block %s", header.Number()) - } - if count := utils.CountOneBits(mask.Bitmap); count < int64(quorum) { - return ctxerror.New("[VerifyHeaderWithSignature] Not enough signature in commitSignature from Block Header", - "need", quorum, "got", count) - } + if e := header.Epoch(); chain.Config().IsStaking(e) { + slotList, err := chain.ReadShardState(e) + if err != nil { + return errors.Wrapf(err, "cannot read shard state") + } + d := quorum.NewDecider(quorum.SuperMajorityStake) + d.SetVoters(slotList.FindCommitteeByID(header.ShardID()).Slots) + if !d.IsQuorumAchievedByMask(mask) { + return ctxerror.New( + "[VerifySeal] Not enough voting power in commitSignature from Block Header", + ) + } + } else { + quorumCount, err := QuorumForBlock(chain, header, reCalculate) + if err != nil { + return errors.Wrapf(err, + "cannot calculate quorum for block %s", header.Number()) + } + if count := utils.CountOneBits(mask.Bitmap); count < int64(quorumCount) { + return ctxerror.New("[VerifyHeaderWithSignature] Not enough signature in commitSignature from Block Header", + "need", quorumCount, "got", count) + } + } blockNumHash := make([]byte, 8) binary.LittleEndian.PutUint64(blockNumHash, header.Number().Uint64()) commitPayload := append(blockNumHash, hash[:]...) diff --git a/node/node_explorer.go b/node/node_explorer.go index 014d77ac1..d8c85fe81 100644 --- a/node/node_explorer.go +++ b/node/node_explorer.go @@ -48,11 +48,8 @@ func (node *Node) ExplorerMessageHandler(payload []byte) { return } - // check has 2f+1 signatures - need := node.Consensus.Decider.TwoThirdsSignersCount() - if count := utils.CountOneBits(mask.Bitmap); count < need { - utils.Logger().Error().Int64("need", need).Int64("have", count). - Msg("[Explorer] not have enough signature") + if node.Consensus.Decider.IsQuorumAchievedByMask(mask) { + utils.Logger().Error().Msg("[Explorer] not have enough signature power") return }