[unit-testing] Add units test for roster.go & calculate.go (#1885)
* [unit-testing] Add unit test for effective stake calculation * [unit-testing] Intermediate commit * [unit-testing] Another intermediate commit * [unit-testing] Add unit test for Roster compute * Remove unnecessary codepull/1890/head
parent
4b46e5f708
commit
1cc2518d31
@ -0,0 +1,140 @@ |
||||
package votepower |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"math/big" |
||||
"math/rand" |
||||
"strconv" |
||||
"testing" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"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() { |
||||
for i := 0; i < harmonyNodes; i++ { |
||||
newSlot := generateRandomSlot() |
||||
newSlot.TotalStake = nil |
||||
slotList = append(slotList, newSlot) |
||||
} |
||||
|
||||
totalStake = numeric.ZeroDec() |
||||
for j := 0; j < stakedNodes; j++ { |
||||
newSlot := generateRandomSlot() |
||||
totalStake = totalStake.Add(*newSlot.TotalStake) |
||||
slotList = append(slotList, newSlot) |
||||
} |
||||
} |
||||
|
||||
func generateRandomSlot() shard.Slot { |
||||
addr := common.Address{} |
||||
addr.SetBytes(big.NewInt(int64(accountGen.Int63n(maxAccountGen))).Bytes()) |
||||
secretKey := bls.SecretKey{} |
||||
secretKey.Deserialize(big.NewInt(int64(keyGen.Int63n(maxKeyGen))).Bytes()) |
||||
key := shard.BlsPublicKey{} |
||||
key.FromLibBLSPublicKey(secretKey.GetPublicKey()) |
||||
stake := numeric.NewDecFromBigInt(big.NewInt(int64(stakeGen.Int63n(maxStakeGen)))) |
||||
return shard.Slot{addr, key, &stake} |
||||
} |
||||
|
||||
func TestCompute(t *testing.T) { |
||||
expectedRoster := NewRoster() |
||||
// Parameterized
|
||||
expectedRoster.HmySlotCount = int64(harmonyNodes) |
||||
// Calculated when generated
|
||||
expectedRoster.RawStakedTotal = totalStake |
||||
for _, slot := range slotList { |
||||
newMember := stakedVoter{ |
||||
IsActive: true, |
||||
IsHarmonyNode: false, |
||||
EarningAccount: slot.EcdsaAddress, |
||||
EffectivePercent: numeric.ZeroDec(), |
||||
RawStake: numeric.ZeroDec(), |
||||
} |
||||
// Not Harmony node
|
||||
if slot.TotalStake != nil { |
||||
newMember.RawStake = *slot.TotalStake |
||||
newMember.EffectivePercent = slot.TotalStake.Quo(expectedRoster.RawStakedTotal).Mul(StakersShare) |
||||
expectedRoster.TheirVotingPowerTotalPercentage = expectedRoster.TheirVotingPowerTotalPercentage.Add(newMember.EffectivePercent) |
||||
} else { |
||||
// Harmony node
|
||||
newMember.IsHarmonyNode = true |
||||
newMember.RawStake = numeric.ZeroDec() |
||||
newMember.EffectivePercent = HarmonysShare.Quo(numeric.NewDec(expectedRoster.HmySlotCount)) |
||||
expectedRoster.OurVotingPowerTotalPercentage = expectedRoster.OurVotingPowerTotalPercentage.Add(newMember.EffectivePercent) |
||||
} |
||||
expectedRoster.Voters[slot.BlsPublicKey] = newMember |
||||
} |
||||
|
||||
computedRoster := Compute(slotList) |
||||
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 { |
||||
// Compare stakedVoter maps
|
||||
voterMatch := true |
||||
for k, voter := range a.Voters { |
||||
if other, exists := b.Voters[k]; exists { |
||||
if !compareStakedVoter(voter, other) { |
||||
t.Errorf("Expecting %s\n Got %s", voter.formatString(), other.formatString()) |
||||
voterMatch = false |
||||
} |
||||
} else { |
||||
t.Errorf("Computed roster missing %s", voter.formatString()) |
||||
voterMatch = false |
||||
} |
||||
} |
||||
return a.OurVotingPowerTotalPercentage.Equal(b.OurVotingPowerTotalPercentage) && |
||||
a.TheirVotingPowerTotalPercentage.Equal(b.TheirVotingPowerTotalPercentage) && |
||||
a.RawStakedTotal.Equal(b.RawStakedTotal) && |
||||
a.HmySlotCount == b.HmySlotCount && voterMatch |
||||
} |
||||
|
||||
func compareStakedVoter(a, b stakedVoter) bool { |
||||
return a.IsActive == b.IsActive && |
||||
a.IsHarmonyNode == b.IsHarmonyNode && |
||||
a.EarningAccount == b.EarningAccount && |
||||
a.EffectivePercent.Equal(b.EffectivePercent) && |
||||
a.RawStake.Equal(b.RawStake) |
||||
} |
||||
|
||||
func (s *stakedVoter) formatString() string { |
||||
type t struct { |
||||
IsActive string `json:"active"` |
||||
IsHarmony string `json:"harmony-node"` |
||||
EarningAccount string `json:"one-address"` |
||||
EffectivePercent string `json:"effective-percent"` |
||||
RawStake string `json:"raw-stake"` |
||||
} |
||||
data := t{ |
||||
strconv.FormatBool(s.IsActive), |
||||
strconv.FormatBool(s.IsHarmonyNode), |
||||
s.EarningAccount.String(), |
||||
s.EffectivePercent.String(), |
||||
s.RawStake.String(), |
||||
} |
||||
output, _ := json.Marshal(data) |
||||
return string(output) |
||||
} |
Loading…
Reference in new issue