github.com/DFWallet/tendermint-cosmos@v0.0.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 "time" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 16 "github.com/DFWallet/tendermint-cosmos/crypto" 17 "github.com/DFWallet/tendermint-cosmos/crypto/ed25519" 18 tmmath "github.com/DFWallet/tendermint-cosmos/libs/math" 19 tmrand "github.com/DFWallet/tendermint-cosmos/libs/rand" 20 tmproto "github.com/DFWallet/tendermint-cosmos/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, 1 / 3}, 496 2: {ValidatorSet{ 497 Validators: []*Validator{ 498 {Address: []byte("a"), ProposerPriority: 100}, 499 {Address: []byte("b"), ProposerPriority: -10}, 500 {Address: []byte("c"), ProposerPriority: 1}}}, 501 1, 91 / 3}, 502 } 503 for i, tc := range tcs { 504 // work on copy to have the old ProposerPriorities: 505 newVset := tc.vs.CopyIncrementProposerPriority(tc.times) 506 for _, val := range tc.vs.Validators { 507 _, updatedVal := newVset.GetByAddress(val.Address) 508 assert.Equal(t, updatedVal.ProposerPriority, val.ProposerPriority-tc.avg, "test case: %v", i) 509 } 510 } 511 } 512 513 func TestAveragingInIncrementProposerPriorityWithVotingPower(t *testing.T) { 514 // Other than TestAveragingInIncrementProposerPriority this is a more complete test showing 515 // how each ProposerPriority changes in relation to the validator's voting power respectively. 516 // average is zero in each round: 517 vp0 := int64(10) 518 vp1 := int64(1) 519 vp2 := int64(1) 520 total := vp0 + vp1 + vp2 521 avg := (vp0 + vp1 + vp2 - total) / 3 522 vals := ValidatorSet{Validators: []*Validator{ 523 {Address: []byte{0}, ProposerPriority: 0, VotingPower: vp0}, 524 {Address: []byte{1}, ProposerPriority: 0, VotingPower: vp1}, 525 {Address: []byte{2}, ProposerPriority: 0, VotingPower: vp2}}} 526 tcs := []struct { 527 vals *ValidatorSet 528 wantProposerPrioritys []int64 529 times int32 530 wantProposer *Validator 531 }{ 532 533 0: { 534 vals.Copy(), 535 []int64{ 536 // Acumm+VotingPower-Avg: 537 0 + vp0 - total - avg, // mostest will be subtracted by total voting power (12) 538 0 + vp1, 539 0 + vp2}, 540 1, 541 vals.Validators[0]}, 542 1: { 543 vals.Copy(), 544 []int64{ 545 (0 + vp0 - total) + vp0 - total - avg, // this will be mostest on 2nd iter, too 546 (0 + vp1) + vp1, 547 (0 + vp2) + vp2}, 548 2, 549 vals.Validators[0]}, // increment twice -> expect average to be subtracted twice 550 2: { 551 vals.Copy(), 552 []int64{ 553 0 + 3*(vp0-total) - avg, // still mostest 554 0 + 3*vp1, 555 0 + 3*vp2}, 556 3, 557 vals.Validators[0]}, 558 3: { 559 vals.Copy(), 560 []int64{ 561 0 + 4*(vp0-total), // still mostest 562 0 + 4*vp1, 563 0 + 4*vp2}, 564 4, 565 vals.Validators[0]}, 566 4: { 567 vals.Copy(), 568 []int64{ 569 0 + 4*(vp0-total) + vp0, // 4 iters was mostest 570 0 + 5*vp1 - total, // now this val is mostest for the 1st time (hence -12==totalVotingPower) 571 0 + 5*vp2}, 572 5, 573 vals.Validators[1]}, 574 5: { 575 vals.Copy(), 576 []int64{ 577 0 + 6*vp0 - 5*total, // mostest again 578 0 + 6*vp1 - total, // mostest once up to here 579 0 + 6*vp2}, 580 6, 581 vals.Validators[0]}, 582 6: { 583 vals.Copy(), 584 []int64{ 585 0 + 7*vp0 - 6*total, // in 7 iters this val is mostest 6 times 586 0 + 7*vp1 - total, // in 7 iters this val is mostest 1 time 587 0 + 7*vp2}, 588 7, 589 vals.Validators[0]}, 590 7: { 591 vals.Copy(), 592 []int64{ 593 0 + 8*vp0 - 7*total, // mostest again 594 0 + 8*vp1 - total, 595 0 + 8*vp2}, 596 8, 597 vals.Validators[0]}, 598 8: { 599 vals.Copy(), 600 []int64{ 601 0 + 9*vp0 - 7*total, 602 0 + 9*vp1 - total, 603 0 + 9*vp2 - total}, // mostest 604 9, 605 vals.Validators[2]}, 606 9: { 607 vals.Copy(), 608 []int64{ 609 0 + 10*vp0 - 8*total, // after 10 iters this is mostest again 610 0 + 10*vp1 - total, // after 6 iters this val is "mostest" once and not in between 611 0 + 10*vp2 - total}, // in between 10 iters this val is "mostest" once 612 10, 613 vals.Validators[0]}, 614 10: { 615 vals.Copy(), 616 []int64{ 617 0 + 11*vp0 - 9*total, 618 0 + 11*vp1 - total, // after 6 iters this val is "mostest" once and not in between 619 0 + 11*vp2 - total}, // after 10 iters this val is "mostest" once 620 11, 621 vals.Validators[0]}, 622 } 623 for i, tc := range tcs { 624 tc.vals.IncrementProposerPriority(tc.times) 625 626 assert.Equal(t, tc.wantProposer.Address, tc.vals.GetProposer().Address, 627 "test case: %v", 628 i) 629 630 for valIdx, val := range tc.vals.Validators { 631 assert.Equal(t, 632 tc.wantProposerPrioritys[valIdx], 633 val.ProposerPriority, 634 "test case: %v, validator: %v", 635 i, 636 valIdx) 637 } 638 } 639 } 640 641 func TestSafeAdd(t *testing.T) { 642 f := func(a, b int64) bool { 643 c, overflow := safeAdd(a, b) 644 return overflow || (!overflow && c == a+b) 645 } 646 if err := quick.Check(f, nil); err != nil { 647 t.Error(err) 648 } 649 } 650 651 func TestSafeAddClip(t *testing.T) { 652 assert.EqualValues(t, math.MaxInt64, safeAddClip(math.MaxInt64, 10)) 653 assert.EqualValues(t, math.MaxInt64, safeAddClip(math.MaxInt64, math.MaxInt64)) 654 assert.EqualValues(t, math.MinInt64, safeAddClip(math.MinInt64, -10)) 655 } 656 657 func TestSafeSubClip(t *testing.T) { 658 assert.EqualValues(t, math.MinInt64, safeSubClip(math.MinInt64, 10)) 659 assert.EqualValues(t, 0, safeSubClip(math.MinInt64, math.MinInt64)) 660 assert.EqualValues(t, math.MinInt64, safeSubClip(math.MinInt64, math.MaxInt64)) 661 assert.EqualValues(t, math.MaxInt64, safeSubClip(math.MaxInt64, -10)) 662 } 663 664 //------------------------------------------------------------------- 665 666 // Check VerifyCommit, VerifyCommitLight and VerifyCommitLightTrusting basic 667 // verification. 668 func TestValidatorSet_VerifyCommit_All(t *testing.T) { 669 var ( 670 privKey = ed25519.GenPrivKey() 671 pubKey = privKey.PubKey() 672 v1 = NewValidator(pubKey, 1000) 673 vset = NewValidatorSet([]*Validator{v1}) 674 675 chainID = "Lalande21185" 676 ) 677 678 vote := examplePrecommit() 679 vote.ValidatorAddress = pubKey.Address() 680 v := vote.ToProto() 681 sig, err := privKey.Sign(VoteSignBytes(chainID, v)) 682 require.NoError(t, err) 683 vote.Signature = sig 684 685 commit := NewCommit(vote.Height, vote.Round, vote.BlockID, []CommitSig{vote.CommitSig()}) 686 687 vote2 := *vote 688 sig2, err := privKey.Sign(VoteSignBytes("EpsilonEridani", v)) 689 require.NoError(t, err) 690 vote2.Signature = sig2 691 692 testCases := []struct { 693 description string 694 chainID string 695 blockID BlockID 696 height int64 697 commit *Commit 698 expErr bool 699 }{ 700 {"good", chainID, vote.BlockID, vote.Height, commit, false}, 701 702 {"wrong signature (#0)", "EpsilonEridani", vote.BlockID, vote.Height, commit, true}, 703 {"wrong block ID", chainID, makeBlockIDRandom(), vote.Height, commit, true}, 704 {"wrong height", chainID, vote.BlockID, vote.Height - 1, commit, true}, 705 706 {"wrong set size: 1 vs 0", chainID, vote.BlockID, vote.Height, 707 NewCommit(vote.Height, vote.Round, vote.BlockID, []CommitSig{}), true}, 708 709 {"wrong set size: 1 vs 2", chainID, vote.BlockID, vote.Height, 710 NewCommit(vote.Height, vote.Round, vote.BlockID, 711 []CommitSig{vote.CommitSig(), {BlockIDFlag: BlockIDFlagAbsent}}), true}, 712 713 {"insufficient voting power: got 0, needed more than 666", chainID, vote.BlockID, vote.Height, 714 NewCommit(vote.Height, vote.Round, vote.BlockID, []CommitSig{{BlockIDFlag: BlockIDFlagAbsent}}), true}, 715 716 {"wrong signature (#0)", chainID, vote.BlockID, vote.Height, 717 NewCommit(vote.Height, vote.Round, vote.BlockID, []CommitSig{vote2.CommitSig()}), true}, 718 } 719 720 for _, tc := range testCases { 721 tc := tc 722 t.Run(tc.description, func(t *testing.T) { 723 err := vset.VerifyCommit(tc.chainID, tc.blockID, tc.height, tc.commit) 724 if tc.expErr { 725 if assert.Error(t, err, "VerifyCommit") { 726 assert.Contains(t, err.Error(), tc.description, "VerifyCommit") 727 } 728 } else { 729 assert.NoError(t, err, "VerifyCommit") 730 } 731 732 err = vset.VerifyCommitLight(tc.chainID, tc.blockID, tc.height, tc.commit) 733 if tc.expErr { 734 if assert.Error(t, err, "VerifyCommitLight") { 735 assert.Contains(t, err.Error(), tc.description, "VerifyCommitLight") 736 } 737 } else { 738 assert.NoError(t, err, "VerifyCommitLight") 739 } 740 }) 741 } 742 } 743 744 func TestValidatorSet_VerifyCommit_CheckAllSignatures(t *testing.T) { 745 var ( 746 chainID = "test_chain_id" 747 h = int64(3) 748 blockID = makeBlockIDRandom() 749 ) 750 751 voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10) 752 commit, err := MakeCommit(blockID, h, 0, voteSet, vals, time.Now()) 753 require.NoError(t, err) 754 755 // malleate 4th signature 756 vote := voteSet.GetByIndex(3) 757 v := vote.ToProto() 758 err = vals[3].SignVote("CentaurusA", v) 759 require.NoError(t, err) 760 vote.Signature = v.Signature 761 commit.Signatures[3] = vote.CommitSig() 762 763 err = valSet.VerifyCommit(chainID, blockID, h, commit) 764 if assert.Error(t, err) { 765 assert.Contains(t, err.Error(), "wrong signature (#3)") 766 } 767 } 768 769 func TestValidatorSet_VerifyCommitLight_ReturnsAsSoonAsMajorityOfVotingPowerSigned(t *testing.T) { 770 var ( 771 chainID = "test_chain_id" 772 h = int64(3) 773 blockID = makeBlockIDRandom() 774 ) 775 776 voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10) 777 commit, err := MakeCommit(blockID, h, 0, voteSet, vals, time.Now()) 778 require.NoError(t, err) 779 780 // malleate 4th signature (3 signatures are enough for 2/3+) 781 vote := voteSet.GetByIndex(3) 782 v := vote.ToProto() 783 err = vals[3].SignVote("CentaurusA", v) 784 require.NoError(t, err) 785 vote.Signature = v.Signature 786 commit.Signatures[3] = vote.CommitSig() 787 788 err = valSet.VerifyCommitLight(chainID, blockID, h, commit) 789 assert.NoError(t, err) 790 } 791 792 func TestValidatorSet_VerifyCommitLightTrusting_ReturnsAsSoonAsTrustLevelOfVotingPowerSigned(t *testing.T) { 793 var ( 794 chainID = "test_chain_id" 795 h = int64(3) 796 blockID = makeBlockIDRandom() 797 ) 798 799 voteSet, valSet, vals := randVoteSet(h, 0, tmproto.PrecommitType, 4, 10) 800 commit, err := MakeCommit(blockID, h, 0, voteSet, vals, time.Now()) 801 require.NoError(t, err) 802 803 // malleate 3rd signature (2 signatures are enough for 1/3+ trust level) 804 vote := voteSet.GetByIndex(2) 805 v := vote.ToProto() 806 err = vals[2].SignVote("CentaurusA", v) 807 require.NoError(t, err) 808 vote.Signature = v.Signature 809 commit.Signatures[2] = vote.CommitSig() 810 811 err = valSet.VerifyCommitLightTrusting(chainID, commit, tmmath.Fraction{Numerator: 1, Denominator: 3}) 812 assert.NoError(t, err) 813 } 814 815 func TestEmptySet(t *testing.T) { 816 817 var valList []*Validator 818 valSet := NewValidatorSet(valList) 819 assert.Panics(t, func() { valSet.IncrementProposerPriority(1) }) 820 assert.Panics(t, func() { valSet.RescalePriorities(100) }) 821 assert.Panics(t, func() { valSet.shiftByAvgProposerPriority() }) 822 assert.Panics(t, func() { assert.Zero(t, computeMaxMinPriorityDiff(valSet)) }) 823 valSet.GetProposer() 824 825 // Add to empty set 826 v1 := newValidator([]byte("v1"), 100) 827 v2 := newValidator([]byte("v2"), 100) 828 valList = []*Validator{v1, v2} 829 assert.NoError(t, valSet.UpdateWithChangeSet(valList)) 830 verifyValidatorSet(t, valSet) 831 832 // Delete all validators from set 833 v1 = newValidator([]byte("v1"), 0) 834 v2 = newValidator([]byte("v2"), 0) 835 delList := []*Validator{v1, v2} 836 assert.Error(t, valSet.UpdateWithChangeSet(delList)) 837 838 // Attempt delete from empty set 839 assert.Error(t, valSet.UpdateWithChangeSet(delList)) 840 841 } 842 843 func TestUpdatesForNewValidatorSet(t *testing.T) { 844 845 v1 := newValidator([]byte("v1"), 100) 846 v2 := newValidator([]byte("v2"), 100) 847 valList := []*Validator{v1, v2} 848 valSet := NewValidatorSet(valList) 849 verifyValidatorSet(t, valSet) 850 851 // Verify duplicates are caught in NewValidatorSet() and it panics 852 v111 := newValidator([]byte("v1"), 100) 853 v112 := newValidator([]byte("v1"), 123) 854 v113 := newValidator([]byte("v1"), 234) 855 valList = []*Validator{v111, v112, v113} 856 assert.Panics(t, func() { NewValidatorSet(valList) }) 857 858 // Verify set including validator with voting power 0 cannot be created 859 v1 = newValidator([]byte("v1"), 0) 860 v2 = newValidator([]byte("v2"), 22) 861 v3 := newValidator([]byte("v3"), 33) 862 valList = []*Validator{v1, v2, v3} 863 assert.Panics(t, func() { NewValidatorSet(valList) }) 864 865 // Verify set including validator with negative voting power cannot be created 866 v1 = newValidator([]byte("v1"), 10) 867 v2 = newValidator([]byte("v2"), -20) 868 v3 = newValidator([]byte("v3"), 30) 869 valList = []*Validator{v1, v2, v3} 870 assert.Panics(t, func() { NewValidatorSet(valList) }) 871 872 } 873 874 type testVal struct { 875 name string 876 power int64 877 } 878 879 func permutation(valList []testVal) []testVal { 880 if len(valList) == 0 { 881 return nil 882 } 883 permList := make([]testVal, len(valList)) 884 perm := tmrand.Perm(len(valList)) 885 for i, v := range perm { 886 permList[v] = valList[i] 887 } 888 return permList 889 } 890 891 func createNewValidatorList(testValList []testVal) []*Validator { 892 valList := make([]*Validator, 0, len(testValList)) 893 for _, val := range testValList { 894 valList = append(valList, newValidator([]byte(val.name), val.power)) 895 } 896 return valList 897 } 898 899 func createNewValidatorSet(testValList []testVal) *ValidatorSet { 900 return NewValidatorSet(createNewValidatorList(testValList)) 901 } 902 903 func valSetTotalProposerPriority(valSet *ValidatorSet) int64 { 904 sum := int64(0) 905 for _, val := range valSet.Validators { 906 // mind overflow 907 sum = safeAddClip(sum, val.ProposerPriority) 908 } 909 return sum 910 } 911 912 func verifyValidatorSet(t *testing.T, valSet *ValidatorSet) { 913 // verify that the capacity and length of validators is the same 914 assert.Equal(t, len(valSet.Validators), cap(valSet.Validators)) 915 916 // verify that the set's total voting power has been updated 917 tvp := valSet.totalVotingPower 918 valSet.updateTotalVotingPower() 919 expectedTvp := valSet.TotalVotingPower() 920 assert.Equal(t, expectedTvp, tvp, 921 "expected TVP %d. Got %d, valSet=%s", expectedTvp, tvp, valSet) 922 923 // verify that validator priorities are centered 924 valsCount := int64(len(valSet.Validators)) 925 tpp := valSetTotalProposerPriority(valSet) 926 assert.True(t, tpp < valsCount && tpp > -valsCount, 927 "expected total priority in (-%d, %d). Got %d", valsCount, valsCount, tpp) 928 929 // verify that priorities are scaled 930 dist := computeMaxMinPriorityDiff(valSet) 931 assert.True(t, dist <= PriorityWindowSizeFactor*tvp, 932 "expected priority distance < %d. Got %d", PriorityWindowSizeFactor*tvp, dist) 933 } 934 935 func toTestValList(valList []*Validator) []testVal { 936 testList := make([]testVal, len(valList)) 937 for i, val := range valList { 938 testList[i].name = string(val.Address) 939 testList[i].power = val.VotingPower 940 } 941 return testList 942 } 943 944 func testValSet(nVals int, power int64) []testVal { 945 vals := make([]testVal, nVals) 946 for i := 0; i < nVals; i++ { 947 vals[i] = testVal{fmt.Sprintf("v%d", i+1), power} 948 } 949 return vals 950 } 951 952 type valSetErrTestCase struct { 953 startVals []testVal 954 updateVals []testVal 955 } 956 957 func executeValSetErrTestCase(t *testing.T, idx int, tt valSetErrTestCase) { 958 // create a new set and apply updates, keeping copies for the checks 959 valSet := createNewValidatorSet(tt.startVals) 960 valSetCopy := valSet.Copy() 961 valList := createNewValidatorList(tt.updateVals) 962 valListCopy := validatorListCopy(valList) 963 err := valSet.UpdateWithChangeSet(valList) 964 965 // for errors check the validator set has not been changed 966 assert.Error(t, err, "test %d", idx) 967 assert.Equal(t, valSet, valSetCopy, "test %v", idx) 968 969 // check the parameter list has not changed 970 assert.Equal(t, valList, valListCopy, "test %v", idx) 971 } 972 973 func TestValSetUpdatesDuplicateEntries(t *testing.T) { 974 testCases := []valSetErrTestCase{ 975 // Duplicate entries in changes 976 { // first entry is duplicated change 977 testValSet(2, 10), 978 []testVal{{"v1", 11}, {"v1", 22}}, 979 }, 980 { // second entry is duplicated change 981 testValSet(2, 10), 982 []testVal{{"v2", 11}, {"v2", 22}}, 983 }, 984 { // change duplicates are separated by a valid change 985 testValSet(2, 10), 986 []testVal{{"v1", 11}, {"v2", 22}, {"v1", 12}}, 987 }, 988 { // change duplicates are separated by a valid change 989 testValSet(3, 10), 990 []testVal{{"v1", 11}, {"v3", 22}, {"v1", 12}}, 991 }, 992 993 // Duplicate entries in remove 994 { // first entry is duplicated remove 995 testValSet(2, 10), 996 []testVal{{"v1", 0}, {"v1", 0}}, 997 }, 998 { // second entry is duplicated remove 999 testValSet(2, 10), 1000 []testVal{{"v2", 0}, {"v2", 0}}, 1001 }, 1002 { // remove duplicates are separated by a valid remove 1003 testValSet(2, 10), 1004 []testVal{{"v1", 0}, {"v2", 0}, {"v1", 0}}, 1005 }, 1006 { // remove duplicates are separated by a valid remove 1007 testValSet(3, 10), 1008 []testVal{{"v1", 0}, {"v3", 0}, {"v1", 0}}, 1009 }, 1010 1011 { // remove and update same val 1012 testValSet(2, 10), 1013 []testVal{{"v1", 0}, {"v2", 20}, {"v1", 30}}, 1014 }, 1015 { // duplicate entries in removes + changes 1016 testValSet(2, 10), 1017 []testVal{{"v1", 0}, {"v2", 20}, {"v2", 30}, {"v1", 0}}, 1018 }, 1019 { // duplicate entries in removes + changes 1020 testValSet(3, 10), 1021 []testVal{{"v1", 0}, {"v3", 5}, {"v2", 20}, {"v2", 30}, {"v1", 0}}, 1022 }, 1023 } 1024 1025 for i, tt := range testCases { 1026 executeValSetErrTestCase(t, i, tt) 1027 } 1028 } 1029 1030 func TestValSetUpdatesOverflows(t *testing.T) { 1031 maxVP := MaxTotalVotingPower 1032 testCases := []valSetErrTestCase{ 1033 { // single update leading to overflow 1034 testValSet(2, 10), 1035 []testVal{{"v1", math.MaxInt64}}, 1036 }, 1037 { // single update leading to overflow 1038 testValSet(2, 10), 1039 []testVal{{"v2", math.MaxInt64}}, 1040 }, 1041 { // add validator leading to overflow 1042 testValSet(1, maxVP), 1043 []testVal{{"v2", math.MaxInt64}}, 1044 }, 1045 { // add validator leading to exceed Max 1046 testValSet(1, maxVP-1), 1047 []testVal{{"v2", 5}}, 1048 }, 1049 { // add validator leading to exceed Max 1050 testValSet(2, maxVP/3), 1051 []testVal{{"v3", maxVP / 2}}, 1052 }, 1053 { // add validator leading to exceed Max 1054 testValSet(1, maxVP), 1055 []testVal{{"v2", maxVP}}, 1056 }, 1057 } 1058 1059 for i, tt := range testCases { 1060 executeValSetErrTestCase(t, i, tt) 1061 } 1062 } 1063 1064 func TestValSetUpdatesOtherErrors(t *testing.T) { 1065 testCases := []valSetErrTestCase{ 1066 { // update with negative voting power 1067 testValSet(2, 10), 1068 []testVal{{"v1", -123}}, 1069 }, 1070 { // update with negative voting power 1071 testValSet(2, 10), 1072 []testVal{{"v2", -123}}, 1073 }, 1074 { // remove non-existing validator 1075 testValSet(2, 10), 1076 []testVal{{"v3", 0}}, 1077 }, 1078 { // delete all validators 1079 []testVal{{"v1", 10}, {"v2", 20}, {"v3", 30}}, 1080 []testVal{{"v1", 0}, {"v2", 0}, {"v3", 0}}, 1081 }, 1082 } 1083 1084 for i, tt := range testCases { 1085 executeValSetErrTestCase(t, i, tt) 1086 } 1087 } 1088 1089 func TestValSetUpdatesBasicTestsExecute(t *testing.T) { 1090 valSetUpdatesBasicTests := []struct { 1091 startVals []testVal 1092 updateVals []testVal 1093 expectedVals []testVal 1094 }{ 1095 { // no changes 1096 testValSet(2, 10), 1097 []testVal{}, 1098 testValSet(2, 10), 1099 }, 1100 { // voting power changes 1101 testValSet(2, 10), 1102 []testVal{{"v2", 22}, {"v1", 11}}, 1103 []testVal{{"v2", 22}, {"v1", 11}}, 1104 }, 1105 { // add new validators 1106 []testVal{{"v2", 20}, {"v1", 10}}, 1107 []testVal{{"v4", 40}, {"v3", 30}}, 1108 []testVal{{"v4", 40}, {"v3", 30}, {"v2", 20}, {"v1", 10}}, 1109 }, 1110 { // add new validator to middle 1111 []testVal{{"v3", 20}, {"v1", 10}}, 1112 []testVal{{"v2", 30}}, 1113 []testVal{{"v2", 30}, {"v3", 20}, {"v1", 10}}, 1114 }, 1115 { // add new validator to beginning 1116 []testVal{{"v3", 20}, {"v2", 10}}, 1117 []testVal{{"v1", 30}}, 1118 []testVal{{"v1", 30}, {"v3", 20}, {"v2", 10}}, 1119 }, 1120 { // delete validators 1121 []testVal{{"v3", 30}, {"v2", 20}, {"v1", 10}}, 1122 []testVal{{"v2", 0}}, 1123 []testVal{{"v3", 30}, {"v1", 10}}, 1124 }, 1125 } 1126 1127 for i, tt := range valSetUpdatesBasicTests { 1128 // create a new set and apply updates, keeping copies for the checks 1129 valSet := createNewValidatorSet(tt.startVals) 1130 valList := createNewValidatorList(tt.updateVals) 1131 err := valSet.UpdateWithChangeSet(valList) 1132 assert.NoError(t, err, "test %d", i) 1133 1134 valListCopy := validatorListCopy(valSet.Validators) 1135 // check that the voting power in the set's validators is not changing if the voting power 1136 // is changed in the list of validators previously passed as parameter to UpdateWithChangeSet. 1137 // this is to make sure copies of the validators are made by UpdateWithChangeSet. 1138 if len(valList) > 0 { 1139 valList[0].VotingPower++ 1140 assert.Equal(t, toTestValList(valListCopy), toTestValList(valSet.Validators), "test %v", i) 1141 1142 } 1143 1144 // check the final validator list is as expected and the set is properly scaled and centered. 1145 assert.Equal(t, tt.expectedVals, toTestValList(valSet.Validators), "test %v", i) 1146 verifyValidatorSet(t, valSet) 1147 } 1148 } 1149 1150 // Test that different permutations of an update give the same result. 1151 func TestValSetUpdatesOrderIndependenceTestsExecute(t *testing.T) { 1152 // startVals - initial validators to create the set with 1153 // updateVals - a sequence of updates to be applied to the set. 1154 // updateVals is shuffled a number of times during testing to check for same resulting validator set. 1155 valSetUpdatesOrderTests := []struct { 1156 startVals []testVal 1157 updateVals []testVal 1158 }{ 1159 0: { // order of changes should not matter, the final validator sets should be the same 1160 []testVal{{"v4", 40}, {"v3", 30}, {"v2", 10}, {"v1", 10}}, 1161 []testVal{{"v4", 44}, {"v3", 33}, {"v2", 22}, {"v1", 11}}}, 1162 1163 1: { // order of additions should not matter 1164 []testVal{{"v2", 20}, {"v1", 10}}, 1165 []testVal{{"v3", 30}, {"v4", 40}, {"v5", 50}, {"v6", 60}}}, 1166 1167 2: { // order of removals should not matter 1168 []testVal{{"v4", 40}, {"v3", 30}, {"v2", 20}, {"v1", 10}}, 1169 []testVal{{"v1", 0}, {"v3", 0}, {"v4", 0}}}, 1170 1171 3: { // order of mixed operations should not matter 1172 []testVal{{"v4", 40}, {"v3", 30}, {"v2", 20}, {"v1", 10}}, 1173 []testVal{{"v1", 0}, {"v3", 0}, {"v2", 22}, {"v5", 50}, {"v4", 44}}}, 1174 } 1175 1176 for i, tt := range valSetUpdatesOrderTests { 1177 // create a new set and apply updates 1178 valSet := createNewValidatorSet(tt.startVals) 1179 valSetCopy := valSet.Copy() 1180 valList := createNewValidatorList(tt.updateVals) 1181 assert.NoError(t, valSetCopy.UpdateWithChangeSet(valList)) 1182 1183 // save the result as expected for next updates 1184 valSetExp := valSetCopy.Copy() 1185 1186 // perform at most 20 permutations on the updates and call UpdateWithChangeSet() 1187 n := len(tt.updateVals) 1188 maxNumPerms := tmmath.MinInt(20, n*n) 1189 for j := 0; j < maxNumPerms; j++ { 1190 // create a copy of original set and apply a random permutation of updates 1191 valSetCopy := valSet.Copy() 1192 valList := createNewValidatorList(permutation(tt.updateVals)) 1193 1194 // check there was no error and the set is properly scaled and centered. 1195 assert.NoError(t, valSetCopy.UpdateWithChangeSet(valList), 1196 "test %v failed for permutation %v", i, valList) 1197 verifyValidatorSet(t, valSetCopy) 1198 1199 // verify the resulting test is same as the expected 1200 assert.Equal(t, valSetCopy, valSetExp, 1201 "test %v failed for permutation %v", i, valList) 1202 } 1203 } 1204 } 1205 1206 // This tests the private function validator_set.go:applyUpdates() function, used only for additions and changes. 1207 // Should perform a proper merge of updatedVals and startVals 1208 func TestValSetApplyUpdatesTestsExecute(t *testing.T) { 1209 valSetUpdatesBasicTests := []struct { 1210 startVals []testVal 1211 updateVals []testVal 1212 expectedVals []testVal 1213 }{ 1214 // additions 1215 0: { // prepend 1216 []testVal{{"v4", 44}, {"v5", 55}}, 1217 []testVal{{"v1", 11}}, 1218 []testVal{{"v1", 11}, {"v4", 44}, {"v5", 55}}}, 1219 1: { // append 1220 []testVal{{"v4", 44}, {"v5", 55}}, 1221 []testVal{{"v6", 66}}, 1222 []testVal{{"v4", 44}, {"v5", 55}, {"v6", 66}}}, 1223 2: { // insert 1224 []testVal{{"v4", 44}, {"v6", 66}}, 1225 []testVal{{"v5", 55}}, 1226 []testVal{{"v4", 44}, {"v5", 55}, {"v6", 66}}}, 1227 3: { // insert multi 1228 []testVal{{"v4", 44}, {"v6", 66}, {"v9", 99}}, 1229 []testVal{{"v5", 55}, {"v7", 77}, {"v8", 88}}, 1230 []testVal{{"v4", 44}, {"v5", 55}, {"v6", 66}, {"v7", 77}, {"v8", 88}, {"v9", 99}}}, 1231 // changes 1232 4: { // head 1233 []testVal{{"v1", 111}, {"v2", 22}}, 1234 []testVal{{"v1", 11}}, 1235 []testVal{{"v1", 11}, {"v2", 22}}}, 1236 5: { // tail 1237 []testVal{{"v1", 11}, {"v2", 222}}, 1238 []testVal{{"v2", 22}}, 1239 []testVal{{"v1", 11}, {"v2", 22}}}, 1240 6: { // middle 1241 []testVal{{"v1", 11}, {"v2", 222}, {"v3", 33}}, 1242 []testVal{{"v2", 22}}, 1243 []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}}}, 1244 7: { // multi 1245 []testVal{{"v1", 111}, {"v2", 222}, {"v3", 333}}, 1246 []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}}, 1247 []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}}}, 1248 // additions and changes 1249 8: { 1250 []testVal{{"v1", 111}, {"v2", 22}}, 1251 []testVal{{"v1", 11}, {"v3", 33}, {"v4", 44}}, 1252 []testVal{{"v1", 11}, {"v2", 22}, {"v3", 33}, {"v4", 44}}}, 1253 } 1254 1255 for i, tt := range valSetUpdatesBasicTests { 1256 // create a new validator set with the start values 1257 valSet := createNewValidatorSet(tt.startVals) 1258 1259 // applyUpdates() with the update values 1260 valList := createNewValidatorList(tt.updateVals) 1261 valSet.applyUpdates(valList) 1262 1263 // check the new list of validators for proper merge 1264 assert.Equal(t, toTestValList(valSet.Validators), tt.expectedVals, "test %v", i) 1265 } 1266 } 1267 1268 type testVSetCfg struct { 1269 name string 1270 startVals []testVal 1271 deletedVals []testVal 1272 updatedVals []testVal 1273 addedVals []testVal 1274 expectedVals []testVal 1275 expErr error 1276 } 1277 1278 func randTestVSetCfg(t *testing.T, nBase, nAddMax int) testVSetCfg { 1279 if nBase <= 0 || nAddMax < 0 { 1280 panic(fmt.Sprintf("bad parameters %v %v", nBase, nAddMax)) 1281 } 1282 1283 const maxPower = 1000 1284 var nOld, nDel, nChanged, nAdd int 1285 1286 nOld = int(tmrand.Uint()%uint(nBase)) + 1 1287 if nBase-nOld > 0 { 1288 nDel = int(tmrand.Uint() % uint(nBase-nOld)) 1289 } 1290 nChanged = nBase - nOld - nDel 1291 1292 if nAddMax > 0 { 1293 nAdd = tmrand.Int()%nAddMax + 1 1294 } 1295 1296 cfg := testVSetCfg{} 1297 1298 cfg.startVals = make([]testVal, nBase) 1299 cfg.deletedVals = make([]testVal, nDel) 1300 cfg.addedVals = make([]testVal, nAdd) 1301 cfg.updatedVals = make([]testVal, nChanged) 1302 cfg.expectedVals = make([]testVal, nBase-nDel+nAdd) 1303 1304 for i := 0; i < nBase; i++ { 1305 cfg.startVals[i] = testVal{fmt.Sprintf("v%d", i), int64(tmrand.Uint()%maxPower + 1)} 1306 if i < nOld { 1307 cfg.expectedVals[i] = cfg.startVals[i] 1308 } 1309 if i >= nOld && i < nOld+nChanged { 1310 cfg.updatedVals[i-nOld] = testVal{fmt.Sprintf("v%d", i), int64(tmrand.Uint()%maxPower + 1)} 1311 cfg.expectedVals[i] = cfg.updatedVals[i-nOld] 1312 } 1313 if i >= nOld+nChanged { 1314 cfg.deletedVals[i-nOld-nChanged] = testVal{fmt.Sprintf("v%d", i), 0} 1315 } 1316 } 1317 1318 for i := nBase; i < nBase+nAdd; i++ { 1319 cfg.addedVals[i-nBase] = testVal{fmt.Sprintf("v%d", i), int64(tmrand.Uint()%maxPower + 1)} 1320 cfg.expectedVals[i-nDel] = cfg.addedVals[i-nBase] 1321 } 1322 1323 sort.Sort(testValsByVotingPower(cfg.startVals)) 1324 sort.Sort(testValsByVotingPower(cfg.deletedVals)) 1325 sort.Sort(testValsByVotingPower(cfg.updatedVals)) 1326 sort.Sort(testValsByVotingPower(cfg.addedVals)) 1327 sort.Sort(testValsByVotingPower(cfg.expectedVals)) 1328 1329 return cfg 1330 1331 } 1332 1333 func applyChangesToValSet(t *testing.T, expErr error, valSet *ValidatorSet, valsLists ...[]testVal) { 1334 changes := make([]testVal, 0) 1335 for _, valsList := range valsLists { 1336 changes = append(changes, valsList...) 1337 } 1338 valList := createNewValidatorList(changes) 1339 err := valSet.UpdateWithChangeSet(valList) 1340 if expErr != nil { 1341 assert.Equal(t, expErr, err) 1342 } else { 1343 assert.NoError(t, err) 1344 } 1345 } 1346 1347 func TestValSetUpdatePriorityOrderTests(t *testing.T) { 1348 const nMaxElections int32 = 5000 1349 1350 testCases := []testVSetCfg{ 1351 0: { // remove high power validator, keep old equal lower power validators 1352 startVals: []testVal{{"v3", 1000}, {"v1", 1}, {"v2", 1}}, 1353 deletedVals: []testVal{{"v3", 0}}, 1354 updatedVals: []testVal{}, 1355 addedVals: []testVal{}, 1356 expectedVals: []testVal{{"v1", 1}, {"v2", 1}}, 1357 }, 1358 1: { // remove high power validator, keep old different power validators 1359 startVals: []testVal{{"v3", 1000}, {"v2", 10}, {"v1", 1}}, 1360 deletedVals: []testVal{{"v3", 0}}, 1361 updatedVals: []testVal{}, 1362 addedVals: []testVal{}, 1363 expectedVals: []testVal{{"v2", 10}, {"v1", 1}}, 1364 }, 1365 2: { // remove high power validator, add new low power validators, keep old lower power 1366 startVals: []testVal{{"v3", 1000}, {"v2", 2}, {"v1", 1}}, 1367 deletedVals: []testVal{{"v3", 0}}, 1368 updatedVals: []testVal{{"v2", 1}}, 1369 addedVals: []testVal{{"v5", 50}, {"v4", 40}}, 1370 expectedVals: []testVal{{"v5", 50}, {"v4", 40}, {"v1", 1}, {"v2", 1}}, 1371 }, 1372 1373 // generate a configuration with 100 validators, 1374 // randomly select validators for updates and deletes, and 1375 // generate 10 new validators to be added 1376 3: randTestVSetCfg(t, 100, 10), 1377 1378 4: randTestVSetCfg(t, 1000, 100), 1379 1380 5: randTestVSetCfg(t, 10, 100), 1381 1382 6: randTestVSetCfg(t, 100, 1000), 1383 1384 7: randTestVSetCfg(t, 1000, 1000), 1385 } 1386 1387 for _, cfg := range testCases { 1388 1389 // create a new validator set 1390 valSet := createNewValidatorSet(cfg.startVals) 1391 verifyValidatorSet(t, valSet) 1392 1393 // run election up to nMaxElections times, apply changes and verify that the priority order is correct 1394 verifyValSetUpdatePriorityOrder(t, valSet, cfg, nMaxElections) 1395 } 1396 } 1397 1398 func verifyValSetUpdatePriorityOrder(t *testing.T, valSet *ValidatorSet, cfg testVSetCfg, nMaxElections int32) { 1399 // Run election up to nMaxElections times, sort validators by priorities 1400 valSet.IncrementProposerPriority(tmrand.Int31()%nMaxElections + 1) 1401 1402 // apply the changes, get the updated validators, sort by priorities 1403 applyChangesToValSet(t, nil, valSet, cfg.addedVals, cfg.updatedVals, cfg.deletedVals) 1404 1405 // basic checks 1406 assert.Equal(t, cfg.expectedVals, toTestValList(valSet.Validators)) 1407 verifyValidatorSet(t, valSet) 1408 1409 // verify that the added validators have the smallest priority: 1410 // - they should be at the beginning of updatedValsPriSorted since it is 1411 // sorted by priority 1412 if len(cfg.addedVals) > 0 { 1413 updatedValsPriSorted := validatorListCopy(valSet.Validators) 1414 sort.Sort(validatorsByPriority(updatedValsPriSorted)) 1415 1416 addedValsPriSlice := updatedValsPriSorted[:len(cfg.addedVals)] 1417 sort.Sort(ValidatorsByVotingPower(addedValsPriSlice)) 1418 assert.Equal(t, cfg.addedVals, toTestValList(addedValsPriSlice)) 1419 1420 // - and should all have the same priority 1421 expectedPri := addedValsPriSlice[0].ProposerPriority 1422 for _, val := range addedValsPriSlice[1:] { 1423 assert.Equal(t, expectedPri, val.ProposerPriority) 1424 } 1425 } 1426 } 1427 1428 func TestNewValidatorSetFromExistingValidators(t *testing.T) { 1429 size := 5 1430 vals := make([]*Validator, size) 1431 for i := 0; i < size; i++ { 1432 pv := NewMockPV() 1433 vals[i] = pv.ExtractIntoValidator(int64(i + 1)) 1434 } 1435 valSet := NewValidatorSet(vals) 1436 valSet.IncrementProposerPriority(5) 1437 1438 newValSet := NewValidatorSet(valSet.Validators) 1439 assert.NotEqual(t, valSet, newValSet) 1440 1441 existingValSet, err := ValidatorSetFromExistingValidators(valSet.Validators) 1442 assert.NoError(t, err) 1443 assert.Equal(t, valSet, existingValSet) 1444 assert.Equal(t, valSet.CopyIncrementProposerPriority(3), existingValSet.CopyIncrementProposerPriority(3)) 1445 } 1446 1447 func TestValSetUpdateOverflowRelated(t *testing.T) { 1448 testCases := []testVSetCfg{ 1449 { 1450 name: "1 no false overflow error messages for updates", 1451 startVals: []testVal{{"v2", MaxTotalVotingPower - 1}, {"v1", 1}}, 1452 updatedVals: []testVal{{"v1", MaxTotalVotingPower - 1}, {"v2", 1}}, 1453 expectedVals: []testVal{{"v1", MaxTotalVotingPower - 1}, {"v2", 1}}, 1454 expErr: nil, 1455 }, 1456 { 1457 // this test shows that it is important to apply the updates in the order of the change in power 1458 // i.e. apply first updates with decreases in power, v2 change in this case. 1459 name: "2 no false overflow error messages for updates", 1460 startVals: []testVal{{"v2", MaxTotalVotingPower - 1}, {"v1", 1}}, 1461 updatedVals: []testVal{{"v1", MaxTotalVotingPower/2 - 1}, {"v2", MaxTotalVotingPower / 2}}, 1462 expectedVals: []testVal{{"v2", MaxTotalVotingPower / 2}, {"v1", MaxTotalVotingPower/2 - 1}}, 1463 expErr: nil, 1464 }, 1465 { 1466 name: "3 no false overflow error messages for deletes", 1467 startVals: []testVal{{"v1", MaxTotalVotingPower - 2}, {"v2", 1}, {"v3", 1}}, 1468 deletedVals: []testVal{{"v1", 0}}, 1469 addedVals: []testVal{{"v4", MaxTotalVotingPower - 2}}, 1470 expectedVals: []testVal{{"v4", MaxTotalVotingPower - 2}, {"v2", 1}, {"v3", 1}}, 1471 expErr: nil, 1472 }, 1473 { 1474 name: "4 no false overflow error messages for adds, updates and deletes", 1475 startVals: []testVal{ 1476 {"v1", MaxTotalVotingPower / 4}, {"v2", MaxTotalVotingPower / 4}, 1477 {"v3", MaxTotalVotingPower / 4}, {"v4", MaxTotalVotingPower / 4}}, 1478 deletedVals: []testVal{{"v2", 0}}, 1479 updatedVals: []testVal{ 1480 {"v1", MaxTotalVotingPower/2 - 2}, {"v3", MaxTotalVotingPower/2 - 3}, {"v4", 2}}, 1481 addedVals: []testVal{{"v5", 3}}, 1482 expectedVals: []testVal{ 1483 {"v1", MaxTotalVotingPower/2 - 2}, {"v3", MaxTotalVotingPower/2 - 3}, {"v5", 3}, {"v4", 2}}, 1484 expErr: nil, 1485 }, 1486 { 1487 name: "5 check panic on overflow is prevented: update 8 validators with power int64(math.MaxInt64)/8", 1488 startVals: []testVal{ 1489 {"v1", 1}, {"v2", 1}, {"v3", 1}, {"v4", 1}, {"v5", 1}, 1490 {"v6", 1}, {"v7", 1}, {"v8", 1}, {"v9", 1}}, 1491 updatedVals: []testVal{ 1492 {"v1", MaxTotalVotingPower}, {"v2", MaxTotalVotingPower}, {"v3", MaxTotalVotingPower}, 1493 {"v4", MaxTotalVotingPower}, {"v5", MaxTotalVotingPower}, {"v6", MaxTotalVotingPower}, 1494 {"v7", MaxTotalVotingPower}, {"v8", MaxTotalVotingPower}, {"v9", 8}}, 1495 expectedVals: []testVal{ 1496 {"v1", 1}, {"v2", 1}, {"v3", 1}, {"v4", 1}, {"v5", 1}, 1497 {"v6", 1}, {"v7", 1}, {"v8", 1}, {"v9", 1}}, 1498 expErr: ErrTotalVotingPowerOverflow, 1499 }, 1500 } 1501 1502 for _, tt := range testCases { 1503 tt := tt 1504 t.Run(tt.name, func(t *testing.T) { 1505 valSet := createNewValidatorSet(tt.startVals) 1506 verifyValidatorSet(t, valSet) 1507 1508 // execute update and verify returned error is as expected 1509 applyChangesToValSet(t, tt.expErr, valSet, tt.addedVals, tt.updatedVals, tt.deletedVals) 1510 1511 // verify updated validator set is as expected 1512 assert.Equal(t, tt.expectedVals, toTestValList(valSet.Validators)) 1513 verifyValidatorSet(t, valSet) 1514 }) 1515 } 1516 } 1517 1518 func TestValidatorSet_VerifyCommitLightTrusting(t *testing.T) { 1519 var ( 1520 blockID = makeBlockIDRandom() 1521 voteSet, originalValset, vals = randVoteSet(1, 1, tmproto.PrecommitType, 6, 1) 1522 commit, err = MakeCommit(blockID, 1, 1, voteSet, vals, time.Now()) 1523 newValSet, _ = RandValidatorSet(2, 1) 1524 ) 1525 require.NoError(t, err) 1526 1527 testCases := []struct { 1528 valSet *ValidatorSet 1529 err bool 1530 }{ 1531 // good 1532 0: { 1533 valSet: originalValset, 1534 err: false, 1535 }, 1536 // bad - no overlap between validator sets 1537 1: { 1538 valSet: newValSet, 1539 err: true, 1540 }, 1541 // good - first two are different but the rest of the same -> >1/3 1542 2: { 1543 valSet: NewValidatorSet(append(newValSet.Validators, originalValset.Validators...)), 1544 err: false, 1545 }, 1546 } 1547 1548 for _, tc := range testCases { 1549 err = tc.valSet.VerifyCommitLightTrusting("test_chain_id", commit, 1550 tmmath.Fraction{Numerator: 1, Denominator: 3}) 1551 if tc.err { 1552 assert.Error(t, err) 1553 } else { 1554 assert.NoError(t, err) 1555 } 1556 } 1557 } 1558 1559 func TestValidatorSet_VerifyCommitLightTrustingErrorsOnOverflow(t *testing.T) { 1560 var ( 1561 blockID = makeBlockIDRandom() 1562 voteSet, valSet, vals = randVoteSet(1, 1, tmproto.PrecommitType, 1, MaxTotalVotingPower) 1563 commit, err = MakeCommit(blockID, 1, 1, voteSet, vals, time.Now()) 1564 ) 1565 require.NoError(t, err) 1566 1567 err = valSet.VerifyCommitLightTrusting("test_chain_id", commit, 1568 tmmath.Fraction{Numerator: 25, Denominator: 55}) 1569 if assert.Error(t, err) { 1570 assert.Contains(t, err.Error(), "int64 overflow") 1571 } 1572 } 1573 1574 func TestSafeMul(t *testing.T) { 1575 testCases := []struct { 1576 a int64 1577 b int64 1578 c int64 1579 overflow bool 1580 }{ 1581 0: {0, 0, 0, false}, 1582 1: {1, 0, 0, false}, 1583 2: {2, 3, 6, false}, 1584 3: {2, -3, -6, false}, 1585 4: {-2, -3, 6, false}, 1586 5: {-2, 3, -6, false}, 1587 6: {math.MaxInt64, 1, math.MaxInt64, false}, 1588 7: {math.MaxInt64 / 2, 2, math.MaxInt64 - 1, false}, 1589 8: {math.MaxInt64 / 2, 3, 0, true}, 1590 9: {math.MaxInt64, 2, 0, true}, 1591 } 1592 1593 for i, tc := range testCases { 1594 c, overflow := safeMul(tc.a, tc.b) 1595 assert.Equal(t, tc.c, c, "#%d", i) 1596 assert.Equal(t, tc.overflow, overflow, "#%d", i) 1597 } 1598 } 1599 1600 func TestValidatorSetProtoBuf(t *testing.T) { 1601 valset, _ := RandValidatorSet(10, 100) 1602 valset2, _ := RandValidatorSet(10, 100) 1603 valset2.Validators[0] = &Validator{} 1604 1605 valset3, _ := RandValidatorSet(10, 100) 1606 valset3.Proposer = nil 1607 1608 valset4, _ := RandValidatorSet(10, 100) 1609 valset4.Proposer = &Validator{} 1610 1611 testCases := []struct { 1612 msg string 1613 v1 *ValidatorSet 1614 expPass1 bool 1615 expPass2 bool 1616 }{ 1617 {"success", valset, true, true}, 1618 {"fail valSet2, pubkey empty", valset2, false, false}, 1619 {"fail nil Proposer", valset3, false, false}, 1620 {"fail empty Proposer", valset4, false, false}, 1621 {"fail empty valSet", &ValidatorSet{}, true, false}, 1622 {"false nil", nil, true, false}, 1623 } 1624 for _, tc := range testCases { 1625 protoValSet, err := tc.v1.ToProto() 1626 if tc.expPass1 { 1627 require.NoError(t, err, tc.msg) 1628 } else { 1629 require.Error(t, err, tc.msg) 1630 } 1631 1632 valSet, err := ValidatorSetFromProto(protoValSet) 1633 if tc.expPass2 { 1634 require.NoError(t, err, tc.msg) 1635 require.EqualValues(t, tc.v1, valSet, tc.msg) 1636 } else { 1637 require.Error(t, err, tc.msg) 1638 } 1639 } 1640 } 1641 1642 //--------------------- 1643 // Sort validators by priority and address 1644 type validatorsByPriority []*Validator 1645 1646 func (valz validatorsByPriority) Len() int { 1647 return len(valz) 1648 } 1649 1650 func (valz validatorsByPriority) Less(i, j int) bool { 1651 if valz[i].ProposerPriority < valz[j].ProposerPriority { 1652 return true 1653 } 1654 if valz[i].ProposerPriority > valz[j].ProposerPriority { 1655 return false 1656 } 1657 return bytes.Compare(valz[i].Address, valz[j].Address) < 0 1658 } 1659 1660 func (valz validatorsByPriority) Swap(i, j int) { 1661 valz[i], valz[j] = valz[j], valz[i] 1662 } 1663 1664 //------------------------------------- 1665 1666 type testValsByVotingPower []testVal 1667 1668 func (tvals testValsByVotingPower) Len() int { 1669 return len(tvals) 1670 } 1671 1672 func (tvals testValsByVotingPower) Less(i, j int) bool { 1673 if tvals[i].power == tvals[j].power { 1674 return bytes.Compare([]byte(tvals[i].name), []byte(tvals[j].name)) == -1 1675 } 1676 return tvals[i].power > tvals[j].power 1677 } 1678 1679 func (tvals testValsByVotingPower) Swap(i, j int) { 1680 tvals[i], tvals[j] = tvals[j], tvals[i] 1681 } 1682 1683 //------------------------------------- 1684 // Benchmark tests 1685 // 1686 func BenchmarkUpdates(b *testing.B) { 1687 const ( 1688 n = 100 1689 m = 2000 1690 ) 1691 // Init with n validators 1692 vs := make([]*Validator, n) 1693 for j := 0; j < n; j++ { 1694 vs[j] = newValidator([]byte(fmt.Sprintf("v%d", j)), 100) 1695 } 1696 valSet := NewValidatorSet(vs) 1697 l := len(valSet.Validators) 1698 1699 // Make m new validators 1700 newValList := make([]*Validator, m) 1701 for j := 0; j < m; j++ { 1702 newValList[j] = newValidator([]byte(fmt.Sprintf("v%d", j+l)), 1000) 1703 } 1704 b.ResetTimer() 1705 1706 for i := 0; i < b.N; i++ { 1707 // Add m validators to valSetCopy 1708 valSetCopy := valSet.Copy() 1709 assert.NoError(b, valSetCopy.UpdateWithChangeSet(newValList)) 1710 } 1711 }