Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Write a test case to verify a new voter sampling #129

Merged
merged 11 commits into from
Nov 12, 2020

Conversation

kukugi
Copy link

@kukugi kukugi commented Oct 23, 2020

Description

This PR is for adding a test case to verify #124.
Verify a new function to elect voters and verify a functions using for sampling


For contributor use:

  • Wrote tests
  • Updated CHANGELOG_PENDING.md
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Updated relevant documentation (docs/) and code comments
  • Re-reviewed Files changed in the Github PR explorer

@kukugi kukugi requested review from torao and egonspace October 23, 2020 05:03
Copy link
Contributor

@torao torao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check these!

@@ -784,6 +784,9 @@ func sortVoters(candidates []*voter) []*voter {
sort.Slice(temp, func(i, j int) bool {
bigA := new(big.Int).Mul(big.NewInt(temp[i].val.VotingPower), big.NewInt(temp[j].val.StakingPower))
bigB := new(big.Int).Mul(big.NewInt(temp[j].val.VotingPower), big.NewInt(temp[i].val.StakingPower))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct to multiply temp[i].val.VotingPower by temp[j].val.StakingPower instead of temp[i]?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is for comparing votingPower(i) / stakingPower(i) and votingPower(j) / stakingPower(j). so compare that way

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it will be right. This code is for comparing two fractions using the fact a/b > c/d iff a*d > b*c.

@@ -784,6 +784,9 @@ func sortVoters(candidates []*voter) []*voter {
sort.Slice(temp, func(i, j int) bool {
bigA := new(big.Int).Mul(big.NewInt(temp[i].val.VotingPower), big.NewInt(temp[j].val.StakingPower))
bigB := new(big.Int).Mul(big.NewInt(temp[j].val.VotingPower), big.NewInt(temp[i].val.StakingPower))
if bigA.Cmp(bigB) == 0 {
return bytes.Compare(temp[i].val.Address, temp[j].val.Address) == -1
}
return bigA.Cmp(bigB) == 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use switch, or use a variable that stores the result instead of executing the same function twice? This loop for sorting will cause a large number of iterations like O(N log N).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, it would be better 👍

@@ -719,6 +643,19 @@ func sameVoters(c1 []*Validator, c2 []*Validator) bool {
}

func TestElectVotersNonDup(t *testing.T) {
for n := 100; n <= 100000; n *= 10 {
Copy link
Contributor

@egonspace egonspace Oct 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is n used at?

@@ -719,6 +643,19 @@ func sameVoters(c1 []*Validator, c2 []*Validator) bool {
}

func TestElectVotersNonDup(t *testing.T) {
for n := 100; n <= 100000; n *= 10 {
validators := newValidatorSet(100, func(i int) int64 {
return int64(100 * (i + 1))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about to use random staking power?

shuffled := validators.Copy()
for i := range shuffled.Validators {
r := rand.Intn(len(shuffled.Validators))
shuffled.Validators[i], shuffled.Validators[r] = shuffled.Validators[r], shuffled.Validators[i]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I didn't know swapping was possible without temp variables. Good!


winners := electVotersNonDup(validators.Copy(), 0, 30)

assert.True(t, isByzantine(winners, validators.totalStakingPower, 30))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although the code was written earlier, the 356 line of isByzantine seems to be wrong.
Should it be topFVotersVotingPower >= totalVotingPower/3 not totalPriority?

Copy link
Contributor

@egonspace egonspace Oct 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And use following to calculate tolerableByzantinePower.

tolerableByzantinePower := totalPriority * tolerableByzantinePercent / 100
// ceiling tolerableByzantinePower
if totalPriority*tolerableByzantinePercent%100 > 0 {
	tolerableByzantinePower++
}

like electVotersNonDup.

Copy link
Contributor

@egonspace egonspace Oct 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And is assert.True right? Shouldn't it be byzantine?

return 1
})

voters1 := electVotersNonDup(validators.Copy(), 1234, 20)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cannot be proved by a single case. We'd better test for many cases using random.

voters := newVotersWithRandomVotingPowerDescending(100000, 100, 1000)
totalStakingPower := int64(1000 * len(voters))

tolerableByzantinePower := totalStakingPower * tolerableByzantinePercent / 100
Copy link
Contributor

@egonspace egonspace Oct 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about to make a separate function for calculating tolerableByzantinePower? It's used at isByzantine and electVotersNonDup, too.

change a staking power to voting power in condition to determine if is voters byzantine
change a type of winpoint to big int. beacause, it is using for sampling only
voters2 := electVotersNonDup(validators.Copy(), 4321, 20)
voters := electVotersNonDup(validators.Copy(), 0, 30)
for n := 1; n <= 100; n++ {
otherVoters := electVotersNonDup(validators.Copy(), rand.Uint64(), 30)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rand.Uint64() may generate 0.


assert.False(t, isByzantine(winners, validators.totalStakingPower, 20))
if len(winners) < n {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this condition needed?

@@ -643,15 +646,16 @@ func sameVoters(c1 []*Validator, c2 []*Validator) bool {
}

func TestElectVotersNonDup(t *testing.T) {
for n := 100; n <= 10000; n *= 10 {
for n := 100; n < 10000; n *= 10 {
Copy link
Contributor

@egonspace egonspace Oct 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loop only repeats twice with 100, 1000 of n.
How about to use for n := 100; n <= 1000; n += 100?
And we must test electVotersNonDup as modifying tolerableByzantinePercent parameter too. I think we'd better take this test out as a separate test.
One more, let's use random for the seed.

func TestElectVotersNonDupVoterCountHardCode(t *testing.T) {
validatorSet := newValidatorSet(100, func(i int) int64 { return int64(i) })
expected := [][]int{
{6, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
line is 141 characters (lll)

validatorSet := newValidatorSet(100, func(i int) int64 { return int64(i) })
expected := [][]int{
{6, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{10, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
line is 142 characters (lll)

expected := [][]int{
{6, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{10, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{20, 20, 20, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
line is 142 characters (lll)

{6, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{10, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{20, 20, 20, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{30, 30, 30, 30, 30, 30, 30, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
line is 142 characters (lll)

{70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 91, 100, 100, 100, 100, 100, 100, 100},
{100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
line is 168 characters (lll)

func TestElectVotersNonDupVoterCountHardCode(t *testing.T) {
validatorSet := newValidatorSet(100, func(i int) int64 { return int64(i) })
expected := [][]int{
{6, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
line is 141 characters (lll)

validatorSet := newValidatorSet(100, func(i int) int64 { return int64(i) })
expected := [][]int{
{6, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{10, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
line is 142 characters (lll)

expected := [][]int{
{6, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{10, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{20, 20, 20, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
line is 142 characters (lll)

{6, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{10, 12, 15, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{20, 20, 20, 21, 21, 26, 29, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{30, 30, 30, 30, 30, 30, 30, 34, 36, 39, 41, 44, 48, 54, 54, 57, 65, 65, 69, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
line is 142 characters (lll)

{70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 71, 76, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 82, 84, 87, 91, 100, 100, 100, 100, 100, 100, 100},
{90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 91, 100, 100, 100, 100, 100, 100, 100},
{100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 [golangci] reported by reviewdog 🐶
line is 168 characters (lll)

@egonspace
Copy link
Contributor

egonspace commented Oct 27, 2020

There are a lot of corrections.

  • added minVoters parameter to electVotersNonDup
  • modify sort functions using in-place
  • fix winPoint calculation (multiply at first and then divide)
  • if there is no sampling satisfying the finality, then return all validators having voting power same to staking power
  • countVoters -> getTolerableByzantinePower (used big.Int considering overflow) and test case for it
  • remove useless function
  • added more test cases

Copy link
Author

@kukugi kukugi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

}
break
}
assert.True(t, isByzantineTolerable(winners, 30))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the same isByzantineTolerable function calls can be replaced with a variable that stores last function call

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it's for debugging. I remove it.

@egonspace egonspace requested review from Kynea0b and zemyblue October 28, 2020 08:03
Copy link
Contributor

@torao torao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK with a few trivial comments

}

func TestElectVotersNonDupByzantineTolerable(t *testing.T) {
rand.Seed(time.Now().UnixNano())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it should be tested under a random situation, it's better to make sure to log the seed value using t.Logf() or use a fixed-value as the seed, so that it can certainly be reproduced if a very rare test-failure occurs.

}

func TestElectVotersNonDupMinVoters(t *testing.T) {
rand.Seed(time.Now().UnixNano())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

@kukugi kukugi self-assigned this Oct 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants