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  }