github.com/pokt-network/tendermint@v0.32.11-0.20230426215212-59310158d3e9/state/store_test.go (about) 1 package state_test 2 3 import ( 4 "fmt" 5 "os" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 dbm "github.com/tendermint/tm-db" 12 13 cfg "github.com/tendermint/tendermint/config" 14 sm "github.com/tendermint/tendermint/state" 15 "github.com/tendermint/tendermint/types" 16 ) 17 18 func TestStoreLoadValidators(t *testing.T) { 19 stateDB := dbm.NewMemDB() 20 val, _ := types.RandValidator(true, 10) 21 vals := types.NewValidatorSet([]*types.Validator{val}) 22 23 // 1) LoadValidators loads validators using a height where they were last changed 24 sm.SaveValidatorsInfo(stateDB, 1, 1, vals) 25 sm.SaveValidatorsInfo(stateDB, 2, 1, vals) 26 loadedVals, err := sm.LoadValidators(stateDB, 2) 27 require.NoError(t, err) 28 assert.NotZero(t, loadedVals.Size()) 29 30 // 2) LoadValidators loads validators using a checkpoint height 31 32 sm.SaveValidatorsInfo(stateDB, sm.ValSetCheckpointInterval, 1, vals) 33 34 loadedVals, err = sm.LoadValidators(stateDB, sm.ValSetCheckpointInterval) 35 require.NoError(t, err) 36 assert.NotZero(t, loadedVals.Size()) 37 } 38 39 func BenchmarkLoadValidators(b *testing.B) { 40 const valSetSize = 100 41 42 config := cfg.ResetTestRoot("state_") 43 defer os.RemoveAll(config.RootDir) 44 dbType := dbm.BackendType(config.DBBackend) 45 stateDB := dbm.NewDB("state", dbType, config.DBDir()) 46 state, err := sm.LoadStateFromDBOrGenesisFile(stateDB, config.GenesisFile()) 47 if err != nil { 48 b.Fatal(err) 49 } 50 state.Validators = genValSet(valSetSize) 51 state.NextValidators = state.Validators.CopyIncrementProposerPriority(1) 52 sm.SaveState(stateDB, state) 53 54 for i := 10; i < 10000000000; i *= 10 { // 10, 100, 1000, ... 55 i := i 56 sm.SaveValidatorsInfo(stateDB, int64(i), state.LastHeightValidatorsChanged, state.NextValidators) 57 58 b.Run(fmt.Sprintf("height=%d", i), func(b *testing.B) { 59 for n := 0; n < b.N; n++ { 60 _, err := sm.LoadValidators(stateDB, int64(i)) 61 if err != nil { 62 b.Fatal(err) 63 } 64 } 65 }) 66 } 67 } 68 69 func TestPruneStates(t *testing.T) { 70 testcases := map[string]struct { 71 makeHeights int64 72 pruneFrom int64 73 pruneTo int64 74 expectErr bool 75 expectVals []int64 76 expectParams []int64 77 expectABCI []int64 78 }{ 79 "error on pruning from 0": {100, 0, 5, true, nil, nil, nil}, 80 "error when from > to": {100, 3, 2, true, nil, nil, nil}, 81 "error when from == to": {100, 3, 3, true, nil, nil, nil}, 82 "error when to does not exist": {100, 1, 101, true, nil, nil, nil}, 83 "prune all": {100, 1, 100, false, []int64{93, 100}, []int64{95, 100}, []int64{100}}, 84 "prune some": {10, 2, 8, false, []int64{1, 3, 8, 9, 10}, 85 []int64{1, 5, 8, 9, 10}, []int64{1, 8, 9, 10}}, 86 "prune across checkpoint": {100001, 1, 100001, false, []int64{99993, 100000, 100001}, 87 []int64{99995, 100001}, []int64{100001}}, 88 } 89 for name, tc := range testcases { 90 tc := tc 91 t.Run(name, func(t *testing.T) { 92 db := dbm.NewMemDB() 93 94 // Generate a bunch of state data. Validators change for heights ending with 3, and 95 // parameters when ending with 5. 96 validator := &types.Validator{Address: []byte{1, 2, 3}, VotingPower: 100} 97 validatorSet := &types.ValidatorSet{ 98 Validators: []*types.Validator{validator}, 99 Proposer: validator, 100 } 101 valsChanged := int64(0) 102 paramsChanged := int64(0) 103 104 for h := int64(1); h <= tc.makeHeights; h++ { 105 if valsChanged == 0 || h%10 == 2 { 106 valsChanged = h + 1 // Have to add 1, since NextValidators is what's stored 107 } 108 if paramsChanged == 0 || h%10 == 5 { 109 paramsChanged = h 110 } 111 112 sm.SaveState(db, sm.State{ 113 LastBlockHeight: h - 1, 114 Validators: validatorSet, 115 NextValidators: validatorSet, 116 ConsensusParams: types.ConsensusParams{ 117 Block: types.BlockParams{MaxBytes: 10e6}, 118 }, 119 LastHeightValidatorsChanged: valsChanged, 120 LastHeightConsensusParamsChanged: paramsChanged, 121 }) 122 sm.SaveABCIResponses(db, h, sm.NewABCIResponses(&types.Block{ 123 Header: types.Header{Height: h}, 124 Data: types.Data{ 125 Txs: types.Txs{ 126 []byte{1}, 127 []byte{2}, 128 []byte{3}, 129 }, 130 }, 131 })) 132 } 133 134 // Test assertions 135 err := sm.PruneStates(db, tc.pruneFrom, tc.pruneTo) 136 if tc.expectErr { 137 require.Error(t, err) 138 return 139 } 140 require.NoError(t, err) 141 142 expectVals := sliceToMap(tc.expectVals) 143 expectParams := sliceToMap(tc.expectParams) 144 expectABCI := sliceToMap(tc.expectABCI) 145 146 for h := int64(1); h <= tc.makeHeights; h++ { 147 vals, err := sm.LoadValidators(db, h) 148 if expectVals[h] { 149 require.NoError(t, err, "validators height %v", h) 150 require.NotNil(t, vals) 151 } else { 152 require.Error(t, err, "validators height %v", h) 153 require.Equal(t, sm.ErrNoValSetForHeight{Height: h}, err) 154 } 155 156 params, err := sm.LoadConsensusParams(db, h) 157 if expectParams[h] { 158 require.NoError(t, err, "params height %v", h) 159 require.False(t, params.Equals(&types.ConsensusParams{})) 160 } else { 161 require.Error(t, err, "params height %v", h) 162 require.Equal(t, sm.ErrNoConsensusParamsForHeight{Height: h}, err) 163 } 164 165 abci, err := sm.LoadABCIResponses(db, h) 166 if expectABCI[h] { 167 require.NoError(t, err, "abci height %v", h) 168 require.NotNil(t, abci) 169 } else { 170 require.Error(t, err, "abci height %v", h) 171 require.Equal(t, sm.ErrNoABCIResponsesForHeight{Height: h}, err) 172 } 173 } 174 }) 175 } 176 } 177 178 func sliceToMap(s []int64) map[int64]bool { 179 m := make(map[int64]bool, len(s)) 180 for _, i := range s { 181 m[i] = true 182 } 183 return m 184 }