mirror of
https://github.com/tendermint/tendermint.git
synced 2026-04-21 08:10:31 +00:00
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
This commit is contained in:
committed by
Ethan Buchman
parent
44b769b1ac
commit
725ed7969a
@@ -45,7 +45,8 @@ func TestValidatorSetBasic(t *testing.T) {
|
||||
assert.Nil(t, vset.Hash())
|
||||
|
||||
// add
|
||||
val = randValidator_()
|
||||
|
||||
val = randValidator_(vset.TotalVotingPower())
|
||||
assert.True(t, vset.Add(val))
|
||||
assert.True(t, vset.HasAddress(val.Address))
|
||||
idx, val2 := vset.GetByAddress(val.Address)
|
||||
@@ -61,7 +62,7 @@ func TestValidatorSetBasic(t *testing.T) {
|
||||
assert.NotPanics(t, func() { vset.IncrementProposerPriority(1) })
|
||||
|
||||
// update
|
||||
assert.False(t, vset.Update(randValidator_()))
|
||||
assert.False(t, vset.Update(randValidator_(vset.TotalVotingPower())))
|
||||
_, val = vset.GetByAddress(val.Address)
|
||||
val.VotingPower += 100
|
||||
proposerPriority := val.ProposerPriority
|
||||
@@ -73,7 +74,7 @@ func TestValidatorSetBasic(t *testing.T) {
|
||||
assert.Equal(t, proposerPriority, val.ProposerPriority)
|
||||
|
||||
// remove
|
||||
val2, removed := vset.Remove(randValidator_().Address)
|
||||
val2, removed := vset.Remove(randValidator_(vset.TotalVotingPower()).Address)
|
||||
assert.Nil(t, val2)
|
||||
assert.False(t, removed)
|
||||
val2, removed = vset.Remove(val.Address)
|
||||
@@ -280,16 +281,20 @@ func randPubKey() crypto.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
|
||||
}
|
||||
|
||||
func randValidatorSet(numValidators int) *ValidatorSet {
|
||||
validators := make([]*Validator, numValidators)
|
||||
totalVotingPower := int64(0)
|
||||
for i := 0; i < numValidators; i++ {
|
||||
validators[i] = randValidator_()
|
||||
validators[i] = randValidator_(totalVotingPower)
|
||||
totalVotingPower += validators[i].VotingPower
|
||||
}
|
||||
return NewValidatorSet(validators)
|
||||
}
|
||||
@@ -342,7 +347,174 @@ func TestAvgProposerPriority(t *testing.T) {
|
||||
got := tc.vs.computeAvgProposerPriority()
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user