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