|
|
|
@ -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) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|