github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/cmd/tendermint/commands/rollback.go (about)

     1  package commands
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/spf13/cobra"
     7  
     8  	"github.com/ari-anchor/sei-tendermint/config"
     9  	"github.com/ari-anchor/sei-tendermint/internal/state"
    10  )
    11  
    12  var removeBlock bool = false
    13  
    14  func MakeRollbackStateCommand(conf *config.Config) *cobra.Command {
    15  	cmd := &cobra.Command{
    16  		Use:   "rollback",
    17  		Short: "rollback tendermint state by one height",
    18  		Long: `
    19  A state rollback is performed to recover from an incorrect application state transition,
    20  when Tendermint has persisted an incorrect app hash and is thus unable to make
    21  progress. Rollback overwrites a state at height n with the state at height n - 1.
    22  The application should also roll back to height n - 1. No blocks are removed, so upon
    23  restarting Tendermint the transactions in block n will be re-executed against the
    24  application.
    25  `,
    26  		RunE: func(cmd *cobra.Command, args []string) error {
    27  			height, hash, err := RollbackState(conf, removeBlock)
    28  			if err != nil {
    29  				return fmt.Errorf("failed to rollback state: %w", err)
    30  			}
    31  
    32  			if removeBlock {
    33  				fmt.Printf("Rolled back both state and block to height %d and hash %X\n", height, hash)
    34  			} else {
    35  				fmt.Printf("Rolled back state to height %d and hash %X\n", height, hash)
    36  			}
    37  			return nil
    38  		},
    39  	}
    40  	cmd.Flags().BoolVar(&removeBlock, "hard", false, "remove last block as well as state")
    41  
    42  	return cmd
    43  }
    44  
    45  // RollbackState takes the state at the current height n and overwrites it with the state
    46  // at height n - 1. Note state here refers to tendermint state not application state.
    47  // Returns the latest state height and app hash alongside an error if there was one.
    48  func RollbackState(config *config.Config, removeBlock bool) (int64, []byte, error) {
    49  	// use the parsed config to load the block and state store
    50  	blockStore, stateStore, err := loadStateAndBlockStore(config)
    51  	fmt.Printf("Current blockStore height=%d hash=%X\n", blockStore.Height(), blockStore.LoadSeenCommit().Hash())
    52  	if err != nil {
    53  		return -1, nil, err
    54  	}
    55  
    56  	defer func() {
    57  		_ = blockStore.Close()
    58  		_ = stateStore.Close()
    59  	}()
    60  
    61  	// rollback the last state
    62  	height, hash, err := state.Rollback(blockStore, stateStore, removeBlock, config.PrivValidator)
    63  	return height, hash, err
    64  }