github.com/okex/exchain@v1.8.0/libs/tendermint/state/store_test.go (about) 1 package state_test 2 3 import ( 4 "fmt" 5 "os" 6 "testing" 7 "time" 8 9 ethcmn "github.com/ethereum/go-ethereum/common" 10 11 "github.com/okex/exchain/libs/tendermint/libs/kv" 12 13 abci "github.com/okex/exchain/libs/tendermint/abci/types" 14 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 18 dbm "github.com/okex/exchain/libs/tm-db" 19 20 cfg "github.com/okex/exchain/libs/tendermint/config" 21 sm "github.com/okex/exchain/libs/tendermint/state" 22 "github.com/okex/exchain/libs/tendermint/types" 23 ) 24 25 func TestStoreLoadValidators(t *testing.T) { 26 stateDB := dbm.NewMemDB() 27 val, _ := types.RandValidator(true, 10) 28 vals := types.NewValidatorSet([]*types.Validator{val}) 29 30 // 1) LoadValidators loads validators using a height where they were last changed 31 sm.SaveValidatorsInfo(stateDB, 1, 1, vals) 32 sm.SaveValidatorsInfo(stateDB, 2, 1, vals) 33 loadedVals, err := sm.LoadValidators(stateDB, 2) 34 require.NoError(t, err) 35 assert.NotZero(t, loadedVals.Size()) 36 37 // 2) LoadValidators loads validators using a checkpoint height 38 39 sm.SaveValidatorsInfo(stateDB, sm.ValSetCheckpointInterval, 1, vals) 40 41 loadedVals, err = sm.LoadValidators(stateDB, sm.ValSetCheckpointInterval) 42 require.NoError(t, err) 43 assert.NotZero(t, loadedVals.Size()) 44 } 45 46 func BenchmarkLoadValidators(b *testing.B) { 47 const valSetSize = 100 48 49 config := cfg.ResetTestRoot("state_") 50 defer os.RemoveAll(config.RootDir) 51 dbType := dbm.BackendType(config.DBBackend) 52 stateDB := dbm.NewDB("state", dbType, config.DBDir()) 53 state, err := sm.LoadStateFromDBOrGenesisFile(stateDB, config.GenesisFile()) 54 if err != nil { 55 b.Fatal(err) 56 } 57 state.Validators = genValSet(valSetSize) 58 state.NextValidators = state.Validators.CopyIncrementProposerPriority(1) 59 sm.SaveState(stateDB, state) 60 61 for i := 10; i < 10000000000; i *= 10 { // 10, 100, 1000, ... 62 i := i 63 sm.SaveValidatorsInfo(stateDB, int64(i), state.LastHeightValidatorsChanged, state.NextValidators) 64 65 b.Run(fmt.Sprintf("height=%d", i), func(b *testing.B) { 66 for n := 0; n < b.N; n++ { 67 _, err := sm.LoadValidators(stateDB, int64(i)) 68 if err != nil { 69 b.Fatal(err) 70 } 71 } 72 }) 73 } 74 } 75 76 func TestPruneStates(t *testing.T) { 77 testcases := map[string]struct { 78 makeHeights int64 79 pruneFrom int64 80 pruneTo int64 81 expectErr bool 82 expectVals []int64 83 expectParams []int64 84 expectABCI []int64 85 }{ 86 "error on pruning from 0": {100, 0, 5, true, nil, nil, nil}, 87 "error when from > to": {100, 3, 2, true, nil, nil, nil}, 88 "error when from == to": {100, 3, 3, true, nil, nil, nil}, 89 "error when to does not exist": {100, 1, 101, true, nil, nil, nil}, 90 "prune all": {100, 1, 100, false, []int64{93, 100}, []int64{95, 100}, []int64{100}}, 91 "prune some": {10, 2, 8, false, []int64{1, 3, 8, 9, 10}, 92 []int64{1, 5, 8, 9, 10}, []int64{1, 8, 9, 10}}, 93 "prune across checkpoint": {100001, 1, 100001, false, []int64{99993, 100000, 100001}, 94 []int64{99995, 100001}, []int64{100001}}, 95 } 96 for name, tc := range testcases { 97 tc := tc 98 t.Run(name, func(t *testing.T) { 99 db := dbm.NewMemDB() 100 101 // Generate a bunch of state data. Validators change for heights ending with 3, and 102 // parameters when ending with 5. 103 validator := &types.Validator{Address: []byte{1, 2, 3}, VotingPower: 100} 104 validatorSet := &types.ValidatorSet{ 105 Validators: []*types.Validator{validator}, 106 Proposer: validator, 107 } 108 valsChanged := int64(0) 109 paramsChanged := int64(0) 110 111 for h := int64(1); h <= tc.makeHeights; h++ { 112 if valsChanged == 0 || h%10 == 2 { 113 valsChanged = h + 1 // Have to add 1, since NextValidators is what's stored 114 } 115 if paramsChanged == 0 || h%10 == 5 { 116 paramsChanged = h 117 } 118 119 sm.SaveState(db, sm.State{ 120 LastBlockHeight: h - 1, 121 Validators: validatorSet, 122 NextValidators: validatorSet, 123 ConsensusParams: types.ConsensusParams{ 124 Block: types.BlockParams{MaxBytes: 10e6}, 125 }, 126 LastHeightValidatorsChanged: valsChanged, 127 LastHeightConsensusParamsChanged: paramsChanged, 128 }) 129 sm.SaveABCIResponses(db, h, sm.NewABCIResponses(&types.Block{ 130 Header: types.Header{Height: h}, 131 Data: types.Data{ 132 Txs: types.Txs{ 133 []byte{1}, 134 []byte{2}, 135 []byte{3}, 136 }, 137 }, 138 })) 139 } 140 141 // Test assertions 142 err := sm.PruneStates(db, tc.pruneFrom, tc.pruneTo) 143 if tc.expectErr { 144 require.Error(t, err) 145 return 146 } 147 require.NoError(t, err) 148 149 expectVals := sliceToMap(tc.expectVals) 150 expectParams := sliceToMap(tc.expectParams) 151 expectABCI := sliceToMap(tc.expectABCI) 152 153 for h := int64(1); h <= tc.makeHeights; h++ { 154 vals, err := sm.LoadValidators(db, h) 155 if expectVals[h] { 156 require.NoError(t, err, "validators height %v", h) 157 require.NotNil(t, vals) 158 } else { 159 require.Error(t, err, "validators height %v", h) 160 require.Equal(t, sm.ErrNoValSetForHeight{Height: h}, err) 161 } 162 163 params, err := sm.LoadConsensusParams(db, h) 164 if expectParams[h] { 165 require.NoError(t, err, "params height %v", h) 166 require.False(t, params.Equals(&types.ConsensusParams{})) 167 } else { 168 require.Error(t, err, "params height %v", h) 169 require.Equal(t, sm.ErrNoConsensusParamsForHeight{Height: h}, err) 170 } 171 172 abci, err := sm.LoadABCIResponses(db, h) 173 if expectABCI[h] { 174 require.NoError(t, err, "abci height %v", h) 175 require.NotNil(t, abci) 176 } else { 177 require.Error(t, err, "abci height %v", h) 178 require.Equal(t, sm.ErrNoABCIResponsesForHeight{Height: h}, err) 179 } 180 } 181 }) 182 } 183 } 184 185 func TestABCIResponsesAmino(t *testing.T) { 186 tmp := ethcmn.HexToHash("testhahs") 187 var resps = []sm.ABCIResponses{ 188 { 189 nil, 190 nil, 191 nil, 192 }, 193 { 194 []*abci.ResponseDeliverTx{}, 195 &abci.ResponseEndBlock{}, 196 &abci.ResponseBeginBlock{}, 197 }, 198 { 199 []*abci.ResponseDeliverTx{ 200 {}, nil, {12, tmp[:], "log", "info", 123, 456, []abci.Event{}, "sss", struct{}{}, []byte{}, 1}, 201 {}, nil, {12, tmp[:], "log", "info", 123, 456, []abci.Event{}, "sss", struct{}{}, []byte{}, 1}, 202 }, 203 &abci.ResponseEndBlock{ 204 ValidatorUpdates: []abci.ValidatorUpdate{ 205 {Power: 100}, 206 }, 207 ConsensusParamUpdates: &abci.ConsensusParams{ 208 &abci.BlockParams{MaxBytes: 1024}, 209 &abci.EvidenceParams{MaxAgeDuration: time.Minute * 100}, 210 &abci.ValidatorParams{PubKeyTypes: []string{"pubkey1", "pubkey2"}}, 211 struct{}{}, []byte{}, 0, 212 }, 213 Events: []abci.Event{{}, {Type: "Event"}}, 214 }, 215 &abci.ResponseBeginBlock{ 216 Events: []abci.Event{ 217 {}, 218 {"", nil, struct{}{}, nil, 0}, 219 { 220 Type: "type", Attributes: []kv.Pair{ 221 {Key: []byte{0x11, 0x22}, Value: []byte{0x33, 0x44}}, 222 {Key: []byte{0x11, 0x22}, Value: []byte{0x33, 0x44}}, 223 {Key: nil, Value: nil}, 224 {Key: []byte{}, Value: []byte{}}, 225 {Key: tmp[:], Value: tmp[:]}, 226 }, 227 }, 228 }, 229 XXX_sizecache: 10, 230 }, 231 }, 232 } 233 234 for _, resp := range resps { 235 expect, err := sm.ModuleCodec.MarshalBinaryBare(resp) 236 require.NoError(t, err) 237 238 actual, err := resp.MarshalToAmino(sm.ModuleCodec) 239 require.NoError(t, err) 240 require.EqualValues(t, expect, actual) 241 242 require.EqualValues(t, len(expect), resp.AminoSize(sm.ModuleCodec)) 243 244 var expectValue sm.ABCIResponses 245 err = sm.ModuleCodec.UnmarshalBinaryBare(expect, &expectValue) 246 require.NoError(t, err) 247 248 var actualValue sm.ABCIResponses 249 err = actualValue.UnmarshalFromAmino(sm.ModuleCodec, expect) 250 require.NoError(t, err) 251 require.EqualValues(t, expectValue, actualValue) 252 } 253 } 254 255 func BenchmarkABCIResponsesMarshalAmino(b *testing.B) { 256 tmp := ethcmn.HexToHash("testhahs") 257 resp := sm.ABCIResponses{ 258 []*abci.ResponseDeliverTx{ 259 {}, nil, {12, tmp[:], "log", "info", 123, 456, []abci.Event{}, "sss", struct{}{}, []byte{}, 1}, 260 }, 261 &abci.ResponseEndBlock{ 262 ValidatorUpdates: []abci.ValidatorUpdate{ 263 {Power: 100}, 264 }, 265 ConsensusParamUpdates: &abci.ConsensusParams{ 266 &abci.BlockParams{MaxBytes: 1024}, 267 &abci.EvidenceParams{MaxAgeDuration: time.Minute * 100}, 268 &abci.ValidatorParams{PubKeyTypes: []string{"pubkey1", "pubkey2"}}, 269 struct{}{}, []byte{}, 0, 270 }, 271 Events: []abci.Event{{}, {Type: "Event"}}, 272 }, 273 &abci.ResponseBeginBlock{ 274 Events: []abci.Event{ 275 {}, 276 {"", nil, struct{}{}, nil, 0}, 277 { 278 Type: "type", Attributes: []kv.Pair{ 279 {Key: []byte{0x11, 0x22}, Value: []byte{0x33, 0x44}}, 280 {Key: []byte{0x11, 0x22}, Value: []byte{0x33, 0x44}}, 281 {Key: nil, Value: nil}, 282 {Key: []byte{}, Value: []byte{}}, 283 {Key: tmp[:], Value: tmp[:]}, 284 }, 285 }, 286 }, 287 XXX_sizecache: 10, 288 }, 289 } 290 291 b.ResetTimer() 292 b.Run("amino", func(b *testing.B) { 293 b.ReportAllocs() 294 for i := 0; i < b.N; i++ { 295 _, _ = sm.ModuleCodec.MarshalBinaryBare(resp) 296 } 297 }) 298 b.Run("marshaller", func(b *testing.B) { 299 b.ReportAllocs() 300 for i := 0; i < b.N; i++ { 301 _, _ = resp.MarshalToAmino(sm.ModuleCodec) 302 } 303 }) 304 } 305 306 func sliceToMap(s []int64) map[int64]bool { 307 m := make(map[int64]bool, len(s)) 308 for _, i := range s { 309 m[i] = true 310 } 311 return m 312 }