Skip to content

Commit

Permalink
feat(cmd): one block rollback (piplabs#157)
Browse files Browse the repository at this point in the history
add cometBFT's one block rollback cmd
  • Loading branch information
zsystm authored and leeren committed Oct 10, 2024
1 parent e5269dc commit edcea73
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 0 deletions.
44 changes: 44 additions & 0 deletions client/app/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,50 @@ func Start(ctx context.Context, cfg Config) (func(context.Context) error, error)
}, nil
}

// TODO: Refactor CreateApp() to be used within the Start function, as most of the code originates from there.
func CreateApp(ctx context.Context, cfg Config) *App {
privVal, err := loadPrivVal(cfg)
if err != nil {
panic(errors.Wrap(err, "load validator key"))
}

db, err := dbm.NewDB("application", cfg.BackendType(), cfg.DataDir())
if err != nil {
panic(errors.Wrap(err, "create db"))
}

baseAppOpts, err := makeBaseAppOpts(cfg)
if err != nil {
panic(errors.Wrap(err, "make base app opts"))
}

engineCl, err := newEngineClient(ctx, cfg)
if err != nil {
panic(err)
}

//nolint:contextcheck // False positive
app, err := newApp(
newSDKLogger(ctx),
db,
engineCl,
baseAppOpts...,
)
if err != nil {
panic(errors.Wrap(err, "create app"))
}
app.Keepers.EVMEngKeeper.SetBuildDelay(cfg.EVMBuildDelay)
app.Keepers.EVMEngKeeper.SetBuildOptimistic(cfg.EVMBuildOptimistic)

addr, err := k1util.PubKeyToAddress(privVal.Key.PrivKey.PubKey())
if err != nil {
panic(errors.Wrap(err, "convert validator pubkey to address"))
}
app.Keepers.EVMEngKeeper.SetValidatorAddress(addr)

return app
}

func newCometNode(ctx context.Context, cfg *cmtcfg.Config, app *App, privVal cmttypes.PrivValidator,
) (*node.Node, error) {
nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile())
Expand Down
60 changes: 60 additions & 0 deletions client/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package cmd

import (
"context"
"fmt"

cmtcmd "github.com/cometbft/cometbft/cmd/cometbft/commands"
"github.com/spf13/cobra"

"github.com/piplabs/story/client/app"
storycfg "github.com/piplabs/story/client/config"
"github.com/piplabs/story/lib/buildinfo"
libcmd "github.com/piplabs/story/lib/cmd"
"github.com/piplabs/story/lib/errors"
"github.com/piplabs/story/lib/log"
)

Expand All @@ -23,6 +26,7 @@ func New() *cobra.Command {
buildinfo.NewVersionCmd(),
newValidatorCmds(),
newStatusCmd(),
newRollbackCmd(app.CreateApp),
)
}

Expand Down Expand Up @@ -60,3 +64,59 @@ func newRunCmd(name string, runFunc func(context.Context, app.Config) error) *co

return cmd
}

// newRollbackCmd returns a new cobra command that rolls back one block of the story consensus client.
func newRollbackCmd(appCreateFunc func(context.Context, app.Config) *app.App) *cobra.Command {
storyCfg := storycfg.DefaultConfig()
logCfg := log.DefaultConfig()

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, _ []string) error {
ctx, err := log.Init(cmd.Context(), logCfg)
if err != nil {
return err
}
if err := libcmd.LogFlags(ctx, cmd.Flags()); err != nil {
return err
}

cometCfg, err := parseCometConfig(ctx, storyCfg.HomeDir)
if err != nil {
return err
}

app := appCreateFunc(ctx, app.Config{
Config: storyCfg,
Comet: cometCfg,
})
height, hash, err := cmtcmd.RollbackState(&cometCfg, storyCfg.RemoveBlock)
if err != nil {
return errors.Wrap(err, "failed to rollback CometBFT state")
}

if err = app.CommitMultiStore().RollbackToVersion(height); err != nil {
return errors.Wrap(err, "failed to rollback to version")
}

fmt.Printf("Rolled back state to height %d and hash %X", height, hash)

return nil
},
}

bindRunFlags(cmd, &storyCfg)
bindRollbackFlags(cmd, &storyCfg)
log.BindFlags(cmd.Flags(), &logCfg)

return cmd
}
4 changes: 4 additions & 0 deletions client/cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ func bindStatusFlags(flags *pflag.FlagSet, cfg *StatusConfig) {
libcmd.BindHomeFlag(flags, &cfg.HomeDir)
}

func bindRollbackFlags(cmd *cobra.Command, cfg *config.Config) {
cmd.Flags().BoolVar(&cfg.RemoveBlock, "hard", false, "remove last block as well as state")
}

// Flag Validation

func validateFlags(flags map[string]string) error {
Expand Down
1 change: 1 addition & 0 deletions client/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ type Config struct {
ExternalAddress string
Seeds string
SeedMode bool
RemoveBlock bool // See cosmos-sdk/server/rollback.go
}

// ConfigFile returns the default path to the toml story config file.
Expand Down

0 comments on commit edcea73

Please sign in to comment.