Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions consensus/quorum/quorom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,38 @@ func TestPolicyStrings(t *testing.T) {
}
}

func TestUniformVerifierQuorumByMask(t *testing.T) {
verifier := &uniformVerifier{pubKeyCnt: 4}
publics := make([]bls.PublicKeyWrapper, verifier.pubKeyCnt)
for i := range publics {
publics[i].Object = bls.RandPrivateKey().GetPublicKey()
publics[i].Bytes.FromLibBLSPublicKey(publics[i].Object)
}

tests := []struct {
name string
bitmap []byte
quorum bool
}{
{name: "no signers", bitmap: []byte{0x00}, quorum: false},
{name: "below threshold", bitmap: []byte{0x03}, quorum: false},
{name: "at threshold", bitmap: []byte{0x07}, quorum: true},
{name: "padding bits", bitmap: []byte{0xf0}, quorum: false},
{name: "nil mask", bitmap: nil, quorum: false},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var mask *bls.Mask
if test.bitmap != nil {
mask = bls.NewMask(publics)
require.NoError(t, mask.SetMask(test.bitmap))
}
assert.Equal(t, test.quorum, verifier.IsQuorumAchievedByMask(mask))
})
}
}

func TestAddingQuoromParticipants(t *testing.T) {
decider := NewDecider(SuperMajorityVote, shard.BeaconChainShardID)

Expand Down
19 changes: 11 additions & 8 deletions consensus/quorum/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,18 @@ func newUniformVerifier(committee *shard.Committee) (*uniformVerifier, error) {
}, nil
}

// IsQuorumAchievedByMask returns whether the quorum is achieved with the provided mask,
// which is whether more than (2/3+1) nodes is included in mask.
// IsQuorumAchievedByMask returns whether the quorum is achieved with the provided mask.
func (uv *uniformVerifier) IsQuorumAchievedByMask(mask *bls_cosi.Mask) bool {
got := int64(len(mask.Publics))
exp := uv.thresholdKeyCount()
// Theoretically speaking, greater or equal will do the work. But current logic is more strict
// without equal, thus conform to current logic implemented.
// (engineImpl.VerifySeal, uniformVoteWeight.IsQuorumAchievedByMask)
return got > exp
if mask == nil {
return false
}
var signerCount int64
for i := range mask.Publics {
if enabled, err := mask.IndexEnabled(i); err == nil && enabled {
signerCount++
}
}
return signerCount >= uv.thresholdKeyCount()
}

func (uv *uniformVerifier) thresholdKeyCount() int64 {
Expand Down
37 changes: 37 additions & 0 deletions internal/chain/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/harmony-one/harmony/block"
blockfactory "github.com/harmony-one/harmony/block/factory"
"github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/consensus/quorum"
consensus_sig "github.com/harmony-one/harmony/consensus/signature"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/numeric"
Expand Down Expand Up @@ -498,6 +499,42 @@ func TestVerifiedSigCacheKeyIncludesShardID(t *testing.T) {
}
}

func TestVerifySignatureRejectsEmptyPreStakingQuorum(t *testing.T) {
chain := makeFakeBlockChain()
eng := NewEngine()
state := makeDefaultCommittee()
committee, err := state.FindCommitteeByID(shard.BeaconChainShardID)
if err != nil {
t.Fatal(err)
}
pubKeys, err := committee.BLSPublicKeys()
if err != nil {
t.Fatal(err)
}
verifier, err := quorum.NewVerifier(committee, big.NewInt(0), false)
if err != nil {
t.Fatal(err)
}
eng.epochCtxCache.Add(epochCtxKey{shardID: shard.BeaconChainShardID, epoch: 0}, epochCtx{
qrVerifier: verifier,
pubKeys: pubKeys,
})

err = eng.verifySignature(chain, payloadArgs{
blockHash: common.Hash{1},
shardID: shard.BeaconChainShardID,
epoch: big.NewInt(0),
number: 2,
viewID: 1,
}, sigArgs{
sig: bls.SerializedSignature{},
bitmap: make([]byte, (len(pubKeys)+7)/8),
})
if err == nil || err.Error() != "not enough signature collected" {
t.Fatalf("expected empty quorum rejection, got %v", err)
}
}

// setupTimestampValidationChain returns a chain wired with the timestamp
// validation fork active, the parent header committed at parentTime, and a
// helper to build child headers parented to it.
Expand Down