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