|
|
|
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"
|
|
|
|
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
|
|
|
|
"github.com/harmony-one/harmony/numeric"
|
|
|
|
"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) {
|
|
|
|
phases := []Phase{
|
|
|
|
Prepare,
|
|
|
|
Commit,
|
|
|
|
ViewChange,
|
|
|
|
}
|
|
|
|
|
|
|
|
expectations := make(map[Phase]string)
|
|
|
|
expectations[Prepare] = "Prepare"
|
|
|
|
expectations[Commit] = "Commit"
|
|
|
|
expectations[ViewChange] = "viewChange"
|
|
|
|
|
|
|
|
for _, phase := range phases {
|
|
|
|
expected := expectations[phase]
|
|
|
|
assert.Equal(t, expected, phase.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPolicyStrings(t *testing.T) {
|
|
|
|
policies := []Policy{
|
|
|
|
SuperMajorityVote,
|
|
|
|
SuperMajorityStake,
|
|
|
|
}
|
|
|
|
|
|
|
|
expectations := make(map[Policy]string)
|
|
|
|
expectations[SuperMajorityVote] = "SuperMajorityVote"
|
|
|
|
expectations[SuperMajorityStake] = "SuperMajorityStake"
|
|
|
|
|
|
|
|
for _, policy := range policies {
|
|
|
|
expected := expectations[policy]
|
|
|
|
assert.Equal(t, expected, policy.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAddingQuoromParticipants(t *testing.T) {
|
|
|
|
decider := NewDecider(SuperMajorityVote, shard.BeaconChainShardID)
|
|
|
|
|
|
|
|
assert.Equal(t, int64(0), decider.ParticipantsCount())
|
|
|
|
|
|
|
|
blsKeys := []harmony_bls.PublicKeyWrapper{}
|
|
|
|
keyCount := int64(5)
|
|
|
|
for i := int64(0); i < keyCount; i++ {
|
|
|
|
blsKey := harmony_bls.RandPrivateKey()
|
|
|
|
wrapper := harmony_bls.PublicKeyWrapper{Object: blsKey.GetPublicKey()}
|
|
|
|
wrapper.Bytes.FromLibBLSPublicKey(wrapper.Object)
|
|
|
|
blsKeys = append(blsKeys, wrapper)
|
|
|
|
}
|
|
|
|
|
|
|
|
decider.UpdateParticipants(blsKeys, []bls.PublicKeyWrapper{})
|
|
|
|
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}, []bls.PublicKeyWrapper{})
|
|
|
|
|
|
|
|
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}, []bls.PublicKeyWrapper{})
|
|
|
|
|
|
|
|
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, []bls.PublicKeyWrapper{})
|
|
|
|
decider.SetVoters(&shard.Committee{
|
|
|
|
ShardID: shard.BeaconChainShardID, Slots: 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, []bls.PublicKeyWrapper{})
|
|
|
|
decider.SetVoters(&shard.Committee{
|
|
|
|
ShardID: shard.BeaconChainShardID, Slots: 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, []bls.PublicKeyWrapper{})
|
|
|
|
decider.SetVoters(&shard.Committee{
|
|
|
|
ShardID: shard.BeaconChainShardID, Slots: 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)
|
|
|
|
}
|
|
|
|
|
|
|
|
aggSig = &bls_core.Sign{}
|
|
|
|
for _, priKey := range []*bls_core.SecretKey{&sKeys[3], &sKeys[4]} {
|
|
|
|
if s := priKey.SignHash(blockHash[:]); s != nil {
|
|
|
|
aggSig.Add(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Aggregate Vote should only contain sig from 0, 1, 3, 4
|
|
|
|
fourSigs := decider.AggregateVotes(Prepare)
|
|
|
|
aggPubKey := &bls_core.PublicKey{}
|
|
|
|
for _, priKey := range []*bls_core.PublicKey{pubKeys[0].Object, pubKeys[1].Object, pubKeys[3].Object, pubKeys[4].Object} {
|
|
|
|
aggPubKey.Add(priKey)
|
|
|
|
}
|
|
|
|
if !fourSigs.VerifyHash(aggPubKey, blockHash[:]) {
|
|
|
|
test.Error("Failed to aggregate votes for 4 keys from 2 aggregate sigs")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestInvalidAggregateSig(test *testing.T) {
|
|
|
|
shard.Schedule = shardingconfig.LocalnetSchedule
|
|
|
|
blockHash := [32]byte{}
|
|
|
|
copy(blockHash[:], []byte("random"))
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
aggSig := &bls_core.Sign{}
|
|
|
|
for _, priKey := range []*bls_core.SecretKey{&sKeys[0], &sKeys[1], &sKeys[2], &sKeys[2]} {
|
|
|
|
if s := priKey.SignHash(blockHash[:]); s != nil {
|
|
|
|
aggSig.Add(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
aggPubKey := &bls_core.PublicKey{}
|
|
|
|
|
|
|
|
for _, priKey := range []*bls_core.PublicKey{pubKeys[0].Object, pubKeys[1].Object, pubKeys[2].Object} {
|
|
|
|
aggPubKey.Add(priKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
if aggSig.VerifyHash(aggPubKey, blockHash[:]) {
|
|
|
|
test.Error("Expect aggregate signature verification to fail due to duplicate signing from one key")
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !aggSig.VerifyHash(aggPubKey, blockHash[:]) {
|
|
|
|
test.Error("Expect aggregate signature verification to succeed with correctly matched keys and sigs")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNthNextHmyExt(test *testing.T) {
|
|
|
|
numHmyNodes := 10
|
|
|
|
numAllExtNodes := 10
|
|
|
|
numAllowlistExtNodes := numAllExtNodes / 2
|
|
|
|
allowlist := shardingconfig.Allowlist{MaxLimitPerShard: numAllowlistExtNodes - 1}
|
|
|
|
blsKeys := []harmony_bls.PublicKeyWrapper{}
|
|
|
|
for i := 0; i < numHmyNodes+numAllExtNodes; i++ {
|
|
|
|
blsKey := harmony_bls.RandPrivateKey()
|
|
|
|
wrapper := harmony_bls.PublicKeyWrapper{Object: blsKey.GetPublicKey()}
|
|
|
|
wrapper.Bytes.FromLibBLSPublicKey(wrapper.Object)
|
|
|
|
blsKeys = append(blsKeys, wrapper)
|
|
|
|
}
|
|
|
|
allowlistLeaders := blsKeys[len(blsKeys)-allowlist.MaxLimitPerShard:]
|
|
|
|
allLeaders := append(blsKeys[:numHmyNodes], allowlistLeaders...)
|
|
|
|
|
|
|
|
decider := NewDecider(SuperMajorityVote, shard.BeaconChainShardID)
|
|
|
|
fakeInstance := shardingconfig.MustNewInstance(2, 20, numHmyNodes, 0, numeric.OneDec(), nil, nil, allowlist, nil, 0)
|
|
|
|
|
|
|
|
decider.UpdateParticipants(blsKeys, allowlistLeaders)
|
|
|
|
for i := 0; i < len(allLeaders); i++ {
|
|
|
|
leader := allLeaders[i]
|
|
|
|
for j := 0; j < len(allLeaders)*2; j++ {
|
|
|
|
expectNextLeader := allLeaders[(i+j)%len(allLeaders)]
|
|
|
|
found, nextLeader := decider.NthNextHmyExt(fakeInstance, &leader, j)
|
|
|
|
if !found {
|
|
|
|
test.Fatal("next leader not found")
|
|
|
|
}
|
|
|
|
if expectNextLeader.Bytes != nextLeader.Bytes {
|
|
|
|
test.Fatal("next leader is not expected")
|
|
|
|
}
|
|
|
|
|
|
|
|
preJ := -j
|
|
|
|
preIndex := (i + len(allLeaders) + preJ%len(allLeaders)) % len(allLeaders)
|
|
|
|
expectPreLeader := allLeaders[preIndex]
|
|
|
|
found, preLeader := decider.NthNextHmyExt(fakeInstance, &leader, preJ)
|
|
|
|
if !found {
|
|
|
|
test.Fatal("previous leader not found")
|
|
|
|
}
|
|
|
|
if expectPreLeader.Bytes != preLeader.Bytes {
|
|
|
|
test.Fatal("previous leader is not expected")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|