You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
4.7 KiB
148 lines
4.7 KiB
package votepower
|
|
|
|
import (
|
|
"math/big"
|
|
"math/rand"
|
|
"testing"
|
|
|
|
"github.com/harmony-one/harmony/crypto/bls"
|
|
|
|
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
bls_core "github.com/harmony-one/bls/ffi/go/bls"
|
|
"github.com/harmony-one/harmony/numeric"
|
|
"github.com/harmony-one/harmony/shard"
|
|
)
|
|
|
|
var (
|
|
slotList shard.SlotList
|
|
totalStake numeric.Dec
|
|
harmonyNodes = 10
|
|
stakedNodes = 10
|
|
maxAccountGen = int64(98765654323123134)
|
|
accountGen = rand.New(rand.NewSource(1337))
|
|
maxKeyGen = int64(98765654323123134)
|
|
keyGen = rand.New(rand.NewSource(42))
|
|
maxStakeGen = int64(200)
|
|
stakeGen = rand.New(rand.NewSource(541))
|
|
)
|
|
|
|
func init() {
|
|
shard.Schedule = shardingconfig.LocalnetSchedule
|
|
for i := 0; i < harmonyNodes; i++ {
|
|
newSlot := generateRandomSlot()
|
|
newSlot.EffectiveStake = nil
|
|
slotList = append(slotList, newSlot)
|
|
}
|
|
|
|
totalStake = numeric.ZeroDec()
|
|
for j := 0; j < stakedNodes; j++ {
|
|
newSlot := generateRandomSlot()
|
|
totalStake = totalStake.Add(*newSlot.EffectiveStake)
|
|
slotList = append(slotList, newSlot)
|
|
}
|
|
}
|
|
|
|
func generateRandomSlot() shard.Slot {
|
|
addr := common.Address{}
|
|
addr.SetBytes(big.NewInt(int64(accountGen.Int63n(maxAccountGen))).Bytes())
|
|
secretKey := bls_core.SecretKey{}
|
|
secretKey.Deserialize(big.NewInt(int64(keyGen.Int63n(maxKeyGen))).Bytes())
|
|
key := bls.SerializedPublicKey{}
|
|
key.FromLibBLSPublicKey(secretKey.GetPublicKey())
|
|
stake := numeric.NewDecFromBigInt(big.NewInt(int64(stakeGen.Int63n(maxStakeGen))))
|
|
return shard.Slot{EcdsaAddress: addr, BLSPublicKey: key, EffectiveStake: &stake}
|
|
}
|
|
|
|
func TestCompute(t *testing.T) {
|
|
expectedRoster := NewRoster(shard.BeaconChainShardID)
|
|
// Calculated when generated
|
|
expectedRoster.TotalEffectiveStake = totalStake
|
|
expectedRoster.HMYSlotCount = int64(harmonyNodes)
|
|
|
|
asDecHMYSlotCount := numeric.NewDec(expectedRoster.HMYSlotCount)
|
|
ourPercentage := numeric.ZeroDec()
|
|
theirPercentage := numeric.ZeroDec()
|
|
|
|
staked := slotList
|
|
for i := range staked {
|
|
member := AccommodateHarmonyVote{
|
|
PureStakedVote: PureStakedVote{
|
|
EarningAccount: staked[i].EcdsaAddress,
|
|
Identity: staked[i].BLSPublicKey,
|
|
GroupPercent: numeric.ZeroDec(),
|
|
EffectiveStake: numeric.ZeroDec(),
|
|
},
|
|
OverallPercent: numeric.ZeroDec(),
|
|
IsHarmonyNode: false,
|
|
}
|
|
|
|
// Real Staker
|
|
harmonyPercent := shard.Schedule.InstanceForEpoch(big.NewInt(3)).HarmonyVotePercent()
|
|
externalPercent := shard.Schedule.InstanceForEpoch(big.NewInt(3)).ExternalVotePercent()
|
|
if e := staked[i].EffectiveStake; e != nil {
|
|
member.EffectiveStake = member.EffectiveStake.Add(*e)
|
|
member.GroupPercent = e.Quo(expectedRoster.TotalEffectiveStake)
|
|
member.OverallPercent = member.GroupPercent.Mul(externalPercent)
|
|
theirPercentage = theirPercentage.Add(member.OverallPercent)
|
|
} else { // Our node
|
|
member.IsHarmonyNode = true
|
|
member.OverallPercent = harmonyPercent.Quo(asDecHMYSlotCount)
|
|
member.GroupPercent = member.OverallPercent.Quo(harmonyPercent)
|
|
ourPercentage = ourPercentage.Add(member.OverallPercent)
|
|
}
|
|
|
|
expectedRoster.Voters[staked[i].BLSPublicKey] = &member
|
|
}
|
|
|
|
expectedRoster.OurVotingPowerTotalPercentage = ourPercentage
|
|
expectedRoster.TheirVotingPowerTotalPercentage = theirPercentage
|
|
|
|
computedRoster, err := Compute(&shard.Committee{
|
|
ShardID: shard.BeaconChainShardID, Slots: slotList,
|
|
}, big.NewInt(3))
|
|
if err != nil {
|
|
t.Error("Computed Roster failed on vote summation to one")
|
|
}
|
|
|
|
if !compareRosters(expectedRoster, computedRoster, t) {
|
|
t.Errorf("Compute Roster mismatch with expected Roster")
|
|
}
|
|
// Check that voting percents sum to 100
|
|
if !computedRoster.OurVotingPowerTotalPercentage.Add(
|
|
computedRoster.TheirVotingPowerTotalPercentage,
|
|
).Equal(numeric.OneDec()) {
|
|
t.Errorf(
|
|
"Total voting power does not equal 1. Harmony voting power: %s, Staked voting power: %s",
|
|
computedRoster.OurVotingPowerTotalPercentage,
|
|
computedRoster.TheirVotingPowerTotalPercentage,
|
|
)
|
|
}
|
|
}
|
|
|
|
func compareRosters(a, b *Roster, t *testing.T) bool {
|
|
voterMatch := true
|
|
for k, voter := range a.Voters {
|
|
if other, exists := b.Voters[k]; exists {
|
|
if !compareStakedVoter(voter, other) {
|
|
t.Error("voter slot not match")
|
|
voterMatch = false
|
|
}
|
|
} else {
|
|
t.Error("computed roster missing")
|
|
voterMatch = false
|
|
}
|
|
}
|
|
return a.OurVotingPowerTotalPercentage.Equal(b.OurVotingPowerTotalPercentage) &&
|
|
a.TheirVotingPowerTotalPercentage.Equal(b.TheirVotingPowerTotalPercentage) &&
|
|
a.TotalEffectiveStake.Equal(b.TotalEffectiveStake) &&
|
|
a.HMYSlotCount == b.HMYSlotCount && voterMatch
|
|
}
|
|
|
|
func compareStakedVoter(a, b *AccommodateHarmonyVote) bool {
|
|
return a.IsHarmonyNode == b.IsHarmonyNode &&
|
|
a.EarningAccount == b.EarningAccount &&
|
|
a.OverallPercent.Equal(b.OverallPercent) &&
|
|
a.EffectiveStake.Equal(b.EffectiveStake)
|
|
}
|
|
|