You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
4.7 KiB

  1. package state_test
  2. import (
  3. "testing"
  4. "github.com/stretchr/testify/require"
  5. dbm "github.com/tendermint/tm-db"
  6. "github.com/tendermint/tendermint/internal/state"
  7. "github.com/tendermint/tendermint/internal/state/mocks"
  8. "github.com/tendermint/tendermint/internal/test/factory"
  9. "github.com/tendermint/tendermint/types"
  10. "github.com/tendermint/tendermint/version"
  11. )
  12. func TestRollback(t *testing.T) {
  13. var (
  14. height int64 = 100
  15. nextHeight int64 = 101
  16. )
  17. blockStore := &mocks.BlockStore{}
  18. stateStore := setupStateStore(t, height)
  19. initialState, err := stateStore.Load()
  20. require.NoError(t, err)
  21. // perform the rollback over a version bump
  22. newParams := types.DefaultConsensusParams()
  23. newParams.Version.AppVersion = 11
  24. newParams.Block.MaxBytes = 1000
  25. nextState := initialState.Copy()
  26. nextState.LastBlockHeight = nextHeight
  27. nextState.Version.Consensus.App = 11
  28. nextState.LastBlockID = factory.MakeBlockID()
  29. nextState.AppHash = factory.RandomHash()
  30. nextState.LastValidators = initialState.Validators
  31. nextState.Validators = initialState.NextValidators
  32. nextState.NextValidators = initialState.NextValidators.CopyIncrementProposerPriority(1)
  33. nextState.ConsensusParams = *newParams
  34. nextState.LastHeightConsensusParamsChanged = nextHeight + 1
  35. nextState.LastHeightValidatorsChanged = nextHeight + 1
  36. // update the state
  37. require.NoError(t, stateStore.Save(nextState))
  38. block := &types.BlockMeta{
  39. BlockID: initialState.LastBlockID,
  40. Header: types.Header{
  41. Height: initialState.LastBlockHeight,
  42. AppHash: factory.RandomHash(),
  43. LastBlockID: factory.MakeBlockID(),
  44. LastResultsHash: initialState.LastResultsHash,
  45. },
  46. }
  47. nextBlock := &types.BlockMeta{
  48. BlockID: initialState.LastBlockID,
  49. Header: types.Header{
  50. Height: nextState.LastBlockHeight,
  51. AppHash: initialState.AppHash,
  52. LastBlockID: block.BlockID,
  53. LastResultsHash: nextState.LastResultsHash,
  54. },
  55. }
  56. blockStore.On("LoadBlockMeta", height).Return(block)
  57. blockStore.On("LoadBlockMeta", nextHeight).Return(nextBlock)
  58. blockStore.On("Height").Return(nextHeight)
  59. // rollback the state
  60. rollbackHeight, rollbackHash, err := state.Rollback(blockStore, stateStore)
  61. require.NoError(t, err)
  62. require.EqualValues(t, height, rollbackHeight)
  63. require.EqualValues(t, initialState.AppHash, rollbackHash)
  64. blockStore.AssertExpectations(t)
  65. // assert that we've recovered the prior state
  66. loadedState, err := stateStore.Load()
  67. require.NoError(t, err)
  68. require.EqualValues(t, initialState, loadedState)
  69. }
  70. func TestRollbackNoState(t *testing.T) {
  71. stateStore := state.NewStore(dbm.NewMemDB())
  72. blockStore := &mocks.BlockStore{}
  73. _, _, err := state.Rollback(blockStore, stateStore)
  74. require.Error(t, err)
  75. require.Contains(t, err.Error(), "no state found")
  76. }
  77. func TestRollbackNoBlocks(t *testing.T) {
  78. const height = int64(100)
  79. stateStore := setupStateStore(t, height)
  80. blockStore := &mocks.BlockStore{}
  81. blockStore.On("Height").Return(height)
  82. blockStore.On("LoadBlockMeta", height).Return(nil)
  83. blockStore.On("LoadBlockMeta", height-1).Return(nil)
  84. _, _, err := state.Rollback(blockStore, stateStore)
  85. require.Error(t, err)
  86. require.Contains(t, err.Error(), "block at height 99 not found")
  87. }
  88. func TestRollbackDifferentStateHeight(t *testing.T) {
  89. const height = int64(100)
  90. stateStore := setupStateStore(t, height)
  91. blockStore := &mocks.BlockStore{}
  92. blockStore.On("Height").Return(height + 2)
  93. _, _, err := state.Rollback(blockStore, stateStore)
  94. require.Error(t, err)
  95. require.Equal(t, err.Error(), "statestore height (100) is not one below or equal to blockstore height (102)")
  96. }
  97. func setupStateStore(t *testing.T, height int64) state.Store {
  98. stateStore := state.NewStore(dbm.NewMemDB())
  99. valSet, _ := factory.RandValidatorSet(5, 10)
  100. params := types.DefaultConsensusParams()
  101. params.Version.AppVersion = 10
  102. initialState := state.State{
  103. Version: state.Version{
  104. Consensus: version.Consensus{
  105. Block: version.BlockProtocol,
  106. App: 10,
  107. },
  108. Software: version.TMVersion,
  109. },
  110. ChainID: factory.DefaultTestChainID,
  111. InitialHeight: 10,
  112. LastBlockID: factory.MakeBlockID(),
  113. AppHash: factory.RandomHash(),
  114. LastResultsHash: factory.RandomHash(),
  115. LastBlockHeight: height,
  116. LastValidators: valSet,
  117. Validators: valSet.CopyIncrementProposerPriority(1),
  118. NextValidators: valSet.CopyIncrementProposerPriority(2),
  119. LastHeightValidatorsChanged: height + 1,
  120. ConsensusParams: *params,
  121. LastHeightConsensusParamsChanged: height + 1,
  122. }
  123. require.NoError(t, stateStore.Bootstrap(initialState))
  124. return stateStore
  125. }