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.

144 lines
4.6 KiB

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