Add more unit tests for vote submission

pull/3374/head
Rongjian Lan 4 years ago
parent 10ca5433ac
commit b13c96bc1e
  1. 420
      consensus/quorum/quorom_test.go
  2. 8
      consensus/quorum/quorum.go

@ -1,11 +1,18 @@
package quorum
import (
"math/big"
"strings"
"testing"
bls_core "github.com/harmony-one/bls/ffi/go/bls"
harmony_bls "github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/configs/sharding"
"github.com/harmony-one/harmony/shard"
"github.com/stretchr/testify/assert"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/crypto/bls"
)
func TestPhaseStrings(t *testing.T) {
@ -59,3 +66,416 @@ func TestAddingQuoromParticipants(t *testing.T) {
decider.UpdateParticipants(blsKeys)
assert.Equal(t, keyCount, decider.ParticipantsCount())
}
func TestSubmitVote(test *testing.T) {
blockHash := [32]byte{}
copy(blockHash[:], []byte("random"))
blockNum := uint64(1000)
viewID := uint64(2)
decider := NewDecider(
SuperMajorityStake, shard.BeaconChainShardID,
)
message := "test string"
blsPriKey1 := bls.RandPrivateKey()
pubKeyWrapper1 := bls.PublicKeyWrapper{Object: blsPriKey1.GetPublicKey()}
pubKeyWrapper1.Bytes.FromLibBLSPublicKey(pubKeyWrapper1.Object)
blsPriKey2 := bls.RandPrivateKey()
pubKeyWrapper2 := bls.PublicKeyWrapper{Object: blsPriKey2.GetPublicKey()}
pubKeyWrapper2.Bytes.FromLibBLSPublicKey(pubKeyWrapper2.Object)
decider.UpdateParticipants([]bls.PublicKeyWrapper{pubKeyWrapper1, pubKeyWrapper2})
if _, err := decider.SubmitVote(
Prepare,
[]bls.SerializedPublicKey{pubKeyWrapper1.Bytes},
blsPriKey1.Sign(message),
common.BytesToHash(blockHash[:]),
blockNum,
viewID,
); err != nil {
test.Log(err)
}
if _, err := decider.SubmitVote(
Prepare,
[]bls.SerializedPublicKey{pubKeyWrapper2.Bytes},
blsPriKey2.Sign(message),
common.BytesToHash(blockHash[:]),
blockNum,
viewID,
); err != nil {
test.Log(err)
}
if decider.SignersCount(Prepare) != 2 {
test.Fatal("SubmitVote failed")
}
aggSig := &bls_core.Sign{}
aggSig.Add(blsPriKey1.Sign(message))
aggSig.Add(blsPriKey2.Sign(message))
if decider.AggregateVotes(Prepare).SerializeToHexStr() != aggSig.SerializeToHexStr() {
test.Fatal("AggregateVotes failed")
}
}
func TestSubmitVoteAggregateSig(test *testing.T) {
blockHash := [32]byte{}
copy(blockHash[:], []byte("random"))
blockNum := uint64(1000)
viewID := uint64(2)
decider := NewDecider(
SuperMajorityStake, shard.BeaconChainShardID,
)
blsPriKey1 := bls.RandPrivateKey()
pubKeyWrapper1 := bls.PublicKeyWrapper{Object: blsPriKey1.GetPublicKey()}
pubKeyWrapper1.Bytes.FromLibBLSPublicKey(pubKeyWrapper1.Object)
blsPriKey2 := bls.RandPrivateKey()
pubKeyWrapper2 := bls.PublicKeyWrapper{Object: blsPriKey2.GetPublicKey()}
pubKeyWrapper2.Bytes.FromLibBLSPublicKey(pubKeyWrapper2.Object)
blsPriKey3 := bls.RandPrivateKey()
pubKeyWrapper3 := bls.PublicKeyWrapper{Object: blsPriKey3.GetPublicKey()}
pubKeyWrapper3.Bytes.FromLibBLSPublicKey(pubKeyWrapper3.Object)
decider.UpdateParticipants([]bls.PublicKeyWrapper{pubKeyWrapper1, pubKeyWrapper2})
decider.SubmitVote(
Prepare,
[]bls.SerializedPublicKey{pubKeyWrapper1.Bytes},
blsPriKey1.SignHash(blockHash[:]),
common.BytesToHash(blockHash[:]),
blockNum,
viewID,
)
aggSig := &bls_core.Sign{}
for _, priKey := range []*bls_core.SecretKey{blsPriKey2, blsPriKey3} {
if s := priKey.SignHash(blockHash[:]); s != nil {
aggSig.Add(s)
}
}
if _, err := decider.SubmitVote(
Prepare,
[]bls.SerializedPublicKey{pubKeyWrapper2.Bytes, pubKeyWrapper3.Bytes},
aggSig,
common.BytesToHash(blockHash[:]),
blockNum,
viewID,
); err != nil {
test.Log(err)
}
if decider.SignersCount(Prepare) != 3 {
test.Fatal("SubmitVote failed")
}
aggSig.Add(blsPriKey1.SignHash(blockHash[:]))
if decider.AggregateVotes(Prepare).SerializeToHexStr() != aggSig.SerializeToHexStr() {
test.Fatal("AggregateVotes failed")
}
if _, err := decider.SubmitVote(
Prepare,
[]bls.SerializedPublicKey{pubKeyWrapper2.Bytes},
aggSig,
common.BytesToHash(blockHash[:]),
blockNum,
viewID,
); err == nil {
test.Fatal("Expect error for duplicate votes from the same key")
}
}
func TestAddNewVote(test *testing.T) {
shard.Schedule = shardingconfig.LocalnetSchedule
blockHash := [32]byte{}
copy(blockHash[:], []byte("random"))
blockNum := uint64(1000)
viewID := uint64(2)
decider := NewDecider(
SuperMajorityStake, shard.BeaconChainShardID,
)
slotList := shard.SlotList{}
sKeys := []bls_core.SecretKey{}
pubKeys := []bls.PublicKeyWrapper{}
quorumNodes := 10
for i := 0; i < quorumNodes; i++ {
newSlot, sKey := generateRandomSlot()
if i < 3 {
newSlot.EffectiveStake = nil
}
sKeys = append(sKeys, sKey)
slotList = append(slotList, newSlot)
wrapper := bls.PublicKeyWrapper{Object: sKey.GetPublicKey()}
wrapper.Bytes.FromLibBLSPublicKey(wrapper.Object)
pubKeys = append(pubKeys, wrapper)
}
decider.UpdateParticipants(pubKeys)
decider.SetVoters(&shard.Committee{
shard.BeaconChainShardID, slotList,
}, big.NewInt(3))
aggSig := &bls_core.Sign{}
for _, priKey := range []*bls_core.SecretKey{&sKeys[0], &sKeys[1], &sKeys[2]} {
if s := priKey.SignHash(blockHash[:]); s != nil {
aggSig.Add(s)
}
}
// aggregate sig from all of 3 harmony nodes
decider.AddNewVote(Prepare,
[]*bls.PublicKeyWrapper{&pubKeys[0], &pubKeys[1], &pubKeys[2]},
aggSig,
common.BytesToHash(blockHash[:]),
blockNum,
viewID)
if !decider.IsQuorumAchieved(Prepare) {
test.Error("quorum should have been achieved with harmony nodes")
}
if decider.SignersCount(Prepare) != 3 {
test.Errorf("signers are incorrect for harmony nodes signing with aggregate sig: have %d, expect %d", decider.SignersCount(Prepare), 3)
}
decider.ResetPrepareAndCommitVotes()
// aggregate sig from 3 external nodes, expect error
aggSig = &bls_core.Sign{}
for _, priKey := range []*bls_core.SecretKey{&sKeys[3], &sKeys[4], &sKeys[5]} {
if s := priKey.SignHash(blockHash[:]); s != nil {
aggSig.Add(s)
}
}
_, err := decider.AddNewVote(Prepare,
[]*bls.PublicKeyWrapper{&pubKeys[3], &pubKeys[4], &pubKeys[5]},
aggSig,
common.BytesToHash(blockHash[:]),
blockNum,
viewID)
if err == nil {
test.Error("Should have error due to aggregate sig from multiple accounts")
}
if decider.IsQuorumAchieved(Prepare) {
test.Fatal("quorum shouldn't have been achieved with external nodes")
}
if decider.SignersCount(Prepare) != 0 {
test.Errorf("signers are incorrect for harmony nodes signing with aggregate sig: have %d, expect %d", decider.SignersCount(Prepare), 0)
}
decider.ResetPrepareAndCommitVotes()
// one sig from external node
_, err = decider.AddNewVote(Prepare,
[]*bls.PublicKeyWrapper{&pubKeys[3]},
sKeys[3].SignHash(blockHash[:]),
common.BytesToHash(blockHash[:]),
blockNum,
viewID)
if err != nil {
test.Error(err)
}
if decider.IsQuorumAchieved(Prepare) {
test.Fatal("quorum shouldn't have been achieved with only one key signing")
}
if decider.SignersCount(Prepare) != 1 {
test.Errorf("signers are incorrect for harmony nodes signing with aggregate sig: have %d, expect %d", decider.SignersCount(Prepare), 1)
}
}
func TestAddNewVoteAggregateSig(test *testing.T) {
shard.Schedule = shardingconfig.LocalnetSchedule
blockHash := [32]byte{}
copy(blockHash[:], []byte("random"))
blockNum := uint64(1000)
viewID := uint64(2)
decider := NewDecider(
SuperMajorityStake, shard.BeaconChainShardID,
)
slotList := shard.SlotList{}
sKeys := []bls_core.SecretKey{}
pubKeys := []bls.PublicKeyWrapper{}
quorumNodes := 5
for i := 0; i < quorumNodes; i++ {
newSlot, sKey := generateRandomSlot()
if i < 3 {
newSlot.EffectiveStake = nil
}
sKeys = append(sKeys, sKey)
slotList = append(slotList, newSlot)
wrapper := bls.PublicKeyWrapper{Object: sKey.GetPublicKey()}
wrapper.Bytes.FromLibBLSPublicKey(wrapper.Object)
pubKeys = append(pubKeys, wrapper)
}
// make all external keys belong to same account
slotList[3].EcdsaAddress = slotList[4].EcdsaAddress
decider.UpdateParticipants(pubKeys)
decider.SetVoters(&shard.Committee{
shard.BeaconChainShardID, slotList,
}, big.NewInt(3))
aggSig := &bls_core.Sign{}
for _, priKey := range []*bls_core.SecretKey{&sKeys[0], &sKeys[1]} {
if s := priKey.SignHash(blockHash[:]); s != nil {
aggSig.Add(s)
}
}
// aggregate sig from all of 2 harmony nodes
decider.AddNewVote(Prepare,
[]*bls.PublicKeyWrapper{&pubKeys[0], &pubKeys[1]},
aggSig,
common.BytesToHash(blockHash[:]),
blockNum,
viewID)
if decider.IsQuorumAchieved(Prepare) {
test.Error("quorum should not have been achieved with 2 harmony nodes")
}
if decider.SignersCount(Prepare) != 2 {
test.Errorf("signers are incorrect for harmony nodes signing with aggregate sig: have %d, expect %d", decider.SignersCount(Prepare), 2)
}
// aggregate sig from all of 2 external nodes
aggSig = &bls_core.Sign{}
for _, priKey := range []*bls_core.SecretKey{&sKeys[3], &sKeys[4]} {
if s := priKey.SignHash(blockHash[:]); s != nil {
aggSig.Add(s)
}
}
decider.AddNewVote(Prepare,
[]*bls.PublicKeyWrapper{&pubKeys[3], &pubKeys[4]},
aggSig,
common.BytesToHash(blockHash[:]),
blockNum,
viewID)
if !decider.IsQuorumAchieved(Prepare) {
test.Error("quorum should have been achieved with 2 harmony nodes")
}
if decider.SignersCount(Prepare) != 4 {
test.Errorf("signers are incorrect for harmony nodes signing with aggregate sig: have %d, expect %d", decider.SignersCount(Prepare), 4)
}
}
func TestAddNewVoteInvalidAggregateSig(test *testing.T) {
shard.Schedule = shardingconfig.LocalnetSchedule
blockHash := [32]byte{}
copy(blockHash[:], []byte("random"))
blockNum := uint64(1000)
viewID := uint64(2)
decider := NewDecider(
SuperMajorityStake, shard.BeaconChainShardID,
)
slotList := shard.SlotList{}
sKeys := []bls_core.SecretKey{}
pubKeys := []bls.PublicKeyWrapper{}
quorumNodes := 8
for i := 0; i < quorumNodes; i++ {
newSlot, sKey := generateRandomSlot()
if i < 3 {
newSlot.EffectiveStake = nil
}
sKeys = append(sKeys, sKey)
slotList = append(slotList, newSlot)
wrapper := bls.PublicKeyWrapper{Object: sKey.GetPublicKey()}
wrapper.Bytes.FromLibBLSPublicKey(wrapper.Object)
pubKeys = append(pubKeys, wrapper)
}
// make all external keys belong to same account
slotList[3].EcdsaAddress = slotList[7].EcdsaAddress
slotList[4].EcdsaAddress = slotList[7].EcdsaAddress
slotList[5].EcdsaAddress = slotList[7].EcdsaAddress
slotList[6].EcdsaAddress = slotList[7].EcdsaAddress
decider.UpdateParticipants(pubKeys)
decider.SetVoters(&shard.Committee{
shard.BeaconChainShardID, slotList,
}, big.NewInt(3))
aggSig := &bls_core.Sign{}
for _, priKey := range []*bls_core.SecretKey{&sKeys[0], &sKeys[1]} {
if s := priKey.SignHash(blockHash[:]); s != nil {
aggSig.Add(s)
}
}
// aggregate sig from all of 2 harmony nodes
decider.AddNewVote(Prepare,
[]*bls.PublicKeyWrapper{&pubKeys[0], &pubKeys[1]},
aggSig,
common.BytesToHash(blockHash[:]),
blockNum,
viewID)
if decider.IsQuorumAchieved(Prepare) {
test.Error("quorum should not have been achieved with 2 harmony nodes")
}
if decider.SignersCount(Prepare) != 2 {
test.Errorf("signers are incorrect for harmony nodes signing with aggregate sig: have %d, expect %d", decider.SignersCount(Prepare), 2)
}
// aggregate sig from all of 2 external nodes
_, err := decider.AddNewVote(Prepare,
[]*bls.PublicKeyWrapper{&pubKeys[3], &pubKeys[4]},
aggSig,
common.BytesToHash(blockHash[:]),
blockNum,
viewID)
if err != nil {
test.Error(err, "expect no error")
}
if decider.SignersCount(Prepare) != 4 {
test.Errorf("signers are incorrect for harmony nodes signing with aggregate sig: have %d, expect %d", decider.SignersCount(Prepare), 4)
}
_, err = decider.AddNewVote(Prepare,
[]*bls.PublicKeyWrapper{&pubKeys[3], &pubKeys[7]},
aggSig,
common.BytesToHash(blockHash[:]),
blockNum,
viewID)
if !strings.Contains(err.Error(), "vote is already submitted") {
test.Error(err, "expect error due to already submitted votes")
}
if decider.SignersCount(Prepare) != 4 {
test.Errorf("signers are incorrect for harmony nodes signing with aggregate sig: have %d, expect %d", decider.SignersCount(Prepare), 4)
}
_, err = decider.AddNewVote(Prepare,
[]*bls.PublicKeyWrapper{&pubKeys[6], &pubKeys[5], &pubKeys[6]},
aggSig,
common.BytesToHash(blockHash[:]),
blockNum,
viewID)
if !strings.Contains(err.Error(), "duplicate key found in votes") {
test.Error(err, "expect error due to duplicate keys in aggregated votes")
}
if decider.SignersCount(Prepare) != 4 {
test.Errorf("signers are incorrect for harmony nodes signing with aggregate sig: have %d, expect %d", decider.SignersCount(Prepare), 4)
}
}

@ -16,7 +16,7 @@ import (
"github.com/pkg/errors"
)
// MessageType is a phase that needs quorum to proceed
// Phase is a phase that needs quorum to proceed
type Phase byte
const (
@ -253,7 +253,13 @@ func (s *cIdentities) SubmitVote(
sig *bls_core.Sign, headerHash common.Hash,
height, viewID uint64,
) (*votepower.Ballot, error) {
seenKeys := map[bls.SerializedPublicKey]struct{}{}
for _, pubKey := range pubkeys {
if _, ok := seenKeys[pubKey]; ok {
return nil, errors.Errorf("duplicate key found in votes %x", pubKey)
}
seenKeys[pubKey] = struct{}{}
if ballet := s.ReadBallot(p, pubKey); ballet != nil {
return nil, errors.Errorf("vote is already submitted %x", pubKey)
}

Loading…
Cancel
Save