Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add missing rollback command #23618

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/rfc/rfc-003-crosslang.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
The Cosmos SDK has historically been a Golang only framework for building blockchain applications.
However, discussions about supporting additional programming languages and virtual machine environments
have been underway since early 2023. Recently, we have identified the following key target user groups:
Recently we have identified the following key target user groups:

1. projects that want to primarily target a single programming language and virtual machine environment besides Golang but who still want to use Cosmos SDK internals for consensus and storage
2. projects that want to integrate multiple programming languages and virtual machine environments into an integrated application

Expand Down Expand Up @@ -170,7 +170,7 @@ for nesting transactions.

**Volatility** describes a message handler's behavior with respect to state and side effects.
It is an enum value that can have one of the following values:
* `volatile`: the handler can have side effects and send `volatile`, `radonly` or `pure` messages to other accounts. Such handlers are expected to both read and write state.
* `volatile`: the handler can have side effects and send `volatile`, `readonly` or `pure` messages to other accounts. Such handlers are expected to both read and write state.
* `readonly`: the handler cannot cause effects side effects and can only send `readonly` or `pure` messages to other accounts. Such handlers are expected to only read state.
* `pure`: the handler cannot cause any side effects and can only call other pure handlers. Such handlers are expected to neither read nor write state.

Expand Down
2 changes: 2 additions & 0 deletions server/v2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Each entry must include the Github issue reference in the following format:

## [Unreleased]

* [#23618](https://github.com/cosmos/cosmos-sdk/pull/23618) Add rollback command

* [#23486](https://github.com/cosmos/cosmos-sdk/pull/23486) Add `server/v2/api/swagger` server component.

## [v2.0.0-beta.2](https://github.com/cosmos/cosmos-sdk/releases/tag/server/v2.0.0-beta.2)
Expand Down
36 changes: 36 additions & 0 deletions server/v2/cometbft/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strconv"
"strings"

cmtcmd "github.com/cometbft/cometbft/cmd/cometbft/commands"
cmtcfg "github.com/cometbft/cometbft/config"
cmtjson "github.com/cometbft/cometbft/libs/json"
"github.com/cometbft/cometbft/node"
Expand Down Expand Up @@ -433,3 +434,38 @@ func printOutput(cmd *cobra.Command, out []byte) error {
}
return nil
}

func (s *CometBFTServer[T]) RollbackStateCmd() *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 {
cfg := client.GetConfigFromCmd(cmd)
// rollback CometBFT state
height, hash, err := cmtcmd.RollbackState(cfg, removeBlock)
if err != nil {
return fmt.Errorf("failed to rollback CometBFT state: %w", err)
}
// rollback the store
// if err := s.store.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
}
Comment on lines +437 to +471
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Rollback logic is incomplete.
The code’s description (“rollback Cosmos SDK and CometBFT state”) contradicts the fact that the application store rollback is commented out. This can lead to inconsistencies where CometBFT state is rolled back, but the Cosmos SDK application state remains at the newer height. Please either remove the lines referencing application rollback from the description or fully implement the store rollback to avoid leaving the system in a partially rolled-back state.

Below is a possible fix to re-enable the store rollback. Adjust as needed to ensure full coordination between CometBFT and Cosmos SDK state:

- // if err :=  s.store.RollbackToVersion(height); err != nil {
- //   return fmt.Errorf("failed to rollback to version: %w", err)
- // }
+ if err := s.store.RollbackToVersion(height); err != nil {
+   return fmt.Errorf("failed to rollback to version: %w", err)
+ }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (s *CometBFTServer[T]) RollbackStateCmd() *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 {
cfg := client.GetConfigFromCmd(cmd)
// rollback CometBFT state
height, hash, err := cmtcmd.RollbackState(cfg, removeBlock)
if err != nil {
return fmt.Errorf("failed to rollback CometBFT state: %w", err)
}
// rollback the store
// if err := s.store.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
}
func (s *CometBFTServer[T]) RollbackStateCmd() *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 {
cfg := client.GetConfigFromCmd(cmd)
// rollback CometBFT state
height, hash, err := cmtcmd.RollbackState(cfg, removeBlock)
if err != nil {
return fmt.Errorf("failed to rollback CometBFT state: %w", err)
}
// rollback the store
if err := s.store.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
}

1 change: 1 addition & 0 deletions server/v2/cometbft/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ func (s *CometBFTServer[T]) CLICommands() serverv2.CLIConfig {
s.BootstrapStateCmd(),
cmtcmd.ResetAllCmd,
cmtcmd.ResetStateCmd,
s.RollbackStateCmd(),
},
Queries: []*cobra.Command{
QueryBlockCmd(),
Expand Down
Loading