github.com/Oyster-zx/tendermint@v0.34.24-fork/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/tendermint/tendermint/config" 12 "github.com/tendermint/tendermint/libs/os" 13 "github.com/tendermint/tendermint/state" 14 "github.com/tendermint/tendermint/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 }