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  }