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