From 001c96723e56c10d8ed3a820f3c89f3ee15aa0f1 Mon Sep 17 00:00:00 2001 From: marbar3778 <marbar3778@yahoo.com> Date: Fri, 10 Jan 2025 13:40:20 +0100 Subject: [PATCH 1/4] all rollback function to replacable --- server/rollback.go | 12 +++++++++--- server/util.go | 23 +++++++++++++++++++---- simapp/simd/cmd/commands.go | 2 +- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/server/rollback.go b/server/rollback.go index 7dd58bcedf64..87eb369e33a3 100644 --- a/server/rollback.go +++ b/server/rollback.go @@ -3,14 +3,20 @@ package server import ( "fmt" - cmtcmd "github.com/cometbft/cometbft/cmd/cometbft/commands" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/server/types" ) +// Rollbackable is an interface that allows for rollback operations. +// It is used to allow for custom rollback operations, such as those provided by the +// DefaultRollbackable implementation. +type Rollbackable interface { + RollbackToVersion(ctx *Context, removeBlock bool) (int64, []byte, error) +} + // NewRollbackCmd creates a command to rollback CometBFT and multistore state by one height. -func NewRollbackCmd[T types.Application](appCreator types.AppCreator[T]) *cobra.Command { +func NewRollbackCmd[T types.Application, R Rollbackable](appCreator types.AppCreator[T], rollbackable R) *cobra.Command { var removeBlock bool cmd := &cobra.Command{ @@ -33,7 +39,7 @@ application. } app := appCreator(ctx.Logger, db, nil, ctx.Viper) // rollback CometBFT state - height, hash, err := cmtcmd.RollbackState(ctx.Config, removeBlock) + height, hash, err := rollbackable.RollbackToVersion(ctx, removeBlock) if err != nil { return fmt.Errorf("failed to rollback CometBFT state: %w", err) } diff --git a/server/util.go b/server/util.go index 58afe6cbab97..aed192675607 100644 --- a/server/util.go +++ b/server/util.go @@ -332,7 +332,7 @@ func interceptConfigs(rootViper *viper.Viper, customAppTemplate string, customCo } // AddCommands add server commands -func AddCommands[T types.Application](rootCmd *cobra.Command, appCreator types.AppCreator[T], opts StartCmdOptions[T]) { +func AddCommands[T types.Application, R Rollbackable](rootCmd *cobra.Command, appCreator types.AppCreator[T], rollbackable R, opts StartCmdOptions[T]) { cometCmd := &cobra.Command{ Use: "comet", Aliases: []string{"cometbft", "tendermint"}, @@ -354,15 +354,30 @@ func AddCommands[T types.Application](rootCmd *cobra.Command, appCreator types.A startCmd, cometCmd, version.NewVersionCommand(), - NewRollbackCmd(appCreator), + NewRollbackCmd(appCreator, rollbackable), ModuleHashByHeightQuery(appCreator), ) } +// DefaultRollbackable is a default implementation of the Rollbackable interface. +type DefaultRollbackable[T types.Application] struct { + appCreator types.AppCreator[T] +} + +// NewDefaultRollbackable creates a new DefaultRollbackable instance. +func NewDefaultRollbackable[T types.Application](appCreator types.AppCreator[T]) *DefaultRollbackable[T] { + return &DefaultRollbackable[T]{appCreator} +} + +// RollbackToVersion implements the Rollbackable interface. +func (d DefaultRollbackable[T]) RollbackToVersion(ctx *Context, removeBlock bool) (int64, []byte, error) { + return cmtcmd.RollbackState(ctx.Config, removeBlock) +} + // AddCommandsWithStartCmdOptions adds server commands with the provided StartCmdOptions. // Deprecated: Use AddCommands directly instead. -func AddCommandsWithStartCmdOptions[T types.Application](rootCmd *cobra.Command, appCreator types.AppCreator[T], opts StartCmdOptions[T]) { - AddCommands(rootCmd, appCreator, opts) +func AddCommandsWithStartCmdOptions[T types.Application, R Rollbackable](rootCmd *cobra.Command, appCreator types.AppCreator[T], rollbackable R, opts StartCmdOptions[T]) { + AddCommands(rootCmd, appCreator, rollbackable, opts) } // AddTestnetCreatorCommand allows chains to create a testnet from the state existing in their node's data directory. diff --git a/simapp/simd/cmd/commands.go b/simapp/simd/cmd/commands.go index 2b6e1a9032af..11792e544c7e 100644 --- a/simapp/simd/cmd/commands.go +++ b/simapp/simd/cmd/commands.go @@ -45,7 +45,7 @@ func initRootCmd( snapshot.Cmd(newApp), ) - server.AddCommands(rootCmd, newApp, server.StartCmdOptions[servertypes.Application]{}) + server.AddCommands(rootCmd, newApp, server.NewDefaultRollbackable(newApp), server.StartCmdOptions[servertypes.Application]{}) // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( From 437f6ba9457fd276e8c19a0dee2f2f5ba24b9c0f Mon Sep 17 00:00:00 2001 From: marbar3778 <marbar3778@yahoo.com> Date: Fri, 10 Jan 2025 14:33:40 +0100 Subject: [PATCH 2/4] minor cleanup --- server/rollback.go | 9 +-------- server/util.go | 41 ++++++++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/server/rollback.go b/server/rollback.go index 87eb369e33a3..ba486b4571af 100644 --- a/server/rollback.go +++ b/server/rollback.go @@ -8,15 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/server/types" ) -// Rollbackable is an interface that allows for rollback operations. -// It is used to allow for custom rollback operations, such as those provided by the -// DefaultRollbackable implementation. -type Rollbackable interface { - RollbackToVersion(ctx *Context, removeBlock bool) (int64, []byte, error) -} - // NewRollbackCmd creates a command to rollback CometBFT and multistore state by one height. -func NewRollbackCmd[T types.Application, R Rollbackable](appCreator types.AppCreator[T], rollbackable R) *cobra.Command { +func NewRollbackCmd[T types.Application, R Rollback](appCreator types.AppCreator[T], rollbackable R) *cobra.Command { var removeBlock bool cmd := &cobra.Command{ diff --git a/server/util.go b/server/util.go index aed192675607..fbbb8b40b704 100644 --- a/server/util.go +++ b/server/util.go @@ -332,7 +332,7 @@ func interceptConfigs(rootViper *viper.Viper, customAppTemplate string, customCo } // AddCommands add server commands -func AddCommands[T types.Application, R Rollbackable](rootCmd *cobra.Command, appCreator types.AppCreator[T], rollbackable R, opts StartCmdOptions[T]) { +func AddCommands[T types.Application, R Rollback](rootCmd *cobra.Command, appCreator types.AppCreator[T], rollbackable R, opts StartCmdOptions[T]) { cometCmd := &cobra.Command{ Use: "comet", Aliases: []string{"cometbft", "tendermint"}, @@ -359,24 +359,9 @@ func AddCommands[T types.Application, R Rollbackable](rootCmd *cobra.Command, ap ) } -// DefaultRollbackable is a default implementation of the Rollbackable interface. -type DefaultRollbackable[T types.Application] struct { - appCreator types.AppCreator[T] -} - -// NewDefaultRollbackable creates a new DefaultRollbackable instance. -func NewDefaultRollbackable[T types.Application](appCreator types.AppCreator[T]) *DefaultRollbackable[T] { - return &DefaultRollbackable[T]{appCreator} -} - -// RollbackToVersion implements the Rollbackable interface. -func (d DefaultRollbackable[T]) RollbackToVersion(ctx *Context, removeBlock bool) (int64, []byte, error) { - return cmtcmd.RollbackState(ctx.Config, removeBlock) -} - // AddCommandsWithStartCmdOptions adds server commands with the provided StartCmdOptions. // Deprecated: Use AddCommands directly instead. -func AddCommandsWithStartCmdOptions[T types.Application, R Rollbackable](rootCmd *cobra.Command, appCreator types.AppCreator[T], rollbackable R, opts StartCmdOptions[T]) { +func AddCommandsWithStartCmdOptions[T types.Application, R Rollback](rootCmd *cobra.Command, appCreator types.AppCreator[T], rollbackable R, opts StartCmdOptions[T]) { AddCommands(rootCmd, appCreator, rollbackable, opts) } @@ -595,3 +580,25 @@ func GetSnapshotStore(appOpts types.AppOptions) (*snapshots.Store, error) { return snapshotStore, nil } + +// Rollbackable is an interface that allows for rollback operations. +// It is used to allow for custom rollback operations, such as those provided by the +// DefaultRollbackable implementation. +type Rollback interface { + RollbackToVersion(ctx *Context, removeBlock bool) (int64, []byte, error) +} + +// DefaultRollbackable is a default implementation of the Rollbackable interface. +type DefaultRollbackable[T types.Application] struct { + appCreator types.AppCreator[T] +} + +// NewDefaultRollbackable creates a new DefaultRollbackable instance. +func NewDefaultRollbackable[T types.Application](appCreator types.AppCreator[T]) *DefaultRollbackable[T] { + return &DefaultRollbackable[T]{appCreator} +} + +// RollbackToVersion implements the Rollbackable interface. +func (d DefaultRollbackable[T]) RollbackToVersion(ctx *Context, removeBlock bool) (int64, []byte, error) { + return cmtcmd.RollbackState(ctx.Config, removeBlock) +} From 104cbcccb5cb2da4339ef65168b6b4fc6031a3ad Mon Sep 17 00:00:00 2001 From: marbar3778 <marbar3778@yahoo.com> Date: Fri, 10 Jan 2025 16:11:33 +0100 Subject: [PATCH 3/4] different design --- CHANGELOG.md | 1 + server/rollback.go | 46 +++++++++++++++++++++++++++++++++++++++++++++- server/util.go | 2 +- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 37cb138cd5e3..8f84834882d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i * (sims) [#23013](https://github.com/cosmos/cosmos-sdk/pull/23013) Integration with app v2 * (x/auth/ante) [#23128](https://github.com/cosmos/cosmos-sdk/pull/23128) Allow custom verifyIsOnCurve when validate tx for public key like ethsecp256k1. +* (server) [#23128](https://github.com/cosmos/cosmos-sdk/pull/23128) Add custom rollback command option. In order to use it, you need to implement the Rollback interface and remove the default rollback command with `cmd.RemoveCommand(cmd.RollbackCmd)` and then add it back with `cmd.AddCommand(cmd.NewCustomRollbackCmd(appCreator, rollbackable))`. ### Improvements diff --git a/server/rollback.go b/server/rollback.go index ba486b4571af..cc6ed2ea8406 100644 --- a/server/rollback.go +++ b/server/rollback.go @@ -3,13 +3,57 @@ package server import ( "fmt" + cmtcmd "github.com/cometbft/cometbft/cmd/cometbft/commands" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/server/types" ) // NewRollbackCmd creates a command to rollback CometBFT and multistore state by one height. -func NewRollbackCmd[T types.Application, R Rollback](appCreator types.AppCreator[T], rollbackable R) *cobra.Command { +func NewRollbackCmd[T types.Application](appCreator types.AppCreator[T]) *cobra.Command { + var removeBlock bool + + cmd := &cobra.Command{ + Use: "rollback", + Short: "rollback Cosmos SDK and CometBFT state by one height", + Long: ` +A state rollback is performed to recover from an incorrect application state transition, +when CometBFT has persisted an incorrect app hash and is thus unable to make +progress. Rollback overwrites a state at height n with the state at height n - 1. +The application also rolls back to height n - 1. No blocks are removed, so upon +restarting CometBFT the transactions in block n will be re-executed against the +application. +`, + RunE: func(cmd *cobra.Command, args []string) error { + ctx := GetServerContextFromCmd(cmd) + + db, err := OpenDB(ctx.Config.RootDir, GetAppDBBackend(ctx.Viper)) + if err != nil { + return err + } + app := appCreator(ctx.Logger, db, nil, ctx.Viper) + // rollback CometBFT state + height, hash, err := cmtcmd.RollbackState(ctx.Config, removeBlock) + if err != nil { + return fmt.Errorf("failed to rollback CometBFT state: %w", err) + } + // rollback the multistore + + if err := app.CommitMultiStore().RollbackToVersion(height); err != nil { + return fmt.Errorf("failed to rollback to version: %w", err) + } + + fmt.Printf("Rolled back state to height %d and hash %X\n", height, hash) + return nil + }, + } + + cmd.Flags().BoolVar(&removeBlock, "hard", false, "remove last block as well as state") + return cmd +} + +// NewRollbackCmdRollback creates a command to set custom rollback functionality and multistore state by one height. +func NewRollbackCmdRollback[T types.Application, R Rollback](appCreator types.AppCreator[T], rollbackable R) *cobra.Command { var removeBlock bool cmd := &cobra.Command{ diff --git a/server/util.go b/server/util.go index fbbb8b40b704..0dea937c4abc 100644 --- a/server/util.go +++ b/server/util.go @@ -354,7 +354,7 @@ func AddCommands[T types.Application, R Rollback](rootCmd *cobra.Command, appCre startCmd, cometCmd, version.NewVersionCommand(), - NewRollbackCmd(appCreator, rollbackable), + NewRollbackCmd(appCreator), ModuleHashByHeightQuery(appCreator), ) } From 063bae10345be4b0f9a54255a5cf0bde2420e294 Mon Sep 17 00:00:00 2001 From: Julien Robert <julien@rbrt.fr> Date: Tue, 14 Jan 2025 09:18:32 +0100 Subject: [PATCH 4/4] revert api breaks --- server/util.go | 6 +++--- simapp/simd/cmd/commands.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/util.go b/server/util.go index 0dea937c4abc..052614142e80 100644 --- a/server/util.go +++ b/server/util.go @@ -332,7 +332,7 @@ func interceptConfigs(rootViper *viper.Viper, customAppTemplate string, customCo } // AddCommands add server commands -func AddCommands[T types.Application, R Rollback](rootCmd *cobra.Command, appCreator types.AppCreator[T], rollbackable R, opts StartCmdOptions[T]) { +func AddCommands[T types.Application](rootCmd *cobra.Command, appCreator types.AppCreator[T], opts StartCmdOptions[T]) { cometCmd := &cobra.Command{ Use: "comet", Aliases: []string{"cometbft", "tendermint"}, @@ -361,8 +361,8 @@ func AddCommands[T types.Application, R Rollback](rootCmd *cobra.Command, appCre // AddCommandsWithStartCmdOptions adds server commands with the provided StartCmdOptions. // Deprecated: Use AddCommands directly instead. -func AddCommandsWithStartCmdOptions[T types.Application, R Rollback](rootCmd *cobra.Command, appCreator types.AppCreator[T], rollbackable R, opts StartCmdOptions[T]) { - AddCommands(rootCmd, appCreator, rollbackable, opts) +func AddCommandsWithStartCmdOptions[T types.Application](rootCmd *cobra.Command, appCreator types.AppCreator[T], opts StartCmdOptions[T]) { + AddCommands(rootCmd, appCreator, opts) } // AddTestnetCreatorCommand allows chains to create a testnet from the state existing in their node's data directory. diff --git a/simapp/simd/cmd/commands.go b/simapp/simd/cmd/commands.go index 11792e544c7e..2b6e1a9032af 100644 --- a/simapp/simd/cmd/commands.go +++ b/simapp/simd/cmd/commands.go @@ -45,7 +45,7 @@ func initRootCmd( snapshot.Cmd(newApp), ) - server.AddCommands(rootCmd, newApp, server.NewDefaultRollbackable(newApp), server.StartCmdOptions[servertypes.Application]{}) + server.AddCommands(rootCmd, newApp, server.StartCmdOptions[servertypes.Application]{}) // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand(