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