github.com/Oyster-zx/tendermint@v0.34.24-fork/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 abci "github.com/tendermint/tendermint/abci/types" 14 cfg "github.com/tendermint/tendermint/config" 15 "github.com/tendermint/tendermint/crypto" 16 "github.com/tendermint/tendermint/crypto/ed25519" 17 tmrand "github.com/tendermint/tendermint/libs/rand" 18 tmstate "github.com/tendermint/tendermint/proto/tendermint/state" 19 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 20 sm "github.com/tendermint/tendermint/state" 21 "github.com/tendermint/tendermint/types" 22 ) 23 24 func TestStoreLoadValidators(t *testing.T) { 25 stateDB := dbm.NewMemDB() 26 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 27 DiscardABCIResponses: false, 28 }) 29 val, _ := types.RandValidator(true, 10) 30 vals := types.NewValidatorSet([]*types.Validator{val}) 31 32 // 1) LoadValidators loads validators using a height where they were last changed 33 err := sm.SaveValidatorsInfo(stateDB, 1, 1, vals) 34 require.NoError(t, err) 35 err = sm.SaveValidatorsInfo(stateDB, 2, 1, vals) 36 require.NoError(t, err) 37 loadedVals, err := stateStore.LoadValidators(2) 38 require.NoError(t, err) 39 assert.NotZero(t, loadedVals.Size()) 40 41 // 2) LoadValidators loads validators using a checkpoint height 42 43 err = sm.SaveValidatorsInfo(stateDB, sm.ValSetCheckpointInterval, 1, vals) 44 require.NoError(t, err) 45 46 loadedVals, err = stateStore.LoadValidators(sm.ValSetCheckpointInterval) 47 require.NoError(t, err) 48 assert.NotZero(t, loadedVals.Size()) 49 } 50 51 func BenchmarkLoadValidators(b *testing.B) { 52 const valSetSize = 100 53 54 config := cfg.ResetTestRoot("state_") 55 defer os.RemoveAll(config.RootDir) 56 dbType := dbm.BackendType(config.DBBackend) 57 stateDB, err := dbm.NewDB("state", dbType, config.DBDir()) 58 require.NoError(b, err) 59 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 60 DiscardABCIResponses: false, 61 }) 62 state, err := stateStore.LoadFromDBOrGenesisFile(config.GenesisFile()) 63 if err != nil { 64 b.Fatal(err) 65 } 66 67 state.Validators = genValSet(valSetSize) 68 state.NextValidators = state.Validators.CopyIncrementProposerPriority(1) 69 err = stateStore.Save(state) 70 require.NoError(b, err) 71 72 for i := 10; i < 10000000000; i *= 10 { // 10, 100, 1000, ... 73 i := i 74 if err := sm.SaveValidatorsInfo(stateDB, 75 int64(i), state.LastHeightValidatorsChanged, state.NextValidators); err != nil { 76 b.Fatal(err) 77 } 78 79 b.Run(fmt.Sprintf("height=%d", i), func(b *testing.B) { 80 for n := 0; n < b.N; n++ { 81 _, err := stateStore.LoadValidators(int64(i)) 82 if err != nil { 83 b.Fatal(err) 84 } 85 } 86 }) 87 } 88 } 89 90 func TestPruneStates(t *testing.T) { 91 testcases := map[string]struct { 92 makeHeights int64 93 pruneFrom int64 94 pruneTo int64 95 expectErr bool 96 expectVals []int64 97 expectParams []int64 98 expectABCI []int64 99 }{ 100 "error on pruning from 0": {100, 0, 5, true, nil, nil, nil}, 101 "error when from > to": {100, 3, 2, true, nil, nil, nil}, 102 "error when from == to": {100, 3, 3, true, nil, nil, nil}, 103 "error when to does not exist": {100, 1, 101, true, nil, nil, nil}, 104 "prune all": {100, 1, 100, false, []int64{93, 100}, []int64{95, 100}, []int64{100}}, 105 "prune some": {10, 2, 8, false, []int64{1, 3, 8, 9, 10}, 106 []int64{1, 5, 8, 9, 10}, []int64{1, 8, 9, 10}}, 107 "prune across checkpoint": {100001, 1, 100001, false, []int64{99993, 100000, 100001}, 108 []int64{99995, 100001}, []int64{100001}}, 109 } 110 for name, tc := range testcases { 111 tc := tc 112 t.Run(name, func(t *testing.T) { 113 db := dbm.NewMemDB() 114 stateStore := sm.NewStore(db, sm.StoreOptions{ 115 DiscardABCIResponses: false, 116 }) 117 pk := ed25519.GenPrivKey().PubKey() 118 119 // Generate a bunch of state data. Validators change for heights ending with 3, and 120 // parameters when ending with 5. 121 validator := &types.Validator{Address: tmrand.Bytes(crypto.AddressSize), VotingPower: 100, PubKey: pk} 122 validatorSet := &types.ValidatorSet{ 123 Validators: []*types.Validator{validator}, 124 Proposer: validator, 125 } 126 valsChanged := int64(0) 127 paramsChanged := int64(0) 128 129 for h := int64(1); h <= tc.makeHeights; h++ { 130 if valsChanged == 0 || h%10 == 2 { 131 valsChanged = h + 1 // Have to add 1, since NextValidators is what's stored 132 } 133 if paramsChanged == 0 || h%10 == 5 { 134 paramsChanged = h 135 } 136 137 state := sm.State{ 138 InitialHeight: 1, 139 LastBlockHeight: h - 1, 140 Validators: validatorSet, 141 NextValidators: validatorSet, 142 ConsensusParams: tmproto.ConsensusParams{ 143 Block: tmproto.BlockParams{MaxBytes: 10e6}, 144 }, 145 LastHeightValidatorsChanged: valsChanged, 146 LastHeightConsensusParamsChanged: paramsChanged, 147 } 148 149 if state.LastBlockHeight >= 1 { 150 state.LastValidators = state.Validators 151 } 152 153 err := stateStore.Save(state) 154 require.NoError(t, err) 155 156 err = stateStore.SaveABCIResponses(h, &tmstate.ABCIResponses{ 157 DeliverTxs: []*abci.ResponseDeliverTx{ 158 {Data: []byte{1}}, 159 {Data: []byte{2}}, 160 {Data: []byte{3}}, 161 }, 162 }) 163 require.NoError(t, err) 164 } 165 166 // Test assertions 167 err := stateStore.PruneStates(tc.pruneFrom, tc.pruneTo) 168 if tc.expectErr { 169 require.Error(t, err) 170 return 171 } 172 require.NoError(t, err) 173 174 expectVals := sliceToMap(tc.expectVals) 175 expectParams := sliceToMap(tc.expectParams) 176 expectABCI := sliceToMap(tc.expectABCI) 177 178 for h := int64(1); h <= tc.makeHeights; h++ { 179 vals, err := stateStore.LoadValidators(h) 180 if expectVals[h] { 181 require.NoError(t, err, "validators height %v", h) 182 require.NotNil(t, vals) 183 } else { 184 require.Error(t, err, "validators height %v", h) 185 require.Equal(t, sm.ErrNoValSetForHeight{Height: h}, err) 186 } 187 188 params, err := stateStore.LoadConsensusParams(h) 189 if expectParams[h] { 190 require.NoError(t, err, "params height %v", h) 191 require.False(t, params.Equal(&tmproto.ConsensusParams{})) 192 } else { 193 require.Error(t, err, "params height %v", h) 194 } 195 196 abci, err := stateStore.LoadABCIResponses(h) 197 if expectABCI[h] { 198 require.NoError(t, err, "abci height %v", h) 199 require.NotNil(t, abci) 200 } else { 201 require.Error(t, err, "abci height %v", h) 202 require.Equal(t, sm.ErrNoABCIResponsesForHeight{Height: h}, err) 203 } 204 } 205 }) 206 } 207 } 208 209 func TestABCIResponsesResultsHash(t *testing.T) { 210 responses := &tmstate.ABCIResponses{ 211 BeginBlock: &abci.ResponseBeginBlock{}, 212 DeliverTxs: []*abci.ResponseDeliverTx{ 213 {Code: 32, Data: []byte("Hello"), Log: "Huh?"}, 214 }, 215 EndBlock: &abci.ResponseEndBlock{}, 216 } 217 218 root := sm.ABCIResponsesResultsHash(responses) 219 220 // root should be Merkle tree root of DeliverTxs responses 221 results := types.NewResults(responses.DeliverTxs) 222 assert.Equal(t, root, results.Hash()) 223 224 // test we can prove first DeliverTx 225 proof := results.ProveResult(0) 226 bz, err := results[0].Marshal() 227 require.NoError(t, err) 228 assert.NoError(t, proof.Verify(root, bz)) 229 } 230 231 func sliceToMap(s []int64) map[int64]bool { 232 m := make(map[int64]bool, len(s)) 233 for _, i := range s { 234 m[i] = true 235 } 236 return m 237 } 238 239 func TestLastABCIResponses(t *testing.T) { 240 // create an empty state store. 241 t.Run("Not persisting responses", func(t *testing.T) { 242 stateDB := dbm.NewMemDB() 243 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 244 DiscardABCIResponses: false, 245 }) 246 responses, err := stateStore.LoadABCIResponses(1) 247 require.Error(t, err) 248 require.Nil(t, responses) 249 // stub the abciresponses. 250 response1 := &tmstate.ABCIResponses{ 251 BeginBlock: &abci.ResponseBeginBlock{}, 252 DeliverTxs: []*abci.ResponseDeliverTx{ 253 {Code: 32, Data: []byte("Hello"), Log: "Huh?"}, 254 }, 255 EndBlock: &abci.ResponseEndBlock{}, 256 } 257 // create new db and state store and set discard abciresponses to false. 258 stateDB = dbm.NewMemDB() 259 stateStore = sm.NewStore(stateDB, sm.StoreOptions{DiscardABCIResponses: false}) 260 height := int64(10) 261 // save the last abci response. 262 err = stateStore.SaveABCIResponses(height, response1) 263 require.NoError(t, err) 264 // search for the last abciresponse and check if it has saved. 265 lastResponse, err := stateStore.LoadLastABCIResponse(height) 266 require.NoError(t, err) 267 // check to see if the saved response height is the same as the loaded height. 268 assert.Equal(t, lastResponse, response1) 269 // use an incorret height to make sure the state store errors. 270 _, err = stateStore.LoadLastABCIResponse(height + 1) 271 assert.Error(t, err) 272 // check if the abci response didnt save in the abciresponses. 273 responses, err = stateStore.LoadABCIResponses(height) 274 require.NoError(t, err, responses) 275 require.Equal(t, response1, responses) 276 }) 277 278 t.Run("persisting responses", func(t *testing.T) { 279 stateDB := dbm.NewMemDB() 280 height := int64(10) 281 // stub the second abciresponse. 282 response2 := &tmstate.ABCIResponses{ 283 BeginBlock: &abci.ResponseBeginBlock{}, 284 DeliverTxs: []*abci.ResponseDeliverTx{ 285 {Code: 44, Data: []byte("Hello again"), Log: "????"}, 286 }, 287 EndBlock: &abci.ResponseEndBlock{}, 288 } 289 // create a new statestore with the responses on. 290 stateStore := sm.NewStore(stateDB, sm.StoreOptions{ 291 DiscardABCIResponses: true, 292 }) 293 // save an additional response. 294 err := stateStore.SaveABCIResponses(height+1, response2) 295 require.NoError(t, err) 296 // check to see if the response saved by calling the last response. 297 lastResponse2, err := stateStore.LoadLastABCIResponse(height + 1) 298 require.NoError(t, err) 299 // check to see if the saved response height is the same as the loaded height. 300 assert.Equal(t, response2, lastResponse2) 301 // should error as we are no longer saving the response. 302 _, err = stateStore.LoadABCIResponses(height + 1) 303 assert.Equal(t, sm.ErrABCIResponsesNotPersisted, err) 304 }) 305 306 }