github.com/vipernet-xyz/tm@v0.34.24/state/rollback_test.go (about) 1 package state_test 2 3 import ( 4 "crypto/rand" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 dbm "github.com/tendermint/tm-db" 9 10 "github.com/vipernet-xyz/tm/crypto" 11 "github.com/vipernet-xyz/tm/crypto/tmhash" 12 tmstate "github.com/vipernet-xyz/tm/proto/tendermint/state" 13 tmversion "github.com/vipernet-xyz/tm/proto/tendermint/version" 14 "github.com/vipernet-xyz/tm/state" 15 "github.com/vipernet-xyz/tm/state/mocks" 16 "github.com/vipernet-xyz/tm/types" 17 "github.com/vipernet-xyz/tm/version" 18 ) 19 20 func TestRollback(t *testing.T) { 21 var ( 22 height int64 = 100 23 nextHeight int64 = 101 24 ) 25 blockStore := &mocks.BlockStore{} 26 stateStore := setupStateStore(t, height) 27 initialState, err := stateStore.Load() 28 require.NoError(t, err) 29 30 // perform the rollback over a version bump 31 newParams := types.DefaultConsensusParams() 32 newParams.Version.AppVersion = 11 33 newParams.Block.MaxBytes = 1000 34 nextState := initialState.Copy() 35 nextState.LastBlockHeight = nextHeight 36 nextState.Version.Consensus.App = 11 37 nextState.LastBlockID = makeBlockIDRandom() 38 nextState.AppHash = tmhash.Sum([]byte("app_hash")) 39 nextState.LastValidators = initialState.Validators 40 nextState.Validators = initialState.NextValidators 41 nextState.NextValidators = initialState.NextValidators.CopyIncrementProposerPriority(1) 42 nextState.ConsensusParams = *newParams 43 nextState.LastHeightConsensusParamsChanged = nextHeight + 1 44 nextState.LastHeightValidatorsChanged = nextHeight + 1 45 46 // update the state 47 require.NoError(t, stateStore.Save(nextState)) 48 49 block := &types.BlockMeta{ 50 BlockID: initialState.LastBlockID, 51 Header: types.Header{ 52 Height: initialState.LastBlockHeight, 53 AppHash: crypto.CRandBytes(tmhash.Size), 54 LastBlockID: makeBlockIDRandom(), 55 LastResultsHash: initialState.LastResultsHash, 56 }, 57 } 58 nextBlock := &types.BlockMeta{ 59 BlockID: initialState.LastBlockID, 60 Header: types.Header{ 61 Height: nextState.LastBlockHeight, 62 AppHash: initialState.AppHash, 63 LastBlockID: block.BlockID, 64 LastResultsHash: nextState.LastResultsHash, 65 }, 66 } 67 blockStore.On("LoadBlockMeta", height).Return(block) 68 blockStore.On("LoadBlockMeta", nextHeight).Return(nextBlock) 69 blockStore.On("Height").Return(nextHeight) 70 71 // rollback the state 72 rollbackHeight, rollbackHash, err := state.Rollback(blockStore, stateStore) 73 require.NoError(t, err) 74 require.EqualValues(t, height, rollbackHeight) 75 require.EqualValues(t, initialState.AppHash, rollbackHash) 76 blockStore.AssertExpectations(t) 77 78 // assert that we've recovered the prior state 79 loadedState, err := stateStore.Load() 80 require.NoError(t, err) 81 require.EqualValues(t, initialState, loadedState) 82 } 83 84 func TestRollbackNoState(t *testing.T) { 85 stateStore := state.NewStore(dbm.NewMemDB(), 86 state.StoreOptions{ 87 DiscardABCIResponses: false, 88 }) 89 blockStore := &mocks.BlockStore{} 90 91 _, _, err := state.Rollback(blockStore, stateStore) 92 require.Error(t, err) 93 require.Contains(t, err.Error(), "no state found") 94 } 95 96 func TestRollbackNoBlocks(t *testing.T) { 97 const height = int64(100) 98 stateStore := setupStateStore(t, height) 99 blockStore := &mocks.BlockStore{} 100 blockStore.On("Height").Return(height) 101 blockStore.On("LoadBlockMeta", height).Return(nil) 102 blockStore.On("LoadBlockMeta", height-1).Return(nil) 103 104 _, _, err := state.Rollback(blockStore, stateStore) 105 require.Error(t, err) 106 require.Contains(t, err.Error(), "block at height 99 not found") 107 } 108 109 func TestRollbackDifferentStateHeight(t *testing.T) { 110 const height = int64(100) 111 stateStore := setupStateStore(t, height) 112 blockStore := &mocks.BlockStore{} 113 blockStore.On("Height").Return(height + 2) 114 115 _, _, err := state.Rollback(blockStore, stateStore) 116 require.Error(t, err) 117 require.Equal(t, err.Error(), "statestore height (100) is not one below or equal to blockstore height (102)") 118 } 119 120 func setupStateStore(t *testing.T, height int64) state.Store { 121 stateStore := state.NewStore(dbm.NewMemDB(), state.StoreOptions{DiscardABCIResponses: false}) 122 valSet, _ := types.RandValidatorSet(5, 10) 123 124 params := types.DefaultConsensusParams() 125 params.Version.AppVersion = 10 126 127 initialState := state.State{ 128 Version: tmstate.Version{ 129 Consensus: tmversion.Consensus{ 130 Block: version.BlockProtocol, 131 App: 10, 132 }, 133 Software: version.TMCoreSemVer, 134 }, 135 ChainID: "test-chain", 136 InitialHeight: 10, 137 LastBlockID: makeBlockIDRandom(), 138 AppHash: tmhash.Sum([]byte("app_hash")), 139 LastResultsHash: tmhash.Sum([]byte("last_results_hash")), 140 LastBlockHeight: height, 141 LastValidators: valSet, 142 Validators: valSet.CopyIncrementProposerPriority(1), 143 NextValidators: valSet.CopyIncrementProposerPriority(2), 144 LastHeightValidatorsChanged: height + 1, 145 ConsensusParams: *params, 146 LastHeightConsensusParamsChanged: height + 1, 147 } 148 require.NoError(t, stateStore.Bootstrap(initialState)) 149 return stateStore 150 } 151 152 func makeBlockIDRandom() types.BlockID { 153 var ( 154 blockHash = make([]byte, tmhash.Size) 155 partSetHash = make([]byte, tmhash.Size) 156 ) 157 rand.Read(blockHash) //nolint: errcheck // ignore errcheck for read 158 rand.Read(partSetHash) //nolint: errcheck // ignore errcheck for read 159 return types.BlockID{ 160 Hash: blockHash, 161 PartSetHeader: types.PartSetHeader{ 162 Total: 123, 163 Hash: partSetHash, 164 }, 165 } 166 }