github.com/vipernet-xyz/tm@v0.34.24/cmd/tendermint/commands/rollback.go (about)

     1  package commands
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  
     7  	"github.com/spf13/cobra"
     8  
     9  	dbm "github.com/tendermint/tm-db"
    10  
    11  	cfg "github.com/vipernet-xyz/tm/config"
    12  	"github.com/vipernet-xyz/tm/libs/os"
    13  	"github.com/vipernet-xyz/tm/state"
    14  	"github.com/vipernet-xyz/tm/store"
    15  )
    16  
    17  var RollbackStateCmd = &cobra.Command{
    18  	Use:   "rollback",
    19  	Short: "rollback tendermint state by one height",
    20  	Long: `
    21  A state rollback is performed to recover from an incorrect application state transition,
    22  when Tendermint has persisted an incorrect app hash and is thus unable to make
    23  progress. Rollback overwrites a state at height n with the state at height n - 1.
    24  The application should also roll back to height n - 1. No blocks are removed, so upon
    25  restarting Tendermint the transactions in block n will be re-executed against the
    26  application.
    27  `,
    28  	RunE: func(cmd *cobra.Command, args []string) error {
    29  		height, hash, err := RollbackState(config)
    30  		if err != nil {
    31  			return fmt.Errorf("failed to rollback state: %w", err)
    32  		}
    33  
    34  		fmt.Printf("Rolled back state to height %d and hash %v", height, hash)
    35  		return nil
    36  	},
    37  }
    38  
    39  // RollbackState takes the state at the current height n and overwrites it with the state
    40  // at height n - 1. Note state here refers to tendermint state not application state.
    41  // Returns the latest state height and app hash alongside an error if there was one.
    42  func RollbackState(config *cfg.Config) (int64, []byte, error) {
    43  	// use the parsed config to load the block and state store
    44  	blockStore, stateStore, err := loadStateAndBlockStore(config)
    45  	if err != nil {
    46  		return -1, nil, err
    47  	}
    48  	defer func() {
    49  		_ = blockStore.Close()
    50  		_ = stateStore.Close()
    51  	}()
    52  
    53  	// rollback the last state
    54  	return state.Rollback(blockStore, stateStore)
    55  }
    56  
    57  func loadStateAndBlockStore(config *cfg.Config) (*store.BlockStore, state.Store, error) {
    58  	dbType := dbm.BackendType(config.DBBackend)
    59  
    60  	if !os.FileExists(filepath.Join(config.DBDir(), "blockstore.db")) {
    61  		return nil, nil, fmt.Errorf("no blockstore found in %v", config.DBDir())
    62  	}
    63  
    64  	// Get BlockStore
    65  	blockStoreDB, err := dbm.NewDB("blockstore", dbType, config.DBDir())
    66  	if err != nil {
    67  		return nil, nil, err
    68  	}
    69  	blockStore := store.NewBlockStore(blockStoreDB)
    70  
    71  	if !os.FileExists(filepath.Join(config.DBDir(), "state.db")) {
    72  		return nil, nil, fmt.Errorf("no statestore found in %v", config.DBDir())
    73  	}
    74  
    75  	// Get StateStore
    76  	stateDB, err := dbm.NewDB("state", dbType, config.DBDir())
    77  	if err != nil {
    78  		return nil, nil, err
    79  	}
    80  	stateStore := state.NewStore(stateDB, state.StoreOptions{
    81  		DiscardABCIResponses: config.Storage.DiscardABCIResponses,
    82  	})
    83  
    84  	return blockStore, stateStore, nil
    85  }