github.com/badrootd/celestia-core@v0.0.0-20240305091328-aa4207a4b25d/state/state_test.go (about) 1 package state_test 2 3 import ( 4 "bytes" 5 "fmt" 6 "math" 7 "math/big" 8 "os" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 dbm "github.com/cometbft/cometbft-db" 15 16 abci "github.com/badrootd/celestia-core/abci/types" 17 cfg "github.com/badrootd/celestia-core/config" 18 "github.com/badrootd/celestia-core/crypto/ed25519" 19 cryptoenc "github.com/badrootd/celestia-core/crypto/encoding" 20 cmtrand "github.com/badrootd/celestia-core/libs/rand" 21 cmtstate "github.com/badrootd/celestia-core/proto/tendermint/state" 22 sm "github.com/badrootd/celestia-core/state" 23 "github.com/badrootd/celestia-core/types" 24 "github.com/badrootd/celestia-core/version" 25 ) 26 27 // setupTestCase does setup common to all test cases. 28 func setupTestCase(t *testing.T) (func(t *testing.T), dbm.DB, sm.State) { 29 config := cfg.ResetTestRoot("state_") 30 dbType := dbm.BackendType(config.DBBackend) 31 stateDB, err := dbm.NewDB("state", dbType, config.DBDir()) 32 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 33 DiscardABCIResponses: false, 34 }) 35 require.NoError(t, err) 36 state, err := stateStore.LoadFromDBOrGenesisFile(config.GenesisFile()) 37 assert.NoError(t, err, "expected no error on LoadStateFromDBOrGenesisFile") 38 err = stateStore.Save(state) 39 require.NoError(t, err) 40 41 tearDown := func(t *testing.T) { os.RemoveAll(config.RootDir) } 42 43 return tearDown, stateDB, state 44 } 45 46 // TestStateCopy tests the correct copying behaviour of State. 47 func TestStateCopy(t *testing.T) { 48 tearDown, _, state := setupTestCase(t) 49 defer tearDown(t) 50 assert := assert.New(t) 51 52 stateCopy := state.Copy() 53 54 assert.True(state.Equals(stateCopy), 55 fmt.Sprintf("expected state and its copy to be identical.\ngot: %v\nexpected: %v\n", 56 stateCopy, state)) 57 58 stateCopy.LastBlockHeight++ 59 stateCopy.LastValidators = state.Validators 60 assert.False(state.Equals(stateCopy), fmt.Sprintf(`expected states to be different. got same 61 %v`, state)) 62 } 63 64 // TestMakeGenesisStateNilValidators tests state's consistency when genesis file's validators field is nil. 65 func TestMakeGenesisStateNilValidators(t *testing.T) { 66 doc := types.GenesisDoc{ 67 ChainID: "dummy", 68 Validators: nil, 69 } 70 require.Nil(t, doc.ValidateAndComplete()) 71 state, err := sm.MakeGenesisState(&doc) 72 require.Nil(t, err) 73 require.Equal(t, 0, len(state.Validators.Validators)) 74 require.Equal(t, 0, len(state.NextValidators.Validators)) 75 } 76 77 func TestMakeGenesisStateSetsAppVersion(t *testing.T) { 78 cp := types.DefaultConsensusParams() 79 appVersion := uint64(5) 80 cp.Version.App = appVersion 81 doc := types.GenesisDoc{ 82 ChainID: "dummy", 83 ConsensusParams: cp, 84 } 85 require.Nil(t, doc.ValidateAndComplete()) 86 state, err := sm.MakeGenesisState(&doc) 87 require.Nil(t, err) 88 require.Equal(t, appVersion, state.Version.Consensus.App) 89 require.Equal(t, version.BlockProtocol, state.Version.Consensus.Block) 90 } 91 92 // TestStateSaveLoad tests saving and loading State from a db. 93 func TestStateSaveLoad(t *testing.T) { 94 tearDown, stateDB, state := setupTestCase(t) 95 defer tearDown(t) 96 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 97 DiscardABCIResponses: false, 98 }) 99 assert := assert.New(t) 100 101 state.LastBlockHeight++ 102 state.LastValidators = state.Validators 103 err := stateStore.Save(state) 104 require.NoError(t, err) 105 106 loadedState, err := stateStore.Load() 107 require.NoError(t, err) 108 assert.True(state.Equals(loadedState), 109 fmt.Sprintf("expected state and its copy to be identical.\ngot: %v\nexpected: %v\n", 110 loadedState, state)) 111 } 112 113 // TestABCIResponsesSaveLoad tests saving and loading ABCIResponses. 114 func TestABCIResponsesSaveLoad1(t *testing.T) { 115 tearDown, stateDB, state := setupTestCase(t) 116 defer tearDown(t) 117 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 118 DiscardABCIResponses: false, 119 }) 120 assert := assert.New(t) 121 122 state.LastBlockHeight++ 123 124 // Build mock responses. 125 block := makeBlock(state, 2) 126 127 abciResponses := new(cmtstate.ABCIResponses) 128 dtxs := make([]*abci.ResponseDeliverTx, 2) 129 abciResponses.DeliverTxs = dtxs 130 131 abciResponses.DeliverTxs[0] = &abci.ResponseDeliverTx{Data: []byte("foo"), Events: nil} 132 abciResponses.DeliverTxs[1] = &abci.ResponseDeliverTx{Data: []byte("bar"), Log: "ok", Events: nil} 133 abciResponses.EndBlock = &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{ 134 types.TM2PB.NewValidatorUpdate(ed25519.GenPrivKey().PubKey(), 10), 135 }} 136 137 err := stateStore.SaveABCIResponses(block.Height, abciResponses) 138 require.NoError(t, err) 139 loadedABCIResponses, err := stateStore.LoadABCIResponses(block.Height) 140 assert.Nil(err) 141 assert.Equal(abciResponses, loadedABCIResponses, 142 fmt.Sprintf("ABCIResponses don't match:\ngot: %v\nexpected: %v\n", 143 loadedABCIResponses, abciResponses)) 144 } 145 146 // TestResultsSaveLoad tests saving and loading ABCI results. 147 func TestABCIResponsesSaveLoad2(t *testing.T) { 148 tearDown, stateDB, _ := setupTestCase(t) 149 defer tearDown(t) 150 assert := assert.New(t) 151 152 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 153 DiscardABCIResponses: false, 154 }) 155 156 cases := [...]struct { 157 // Height is implied to equal index+2, 158 // as block 1 is created from genesis. 159 added []*abci.ResponseDeliverTx 160 expected []*abci.ResponseDeliverTx 161 }{ 162 0: { 163 nil, 164 nil, 165 }, 166 1: { 167 []*abci.ResponseDeliverTx{ 168 {Code: 32, Data: []byte("Hello"), Log: "Huh?"}, 169 }, 170 []*abci.ResponseDeliverTx{ 171 {Code: 32, Data: []byte("Hello")}, 172 }}, 173 2: { 174 []*abci.ResponseDeliverTx{ 175 {Code: 383}, 176 { 177 Data: []byte("Gotcha!"), 178 Events: []abci.Event{ 179 {Type: "type1", Attributes: []abci.EventAttribute{{Key: "a", Value: "1"}}}, 180 {Type: "type2", Attributes: []abci.EventAttribute{{Key: "build", Value: "stuff"}}}, 181 }, 182 }, 183 }, 184 []*abci.ResponseDeliverTx{ 185 {Code: 383, Data: nil}, 186 {Code: 0, Data: []byte("Gotcha!"), Events: []abci.Event{ 187 {Type: "type1", Attributes: []abci.EventAttribute{{Key: "a", Value: "1"}}}, 188 {Type: "type2", Attributes: []abci.EventAttribute{{Key: "build", Value: "stuff"}}}, 189 }}, 190 }}, 191 3: { 192 nil, 193 nil, 194 }, 195 4: { 196 []*abci.ResponseDeliverTx{nil}, 197 nil, 198 }, 199 } 200 201 // Query all before, this should return error. 202 for i := range cases { 203 h := int64(i + 1) 204 res, err := stateStore.LoadABCIResponses(h) 205 assert.Error(err, "%d: %#v", i, res) 206 } 207 208 // Add all cases. 209 for i, tc := range cases { 210 h := int64(i + 1) // last block height, one below what we save 211 responses := &cmtstate.ABCIResponses{ 212 BeginBlock: &abci.ResponseBeginBlock{}, 213 DeliverTxs: tc.added, 214 EndBlock: &abci.ResponseEndBlock{}, 215 } 216 err := stateStore.SaveABCIResponses(h, responses) 217 require.NoError(t, err) 218 } 219 220 // Query all before, should return expected value. 221 for i, tc := range cases { 222 h := int64(i + 1) 223 res, err := stateStore.LoadABCIResponses(h) 224 if assert.NoError(err, "%d", i) { 225 t.Log(res) 226 responses := &cmtstate.ABCIResponses{ 227 BeginBlock: &abci.ResponseBeginBlock{}, 228 DeliverTxs: tc.expected, 229 EndBlock: &abci.ResponseEndBlock{}, 230 } 231 assert.Equal(sm.ABCIResponsesResultsHash(responses), sm.ABCIResponsesResultsHash(res), "%d", i) 232 } 233 } 234 } 235 236 // TestValidatorSimpleSaveLoad tests saving and loading validators. 237 func TestValidatorSimpleSaveLoad(t *testing.T) { 238 tearDown, stateDB, state := setupTestCase(t) 239 defer tearDown(t) 240 assert := assert.New(t) 241 242 statestore := sm.NewStore(stateDB, sm.StoreOptions{ 243 DiscardABCIResponses: false, 244 }) 245 246 // Can't load anything for height 0. 247 _, err := statestore.LoadValidators(0) 248 assert.IsType(sm.ErrNoValSetForHeight{}, err, "expected err at height 0") 249 250 // Should be able to load for height 1. 251 v, err := statestore.LoadValidators(1) 252 assert.Nil(err, "expected no err at height 1") 253 assert.Equal(v.Hash(), state.Validators.Hash(), "expected validator hashes to match") 254 255 // Should be able to load for height 2. 256 v, err = statestore.LoadValidators(2) 257 assert.Nil(err, "expected no err at height 2") 258 assert.Equal(v.Hash(), state.NextValidators.Hash(), "expected validator hashes to match") 259 260 // Increment height, save; should be able to load for next & next next height. 261 state.LastBlockHeight++ 262 nextHeight := state.LastBlockHeight + 1 263 err = statestore.Save(state) 264 require.NoError(t, err) 265 vp0, err := statestore.LoadValidators(nextHeight + 0) 266 assert.Nil(err, "expected no err") 267 vp1, err := statestore.LoadValidators(nextHeight + 1) 268 assert.Nil(err, "expected no err") 269 assert.Equal(vp0.Hash(), state.Validators.Hash(), "expected validator hashes to match") 270 assert.Equal(vp1.Hash(), state.NextValidators.Hash(), "expected next validator hashes to match") 271 } 272 273 // TestValidatorChangesSaveLoad tests saving and loading a validator set with changes. 274 func TestOneValidatorChangesSaveLoad(t *testing.T) { 275 tearDown, stateDB, state := setupTestCase(t) 276 defer tearDown(t) 277 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 278 DiscardABCIResponses: false, 279 }) 280 281 // Change vals at these heights. 282 changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20} 283 N := len(changeHeights) 284 285 // Build the validator history by running updateState 286 // with the right validator set for each height. 287 highestHeight := changeHeights[N-1] + 5 288 changeIndex := 0 289 _, val := state.Validators.GetByIndex(0) 290 power := val.VotingPower 291 var err error 292 var validatorUpdates []*types.Validator 293 for i := int64(1); i < highestHeight; i++ { 294 // When we get to a change height, use the next pubkey. 295 if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] { 296 changeIndex++ 297 power++ 298 } 299 header, blockID, responses := makeHeaderPartsResponsesValPowerChange(state, power) 300 validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates) 301 require.NoError(t, err) 302 state, err = sm.UpdateState(state, blockID, &header, responses, validatorUpdates) 303 require.NoError(t, err) 304 err := stateStore.Save(state) 305 require.NoError(t, err) 306 } 307 308 // On each height change, increment the power by one. 309 testCases := make([]int64, highestHeight) 310 changeIndex = 0 311 power = val.VotingPower 312 for i := int64(1); i < highestHeight+1; i++ { 313 // We get to the height after a change height use the next pubkey (note 314 // our counter starts at 0 this time). 315 if changeIndex < len(changeHeights) && i == changeHeights[changeIndex]+1 { 316 changeIndex++ 317 power++ 318 } 319 testCases[i-1] = power 320 } 321 322 for i, power := range testCases { 323 v, err := stateStore.LoadValidators(int64(i + 1 + 1)) // +1 because vset changes delayed by 1 block. 324 assert.Nil(t, err, fmt.Sprintf("expected no err at height %d", i)) 325 assert.Equal(t, v.Size(), 1, "validator set size is greater than 1: %d", v.Size()) 326 _, val := v.GetByIndex(0) 327 328 assert.Equal(t, val.VotingPower, power, fmt.Sprintf(`unexpected powerat 329 height %d`, i)) 330 } 331 } 332 333 func TestProposerFrequency(t *testing.T) { 334 335 // some explicit test cases 336 testCases := []struct { 337 powers []int64 338 }{ 339 // 2 vals 340 {[]int64{1, 1}}, 341 {[]int64{1, 2}}, 342 {[]int64{1, 100}}, 343 {[]int64{5, 5}}, 344 {[]int64{5, 100}}, 345 {[]int64{50, 50}}, 346 {[]int64{50, 100}}, 347 {[]int64{1, 1000}}, 348 349 // 3 vals 350 {[]int64{1, 1, 1}}, 351 {[]int64{1, 2, 3}}, 352 {[]int64{1, 2, 3}}, 353 {[]int64{1, 1, 10}}, 354 {[]int64{1, 1, 100}}, 355 {[]int64{1, 10, 100}}, 356 {[]int64{1, 1, 1000}}, 357 {[]int64{1, 10, 1000}}, 358 {[]int64{1, 100, 1000}}, 359 360 // 4 vals 361 {[]int64{1, 1, 1, 1}}, 362 {[]int64{1, 2, 3, 4}}, 363 {[]int64{1, 1, 1, 10}}, 364 {[]int64{1, 1, 1, 100}}, 365 {[]int64{1, 1, 1, 1000}}, 366 {[]int64{1, 1, 10, 100}}, 367 {[]int64{1, 1, 10, 1000}}, 368 {[]int64{1, 1, 100, 1000}}, 369 {[]int64{1, 10, 100, 1000}}, 370 } 371 372 for caseNum, testCase := range testCases { 373 // run each case 5 times to sample different 374 // initial priorities 375 for i := 0; i < 5; i++ { 376 valSet := genValSetWithPowers(testCase.powers) 377 testProposerFreq(t, caseNum, valSet) 378 } 379 } 380 381 // some random test cases with up to 100 validators 382 maxVals := 100 383 maxPower := 1000 384 nTestCases := 5 385 for i := 0; i < nTestCases; i++ { 386 N := cmtrand.Int()%maxVals + 1 387 vals := make([]*types.Validator, N) 388 totalVotePower := int64(0) 389 for j := 0; j < N; j++ { 390 // make sure votePower > 0 391 votePower := int64(cmtrand.Int()%maxPower) + 1 392 totalVotePower += votePower 393 privVal := types.NewMockPV() 394 pubKey, err := privVal.GetPubKey() 395 require.NoError(t, err) 396 val := types.NewValidator(pubKey, votePower) 397 val.ProposerPriority = cmtrand.Int64() 398 vals[j] = val 399 } 400 valSet := types.NewValidatorSet(vals) 401 valSet.RescalePriorities(totalVotePower) 402 testProposerFreq(t, i, valSet) 403 } 404 } 405 406 // new val set with given powers and random initial priorities 407 func genValSetWithPowers(powers []int64) *types.ValidatorSet { 408 size := len(powers) 409 vals := make([]*types.Validator, size) 410 totalVotePower := int64(0) 411 for i := 0; i < size; i++ { 412 totalVotePower += powers[i] 413 val := types.NewValidator(ed25519.GenPrivKey().PubKey(), powers[i]) 414 val.ProposerPriority = cmtrand.Int64() 415 vals[i] = val 416 } 417 valSet := types.NewValidatorSet(vals) 418 valSet.RescalePriorities(totalVotePower) 419 return valSet 420 } 421 422 // test a proposer appears as frequently as expected 423 func testProposerFreq(t *testing.T, caseNum int, valSet *types.ValidatorSet) { 424 N := valSet.Size() 425 totalPower := valSet.TotalVotingPower() 426 427 // run the proposer selection and track frequencies 428 runMult := 1 429 runs := int(totalPower) * runMult 430 freqs := make([]int, N) 431 for i := 0; i < runs; i++ { 432 prop := valSet.GetProposer() 433 idx, _ := valSet.GetByAddress(prop.Address) 434 freqs[idx]++ 435 valSet.IncrementProposerPriority(1) 436 } 437 438 // assert frequencies match expected (max off by 1) 439 for i, freq := range freqs { 440 _, val := valSet.GetByIndex(int32(i)) 441 expectFreq := int(val.VotingPower) * runMult 442 gotFreq := freq 443 abs := int(math.Abs(float64(expectFreq - gotFreq))) 444 445 // max bound on expected vs seen freq was proven 446 // to be 1 for the 2 validator case in 447 // https://github.com/cwgoes/tm-proposer-idris 448 // and inferred to generalize to N-1 449 bound := N - 1 450 require.True( 451 t, 452 abs <= bound, 453 fmt.Sprintf("Case %d val %d (%d): got %d, expected %d", caseNum, i, N, gotFreq, expectFreq), 454 ) 455 } 456 } 457 458 // TestProposerPriorityDoesNotGetResetToZero assert that we preserve accum when calling updateState 459 // see https://github.com/cometbft/cometbft/issues/2718 460 func TestProposerPriorityDoesNotGetResetToZero(t *testing.T) { 461 tearDown, _, state := setupTestCase(t) 462 defer tearDown(t) 463 val1VotingPower := int64(10) 464 val1PubKey := ed25519.GenPrivKey().PubKey() 465 val1 := &types.Validator{Address: val1PubKey.Address(), PubKey: val1PubKey, VotingPower: val1VotingPower} 466 467 state.Validators = types.NewValidatorSet([]*types.Validator{val1}) 468 state.NextValidators = state.Validators 469 470 // NewValidatorSet calls IncrementProposerPriority but uses on a copy of val1 471 assert.EqualValues(t, 0, val1.ProposerPriority) 472 473 block := makeBlock(state, state.LastBlockHeight+1) 474 blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} 475 abciResponses := &cmtstate.ABCIResponses{ 476 BeginBlock: &abci.ResponseBeginBlock{}, 477 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 478 } 479 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 480 require.NoError(t, err) 481 updatedState, err := sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 482 assert.NoError(t, err) 483 curTotal := val1VotingPower 484 // one increment step and one validator: 0 + power - total_power == 0 485 assert.Equal(t, 0+val1VotingPower-curTotal, updatedState.NextValidators.Validators[0].ProposerPriority) 486 487 // add a validator 488 val2PubKey := ed25519.GenPrivKey().PubKey() 489 val2VotingPower := int64(100) 490 fvp, err := cryptoenc.PubKeyToProto(val2PubKey) 491 require.NoError(t, err) 492 493 updateAddVal := abci.ValidatorUpdate{PubKey: fvp, Power: val2VotingPower} 494 validatorUpdates, err = types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{updateAddVal}) 495 assert.NoError(t, err) 496 updatedState2, err := sm.UpdateState(updatedState, blockID, &block.Header, abciResponses, validatorUpdates) 497 assert.NoError(t, err) 498 499 require.Equal(t, len(updatedState2.NextValidators.Validators), 2) 500 _, updatedVal1 := updatedState2.NextValidators.GetByAddress(val1PubKey.Address()) 501 _, addedVal2 := updatedState2.NextValidators.GetByAddress(val2PubKey.Address()) 502 503 // adding a validator should not lead to a ProposerPriority equal to zero (unless the combination of averaging and 504 // incrementing would cause so; which is not the case here) 505 // Steps from adding new validator: 506 // 0 - val1 prio is 0, TVP after add: 507 wantVal1Prio := int64(0) 508 totalPowerAfter := val1VotingPower + val2VotingPower 509 // 1. Add - Val2 should be initially added with (-123) => 510 wantVal2Prio := -(totalPowerAfter + (totalPowerAfter >> 3)) 511 // 2. Scale - noop 512 // 3. Center - with avg, resulting val2:-61, val1:62 513 avg := big.NewInt(0).Add(big.NewInt(wantVal1Prio), big.NewInt(wantVal2Prio)) 514 avg.Div(avg, big.NewInt(2)) 515 wantVal2Prio -= avg.Int64() // -61 516 wantVal1Prio -= avg.Int64() // 62 517 518 // 4. Steps from IncrementProposerPriority 519 wantVal1Prio += val1VotingPower // 72 520 wantVal2Prio += val2VotingPower // 39 521 wantVal1Prio -= totalPowerAfter // -38 as val1 is proposer 522 523 assert.Equal(t, wantVal1Prio, updatedVal1.ProposerPriority) 524 assert.Equal(t, wantVal2Prio, addedVal2.ProposerPriority) 525 526 // Updating a validator does not reset the ProposerPriority to zero: 527 // 1. Add - Val2 VotingPower change to 1 => 528 updatedVotingPowVal2 := int64(1) 529 updateVal := abci.ValidatorUpdate{PubKey: fvp, Power: updatedVotingPowVal2} 530 validatorUpdates, err = types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{updateVal}) 531 assert.NoError(t, err) 532 533 // this will cause the diff of priorities (77) 534 // to be larger than threshold == 2*totalVotingPower (22): 535 updatedState3, err := sm.UpdateState(updatedState2, blockID, &block.Header, abciResponses, validatorUpdates) 536 assert.NoError(t, err) 537 538 require.Equal(t, len(updatedState3.NextValidators.Validators), 2) 539 _, prevVal1 := updatedState3.Validators.GetByAddress(val1PubKey.Address()) 540 _, prevVal2 := updatedState3.Validators.GetByAddress(val2PubKey.Address()) 541 _, updatedVal1 = updatedState3.NextValidators.GetByAddress(val1PubKey.Address()) 542 _, updatedVal2 := updatedState3.NextValidators.GetByAddress(val2PubKey.Address()) 543 544 // 2. Scale 545 // old prios: v1(10):-38, v2(1):39 546 wantVal1Prio = prevVal1.ProposerPriority 547 wantVal2Prio = prevVal2.ProposerPriority 548 // scale to diffMax = 22 = 2 * tvp, diff=39-(-38)=77 549 // new totalPower 550 totalPower := updatedVal1.VotingPower + updatedVal2.VotingPower 551 dist := wantVal2Prio - wantVal1Prio 552 // ratio := (dist + 2*totalPower - 1) / 2*totalPower = 98/22 = 4 553 ratio := (dist + 2*totalPower - 1) / (2 * totalPower) 554 // v1(10):-38/4, v2(1):39/4 555 wantVal1Prio /= ratio // -9 556 wantVal2Prio /= ratio // 9 557 558 // 3. Center - noop 559 // 4. IncrementProposerPriority() -> 560 // v1(10):-9+10, v2(1):9+1 -> v2 proposer so subsract tvp(11) 561 // v1(10):1, v2(1):-1 562 wantVal2Prio += updatedVal2.VotingPower // 10 -> prop 563 wantVal1Prio += updatedVal1.VotingPower // 1 564 wantVal2Prio -= totalPower // -1 565 566 assert.Equal(t, wantVal2Prio, updatedVal2.ProposerPriority) 567 assert.Equal(t, wantVal1Prio, updatedVal1.ProposerPriority) 568 } 569 570 func TestProposerPriorityProposerAlternates(t *testing.T) { 571 // Regression test that would fail if the inner workings of 572 // IncrementProposerPriority change. 573 // Additionally, make sure that same power validators alternate if both 574 // have the same voting power (and the 2nd was added later). 575 tearDown, _, state := setupTestCase(t) 576 defer tearDown(t) 577 val1VotingPower := int64(10) 578 val1PubKey := ed25519.GenPrivKey().PubKey() 579 val1 := &types.Validator{Address: val1PubKey.Address(), PubKey: val1PubKey, VotingPower: val1VotingPower} 580 581 // reset state validators to above validator 582 state.Validators = types.NewValidatorSet([]*types.Validator{val1}) 583 state.NextValidators = state.Validators 584 // we only have one validator: 585 assert.Equal(t, val1PubKey.Address(), state.Validators.Proposer.Address) 586 587 block := makeBlock(state, state.LastBlockHeight+1) 588 blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} 589 // no updates: 590 abciResponses := &cmtstate.ABCIResponses{ 591 BeginBlock: &abci.ResponseBeginBlock{}, 592 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 593 } 594 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 595 require.NoError(t, err) 596 597 updatedState, err := sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 598 assert.NoError(t, err) 599 600 // 0 + 10 (initial prio) - 10 (avg) - 10 (mostest - total) = -10 601 totalPower := val1VotingPower 602 wantVal1Prio := 0 + val1VotingPower - totalPower 603 assert.Equal(t, wantVal1Prio, updatedState.NextValidators.Validators[0].ProposerPriority) 604 assert.Equal(t, val1PubKey.Address(), updatedState.NextValidators.Proposer.Address) 605 606 // add a validator with the same voting power as the first 607 val2PubKey := ed25519.GenPrivKey().PubKey() 608 fvp, err := cryptoenc.PubKeyToProto(val2PubKey) 609 require.NoError(t, err) 610 updateAddVal := abci.ValidatorUpdate{PubKey: fvp, Power: val1VotingPower} 611 validatorUpdates, err = types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{updateAddVal}) 612 assert.NoError(t, err) 613 614 updatedState2, err := sm.UpdateState(updatedState, blockID, &block.Header, abciResponses, validatorUpdates) 615 assert.NoError(t, err) 616 617 require.Equal(t, len(updatedState2.NextValidators.Validators), 2) 618 assert.Equal(t, updatedState2.Validators, updatedState.NextValidators) 619 620 // val1 will still be proposer as val2 just got added: 621 assert.Equal(t, val1PubKey.Address(), updatedState.NextValidators.Proposer.Address) 622 assert.Equal(t, updatedState2.Validators.Proposer.Address, updatedState2.NextValidators.Proposer.Address) 623 assert.Equal(t, updatedState2.Validators.Proposer.Address, val1PubKey.Address()) 624 assert.Equal(t, updatedState2.NextValidators.Proposer.Address, val1PubKey.Address()) 625 626 _, updatedVal1 := updatedState2.NextValidators.GetByAddress(val1PubKey.Address()) 627 _, oldVal1 := updatedState2.Validators.GetByAddress(val1PubKey.Address()) 628 _, updatedVal2 := updatedState2.NextValidators.GetByAddress(val2PubKey.Address()) 629 630 // 1. Add 631 val2VotingPower := val1VotingPower 632 totalPower = val1VotingPower + val2VotingPower // 20 633 v2PrioWhenAddedVal2 := -(totalPower + (totalPower >> 3)) // -22 634 // 2. Scale - noop 635 // 3. Center 636 avgSum := big.NewInt(0).Add(big.NewInt(v2PrioWhenAddedVal2), big.NewInt(oldVal1.ProposerPriority)) 637 avg := avgSum.Div(avgSum, big.NewInt(2)) // -11 638 expectedVal2Prio := v2PrioWhenAddedVal2 - avg.Int64() // -11 639 expectedVal1Prio := oldVal1.ProposerPriority - avg.Int64() // 11 640 // 4. Increment 641 expectedVal2Prio += val2VotingPower // -11 + 10 = -1 642 expectedVal1Prio += val1VotingPower // 11 + 10 == 21 643 expectedVal1Prio -= totalPower // 1, val1 proposer 644 645 assert.EqualValues(t, expectedVal1Prio, updatedVal1.ProposerPriority) 646 assert.EqualValues( 647 t, 648 expectedVal2Prio, 649 updatedVal2.ProposerPriority, 650 "unexpected proposer priority for validator: %v", 651 updatedVal2, 652 ) 653 654 validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 655 require.NoError(t, err) 656 657 updatedState3, err := sm.UpdateState(updatedState2, blockID, &block.Header, abciResponses, validatorUpdates) 658 assert.NoError(t, err) 659 660 assert.Equal(t, updatedState3.Validators.Proposer.Address, updatedState3.NextValidators.Proposer.Address) 661 662 assert.Equal(t, updatedState3.Validators, updatedState2.NextValidators) 663 _, updatedVal1 = updatedState3.NextValidators.GetByAddress(val1PubKey.Address()) 664 _, updatedVal2 = updatedState3.NextValidators.GetByAddress(val2PubKey.Address()) 665 666 // val1 will still be proposer: 667 assert.Equal(t, val1PubKey.Address(), updatedState3.NextValidators.Proposer.Address) 668 669 // check if expected proposer prio is matched: 670 // Increment 671 expectedVal2Prio2 := expectedVal2Prio + val2VotingPower // -1 + 10 = 9 672 expectedVal1Prio2 := expectedVal1Prio + val1VotingPower // 1 + 10 == 11 673 expectedVal1Prio2 -= totalPower // -9, val1 proposer 674 675 assert.EqualValues( 676 t, 677 expectedVal1Prio2, 678 updatedVal1.ProposerPriority, 679 "unexpected proposer priority for validator: %v", 680 updatedVal2, 681 ) 682 assert.EqualValues( 683 t, 684 expectedVal2Prio2, 685 updatedVal2.ProposerPriority, 686 "unexpected proposer priority for validator: %v", 687 updatedVal2, 688 ) 689 690 // no changes in voting power and both validators have same voting power 691 // -> proposers should alternate: 692 oldState := updatedState3 693 abciResponses = &cmtstate.ABCIResponses{ 694 BeginBlock: &abci.ResponseBeginBlock{}, 695 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 696 } 697 validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 698 require.NoError(t, err) 699 700 oldState, err = sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) 701 assert.NoError(t, err) 702 expectedVal1Prio2 = 1 703 expectedVal2Prio2 = -1 704 expectedVal1Prio = -9 705 expectedVal2Prio = 9 706 707 for i := 0; i < 1000; i++ { 708 // no validator updates: 709 abciResponses := &cmtstate.ABCIResponses{ 710 BeginBlock: &abci.ResponseBeginBlock{}, 711 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 712 } 713 validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 714 require.NoError(t, err) 715 716 updatedState, err := sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) 717 assert.NoError(t, err) 718 // alternate (and cyclic priorities): 719 assert.NotEqual( 720 t, 721 updatedState.Validators.Proposer.Address, 722 updatedState.NextValidators.Proposer.Address, 723 "iter: %v", 724 i, 725 ) 726 assert.Equal(t, oldState.Validators.Proposer.Address, updatedState.NextValidators.Proposer.Address, "iter: %v", i) 727 728 _, updatedVal1 = updatedState.NextValidators.GetByAddress(val1PubKey.Address()) 729 _, updatedVal2 = updatedState.NextValidators.GetByAddress(val2PubKey.Address()) 730 731 if i%2 == 0 { 732 assert.Equal(t, updatedState.Validators.Proposer.Address, val2PubKey.Address()) 733 assert.Equal(t, expectedVal1Prio, updatedVal1.ProposerPriority) // -19 734 assert.Equal(t, expectedVal2Prio, updatedVal2.ProposerPriority) // 0 735 } else { 736 assert.Equal(t, updatedState.Validators.Proposer.Address, val1PubKey.Address()) 737 assert.Equal(t, expectedVal1Prio2, updatedVal1.ProposerPriority) // -9 738 assert.Equal(t, expectedVal2Prio2, updatedVal2.ProposerPriority) // -10 739 } 740 // update for next iteration: 741 oldState = updatedState 742 } 743 } 744 745 func TestLargeGenesisValidator(t *testing.T) { 746 tearDown, _, state := setupTestCase(t) 747 defer tearDown(t) 748 749 genesisVotingPower := types.MaxTotalVotingPower / 1000 750 genesisPubKey := ed25519.GenPrivKey().PubKey() 751 // fmt.Println("genesis addr: ", genesisPubKey.Address()) 752 genesisVal := &types.Validator{ 753 Address: genesisPubKey.Address(), 754 PubKey: genesisPubKey, 755 VotingPower: genesisVotingPower, 756 } 757 // reset state validators to above validator 758 state.Validators = types.NewValidatorSet([]*types.Validator{genesisVal}) 759 state.NextValidators = state.Validators 760 require.True(t, len(state.Validators.Validators) == 1) 761 762 // update state a few times with no validator updates 763 // asserts that the single validator's ProposerPrio stays the same 764 oldState := state 765 for i := 0; i < 10; i++ { 766 // no updates: 767 abciResponses := &cmtstate.ABCIResponses{ 768 BeginBlock: &abci.ResponseBeginBlock{}, 769 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 770 } 771 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 772 require.NoError(t, err) 773 774 block := makeBlock(oldState, oldState.LastBlockHeight+1) 775 blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} 776 777 updatedState, err := sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) 778 require.NoError(t, err) 779 // no changes in voting power (ProposerPrio += VotingPower == Voting in 1st round; than shiftByAvg == 0, 780 // than -Total == -Voting) 781 // -> no change in ProposerPrio (stays zero): 782 assert.EqualValues(t, oldState.NextValidators, updatedState.NextValidators) 783 assert.EqualValues(t, 0, updatedState.NextValidators.Proposer.ProposerPriority) 784 785 oldState = updatedState 786 } 787 // add another validator, do a few iterations (create blocks), 788 // add more validators with same voting power as the 2nd 789 // let the genesis validator "unbond", 790 // see how long it takes until the effect wears off and both begin to alternate 791 // see: https://github.com/cometbft/cometbft/issues/2960 792 firstAddedValPubKey := ed25519.GenPrivKey().PubKey() 793 firstAddedValVotingPower := int64(10) 794 fvp, err := cryptoenc.PubKeyToProto(firstAddedValPubKey) 795 require.NoError(t, err) 796 firstAddedVal := abci.ValidatorUpdate{PubKey: fvp, Power: firstAddedValVotingPower} 797 validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{firstAddedVal}) 798 assert.NoError(t, err) 799 abciResponses := &cmtstate.ABCIResponses{ 800 BeginBlock: &abci.ResponseBeginBlock{}, 801 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{firstAddedVal}}, 802 } 803 block := makeBlock(oldState, oldState.LastBlockHeight+1) 804 blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} 805 updatedState, err := sm.UpdateState(oldState, blockID, &block.Header, abciResponses, validatorUpdates) 806 require.NoError(t, err) 807 808 lastState := updatedState 809 for i := 0; i < 200; i++ { 810 // no updates: 811 abciResponses := &cmtstate.ABCIResponses{ 812 BeginBlock: &abci.ResponseBeginBlock{}, 813 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 814 } 815 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 816 require.NoError(t, err) 817 818 block := makeBlock(lastState, lastState.LastBlockHeight+1) 819 blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} 820 821 updatedStateInner, err := sm.UpdateState(lastState, blockID, &block.Header, abciResponses, validatorUpdates) 822 require.NoError(t, err) 823 lastState = updatedStateInner 824 } 825 // set state to last state of above iteration 826 state = lastState 827 828 // set oldState to state before above iteration 829 oldState = updatedState 830 _, oldGenesisVal := oldState.NextValidators.GetByAddress(genesisVal.Address) 831 _, newGenesisVal := state.NextValidators.GetByAddress(genesisVal.Address) 832 _, addedOldVal := oldState.NextValidators.GetByAddress(firstAddedValPubKey.Address()) 833 _, addedNewVal := state.NextValidators.GetByAddress(firstAddedValPubKey.Address()) 834 // expect large negative proposer priority for both (genesis validator decreased, 2nd validator increased): 835 assert.True(t, oldGenesisVal.ProposerPriority > newGenesisVal.ProposerPriority) 836 assert.True(t, addedOldVal.ProposerPriority < addedNewVal.ProposerPriority) 837 838 // add 10 validators with the same voting power as the one added directly after genesis: 839 for i := 0; i < 10; i++ { 840 addedPubKey := ed25519.GenPrivKey().PubKey() 841 ap, err := cryptoenc.PubKeyToProto(addedPubKey) 842 require.NoError(t, err) 843 addedVal := abci.ValidatorUpdate{PubKey: ap, Power: firstAddedValVotingPower} 844 validatorUpdates, err := types.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{addedVal}) 845 assert.NoError(t, err) 846 847 abciResponses := &cmtstate.ABCIResponses{ 848 BeginBlock: &abci.ResponseBeginBlock{}, 849 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{addedVal}}, 850 } 851 block := makeBlock(oldState, oldState.LastBlockHeight+1) 852 blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} 853 state, err = sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 854 require.NoError(t, err) 855 } 856 require.Equal(t, 10+2, len(state.NextValidators.Validators)) 857 858 // remove genesis validator: 859 gp, err := cryptoenc.PubKeyToProto(genesisPubKey) 860 require.NoError(t, err) 861 removeGenesisVal := abci.ValidatorUpdate{PubKey: gp, Power: 0} 862 abciResponses = &cmtstate.ABCIResponses{ 863 BeginBlock: &abci.ResponseBeginBlock{}, 864 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: []abci.ValidatorUpdate{removeGenesisVal}}, 865 } 866 block = makeBlock(oldState, oldState.LastBlockHeight+1) 867 blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} 868 validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 869 require.NoError(t, err) 870 updatedState, err = sm.UpdateState(state, blockID, &block.Header, abciResponses, validatorUpdates) 871 require.NoError(t, err) 872 // only the first added val (not the genesis val) should be left 873 assert.Equal(t, 11, len(updatedState.NextValidators.Validators)) 874 875 // call update state until the effect for the 3rd added validator 876 // being proposer for a long time after the genesis validator left wears off: 877 curState := updatedState 878 count := 0 879 isProposerUnchanged := true 880 for isProposerUnchanged { 881 abciResponses := &cmtstate.ABCIResponses{ 882 BeginBlock: &abci.ResponseBeginBlock{}, 883 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 884 } 885 validatorUpdates, err = types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 886 require.NoError(t, err) 887 block = makeBlock(curState, curState.LastBlockHeight+1) 888 blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} 889 curState, err = sm.UpdateState(curState, blockID, &block.Header, abciResponses, validatorUpdates) 890 require.NoError(t, err) 891 if !bytes.Equal(curState.Validators.Proposer.Address, curState.NextValidators.Proposer.Address) { 892 isProposerUnchanged = false 893 } 894 count++ 895 } 896 updatedState = curState 897 // the proposer changes after this number of blocks 898 firstProposerChangeExpectedAfter := 1 899 assert.Equal(t, firstProposerChangeExpectedAfter, count) 900 // store proposers here to see if we see them again in the same order: 901 numVals := len(updatedState.Validators.Validators) 902 proposers := make([]*types.Validator, numVals) 903 for i := 0; i < 100; i++ { 904 // no updates: 905 abciResponses := &cmtstate.ABCIResponses{ 906 BeginBlock: &abci.ResponseBeginBlock{}, 907 EndBlock: &abci.ResponseEndBlock{ValidatorUpdates: nil}, 908 } 909 validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponses.EndBlock.ValidatorUpdates) 910 require.NoError(t, err) 911 912 block := makeBlock(updatedState, updatedState.LastBlockHeight+1) 913 blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: block.MakePartSet(testPartSize).Header()} 914 915 updatedState, err = sm.UpdateState(updatedState, blockID, &block.Header, abciResponses, validatorUpdates) 916 require.NoError(t, err) 917 if i > numVals { // expect proposers to cycle through after the first iteration (of numVals blocks): 918 if proposers[i%numVals] == nil { 919 proposers[i%numVals] = updatedState.NextValidators.Proposer 920 } else { 921 assert.Equal(t, proposers[i%numVals], updatedState.NextValidators.Proposer) 922 } 923 } 924 } 925 } 926 927 func TestStoreLoadValidatorsIncrementsProposerPriority(t *testing.T) { 928 const valSetSize = 2 929 tearDown, stateDB, state := setupTestCase(t) 930 t.Cleanup(func() { tearDown(t) }) 931 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 932 DiscardABCIResponses: false, 933 }) 934 state.Validators = genValSet(valSetSize) 935 state.NextValidators = state.Validators.CopyIncrementProposerPriority(1) 936 err := stateStore.Save(state) 937 require.NoError(t, err) 938 939 nextHeight := state.LastBlockHeight + 1 940 941 v0, err := stateStore.LoadValidators(nextHeight) 942 assert.Nil(t, err) 943 acc0 := v0.Validators[0].ProposerPriority 944 945 v1, err := stateStore.LoadValidators(nextHeight + 1) 946 assert.Nil(t, err) 947 acc1 := v1.Validators[0].ProposerPriority 948 949 assert.NotEqual(t, acc1, acc0, "expected ProposerPriority value to change between heights") 950 } 951 952 // TestValidatorChangesSaveLoad tests saving and loading a validator set with 953 // changes. 954 func TestManyValidatorChangesSaveLoad(t *testing.T) { 955 const valSetSize = 7 956 tearDown, stateDB, state := setupTestCase(t) 957 defer tearDown(t) 958 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 959 DiscardABCIResponses: false, 960 }) 961 require.Equal(t, int64(0), state.LastBlockHeight) 962 state.Validators = genValSet(valSetSize) 963 state.NextValidators = state.Validators.CopyIncrementProposerPriority(1) 964 err := stateStore.Save(state) 965 require.NoError(t, err) 966 967 _, valOld := state.Validators.GetByIndex(0) 968 var pubkeyOld = valOld.PubKey 969 pubkey := ed25519.GenPrivKey().PubKey() 970 971 // Swap the first validator with a new one (validator set size stays the same). 972 header, blockID, responses := makeHeaderPartsResponsesValPubKeyChange(state, pubkey) 973 974 // Save state etc. 975 var validatorUpdates []*types.Validator 976 validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates) 977 require.NoError(t, err) 978 state, err = sm.UpdateState(state, blockID, &header, responses, validatorUpdates) 979 require.Nil(t, err) 980 nextHeight := state.LastBlockHeight + 1 981 err = stateStore.Save(state) 982 require.NoError(t, err) 983 984 // Load nextheight, it should be the oldpubkey. 985 v0, err := stateStore.LoadValidators(nextHeight) 986 assert.Nil(t, err) 987 assert.Equal(t, valSetSize, v0.Size()) 988 index, val := v0.GetByAddress(pubkeyOld.Address()) 989 assert.NotNil(t, val) 990 if index < 0 { 991 t.Fatal("expected to find old validator") 992 } 993 994 // Load nextheight+1, it should be the new pubkey. 995 v1, err := stateStore.LoadValidators(nextHeight + 1) 996 assert.Nil(t, err) 997 assert.Equal(t, valSetSize, v1.Size()) 998 index, val = v1.GetByAddress(pubkey.Address()) 999 assert.NotNil(t, val) 1000 if index < 0 { 1001 t.Fatal("expected to find newly added validator") 1002 } 1003 } 1004 1005 func TestStateMakeBlock(t *testing.T) { 1006 tearDown, _, state := setupTestCase(t) 1007 defer tearDown(t) 1008 1009 proposerAddress := state.Validators.GetProposer().Address 1010 stateVersion := state.Version.Consensus 1011 block := makeBlock(state, 2) 1012 1013 // test we set some fields 1014 assert.Equal(t, stateVersion, block.Version) 1015 assert.Equal(t, proposerAddress, block.ProposerAddress) 1016 } 1017 1018 // TestConsensusParamsChangesSaveLoad tests saving and loading consensus params 1019 // with changes. 1020 func TestConsensusParamsChangesSaveLoad(t *testing.T) { 1021 tearDown, stateDB, state := setupTestCase(t) 1022 defer tearDown(t) 1023 1024 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 1025 DiscardABCIResponses: false, 1026 }) 1027 1028 // Change vals at these heights. 1029 changeHeights := []int64{1, 2, 4, 5, 10, 15, 16, 17, 20} 1030 N := len(changeHeights) 1031 1032 // Each valset is just one validator. 1033 // create list of them. 1034 params := make([]types.ConsensusParams, N+1) 1035 params[0] = state.ConsensusParams 1036 for i := 1; i < N+1; i++ { 1037 params[i] = *types.DefaultConsensusParams() 1038 params[i].Block.MaxBytes += int64(i) 1039 1040 } 1041 1042 // Build the params history by running updateState 1043 // with the right params set for each height. 1044 highestHeight := changeHeights[N-1] + 5 1045 changeIndex := 0 1046 cp := params[changeIndex] 1047 var err error 1048 var validatorUpdates []*types.Validator 1049 for i := int64(1); i < highestHeight; i++ { 1050 // When we get to a change height, use the next params. 1051 if changeIndex < len(changeHeights) && i == changeHeights[changeIndex] { 1052 changeIndex++ 1053 cp = params[changeIndex] 1054 } 1055 header, blockID, responses := makeHeaderPartsResponsesParams(state, cp.ToProto()) 1056 validatorUpdates, err = types.PB2TM.ValidatorUpdates(responses.EndBlock.ValidatorUpdates) 1057 require.NoError(t, err) 1058 state, err = sm.UpdateState(state, blockID, &header, responses, validatorUpdates) 1059 1060 require.Nil(t, err) 1061 err := stateStore.Save(state) 1062 require.NoError(t, err) 1063 } 1064 1065 // Make all the test cases by using the same params until after the change. 1066 testCases := make([]paramsChangeTestCase, highestHeight) 1067 changeIndex = 0 1068 cp = params[changeIndex] 1069 for i := int64(1); i < highestHeight+1; i++ { 1070 // We get to the height after a change height use the next pubkey (note 1071 // our counter starts at 0 this time). 1072 if changeIndex < len(changeHeights) && i == changeHeights[changeIndex]+1 { 1073 changeIndex++ 1074 cp = params[changeIndex] 1075 } 1076 testCases[i-1] = paramsChangeTestCase{i, cp} 1077 } 1078 1079 for _, testCase := range testCases { 1080 p, err := stateStore.LoadConsensusParams(testCase.height) 1081 assert.Nil(t, err, fmt.Sprintf("expected no err at height %d", testCase.height)) 1082 assert.EqualValues(t, testCase.params, p, fmt.Sprintf(`unexpected consensus params at 1083 height %d`, testCase.height)) 1084 } 1085 } 1086 1087 func TestStateProto(t *testing.T) { 1088 tearDown, _, state := setupTestCase(t) 1089 defer tearDown(t) 1090 1091 tc := []struct { 1092 testName string 1093 state *sm.State 1094 expPass1 bool 1095 expPass2 bool 1096 }{ 1097 {"empty state", &sm.State{}, true, false}, 1098 {"nil failure state", nil, false, false}, 1099 {"success state", &state, true, true}, 1100 } 1101 1102 for _, tt := range tc { 1103 tt := tt 1104 pbs, err := tt.state.ToProto() 1105 if !tt.expPass1 { 1106 assert.Error(t, err) 1107 } else { 1108 assert.NoError(t, err, tt.testName) 1109 } 1110 1111 smt, err := sm.FromProto(pbs) 1112 if tt.expPass2 { 1113 require.NoError(t, err, tt.testName) 1114 require.Equal(t, tt.state, smt, tt.testName) 1115 } else { 1116 require.Error(t, err, tt.testName) 1117 } 1118 } 1119 }