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.

89 lines
2.8 KiB

  1. package state
  2. import (
  3. "errors"
  4. "fmt"
  5. tmstate "github.com/tendermint/tendermint/proto/tendermint/state"
  6. tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
  7. "github.com/tendermint/tendermint/version"
  8. )
  9. // Rollback overwrites the current Tendermint state (height n) with the most
  10. // recent previous state (height n - 1).
  11. // Note that this function does not affect application state.
  12. func Rollback(bs BlockStore, ss Store) (int64, []byte, error) {
  13. invalidState, err := ss.Load()
  14. if err != nil {
  15. return -1, nil, err
  16. }
  17. if invalidState.IsEmpty() {
  18. return -1, nil, errors.New("no state found")
  19. }
  20. rollbackHeight := invalidState.LastBlockHeight
  21. rollbackBlock := bs.LoadBlockMeta(rollbackHeight)
  22. if rollbackBlock == nil {
  23. return -1, nil, fmt.Errorf("block at height %d not found", rollbackHeight)
  24. }
  25. previousValidatorSet, err := ss.LoadValidators(rollbackHeight - 1)
  26. if err != nil {
  27. return -1, nil, err
  28. }
  29. previousParams, err := ss.LoadConsensusParams(rollbackHeight)
  30. if err != nil {
  31. return -1, nil, err
  32. }
  33. valChangeHeight := invalidState.LastHeightValidatorsChanged
  34. // this can only happen if the validator set changed since the last block
  35. if valChangeHeight > rollbackHeight {
  36. valChangeHeight = rollbackHeight
  37. }
  38. paramsChangeHeight := invalidState.LastHeightConsensusParamsChanged
  39. // this can only happen if params changed from the last block
  40. if paramsChangeHeight > rollbackHeight {
  41. paramsChangeHeight = rollbackHeight
  42. }
  43. // build the new state from the old state and the prior block
  44. rolledBackState := State{
  45. Version: tmstate.Version{
  46. Consensus: tmversion.Consensus{
  47. Block: version.BlockProtocol,
  48. App: previousParams.Version.AppVersion,
  49. },
  50. Software: version.TMCoreSemVer,
  51. },
  52. // immutable fields
  53. ChainID: invalidState.ChainID,
  54. InitialHeight: invalidState.InitialHeight,
  55. LastBlockHeight: invalidState.LastBlockHeight - 1,
  56. LastBlockID: rollbackBlock.Header.LastBlockID,
  57. LastBlockTime: rollbackBlock.Header.Time,
  58. NextValidators: invalidState.Validators,
  59. Validators: invalidState.LastValidators,
  60. LastValidators: previousValidatorSet,
  61. LastHeightValidatorsChanged: valChangeHeight,
  62. ConsensusParams: previousParams,
  63. LastHeightConsensusParamsChanged: paramsChangeHeight,
  64. LastResultsHash: rollbackBlock.Header.LastResultsHash,
  65. AppHash: rollbackBlock.Header.AppHash,
  66. }
  67. // persist the new state. This overrides the invalid one. NOTE: this will also
  68. // persist the validator set and consensus params over the existing structures,
  69. // but both should be the same
  70. if err := ss.Save(rolledBackState); err != nil {
  71. return -1, nil, fmt.Errorf("failed to save rolled back state: %w", err)
  72. }
  73. return rolledBackState.LastBlockHeight, rolledBackState.AppHash, nil
  74. }