github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/types/validator_set_test.go (about) 1 package types 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "math" 8 "math/rand" 9 "sort" 10 "strings" 11 "testing" 12 "testing/quick" 13 "time" 14 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 18 "github.com/ari-anchor/sei-tendermint/crypto" 19 "github.com/ari-anchor/sei-tendermint/crypto/ed25519" 20 tmmath "github.com/ari-anchor/sei-tendermint/libs/math" 21 tmrand "github.com/ari-anchor/sei-tendermint/libs/rand" 22 tmproto "github.com/ari-anchor/sei-tendermint/proto/tendermint/types" 23 ) 24 25 func TestValidatorSetBasic(t *testing.T) { 26 // empty or nil validator lists are allowed, 27 // but attempting to IncrementProposerPriority on them will panic. 28 vset := NewValidatorSet([]*Validator{}) 29 assert.Panics(t, func() { vset.IncrementProposerPriority(1) }) 30 31 vset = NewValidatorSet(nil) 32 assert.Panics(t, func() { vset.IncrementProposerPriority(1) }) 33 34 assert.EqualValues(t, vset, vset.Copy()) 35 assert.False(t, vset.HasAddress([]byte("some val"))) 36 idx, val := vset.GetByAddress([]byte("some val")) 37 assert.EqualValues(t, -1, idx) 38 assert.Nil(t, val) 39 addr, val := vset.GetByIndex(-100) 40 assert.Nil(t, addr) 41 assert.Nil(t, val) 42 addr, val = vset.GetByIndex(0) 43 assert.Nil(t, addr) 44 assert.Nil(t, val) 45 addr, val = vset.GetByIndex(100) 46 assert.Nil(t, addr) 47 assert.Nil(t, val) 48 assert.Zero(t, vset.Size()) 49 assert.Equal(t, int64(0), vset.TotalVotingPower()) 50 assert.Nil(t, vset.GetProposer()) 51 assert.Equal(t, []byte{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 52 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 53 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, vset.Hash()) 54 // add 55 val = randModuloValidator(vset.TotalVotingPower()) 56 assert.NoError(t, vset.UpdateWithChangeSet([]*Validator{val})) 57 58 assert.True(t, vset.HasAddress(val.Address)) 59 idx, _ = vset.GetByAddress(val.Address) 60 assert.EqualValues(t, 0, idx) 61 addr, _ = vset.GetByIndex(0) 62 assert.Equal(t, []byte(val.Address), addr) 63 assert.Equal(t, 1, vset.Size()) 64 assert.Equal(t, val.VotingPower, vset.TotalVotingPower()) 65 assert.NotNil(t, vset.Hash()) 66 assert.NotPanics(t, func() { vset.IncrementProposerPriority(1) }) 67 assert.Equal(t, val.Address, vset.GetProposer().Address) 68 69 // update 70 val = randModuloValidator(vset.TotalVotingPower()) 71 assert.NoError(t, vset.UpdateWithChangeSet([]*Validator{val})) 72 _, val = vset.GetByAddress(val.Address) 73 val.VotingPower += 100 74 proposerPriority := val.ProposerPriority 75 76 val.ProposerPriority = 0 77 assert.NoError(t, vset.UpdateWithChangeSet([]*Validator{val})) 78 _, val = vset.GetByAddress(val.Address) 79 assert.Equal(t, proposerPriority, val.ProposerPriority) 80 81 } 82 83 func TestValidatorSetValidateBasic(t *testing.T) { 84 ctx, cancel := context.WithCancel(context.Background()) 85 defer cancel() 86 87 val, _, err := randValidator(ctx, false, 1) 88 require.NoError(t, err) 89 90 badVal := &Validator{} 91 92 testCases := []struct { 93 vals ValidatorSet 94 err bool 95 msg string 96 }{ 97 { 98 vals: ValidatorSet{}, 99 err: true, 100 msg: "validator set is nil or empty", 101 }, 102 { 103 vals: ValidatorSet{ 104 Validators: []*Validator{}, 105 }, 106 err: true, 107 msg: "validator set is nil or empty", 108 }, 109 { 110 vals: ValidatorSet{ 111 Validators: []*Validator{val}, 112 }, 113 err: true, 114 msg: "proposer failed validate basic, error: nil validator", 115 }, 116 { 117 vals: ValidatorSet{ 118 Validators: []*Validator{badVal}, 119 }, 120 err: true, 121 msg: "invalid validator #0: validator does not have a public key", 122 }, 123 { 124 vals: ValidatorSet{ 125 Validators: []*Validator{val}, 126 Proposer: val, 127 }, 128 err: false, 129 msg: "", 130 }, 131 } 132 133 for _, tc := range testCases { 134 err := tc.vals.ValidateBasic() 135 if tc.err { 136 if assert.Error(t, err) { 137 assert.Equal(t, tc.msg, err.Error()) 138 } 139 } else { 140 assert.NoError(t, err) 141 } 142 } 143 144 } 145 146 func TestCopy(t *testing.T) { 147 vset := randModuloValidatorSet(10) 148 vsetHash := vset.Hash() 149 if len(vsetHash) == 0 { 150 t.Fatalf("ValidatorSet had unexpected zero hash") 151 } 152 153 vsetCopy := vset.Copy() 154 vsetCopyHash := vsetCopy.Hash() 155 156 if !bytes.Equal(vsetHash, vsetCopyHash) { 157 t.Fatalf("ValidatorSet copy had wrong hash. Orig: %X, Copy: %X", vsetHash, vsetCopyHash) 158 } 159 } 160 161 // Test that IncrementProposerPriority requires positive times. 162 func TestIncrementProposerPriorityPositiveTimes(t *testing.T) { 163 vset := NewValidatorSet([]*Validator{ 164 newValidator([]byte("foo"), 1000), 165 newValidator([]byte("bar"), 300), 166 newValidator([]byte("baz"), 330), 167 }) 168 169 assert.Panics(t, func() { vset.IncrementProposerPriority(-1) }) 170 assert.Panics(t, func() { vset.IncrementProposerPriority(0) }) 171 vset.IncrementProposerPriority(1) 172 } 173 174 func BenchmarkValidatorSetCopy(b *testing.B) { 175 b.StopTimer() 176 vset := NewValidatorSet([]*Validator{}) 177 for i := 0; i < 1000; i++ { 178 privKey := ed25519.GenPrivKey() 179 pubKey := privKey.PubKey() 180 val := NewValidator(pubKey, 10) 181 err := vset.UpdateWithChangeSet([]*Validator{val}) 182 require.NoError(b, err) 183 } 184 b.StartTimer() 185 186 for i := 0; i < b.N; i++ { 187 vset.Copy() 188 } 189 } 190 191 //------------------------------------------------------------------- 192 193 func TestProposerSelection1(t *testing.T) { 194 vset := NewValidatorSet([]*Validator{ 195 newValidator([]byte("foo"), 1000), 196 newValidator([]byte("bar"), 300), 197 newValidator([]byte("baz"), 330), 198 }) 199 var proposers []string 200 for i := 0; i < 99; i++ { 201 val := vset.GetProposer() 202 proposers = append(proposers, string(val.Address)) 203 vset.IncrementProposerPriority(1) 204 } 205 expected := `foo baz foo bar foo foo baz foo bar foo foo baz foo foo bar foo baz foo foo bar` + 206 ` foo foo baz foo bar foo foo baz foo bar foo foo baz foo foo bar foo baz foo foo bar` + 207 ` foo baz foo foo bar foo baz foo foo bar foo baz foo foo foo baz bar foo foo foo baz` + 208 ` foo bar foo foo baz foo bar foo foo baz foo bar foo foo baz foo bar foo foo baz foo` + 209 ` foo bar foo baz foo foo bar foo baz foo foo bar foo baz foo foo` 210 if expected != strings.Join(proposers, " ") { 211 t.Errorf("expected sequence of proposers was\n%v\nbut got \n%v", expected, strings.Join(proposers, " ")) 212 } 213 } 214 215 func TestProposerSelection2(t *testing.T) { 216 addr0 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 217 addr1 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} 218 addr2 := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2} 219 220 // when all voting power is same, we go in order of addresses 221 val0, val1, val2 := newValidator(addr0, 100), newValidator(addr1, 100), newValidator(addr2, 100) 222 valList := []*Validator{val0, val1, val2} 223 vals := NewValidatorSet(valList) 224 for i := 0; i < len(valList)*5; i++ { 225 ii := (i) % len(valList) 226 prop := vals.GetProposer() 227 if !bytes.Equal(prop.Address, valList[ii].Address) { 228 t.Fatalf("(%d): Expected %X. Got %X", i, valList[ii].Address, prop.Address) 229 } 230 vals.IncrementProposerPriority(1) 231 } 232 233 // One validator has more than the others, but not enough to propose twice in a row 234 *val2 = *newValidator(addr2, 400) 235 vals = NewValidatorSet(valList) 236 // vals.IncrementProposerPriority(1) 237 prop := vals.GetProposer() 238 if !bytes.Equal(prop.Address, addr2) { 239 t.Fatalf("Expected address with highest voting power to be first proposer. Got %X", prop.Address) 240 } 241 vals.IncrementProposerPriority(1) 242 prop = vals.GetProposer() 243 if !bytes.Equal(prop.Address, addr0) { 244 t.Fatalf("Expected smallest address to be validator. Got %X", prop.Address) 245 } 246 247 // One validator has more than the others, and enough to be proposer twice in a row 248 *val2 = *newValidator(addr2, 401) 249 vals = NewValidatorSet(valList) 250 prop = vals.GetProposer() 251 if !bytes.Equal(prop.Address, addr2) { 252 t.Fatalf("Expected address with highest voting power to be first proposer. Got %X", prop.Address) 253 } 254 vals.IncrementProposerPriority(1) 255 prop = vals.GetProposer() 256 if !bytes.Equal(prop.Address, addr2) { 257 t.Fatalf("Expected address with highest voting power to be second proposer. Got %X", prop.Address) 258 } 259 vals.IncrementProposerPriority(1) 260 prop = vals.GetProposer() 261 if !bytes.Equal(prop.Address, addr0) { 262 t.Fatalf("Expected smallest address to be validator. Got %X", prop.Address) 263 } 264 265 // each validator should be the proposer a proportional number of times 266 val0, val1, val2 = newValidator(addr0, 4), newValidator(addr1, 5), newValidator(addr2, 3) 267 valList = []*Validator{val0, val1, val2} 268 propCount := make([]int, 3) 269 vals = NewValidatorSet(valList) 270 N := 1 271 for i := 0; i < 120*N; i++ { 272 prop := vals.GetProposer() 273 ii := prop.Address[19] 274 propCount[ii]++ 275 vals.IncrementProposerPriority(1) 276 } 277 278 if propCount[0] != 40*N { 279 t.Fatalf( 280 "Expected prop count for validator with 4/12 of voting power to be %d/%d. Got %d/%d", 281 40*N, 282 120*N, 283 propCount[0], 284 120*N, 285 ) 286 } 287 if propCount[1] != 50*N { 288 t.Fatalf( 289 "Expected prop count for validator with 5/12 of voting power to be %d/%d. Got %d/%d", 290 50*N, 291 120*N, 292 propCount[1], 293 120*N, 294 ) 295 } 296 if propCount[2] != 30*N { 297 t.Fatalf( 298 "Expected prop count for validator with 3/12 of voting power to be %d/%d. Got %d/%d", 299 30*N, 300 120*N, 301 propCount[2], 302 120*N, 303 ) 304 } 305 } 306 307 func TestProposerSelection3(t *testing.T) { 308 vset := NewValidatorSet([]*Validator{ 309 newValidator([]byte("avalidator_address12"), 1), 310 newValidator([]byte("bvalidator_address12"), 1), 311 newValidator([]byte("cvalidator_address12"), 1), 312 newValidator([]byte("dvalidator_address12"), 1), 313 }) 314 315 proposerOrder := make([]*Validator, 4) 316 for i := 0; i < 4; i++ { 317 // need to give all validators to have keys 318 pk := ed25519.GenPrivKey().PubKey() 319 vset.Validators[i].PubKey = pk 320 proposerOrder[i] = vset.GetProposer() 321 vset.IncrementProposerPriority(1) 322 } 323 324 // i for the loop 325 // j for the times 326 // we should go in order for ever, despite some IncrementProposerPriority with times > 1 327 var ( 328 i int 329 j int32 330 ) 331 for ; i < 10000; i++ { 332 got := vset.GetProposer().Address 333 expected := proposerOrder[j%4].Address 334 if !bytes.Equal(got, expected) { 335 t.Fatalf(fmt.Sprintf("vset.Proposer (%X) does not match expected proposer (%X) for (%d, %d)", got, expected, i, j)) 336 } 337 338 // serialize, deserialize, check proposer 339 b := vset.toBytes(t) 340 vset = vset.fromBytes(t, b) 341 342 computed := vset.GetProposer() // findGetProposer() 343 if i != 0 { 344 if !bytes.Equal(got, computed.Address) { 345 t.Fatalf( 346 fmt.Sprintf( 347 "vset.Proposer (%X) does not match computed proposer (%X) for (%d, %d)", 348 got, 349 computed.Address, 350 i, 351 j, 352 ), 353 ) 354 } 355 } 356 357 // times is usually 1 358 times := int32(1) 359 mod := (rand.Int() % 5) + 1 360 if rand.Int()%mod > 0 { 361 // sometimes its up to 5 362 times = (rand.Int31() % 4) + 1 363 } 364 vset.IncrementProposerPriority(times) 365 366 j += times 367 } 368 } 369 370 func newValidator(address []byte, power int64) *Validator { 371 return &Validator{Address: address, VotingPower: power} 372 } 373 374 func randPubKey() crypto.PubKey { 375 pubKey := make(ed25519.PubKey, ed25519.PubKeySize) 376 copy(pubKey, tmrand.Bytes(32)) 377 return ed25519.PubKey(tmrand.Bytes(32)) 378 } 379 380 func randModuloValidator(totalVotingPower int64) *Validator { 381 // this modulo limits the ProposerPriority/VotingPower to stay in the 382 // bounds of MaxTotalVotingPower minus the already existing voting power: 383 val := NewValidator(randPubKey(), int64(rand.Uint64()%uint64(MaxTotalVotingPower-totalVotingPower))) 384 val.ProposerPriority = rand.Int63() % (MaxTotalVotingPower - totalVotingPower) 385 return val 386 } 387 388 func randValidator(ctx context.Context, randPower bool, minPower int64) (*Validator, PrivValidator, error) { 389 privVal := NewMockPV() 390 votePower := minPower 391 if randPower { 392 votePower += int64(rand.Uint32()) 393 } 394 pubKey, err := privVal.GetPubKey(ctx) 395 if err != nil { 396 return nil, nil, err 397 } 398 399 val := NewValidator(pubKey, votePower) 400 return val, privVal, nil 401 } 402 403 func randModuloValidatorSet(numValidators int) *ValidatorSet { 404 validators := make([]*Validator, numValidators) 405 totalVotingPower := int64(0) 406 for i := 0; i < numValidators; i++ { 407 validators[i] = randModuloValidator(totalVotingPower) 408 totalVotingPower += validators[i].VotingPower 409 } 410 return NewValidatorSet(validators) 411 } 412 413 func (vals *ValidatorSet) toBytes(t *testing.T) []byte { 414 pbvs, err := vals.ToProto() 415 require.NoError(t, err) 416 417 bz, err := pbvs.Marshal() 418 require.NoError(t, err) 419 420 return bz 421 } 422 423 func (vals *ValidatorSet) fromBytes(t *testing.T, b []byte) *ValidatorSet { 424 pbvs := new(tmproto.ValidatorSet) 425 err := pbvs.Unmarshal(b) 426 require.NoError(t, err) 427 428 vs, err := ValidatorSetFromProto(pbvs) 429 require.NoError(t, err) 430 431 return vs 432 } 433 434 //------------------------------------------------------------------- 435 436 func TestValidatorSetTotalVotingPowerPanicsOnOverflow(t *testing.T) { 437 // NewValidatorSet calls IncrementProposerPriority which calls TotalVotingPower() 438 // which should panic on overflows: 439 shouldPanic := func() { 440 NewValidatorSet([]*Validator{ 441 {Address: []byte("a"), VotingPower: math.MaxInt64, ProposerPriority: 0}, 442 {Address: []byte("b"), VotingPower: math.MaxInt64, ProposerPriority: 0}, 443 {Address: []byte("c"), VotingPower: math.MaxInt64, ProposerPriority: 0}, 444 }) 445 } 446 447 assert.Panics(t, shouldPanic) 448 } 449 450 func TestAvgProposerPriority(t *testing.T) { 451 // Create Validator set without calling IncrementProposerPriority: 452 tcs := []struct { 453 vs ValidatorSet 454 want int64 455 }{ 456 0: {ValidatorSet{Validators: []*Validator{{ProposerPriority: 0}, {ProposerPriority: 0}, {ProposerPriority: 0}}}, 0}, 457 1: { 458 ValidatorSet{ 459 Validators: []*Validator{{ProposerPriority: math.MaxInt64}, {ProposerPriority: 0}, {ProposerPriority: 0}}, 460 }, math.MaxInt64 / 3, 461 }, 462 2: { 463 ValidatorSet{ 464 Validators: []*Validator{{ProposerPriority: math.MaxInt64}, {ProposerPriority: 0}}, 465 }, math.MaxInt64 / 2, 466 }, 467 3: { 468 ValidatorSet{ 469 Validators: []*Validator{{ProposerPriority: math.MaxInt64}, {ProposerPriority: math.MaxInt64}}, 470 }, math.MaxInt64, 471 }, 472 4: { 473 ValidatorSet{ 474 Validators: []*Validator{{ProposerPriority: math.MinInt64}, {ProposerPriority: math.MinInt64}}, 475 }, math.MinInt64, 476 }, 477 } 478 for i, tc := range tcs { 479 got := tc.vs.computeAvgProposerPriority() 480 assert.Equal(t, tc.want, got, "test case: %v", i) 481 } 482 } 483 484 func TestAveragingInIncrementProposerPriority(t *testing.T) { 485 // Test that the averaging works as expected inside of IncrementProposerPriority. 486 // Each validator comes with zero voting power which simplifies reasoning about 487 // the expected ProposerPriority. 488 tcs := []struct { 489 vs ValidatorSet 490 times int32 491 avg int64 492 }{ 493 0: {ValidatorSet{ 494 Validators: []*Validator{ 495 {Address: []byte("a"), ProposerPriority: 1}, 496 {Address: []byte("b"), ProposerPriority: 2}, 497 {Address: []byte("c"), ProposerPriority: 3}}}, 498 1, 2}, 499 1: {ValidatorSet{ 500 Validators: []*Validator{ 501 {Address: []byte("a"), ProposerPriority: 10}, 502 {Address: []byte("b"), ProposerPriority: -10}, 503 {Address: []byte("c"), ProposerPriority: 1}}}, 504 // this should average twice but the average should be 0 after the first iteration 505 // (voting power is 0 -> no changes) 506 11, 0}, 507 2: {ValidatorSet{ 508 Validators: []*Validator{ 509 {Address: []byte("a"), ProposerPriority: 100}, 510 {Address: []byte("b"), ProposerPriority: -10}, 511 {Address: []byte("c"), ProposerPriority: 1}}}, 512 1, 91 / 3}, 513 } 514 for i, tc := range tcs { 515 // work on copy to have the old ProposerPriorities: 516 newVset := tc.vs.CopyIncrementProposerPriority(tc.times) 517 for _, val := range tc.vs.Validators { 518 _, updatedVal := newVset.GetByAddress(val.Address) 519 assert.Equal(t, updatedVal.ProposerPriority, val.ProposerPriority-tc.avg, "test case: %v", i) 520 } 521 } 522 } 523 524 func TestAveragingInIncrementProposerPriorityWithVotingPower(t *testing.T) { 525 // Other than TestAveragingInIncrementProposerPriority this is a more complete test showing 526 // how each ProposerPriority changes in relation to the validator's voting power respectively. 527 // average is zero in each round: 528 vp0 := int64(10) 529 vp1 := int64(1) 530 vp2 := int64(1) 531 total := vp0 + vp1 + vp2 532 avg := (vp0 + vp1 + vp2 - total) / 3 533 vals := ValidatorSet{Validators: []*Validator{ 534 {Address: []byte{0}, ProposerPriority: 0, VotingPower: vp0}, 535 {Address: []byte{1}, ProposerPriority: 0, VotingPower: vp1}, 536 {Address: []byte{2}, ProposerPriority: 0, VotingPower: vp2}}} 537 tcs := []struct { 538 vals *ValidatorSet 539 wantProposerPrioritys []int64 540 times int32 541 wantProposer *Validator 542 }{ 543 544 0: { 545 vals.Copy(), 546 []int64{ 547 // Acumm+VotingPower-Avg: 548 0 + vp0 - total - avg, // mostest will be subtracted by total voting power (12) 549 0 + vp1, 550 0 + vp2}, 551 1, 552 vals.Validators[0]}, 553 1: { 554 vals.Copy(), 555 []int64{ 556 (0 + vp0 - total) + vp0 - total - avg, // this will be mostest on 2nd iter, too 557 (0 + vp1) + vp1, 558 (0 + vp2) + vp2}, 559 2, 560 vals.Validators[0]}, // increment twice -> expect average to be subtracted twice 561 2: { 562 vals.Copy(), 563 []int64{ 564 0 + 3*(vp0-total) - avg, // still mostest 565 0 + 3*vp1, 566 0 + 3*vp2}, 567 3, 568 vals.Validators[0]}, 569 3: { 570 vals.Copy(), 571 []int64{ 572 0 + 4*(vp0-total), // still mostest 573 0 + 4*vp1, 574 0 + 4*vp2}, 575 4, 576 vals.Validators[0]}, 577 4: { 578 vals.Copy(), 579 []int64{ 580 0 + 4*(vp0-total) + vp0, // 4 iters was mostest 581 0 + 5*vp1 - total, // now this val is mostest for the 1st time (hence -12==totalVotingPower) 582 0 + 5*vp2}, 583 5, 584 vals.Validators[1]}, 585 5: { 586 vals.Copy(), 587 []int64{ 588 0 + 6*vp0 - 5*total, // mostest again 589 0 + 6*vp1 - total, // mostest once up to here 590 0 + 6*vp2}, 591 6, 592 vals.Validators[0]}, 593 6: { 594 vals.Copy(), 595 []int64{ 596 0 + 7*vp0 - 6*total, // in 7 iters this val is mostest 6 times 597 0 + 7*vp1 - total, // in 7 iters this val is mostest 1 time 598 0 + 7*vp2}, 599 7, 600 vals.Validators[0]}, 601 7: { 602 vals.Copy(), 603 []int64{ 604 0 + 8*vp0 - 7*total, // mostest again 605 0 + 8*vp1 - total, 606 0 + 8*vp2}, 607 8, 608 vals.Validators[0]}, 609 8: { 610 vals.Copy(), 611 []int64{ 612 0 + 9*vp0 - 7*total, 613 0 + 9*vp1 - total, 614 0 + 9*vp2 - total}, // mostest 615 9, 616 vals.Validators[2]}, 617 9: { 618 vals.Copy(), 619 []int64{ 620 0 + 10*vp0 - 8*total, // after 10 iters this is mostest again 621 0 + 10*vp1 - total, // after 6 iters this val is "mostest" once and not in between 622 0 + 10*vp2 - total}, // in between 10 iters this val is "mostest" once 623 10, 624 vals.Validators[0]}, 625 10: { 626 vals.Copy(), 627 []int64{ 628 0 + 11*vp0 - 9*total, 629 0 + 11*vp1 - total, // after 6 iters this val is "mostest" once and not in between 630 0 + 11*vp2 - total}, // after 10 iters this val is "mostest" once 631 11, 632 vals.Validators[0]}, 633 } 634 for i, tc := range tcs { 635 tc.vals.IncrementProposerPriority(tc.times) 636 637 assert.Equal(t, tc.wantProposer.Address, tc.vals.GetProposer().Address, 638 "test case: %v", 639 i) 640 641 for valIdx, val := range tc.vals.Validators { 642 assert.Equal(t, 643 tc.wantProposerPrioritys[valIdx], 644 val.ProposerPriority, 645 "test case: %v, validator: %v", 646 i, 647 valIdx) 648 } 649 } 650 } 651 652 func TestSafeAdd(t *testing.T) { 653 f := func(a, b int64) bool { 654 c, overflow := safeAdd(a, b) 655 return overflow || (!overflow && c == a+b) 656 } 657 if err := quick.Check(f, nil); err != nil { 658 t.Error(err) 659 } 660 } 661 662 func TestSafeAddClip(t *testing.T) { 663 assert.EqualValues(t, math.MaxInt64, safeAddClip(math.MaxInt64, 10)) 664 assert.EqualValues(t, math.MaxInt64, safeAddClip(math.MaxInt64, math.MaxInt64)) 665 assert.EqualValues(t, math.MinInt64, safeAddClip(math.MinInt64, -10)) 666 } 667 668 func TestSafeSubClip(t *testing.T) { 669 assert.EqualValues(t, math.MinInt64, safeSubClip(math.MinInt64, 10)) 670 assert.EqualValues(t, 0, safeSubClip(math.MinInt64, math.MinInt64)) 671 assert.EqualValues(t, math.MinInt64, safeSubClip(math.MinInt64, math.MaxInt64)) 672 assert.EqualValues(t, math.MaxInt64, safeSubClip(math.MaxInt64, -10)) 673 } 674 675 //------------------------------------------------------------------- 676 677 func TestEmptySet(t *testing.T) { 678 679 var valList []*Validator 680 valSet := NewValidatorSet(valList) 681 assert.Panics(t, func() { valSet.IncrementProposerPriority(1) }) 682 assert.Panics(t, func() { valSet.RescalePriorities(100) }) 683 assert.Panics(t, func() { valSet.shiftByAvgProposerPriority() }) 684 assert.Panics(t, func() { assert.Zero(t, computeMaxMinPriorityDiff(valSet)) }) 685 valSet.GetProposer() 686 687 // Add to empty set 688 v1 := newValidator([]byte("v1"), 100) 689 v2 := newValidator([]byte("v2"), 100) 690 valList = []*Validator{v1, v2} 691 assert.NoError(t, valSet.UpdateWithChangeSet(valList)) 692 verifyValidatorSet(t, valSet) 693 694 // Delete all validators from set 695 v1 = newValidator([]byte("v1"), 0) 696 v2 = newValidator([]byte("v2"), 0) 697 delList := []*Validator{v1, v2} 698 assert.Error(t, valSet.UpdateWithChangeSet(delList)) 699 700 // Attempt delete from empty set 701 assert.Error(t, valSet.UpdateWithChangeSet(delList)) 702 703 } 704 705 func TestUpdatesForNewValidatorSet(t *testing.T) { 706 707 v1 := newValidator([]byte("v1"), 100) 708 v2 := newValidator([]byte("v2"), 100) 709 valList := []*Validator{v1, v2} 710 valSet := NewValidatorSet(valList) 711 verifyValidatorSet(t, valSet) 712 713 // Verify duplicates are caught in NewValidatorSet() and it panics 714 v111 := newValidator([]byte("v1"), 100) 715 v112 := newValidator([]byte("v1"), 123) 716 v113 := newValidator([]byte("v1"), 234) 717 valList = []*Validator{v111, v112, v113} 718 assert.Panics(t, func() { NewValidatorSet(valList) }) 719 720 // Verify set including validator with voting power 0 cannot be created 721 v1 = newValidator([]byte("v1"), 0) 722 v2 = newValidator([]byte("v2"), 22) 723 v3 := newValidator([]byte("v3"), 33) 724 valList = []*Validator{v1, v2, v3} 725 assert.Panics(t, func() { NewValidatorSet(valList) }) 726 727 // Verify set including validator with negative voting power cannot be created 728 v1 = newValidator([]byte("v1"), 10) 729 v2 = newValidator([]byte("v2"), -20) 730 v3 = newValidator([]byte("v3"), 30) 731 valList = []*Validator{v1, v2, v3} 732 assert.Panics(t, func() { NewValidatorSet(valList) }) 733 734 } 735 736 type testVal struct { 737 name string 738 power int64 739 } 740 741 func permutation(valList []testVal) []testVal { 742 if len(valList) == 0 { 743 return nil 744 } 745 permList := make([]testVal, len(valList)) 746 perm := rand.Perm(len(valList)) 747 for i, v := range perm { 748 permList[v] = valList[i] 749 } 750 return permList 751 } 752 753 func createNewValidatorList(testValList []testVal) []*Validator { 754 valList := make([]*Validator, 0, len(testValList)) 755 for _, val := range testValList { 756 valList = append(valList, newValidator([]byte(val.name), val.power)) 757 } 758 return valList 759 } 760 761 func createNewValidatorSet(testValList []testVal) *ValidatorSet { 762 return NewValidatorSet(createNewValidatorList(testValList)) 763 } 764 765 func valSetTotalProposerPriority(valSet *ValidatorSet) int64 { 766 sum := int64(0) 767 for _, val := range valSet.Validators { 768 // mind overflow 769 sum = safeAddClip(sum, val.ProposerPriority) 770 } 771 return sum 772 } 773 774 func verifyValidatorSet(t *testing.T, valSet *ValidatorSet) { 775 // verify that the capacity and length of validators is the same 776 assert.Equal(t, len(valSet.Validators), cap(valSet.Validators)) 777 778 // verify that the set's total voting power has been updated 779 tvp := valSet.totalVotingPower 780 valSet.updateTotalVotingPower() 781 expectedTvp := valSet.TotalVotingPower() 782 assert.Equal(t, expectedTvp, tvp, 783 "expected TVP %d. Got %d, valSet=%s", expectedTvp, tvp, valSet) 784 785 // verify that validator priorities are centered 786 valsCount := int64(len(valSet.Validators)) 787 tpp := valSetTotalProposerPriority(valSet) 788 assert.True(t, tpp < valsCount && tpp > -valsCount, 789 "expected total priority in (-%d, %d). Got %d", valsCount, valsCount, tpp) 790 791 // verify that priorities are scaled 792 dist := computeMaxMinPriorityDiff(valSet) 793 assert.True(t, dist <= PriorityWindowSizeFactor*tvp, 794 "expected priority distance < %d. Got %d", PriorityWindowSizeFactor*tvp, dist) 795 } 796 797 func toTestValList(valList []*Validator) []testVal { 798 testList := make([]testVal, len(valList)) 799 for i, val := range valList { 800 testList[i].name = string(val.Address) 801 testList[i].power = val.VotingPower 802 } 803 return testList 804 } 805 806 func testValSet(nVals int, power int64) []testVal { 807 vals := make([]testVal, nVals) 808 for i := 0; i < nVals; i++ { 809 vals[i] = testVal{fmt.Sprintf("v%d", i+1), power} 810 } 811 return vals 812 } 813 814 type valSetErrTestCase struct { 815 startVals []testVal 816 updateVals []testVal 817 } 818 819 func executeValSetErrTestCase(t *testing.T, idx int, tt valSetErrTestCase) { 820 // create a new set and apply updates, keeping copies for the checks 821 valSet := createNewValidatorSet(tt.startVals) 822 valSetCopy := valSet.Copy() 823 valList := createNewValidatorList(tt.updateVals) 824 valListCopy := validatorListCopy(valList) 825 err := valSet.UpdateWithChangeSet(valList) 826 827 // for errors check the validator set has not been changed 828 assert.Error(t, err, "test %d", idx) 829 assert.Equal(t, valSet, valSetCopy, "test %v", idx) 830 831 // check the parameter list has not changed 832 assert.Equal(t, valList, valListCopy, "test %v", idx) 833 } 834 835 func TestValSetUpdatesDuplicateEntries(t *testing.T) { 836 testCases := []valSetErrTestCase{ 837 // Duplicate entries in changes 838 { // first entry is duplicated change 839 testValSet(2, 10), 840 []testVal{{"v1", 11}, {"v1", 22}}, 841 }, 842 { // second entry is duplicated change 843 testValSet(2, 10), 844 []testVal{{"v2", 11}, {"v2", 22}}, 845 }, 846 { // change duplicates are separated by a valid change 847 testValSet(2, 10), 848 []testVal{{"v1", 11}, {"v2", 22}, {"v1", 12}}, 849 }, 850 { // change duplicates are separated by a valid change 851 testValSet(3, 10), 852 []testVal{{"v1", 11}, {"v3", 22}, {"v1", 12}}, 853 }, 854 855 // Duplicate entries in remove 856 { // first entry is duplicated remove 857 testValSet(2, 10), 858 []testVal{{"v1", 0}, {"v1", 0}}, 859 }, 860 { // second entry is duplicated remove 861 testValSet(2, 10), 862 []testVal{{"v2", 0}, {"v2", 0}}, 863 }, 864 { // remove duplicates are separated by a valid remove 865 testValSet(2, 10), 866 []testVal{{"v1", 0}, {"v2", 0}, {"v1", 0}}, 867 }, 868 { // remove duplicates are separated by a valid remove 869 testValSet(3, 10), 870 []testVal{{"v1", 0}, {"v3", 0}, {"v1", 0}}, 871 }, 872 873 { // remove and update same val 874 testValSet(2, 10), 875 []testVal{{"v1", 0}, {"v2", 20}, {"v1", 30}}, 876 }, 877 { // duplicate entries in removes + changes 878 testValSet(2, 10), 879 []testVal{{"v1", 0}, {"v2", 20}, {"v2", 30}, {"v1", 0}}, 880 }, 881 { // duplicate entries in removes + changes 882 testValSet(3, 10), 883 []testVal{{"v1", 0}, {"v3", 5}, {"v2", 20}, {"v2", 30}, {"v1", 0}}, 884 }, 885 } 886 887 for i, tt := range testCases { 888 executeValSetErrTestCase(t, i, tt) 889 } 890 } 891 892 func TestValSetUpdatesOverflows(t *testing.T) { 893 maxVP := MaxTotalVotingPower 894 testCases := []valSetErrTestCase{ 895 { // single update leading to overflow 896 testValSet(2, 10), 897 []testVal{{"v1", math.MaxInt64}}, 898 }, 899 { // single update leading to overflow 900 testValSet(2, 10), 901 []testVal{{"v2", math.MaxInt64}}, 902 }, 903 { // add validator leading to overflow 904 testValSet(1, maxVP), 905 []testVal{{"v2", math.MaxInt64}}, 906 }, 907 { // add validator leading to exceed Max 908 testValSet(1, maxVP-1), 909 []testVal{{"v2", 5}}, 910 }, 911 { // add validator leading to exceed Max 912 testValSet(2, maxVP/3), 913 []testVal{{"v3", maxVP / 2}}, 914 }, 915 { // add validator leading to exceed Max 916 testValSet(1, maxVP), 917 []testVal{{"v2", maxVP}}, 918 }, 919 } 920 921 for i, tt := range testCases { 922 executeValSetErrTestCase(t, i, tt) 923 } 924 } 925 926 func TestValSetUpdatesOtherErrors(t *testing.T) { 927 testCases := []valSetErrTestCase{ 928 { // update with negative voting power 929 testValSet(2, 10), 930 []testVal{{"v1", -123}}, 931 }, 932 { // update with negative voting power 933 testValSet(2, 10), 934 []testVal{{"v2", -123}}, 935 }, 936 { // remove non-existing validator 937 testValSet(2, 10), 938 []testVal{{"v3", 0}}, 939 }, 940 { // delete all validators 941 []testVal{{"v1", 10}, {"v2", 20}, {"v3", 30}}, 942 []testVal{{"v1", 0}, {"v2", 0}, {"v3", 0}}, 943 }, 944 } 945 946 for i, tt := range testCases { 947 executeValSetErrTestCase(t, i, tt) 948 } 949 } 950 951 func TestValSetUpdatesBasicTestsExecute(t *testing.T) { 952 valSetUpdatesBasicTests := []struct { 953 startVals []testVal 954 updateVals []testVal 955 expectedVals []testVal 956 }{ 957 { // no changes 958 testValSet(2, 10), 959 []testVal{}, 960 testValSet(2, 10), 961 }, 962 { // voting power changes 963 testValSet(2, 10), 964 []testVal{{"v2", 22}, {"v1", 11}}, 965 []testVal{{"v2", 22}, {"v1", 11}}, 966 }, 967 { // add new validators 968 []testVal{{"v2", 20}, {"v1", 10}}, 969 []testVal{{"v4", 40}, {"v3", 30}}, 970 []testVal{{"v4", 40}, {"v3", 30}, {"v2", 20}, {"v1", 10}}, 971 }, 972 { // add new validator to middle 973 []testVal{{"v3", 20}, {"v1", 10}}, 974 []testVal{{"v2", 30}}, 975 []testVal{{"v2", 30}, {"v3", 20}, {"v1", 10}}, 976 }, 977 { // add new validator to beginning 978 []testVal{{"v3", 20}, {"v2", 10}}, 979 []testVal{{"v1", 30}}, 980 []testVal{{"v1", 30}, {"v3", 20}, {"v2", 10}}, 981 }, 982 { // delete validators 983 []testVal{{"v3", 30}, {"v2", 20}, {"v1", 10}}, 984 []testVal{{"v2", 0}}, 985 []testVal{{"v3", 30}, {"v1", 10}}, 986 }, 987 } 988 989 for i, tt := range valSetUpdatesBasicTests { 990 // create a new set and apply updates, keeping copies for the checks 991 valSet := createNewValidatorSet(tt.startVals) 992 valList := createNewValidatorList(tt.updateVals) 993 err := valSet.UpdateWithChangeSet(valList) 994 assert.NoError(t, err, "test %d", i) 995 996 valListCopy := validatorListCopy(valSet.Validators) 997 // check that the voting power in the set's validators is not changing if the voting power 998 // is changed in the list of validators previously passed as parameter to UpdateWithChangeSet. 999 // this is to make sure copies of the validators are made by UpdateWithChangeSet. 1000 if len(valList) > 0 { 1001 valList[0].VotingPower++ 1002 assert.Equal(t, toTestValList(valListCopy), toTestValList(valSet.Validators), "test %v", i) 1003 1004 } 1005 1006 // check the final validator list is as expected and the set is properly scaled and centered. 1007 assert.Equal(t, tt.expectedVals, toTestValList(valSet.Validators), "test %v", i) 1008 verifyValidatorSet(t, valSet) 1009 } 1010 } 1011 1012 // Test that different permutations of an update give the same result. 1013 func TestValSetUpdatesOrderIndependenceTestsExecute(t *testing.T) { 1014 // startVals - initial validators to create the set with 1015 // updateVals - a sequence of updates to be applied to the set. 1016 // updateVals is shuffled a number of times during testing to check for same resulting validator set. 1017 valSetUpdatesOrderTests := []struct { 1018 startVals []testVal 1019 updateVals []testVal 1020 }{ 1021 0: { // order of changes should not matter, the final validator sets should be the same 1022 []testVal{{"v4", 40}, {"v3", 30}, {"v2", 10}, {"v1", 10}}, 1023 []testVal{{"v4", 44}, {"v3", 33}, {"v2", 22}, {"v1", 11}}}, 1024 1025 1: { // order of additions should not matter 1026 []testVal{{"v2", 20}, {"v1", 10}}, 1027 []testVal{{"v3", 30}, {"v4", 40}, {"v5", 50}, {"v6", 60}}}, 1028 1029 2: { // order of removals should not matter 1030 []testVal{{"v4", 40}, {"v3", 30}, {"v2", 20}, {"v1", 10}}, 1031 []testVal{{"v1", 0}, {"v3", 0}, {"v4", 0}}}, 1032 1033 3: { // order of mixed operations should not matter 1034 []testVal{{"v4", 40}, {"v3", 30}, {"v2", 20}, {"v1", 10}}, 1035 []testVal{{"v1", 0}, {"v3", 0}, {"v2", 22}, {"v5", 50}, {"v4", 44}}}, 1036 } 1037 1038 for i, tt := range valSetUpdatesOrderTests { 1039 // create a new set and apply updates 1040 valSet := createNewValidatorSet(tt.startVals) 1041 valSetCopy := valSet.Copy() 1042 valList := createNewValidatorList(tt.updateVals) 1043 assert.NoError(t, valSetCopy.UpdateWithChangeSet(valList)) 1044 1045 // save the result as expected for next updates 1046 valSetExp := valSetCopy.Copy() 1047 1048 // perform at most 20 permutations on the updates and call UpdateWithChangeSet() 1049 n := len(tt.updateVals) 1050 maxNumPerms := tmmath.MinInt(20, n*n) 1051 for j := 0; j < maxNumPerms; j++ { 1052 // create a copy of original set and apply a random permutation of updates 1053 valSetCopy := valSet.Copy() 1054 valList := createNewValidatorList(permutation(tt.updateVals)) 1055 1056 // check there was no error and the set is properly scaled and centered. 1057 assert.NoError(t, valSetCopy.UpdateWithChangeSet(valList), 1058 "test %v failed for permutation %v", i, valList) 1059 verifyValidatorSet(t, valSetCopy) 1060 1061 // verify the resulting test is same as the expected 1062 assert.Equal(t, valSetCopy, valSetExp, 1063 "test %v failed for permutation %v", i, valList) 1064 } 1065 } 1066 } 1067 1068 // This tests the private function validator_set.go:applyUpdates() function, used only for additions and changes. 1069 // Should perform a proper merge of updatedVals and startVals 1070 func TestValSetApplyUpdatesTestsExecute(t *testing.T) { 1071 valSetUpdatesBasicTests := []struct { 1072 startVals []testVal 1073 updateVals []testVal 1074 expectedVals []testVal 1075 }{ 1076 // additions 1077 0: { // prepend 1078 []testVal{{"v4", 44}, {"v5", 55}}, 1079 []testVal{{"v1", 11}}, 1080 []testVal{{"v1", 11}, {"v4", 44}, {"v5", 55}}}, 1081 1: { // append 1082 []testVal{{"v4", 44}, {"v5", 55}}, 1083 []testVal{{"v6", 66}}, 1084 []testVal{{"v4", 44}, {"v5", 55}, {"v6", 66}}}, 1085 2: { // insert 1086 []testVal{{"v4", 44}, {"v6", 66}}, 1087 []testVal{{"v5", 55}}, 1088 []testVal{{"v4", 44}, {"v5", 55}, {"v6", 66}}}, 1089 3: { // insert multi 1090 []testVal{{"v4", 44}, {"v6", 66}, {"v9", 99}}, 1091 []testVal{{"v5", 55}, {"v7", 77}, {"v8", 88}}, 1092 []testVal{{"v4", 44}, {"v5", 55}, {"v6", 66}, {"v7", 77}, {"v8", 88}, {"v9", 99}}}, 1093 // changes 1094 4: { // head 1095 []testVal{{"v1", 111}, {"v2", 22}}, 1096 []testVal{{"v1", 11}}, 1097 []testVal{{"v1", 11}, {"v2", 22}}}, 1098 5: { // tail 1099 []testVal{{"v1", 11}, {"v2", 222}}, 1100 []testVal{{"v2", 22}}, 1101 []testVal{{"v1", 11}, {"v2", 22}}}, 1102 6: { // middle 1103 []testVal{{"v1", 11}, {"v2", 222}, {"v3", 33}}, 1104 []testVal{{"v2", 22}}, 1105 []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}}}, 1106 7: { // multi 1107 []testVal{{"v1", 111}, {"v2", 222}, {"v3", 333}}, 1108 []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}}, 1109 []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}}}, 1110 // additions and changes 1111 8: { 1112 []testVal{{"v1", 111}, {"v2", 22}}, 1113 []testVal{{"v1", 11}, {"v3", 33}, {"v4", 44}}, 1114 []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}, {"v4", 44}}}, 1115 } 1116 1117 for i, tt := range valSetUpdatesBasicTests { 1118 // create a new validator set with the start values 1119 valSet := createNewValidatorSet(tt.startVals) 1120 1121 // applyUpdates() with the update values 1122 valList := createNewValidatorList(tt.updateVals) 1123 valSet.applyUpdates(valList) 1124 1125 // check the new list of validators for proper merge 1126 assert.Equal(t, toTestValList(valSet.Validators), tt.expectedVals, "test %v", i) 1127 } 1128 } 1129 1130 type testVSetCfg struct { 1131 name string 1132 startVals []testVal 1133 deletedVals []testVal 1134 updatedVals []testVal 1135 addedVals []testVal 1136 expectedVals []testVal 1137 expErr error 1138 } 1139 1140 func randTestVSetCfg(t *testing.T, nBase, nAddMax int) testVSetCfg { 1141 if nBase <= 0 || nAddMax < 0 { 1142 t.Fatalf("bad parameters %v %v", nBase, nAddMax) 1143 } 1144 1145 const maxPower = 1000 1146 var nOld, nDel, nChanged, nAdd int 1147 1148 nOld = int(uint(rand.Int())%uint(nBase)) + 1 1149 if nBase-nOld > 0 { 1150 nDel = int(uint(rand.Int()) % uint(nBase-nOld)) 1151 } 1152 nChanged = nBase - nOld - nDel 1153 1154 if nAddMax > 0 { 1155 nAdd = rand.Int()%nAddMax + 1 1156 } 1157 1158 cfg := testVSetCfg{} 1159 1160 cfg.startVals = make([]testVal, nBase) 1161 cfg.deletedVals = make([]testVal, nDel) 1162 cfg.addedVals = make([]testVal, nAdd) 1163 cfg.updatedVals = make([]testVal, nChanged) 1164 cfg.expectedVals = make([]testVal, nBase-nDel+nAdd) 1165 1166 for i := 0; i < nBase; i++ { 1167 cfg.startVals[i] = testVal{fmt.Sprintf("v%d", i), int64(uint(rand.Int())%maxPower + 1)} 1168 if i < nOld { 1169 cfg.expectedVals[i] = cfg.startVals[i] 1170 } 1171 if i >= nOld && i < nOld+nChanged { 1172 cfg.updatedVals[i-nOld] = testVal{fmt.Sprintf("v%d", i), int64(uint(rand.Int())%maxPower + 1)} 1173 cfg.expectedVals[i] = cfg.updatedVals[i-nOld] 1174 } 1175 if i >= nOld+nChanged { 1176 cfg.deletedVals[i-nOld-nChanged] = testVal{fmt.Sprintf("v%d", i), 0} 1177 } 1178 } 1179 1180 for i := nBase; i < nBase+nAdd; i++ { 1181 cfg.addedVals[i-nBase] = testVal{fmt.Sprintf("v%d", i), int64(uint(rand.Int())%maxPower + 1)} 1182 cfg.expectedVals[i-nDel] = cfg.addedVals[i-nBase] 1183 } 1184 1185 sort.Sort(testValsByVotingPower(cfg.startVals)) 1186 sort.Sort(testValsByVotingPower(cfg.deletedVals)) 1187 sort.Sort(testValsByVotingPower(cfg.updatedVals)) 1188 sort.Sort(testValsByVotingPower(cfg.addedVals)) 1189 sort.Sort(testValsByVotingPower(cfg.expectedVals)) 1190 1191 return cfg 1192 1193 } 1194 1195 func applyChangesToValSet(t *testing.T, expErr error, valSet *ValidatorSet, valsLists ...[]testVal) { 1196 changes := make([]testVal, 0) 1197 for _, valsList := range valsLists { 1198 changes = append(changes, valsList...) 1199 } 1200 valList := createNewValidatorList(changes) 1201 err := valSet.UpdateWithChangeSet(valList) 1202 if expErr != nil { 1203 assert.Equal(t, expErr, err) 1204 } else { 1205 assert.NoError(t, err) 1206 } 1207 } 1208 1209 func TestValSetUpdatePriorityOrderTests(t *testing.T) { 1210 const nMaxElections int32 = 5000 1211 1212 testCases := []testVSetCfg{ 1213 0: { // remove high power validator, keep old equal lower power validators 1214 startVals: []testVal{{"v3", 1000}, {"v1", 1}, {"v2", 1}}, 1215 deletedVals: []testVal{{"v3", 0}}, 1216 updatedVals: []testVal{}, 1217 addedVals: []testVal{}, 1218 expectedVals: []testVal{{"v1", 1}, {"v2", 1}}, 1219 }, 1220 1: { // remove high power validator, keep old different power validators 1221 startVals: []testVal{{"v3", 1000}, {"v2", 10}, {"v1", 1}}, 1222 deletedVals: []testVal{{"v3", 0}}, 1223 updatedVals: []testVal{}, 1224 addedVals: []testVal{}, 1225 expectedVals: []testVal{{"v2", 10}, {"v1", 1}}, 1226 }, 1227 2: { // remove high power validator, add new low power validators, keep old lower power 1228 startVals: []testVal{{"v3", 1000}, {"v2", 2}, {"v1", 1}}, 1229 deletedVals: []testVal{{"v3", 0}}, 1230 updatedVals: []testVal{{"v2", 1}}, 1231 addedVals: []testVal{{"v5", 50}, {"v4", 40}}, 1232 expectedVals: []testVal{{"v5", 50}, {"v4", 40}, {"v1", 1}, {"v2", 1}}, 1233 }, 1234 1235 // generate a configuration with 100 validators, 1236 // randomly select validators for updates and deletes, and 1237 // generate 10 new validators to be added 1238 3: randTestVSetCfg(t, 100, 10), 1239 1240 4: randTestVSetCfg(t, 1000, 100), 1241 1242 5: randTestVSetCfg(t, 10, 100), 1243 1244 6: randTestVSetCfg(t, 100, 1000), 1245 1246 7: randTestVSetCfg(t, 1000, 1000), 1247 } 1248 1249 for _, cfg := range testCases { 1250 1251 // create a new validator set 1252 valSet := createNewValidatorSet(cfg.startVals) 1253 verifyValidatorSet(t, valSet) 1254 1255 // run election up to nMaxElections times, apply changes and verify that the priority order is correct 1256 verifyValSetUpdatePriorityOrder(t, valSet, cfg, nMaxElections) 1257 } 1258 } 1259 1260 func verifyValSetUpdatePriorityOrder(t *testing.T, valSet *ValidatorSet, cfg testVSetCfg, nMaxElections int32) { 1261 // Run election up to nMaxElections times, sort validators by priorities 1262 valSet.IncrementProposerPriority(rand.Int31()%nMaxElections + 1) 1263 1264 // apply the changes, get the updated validators, sort by priorities 1265 applyChangesToValSet(t, nil, valSet, cfg.addedVals, cfg.updatedVals, cfg.deletedVals) 1266 1267 // basic checks 1268 assert.Equal(t, cfg.expectedVals, toTestValList(valSet.Validators)) 1269 verifyValidatorSet(t, valSet) 1270 1271 // verify that the added validators have the smallest priority: 1272 // - they should be at the beginning of updatedValsPriSorted since it is 1273 // sorted by priority 1274 if len(cfg.addedVals) > 0 { 1275 updatedValsPriSorted := validatorListCopy(valSet.Validators) 1276 sort.Sort(validatorsByPriority(updatedValsPriSorted)) 1277 1278 addedValsPriSlice := updatedValsPriSorted[:len(cfg.addedVals)] 1279 sort.Sort(ValidatorsByVotingPower(addedValsPriSlice)) 1280 assert.Equal(t, cfg.addedVals, toTestValList(addedValsPriSlice)) 1281 1282 // - and should all have the same priority 1283 expectedPri := addedValsPriSlice[0].ProposerPriority 1284 for _, val := range addedValsPriSlice[1:] { 1285 assert.Equal(t, expectedPri, val.ProposerPriority) 1286 } 1287 } 1288 } 1289 1290 func TestNewValidatorSetFromExistingValidators(t *testing.T) { 1291 ctx, cancel := context.WithCancel(context.Background()) 1292 defer cancel() 1293 1294 size := 5 1295 vals := make([]*Validator, size) 1296 for i := 0; i < size; i++ { 1297 pv := NewMockPV() 1298 vals[i] = pv.ExtractIntoValidator(ctx, int64(i+1)) 1299 } 1300 valSet := NewValidatorSet(vals) 1301 valSet.IncrementProposerPriority(5) 1302 1303 newValSet := NewValidatorSet(valSet.Validators) 1304 assert.NotEqual(t, valSet, newValSet) 1305 1306 existingValSet, err := ValidatorSetFromExistingValidators(valSet.Validators) 1307 assert.NoError(t, err) 1308 assert.Equal(t, valSet, existingValSet) 1309 assert.Equal(t, valSet.CopyIncrementProposerPriority(3), existingValSet.CopyIncrementProposerPriority(3)) 1310 } 1311 1312 func TestValSetUpdateOverflowRelated(t *testing.T) { 1313 testCases := []testVSetCfg{ 1314 { 1315 name: "1 no false overflow error messages for updates", 1316 startVals: []testVal{{"v2", MaxTotalVotingPower - 1}, {"v1", 1}}, 1317 updatedVals: []testVal{{"v1", MaxTotalVotingPower - 1}, {"v2", 1}}, 1318 expectedVals: []testVal{{"v1", MaxTotalVotingPower - 1}, {"v2", 1}}, 1319 expErr: nil, 1320 }, 1321 { 1322 // this test shows that it is important to apply the updates in the order of the change in power 1323 // i.e. apply first updates with decreases in power, v2 change in this case. 1324 name: "2 no false overflow error messages for updates", 1325 startVals: []testVal{{"v2", MaxTotalVotingPower - 1}, {"v1", 1}}, 1326 updatedVals: []testVal{{"v1", MaxTotalVotingPower/2 - 1}, {"v2", MaxTotalVotingPower / 2}}, 1327 expectedVals: []testVal{{"v2", MaxTotalVotingPower / 2}, {"v1", MaxTotalVotingPower/2 - 1}}, 1328 expErr: nil, 1329 }, 1330 { 1331 name: "3 no false overflow error messages for deletes", 1332 startVals: []testVal{{"v1", MaxTotalVotingPower - 2}, {"v2", 1}, {"v3", 1}}, 1333 deletedVals: []testVal{{"v1", 0}}, 1334 addedVals: []testVal{{"v4", MaxTotalVotingPower - 2}}, 1335 expectedVals: []testVal{{"v4", MaxTotalVotingPower - 2}, {"v2", 1}, {"v3", 1}}, 1336 expErr: nil, 1337 }, 1338 { 1339 name: "4 no false overflow error messages for adds, updates and deletes", 1340 startVals: []testVal{ 1341 {"v1", MaxTotalVotingPower / 4}, {"v2", MaxTotalVotingPower / 4}, 1342 {"v3", MaxTotalVotingPower / 4}, {"v4", MaxTotalVotingPower / 4}}, 1343 deletedVals: []testVal{{"v2", 0}}, 1344 updatedVals: []testVal{ 1345 {"v1", MaxTotalVotingPower/2 - 2}, {"v3", MaxTotalVotingPower/2 - 3}, {"v4", 2}}, 1346 addedVals: []testVal{{"v5", 3}}, 1347 expectedVals: []testVal{ 1348 {"v1", MaxTotalVotingPower/2 - 2}, {"v3", MaxTotalVotingPower/2 - 3}, {"v5", 3}, {"v4", 2}}, 1349 expErr: nil, 1350 }, 1351 { 1352 name: "5 check panic on overflow is prevented: update 8 validators with power int64(math.MaxInt64)/8", 1353 startVals: []testVal{ 1354 {"v1", 1}, {"v2", 1}, {"v3", 1}, {"v4", 1}, {"v5", 1}, 1355 {"v6", 1}, {"v7", 1}, {"v8", 1}, {"v9", 1}}, 1356 updatedVals: []testVal{ 1357 {"v1", MaxTotalVotingPower}, {"v2", MaxTotalVotingPower}, {"v3", MaxTotalVotingPower}, 1358 {"v4", MaxTotalVotingPower}, {"v5", MaxTotalVotingPower}, {"v6", MaxTotalVotingPower}, 1359 {"v7", MaxTotalVotingPower}, {"v8", MaxTotalVotingPower}, {"v9", 8}}, 1360 expectedVals: []testVal{ 1361 {"v1", 1}, {"v2", 1}, {"v3", 1}, {"v4", 1}, {"v5", 1}, 1362 {"v6", 1}, {"v7", 1}, {"v8", 1}, {"v9", 1}}, 1363 expErr: ErrTotalVotingPowerOverflow, 1364 }, 1365 } 1366 1367 for _, tt := range testCases { 1368 tt := tt 1369 t.Run(tt.name, func(t *testing.T) { 1370 valSet := createNewValidatorSet(tt.startVals) 1371 verifyValidatorSet(t, valSet) 1372 1373 // execute update and verify returned error is as expected 1374 applyChangesToValSet(t, tt.expErr, valSet, tt.addedVals, tt.updatedVals, tt.deletedVals) 1375 1376 // verify updated validator set is as expected 1377 assert.Equal(t, tt.expectedVals, toTestValList(valSet.Validators)) 1378 verifyValidatorSet(t, valSet) 1379 }) 1380 } 1381 } 1382 1383 func TestSafeMul(t *testing.T) { 1384 testCases := []struct { 1385 a int64 1386 b int64 1387 c int64 1388 overflow bool 1389 }{ 1390 0: {0, 0, 0, false}, 1391 1: {1, 0, 0, false}, 1392 2: {2, 3, 6, false}, 1393 3: {2, -3, -6, false}, 1394 4: {-2, -3, 6, false}, 1395 5: {-2, 3, -6, false}, 1396 6: {math.MaxInt64, 1, math.MaxInt64, false}, 1397 7: {math.MaxInt64 / 2, 2, math.MaxInt64 - 1, false}, 1398 8: {math.MaxInt64 / 2, 3, 0, true}, 1399 9: {math.MaxInt64, 2, 0, true}, 1400 } 1401 1402 for i, tc := range testCases { 1403 c, overflow := safeMul(tc.a, tc.b) 1404 assert.Equal(t, tc.c, c, "#%d", i) 1405 assert.Equal(t, tc.overflow, overflow, "#%d", i) 1406 } 1407 } 1408 1409 func TestValidatorSetProtoBuf(t *testing.T) { 1410 ctx, cancel := context.WithCancel(context.Background()) 1411 defer cancel() 1412 1413 valset, _ := randValidatorPrivValSet(ctx, t, 10, 100) 1414 valset2, _ := randValidatorPrivValSet(ctx, t, 10, 100) 1415 valset2.Validators[0] = &Validator{} 1416 1417 valset3, _ := randValidatorPrivValSet(ctx, t, 10, 100) 1418 valset3.Proposer = nil 1419 1420 valset4, _ := randValidatorPrivValSet(ctx, t, 10, 100) 1421 1422 valset4.Proposer = &Validator{} 1423 1424 testCases := []struct { 1425 msg string 1426 v1 *ValidatorSet 1427 expPass1 bool 1428 expPass2 bool 1429 }{ 1430 {"success", valset, true, true}, 1431 {"fail valSet2, pubkey empty", valset2, false, false}, 1432 {"fail nil Proposer", valset3, false, false}, 1433 {"fail empty Proposer", valset4, false, false}, 1434 {"fail empty valSet", &ValidatorSet{}, true, false}, 1435 {"false nil", nil, true, false}, 1436 } 1437 for _, tc := range testCases { 1438 protoValSet, err := tc.v1.ToProto() 1439 if tc.expPass1 { 1440 require.NoError(t, err, tc.msg) 1441 } else { 1442 require.Error(t, err, tc.msg) 1443 } 1444 1445 valSet, err := ValidatorSetFromProto(protoValSet) 1446 if tc.expPass2 { 1447 require.NoError(t, err, tc.msg) 1448 require.EqualValues(t, tc.v1, valSet, tc.msg) 1449 } else { 1450 require.Error(t, err, tc.msg) 1451 } 1452 } 1453 } 1454 1455 // --------------------- 1456 // Sort validators by priority and address 1457 type validatorsByPriority []*Validator 1458 1459 func (valz validatorsByPriority) Len() int { 1460 return len(valz) 1461 } 1462 1463 func (valz validatorsByPriority) Less(i, j int) bool { 1464 if valz[i].ProposerPriority < valz[j].ProposerPriority { 1465 return true 1466 } 1467 if valz[i].ProposerPriority > valz[j].ProposerPriority { 1468 return false 1469 } 1470 return bytes.Compare(valz[i].Address, valz[j].Address) < 0 1471 } 1472 1473 func (valz validatorsByPriority) Swap(i, j int) { 1474 valz[i], valz[j] = valz[j], valz[i] 1475 } 1476 1477 //------------------------------------- 1478 1479 type testValsByVotingPower []testVal 1480 1481 func (tvals testValsByVotingPower) Len() int { 1482 return len(tvals) 1483 } 1484 1485 func (tvals testValsByVotingPower) Less(i, j int) bool { 1486 if tvals[i].power == tvals[j].power { 1487 return bytes.Compare([]byte(tvals[i].name), []byte(tvals[j].name)) == -1 1488 } 1489 return tvals[i].power > tvals[j].power 1490 } 1491 1492 func (tvals testValsByVotingPower) Swap(i, j int) { 1493 tvals[i], tvals[j] = tvals[j], tvals[i] 1494 } 1495 1496 // ------------------------------------- 1497 // Benchmark tests 1498 func BenchmarkUpdates(b *testing.B) { 1499 const ( 1500 n = 100 1501 m = 2000 1502 ) 1503 // Init with n validators 1504 vs := make([]*Validator, n) 1505 for j := 0; j < n; j++ { 1506 vs[j] = newValidator([]byte(fmt.Sprintf("v%d", j)), 100) 1507 } 1508 valSet := NewValidatorSet(vs) 1509 l := len(valSet.Validators) 1510 1511 // Make m new validators 1512 newValList := make([]*Validator, m) 1513 for j := 0; j < m; j++ { 1514 newValList[j] = newValidator([]byte(fmt.Sprintf("v%d", j+l)), 1000) 1515 } 1516 b.ResetTimer() 1517 1518 for i := 0; i < b.N; i++ { 1519 // Add m validators to valSetCopy 1520 valSetCopy := valSet.Copy() 1521 assert.NoError(b, valSetCopy.UpdateWithChangeSet(newValList)) 1522 } 1523 } 1524 1525 func BenchmarkValidatorSet_VerifyCommit_Ed25519(b *testing.B) { // nolint 1526 ctx, cancel := context.WithCancel(context.Background()) 1527 defer cancel() 1528 1529 for _, n := range []int{1, 8, 64, 1024} { 1530 n := n 1531 var ( 1532 chainID = "test_chain_id" 1533 h = int64(3) 1534 blockID = makeBlockIDRandom() 1535 ) 1536 b.Run(fmt.Sprintf("valset size %d", n), func(b *testing.B) { 1537 b.ReportAllocs() 1538 // generate n validators 1539 voteSet, valSet, vals := randVoteSet(ctx, b, h, 0, tmproto.PrecommitType, n, int64(n*5)) 1540 // create a commit with n validators 1541 extCommit, err := makeExtCommit(ctx, blockID, h, 0, voteSet, vals, time.Now()) 1542 require.NoError(b, err) 1543 commit := extCommit.ToCommit() 1544 1545 for i := 0; i < b.N/n; i++ { 1546 err = valSet.VerifyCommit(chainID, blockID, h, commit) 1547 assert.NoError(b, err) 1548 } 1549 }) 1550 } 1551 } 1552 1553 func BenchmarkValidatorSet_VerifyCommitLight_Ed25519(b *testing.B) { // nolint 1554 ctx, cancel := context.WithCancel(context.Background()) 1555 defer cancel() 1556 1557 for _, n := range []int{1, 8, 64, 1024} { 1558 n := n 1559 var ( 1560 chainID = "test_chain_id" 1561 h = int64(3) 1562 blockID = makeBlockIDRandom() 1563 ) 1564 b.Run(fmt.Sprintf("valset size %d", n), func(b *testing.B) { 1565 b.ReportAllocs() 1566 // generate n validators 1567 voteSet, valSet, vals := randVoteSet(ctx, b, h, 0, tmproto.PrecommitType, n, int64(n*5)) 1568 1569 // create a commit with n validators 1570 extCommit, err := makeExtCommit(ctx, blockID, h, 0, voteSet, vals, time.Now()) 1571 require.NoError(b, err) 1572 commit := extCommit.ToCommit() 1573 1574 for i := 0; i < b.N/n; i++ { 1575 err = valSet.VerifyCommitLight(chainID, blockID, h, commit) 1576 assert.NoError(b, err) 1577 } 1578 }) 1579 } 1580 } 1581 1582 func BenchmarkValidatorSet_VerifyCommitLightTrusting_Ed25519(b *testing.B) { 1583 ctx, cancel := context.WithCancel(context.Background()) 1584 defer cancel() 1585 1586 for _, n := range []int{1, 8, 64, 1024} { 1587 n := n 1588 var ( 1589 chainID = "test_chain_id" 1590 h = int64(3) 1591 blockID = makeBlockIDRandom() 1592 ) 1593 b.Run(fmt.Sprintf("valset size %d", n), func(b *testing.B) { 1594 b.ReportAllocs() 1595 // generate n validators 1596 voteSet, valSet, vals := randVoteSet(ctx, b, h, 0, tmproto.PrecommitType, n, int64(n*5)) 1597 // create a commit with n validators 1598 extCommit, err := makeExtCommit(ctx, blockID, h, 0, voteSet, vals, time.Now()) 1599 require.NoError(b, err) 1600 commit := extCommit.ToCommit() 1601 1602 for i := 0; i < b.N/n; i++ { 1603 err = valSet.VerifyCommitLightTrusting(chainID, commit, tmmath.Fraction{Numerator: 1, Denominator: 3}) 1604 assert.NoError(b, err) 1605 } 1606 }) 1607 } 1608 } 1609 1610 // Testing Utils 1611 1612 // deterministicValidatorSet returns a deterministic validator set (size: +numValidators+), 1613 // where each validator has a power of 50 1614 // 1615 // EXPOSED FOR TESTING. 1616 func deterministicValidatorSet(ctx context.Context, t *testing.T) (*ValidatorSet, []PrivValidator) { 1617 var ( 1618 valz = make([]*Validator, 10) 1619 privValidators = make([]PrivValidator, 10) 1620 ) 1621 1622 t.Helper() 1623 1624 for i := 0; i < 10; i++ { 1625 // val, privValidator := DeterministicValidator(ed25519.PrivKey([]byte(deterministicKeys[i]))) 1626 val, privValidator := deterministicValidator(ctx, t, ed25519.GenPrivKeyFromSecret([]byte(fmt.Sprintf("key: %x", i)))) 1627 valz[i] = val 1628 privValidators[i] = privValidator 1629 } 1630 1631 sort.Sort(PrivValidatorsByAddress(privValidators)) 1632 1633 return NewValidatorSet(valz), privValidators 1634 }