Browse Source

Add some ProposerPriority tests (#2946)

* WIP: tests for #2785

* rebase onto develop

* add Bucky's test without changing ValidatorSet.Update

* make TestValidatorSetBasic fail

* add ProposerPriority preserving fix to ValidatorSet.Update to fix
TestValidatorSetBasic

* fix randValidator_ to stay in bounds of MaxTotalVotingPower

* check for expected proposer and remove some duplicate code

* actually limit the voting power of random validator ...

* fix test
pull/2953/head
Ismail Khoffi 6 years ago
committed by Ethan Buchman
parent
commit
725ed7969a
1 changed files with 179 additions and 7 deletions
  1. +179
    -7
      types/validator_set_test.go

+ 179
- 7
types/validator_set_test.go View File

@ -45,7 +45,8 @@ func TestValidatorSetBasic(t *testing.T) {
assert.Nil(t, vset.Hash()) assert.Nil(t, vset.Hash())
// add // add
val = randValidator_()
val = randValidator_(vset.TotalVotingPower())
assert.True(t, vset.Add(val)) assert.True(t, vset.Add(val))
assert.True(t, vset.HasAddress(val.Address)) assert.True(t, vset.HasAddress(val.Address))
idx, val2 := vset.GetByAddress(val.Address) idx, val2 := vset.GetByAddress(val.Address)
@ -61,7 +62,7 @@ func TestValidatorSetBasic(t *testing.T) {
assert.NotPanics(t, func() { vset.IncrementProposerPriority(1) }) assert.NotPanics(t, func() { vset.IncrementProposerPriority(1) })
// update // update
assert.False(t, vset.Update(randValidator_()))
assert.False(t, vset.Update(randValidator_(vset.TotalVotingPower())))
_, val = vset.GetByAddress(val.Address) _, val = vset.GetByAddress(val.Address)
val.VotingPower += 100 val.VotingPower += 100
proposerPriority := val.ProposerPriority proposerPriority := val.ProposerPriority
@ -73,7 +74,7 @@ func TestValidatorSetBasic(t *testing.T) {
assert.Equal(t, proposerPriority, val.ProposerPriority) assert.Equal(t, proposerPriority, val.ProposerPriority)
// remove // remove
val2, removed := vset.Remove(randValidator_().Address)
val2, removed := vset.Remove(randValidator_(vset.TotalVotingPower()).Address)
assert.Nil(t, val2) assert.Nil(t, val2)
assert.False(t, removed) assert.False(t, removed)
val2, removed = vset.Remove(val.Address) val2, removed = vset.Remove(val.Address)
@ -280,16 +281,20 @@ func randPubKey() crypto.PubKey {
return ed25519.PubKeyEd25519(pubKey) return ed25519.PubKeyEd25519(pubKey)
} }
func randValidator_() *Validator {
val := NewValidator(randPubKey(), cmn.RandInt64())
val.ProposerPriority = cmn.RandInt64() % MaxTotalVotingPower
func randValidator_(totalVotingPower int64) *Validator {
// this modulo limits the ProposerPriority/VotingPower to stay in the
// bounds of MaxTotalVotingPower minus the already existing voting power:
val := NewValidator(randPubKey(), cmn.RandInt64()%(MaxTotalVotingPower-totalVotingPower))
val.ProposerPriority = cmn.RandInt64() % (MaxTotalVotingPower - totalVotingPower)
return val return val
} }
func randValidatorSet(numValidators int) *ValidatorSet { func randValidatorSet(numValidators int) *ValidatorSet {
validators := make([]*Validator, numValidators) validators := make([]*Validator, numValidators)
totalVotingPower := int64(0)
for i := 0; i < numValidators; i++ { for i := 0; i < numValidators; i++ {
validators[i] = randValidator_()
validators[i] = randValidator_(totalVotingPower)
totalVotingPower += validators[i].VotingPower
} }
return NewValidatorSet(validators) return NewValidatorSet(validators)
} }
@ -342,7 +347,174 @@ func TestAvgProposerPriority(t *testing.T) {
got := tc.vs.computeAvgProposerPriority() got := tc.vs.computeAvgProposerPriority()
assert.Equal(t, tc.want, got, "test case: %v", i) assert.Equal(t, tc.want, got, "test case: %v", i)
} }
}
func TestAveragingInIncrementProposerPriority(t *testing.T) {
// Test that the averaging works as expected inside of IncrementProposerPriority.
// Each validator comes with zero voting power which simplifies reasoning about
// the expected ProposerPriority.
tcs := []struct {
vs ValidatorSet
times int
avg int64
}{
0: {ValidatorSet{
Validators: []*Validator{
{Address: []byte("a"), ProposerPriority: 1},
{Address: []byte("b"), ProposerPriority: 2},
{Address: []byte("c"), ProposerPriority: 3}}},
1, 2},
1: {ValidatorSet{
Validators: []*Validator{
{Address: []byte("a"), ProposerPriority: 10},
{Address: []byte("b"), ProposerPriority: -10},
{Address: []byte("c"), ProposerPriority: 1}}},
// this should average twice but the average should be 0 after the first iteration
// (voting power is 0 -> no changes)
11, 1 / 3},
2: {ValidatorSet{
Validators: []*Validator{
{Address: []byte("a"), ProposerPriority: 100},
{Address: []byte("b"), ProposerPriority: -10},
{Address: []byte("c"), ProposerPriority: 1}}},
1, 91 / 3},
}
for i, tc := range tcs {
// work on copy to have the old ProposerPriorities:
newVset := tc.vs.CopyIncrementProposerPriority(tc.times)
for _, val := range tc.vs.Validators {
_, updatedVal := newVset.GetByAddress(val.Address)
assert.Equal(t, updatedVal.ProposerPriority, val.ProposerPriority-tc.avg, "test case: %v", i)
}
}
}
func TestAveragingInIncrementProposerPriorityWithVotingPower(t *testing.T) {
// Other than TestAveragingInIncrementProposerPriority this is a more complete test showing
// how each ProposerPriority changes in relation to the validator's voting power respectively.
vals := ValidatorSet{Validators: []*Validator{
{Address: []byte{0}, ProposerPriority: 0, VotingPower: 10},
{Address: []byte{1}, ProposerPriority: 0, VotingPower: 1},
{Address: []byte{2}, ProposerPriority: 0, VotingPower: 1}}}
tcs := []struct {
vals *ValidatorSet
wantProposerPrioritys []int64
times int
wantProposer *Validator
}{
0: {
vals.Copy(),
[]int64{
// Acumm+VotingPower-Avg:
0 + 10 - 12 - 4, // mostest will be subtracted by total voting power (12)
0 + 1 - 4,
0 + 1 - 4},
1,
vals.Validators[0]},
1: {
vals.Copy(),
[]int64{
(0 + 10 - 12 - 4) + 10 - 12 + 4, // this will be mostest on 2nd iter, too
(0 + 1 - 4) + 1 + 4,
(0 + 1 - 4) + 1 + 4},
2,
vals.Validators[0]}, // increment twice -> expect average to be subtracted twice
2: {
vals.Copy(),
[]int64{
((0 + 10 - 12 - 4) + 10 - 12) + 10 - 12 + 4, // still mostest
((0 + 1 - 4) + 1) + 1 + 4,
((0 + 1 - 4) + 1) + 1 + 4},
3,
vals.Validators[0]},
3: {
vals.Copy(),
[]int64{
0 + 4*(10-12) + 4 - 4, // still mostest
0 + 4*1 + 4 - 4,
0 + 4*1 + 4 - 4},
4,
vals.Validators[0]},
4: {
vals.Copy(),
[]int64{
0 + 4*(10-12) + 10 + 4 - 4, // 4 iters was mostest
0 + 5*1 - 12 + 4 - 4, // now this val is mostest for the 1st time (hence -12==totalVotingPower)
0 + 5*1 + 4 - 4},
5,
vals.Validators[1]},
5: {
vals.Copy(),
[]int64{
0 + 6*10 - 5*12 + 4 - 4, // mostest again
0 + 6*1 - 12 + 4 - 4, // mostest once up to here
0 + 6*1 + 4 - 4},
6,
vals.Validators[0]},
6: {
vals.Copy(),
[]int64{
0 + 7*10 - 6*12 + 4 - 4, // in 7 iters this val is mostest 6 times
0 + 7*1 - 12 + 4 - 4, // in 7 iters this val is mostest 1 time
0 + 7*1 + 4 - 4},
7,
vals.Validators[0]},
7: {
vals.Copy(),
[]int64{
0 + 8*10 - 7*12 + 4 - 4, // mostest
0 + 8*1 - 12 + 4 - 4,
0 + 8*1 + 4 - 4},
8,
vals.Validators[0]},
8: {
vals.Copy(),
[]int64{
0 + 9*10 - 7*12 + 4 - 4,
0 + 9*1 - 12 + 4 - 4,
0 + 9*1 - 12 + 4 - 4}, // mostest
9,
vals.Validators[2]},
9: {
vals.Copy(),
[]int64{
0 + 10*10 - 8*12 + 4 - 4, // after 10 iters this is mostest again
0 + 10*1 - 12 + 4 - 4, // after 6 iters this val is "mostest" once and not in between
0 + 10*1 - 12 + 4 - 4}, // in between 10 iters this val is "mostest" once
10,
vals.Validators[0]},
10: {
vals.Copy(),
[]int64{
// shift twice inside incrementProposerPriority (shift every 10th iter);
// don't shift at the end of IncremenctProposerPriority
// last avg should be zero because
// ProposerPriority of validator 0: (0 + 11*10 - 8*12 - 4) == 10
// ProposerPriority of validator 1 and 2: (0 + 11*1 - 12 - 4) == -5
// and (10 + 5 - 5) / 3 == 0
0 + 11*10 - 8*12 - 4 - 12 - 0,
0 + 11*1 - 12 - 4 - 0, // after 6 iters this val is "mostest" once and not in between
0 + 11*1 - 12 - 4 - 0}, // after 10 iters this val is "mostest" once
11,
vals.Validators[0]},
}
for i, tc := range tcs {
tc.vals.IncrementProposerPriority(tc.times)
assert.Equal(t, tc.wantProposer.Address, tc.vals.GetProposer().Address,
"test case: %v",
i)
for valIdx, val := range tc.vals.Validators {
assert.Equal(t,
tc.wantProposerPrioritys[valIdx],
val.ProposerPriority,
"test case: %v, validator: %v",
i,
valIdx)
}
}
} }
func TestSafeAdd(t *testing.T) { func TestSafeAdd(t *testing.T) {


Loading…
Cancel
Save