Skip to content

Commit

Permalink
feat: add local snapshots management commands
Browse files Browse the repository at this point in the history
- `appd snapshots list`
  list local snapshots
- `appd snapshots restore`
  restore from a local snapshot
  • Loading branch information
yihuang committed May 9, 2023
1 parent 2f21cb5 commit 50fb51f
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/bank) [#15764](https://github.com/cosmos/cosmos-sdk/pull/15764) Speedup x/bank InitGenesis
* (x/auth) [#15867](https://github.com/cosmos/cosmos-sdk/pull/15867) Support better logging for signature verification failure.
* (types/query) [#16041](https://github.com/cosmos/cosmos-sdk/pull/16041) change pagination max limit to a variable in order to be modifed by application devs
* (store) [#]() Add local snapshots management commands.

### State Machine Breaking

Expand Down
20 changes: 20 additions & 0 deletions client/snapshot/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package snapshot

import (
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/spf13/cobra"
)

// Cmd returns the snapshots group command
func Cmd(appCreator servertypes.AppCreator) *cobra.Command {
cmd := &cobra.Command{
Use: "snapshots",
Short: "Manage local snapshots",
Long: "Manage local snapshots",
}
cmd.AddCommand(
ListSnapshotsCmd(appCreator),
RestoreSnapshotCmd(appCreator),
)
return cmd
}
34 changes: 34 additions & 0 deletions client/snapshot/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package snapshot

import (
"fmt"

"github.com/cosmos/cosmos-sdk/server"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/spf13/cobra"
)

// ListSnapshotsCmd returns the command to list local snapshots
func ListSnapshotsCmd(appCreator servertypes.AppCreator) *cobra.Command {
return &cobra.Command{
Use: "list",
Short: "List snapshots",
Long: "List snapshots",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := server.GetServerContextFromCmd(cmd)
snapshotStore, err := server.GetSnapshotStore(ctx.Viper)
if err != nil {
return err
}
snapshots, err := snapshotStore.List()
if err != nil {
return fmt.Errorf("failed to list snapshots: %w", err)
}
for _, snapshot := range snapshots {
fmt.Println("height:", snapshot.Height, "format:", snapshot.Format, "chunks:", snapshot.Chunks)
}

return nil
},
}
}
51 changes: 51 additions & 0 deletions client/snapshot/restore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package snapshot

import (
"path/filepath"
"strconv"

"cosmossdk.io/log"
"github.com/spf13/cobra"

dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/cosmos-sdk/server"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
)

// RestoreSnapshotCmd returns a command to restore a snapshot
func RestoreSnapshotCmd(appCreator servertypes.AppCreator) *cobra.Command {
cmd := &cobra.Command{
Use: "restore <height> <format>",
Short: "Restore app state from local snapshot",
Long: "Restore app state from local snapshot",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := server.GetServerContextFromCmd(cmd)

height, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
format, err := strconv.ParseUint(args[1], 10, 32)
if err != nil {
return err
}

home := ctx.Config.RootDir
db, err := openDB(home, server.GetAppDBBackend(ctx.Viper))
if err != nil {
return err
}
logger := log.NewLogger(cmd.OutOrStdout())
app := appCreator(logger, db, nil, ctx.Viper)

sm := app.SnapshotManager()
return sm.RestoreLocalSnapshot(height, uint32(format))
},
}
return cmd
}

func openDB(rootDir string, backendType dbm.BackendType) (dbm.DB, error) {
dataDir := filepath.Join(rootDir, "data")
return dbm.NewDB("application", backendType, dataDir)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ require (
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect
Expand Down
3 changes: 2 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -636,8 +636,9 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
Expand Down
4 changes: 4 additions & 0 deletions server/types/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io"

"cosmossdk.io/log"
"cosmossdk.io/store/snapshots"
storetypes "cosmossdk.io/store/types"
abci "github.com/cometbft/cometbft/abci/types"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
Expand Down Expand Up @@ -54,6 +55,9 @@ type (

// CommitMultiStore return the multistore instance
CommitMultiStore() storetypes.CommitMultiStore

// Return the snapshot manager
SnapshotManager() *snapshots.Manager
}

// AppCreator is a function that allows us to lazily initialize an
Expand Down
30 changes: 20 additions & 10 deletions server/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,16 +468,7 @@ func DefaultBaseappOptions(appOpts types.AppOptions) []func(*baseapp.BaseApp) {
chainID = appGenesis.ChainID
}

snapshotDir := filepath.Join(homeDir, "data", "snapshots")
if err = os.MkdirAll(snapshotDir, os.ModePerm); err != nil {
panic(fmt.Errorf("failed to create snapshots directory: %w", err))
}

snapshotDB, err := dbm.NewDB("metadata", GetAppDBBackend(appOpts), snapshotDir)
if err != nil {
panic(err)
}
snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir)
snapshotStore, err := GetSnapshotStore(appOpts)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -508,3 +499,22 @@ func DefaultBaseappOptions(appOpts types.AppOptions) []func(*baseapp.BaseApp) {
baseapp.SetChainID(chainID),
}
}

func GetSnapshotStore(appOpts types.AppOptions) (*snapshots.Store, error) {
homeDir := cast.ToString(appOpts.Get(flags.FlagHome))
snapshotDir := filepath.Join(homeDir, "data", "snapshots")
if err := os.MkdirAll(snapshotDir, os.ModePerm); err != nil {
return nil, fmt.Errorf("failed to create snapshots directory: %w", err)
}

snapshotDB, err := dbm.NewDB("metadata", GetAppDBBackend(appOpts), snapshotDir)
if err != nil {
return nil, err
}
snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir)
if err != nil {
return nil, err
}

return snapshotStore, nil
}
2 changes: 2 additions & 0 deletions simapp/simd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/pruning"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/snapshot"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
Expand Down Expand Up @@ -191,6 +192,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig, b
debug.Cmd(),
confixcmd.ConfigCommand(),
pruning.Cmd(newApp),
snapshot.Cmd(newApp),
)

server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, appExport, addModuleInitFlags)
Expand Down
2 changes: 2 additions & 0 deletions simapp/simd/cmd/root_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/pruning"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/snapshot"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/server"
Expand Down Expand Up @@ -207,6 +208,7 @@ func initRootCmd(
debug.Cmd(),
confixcmd.ConfigCommand(),
pruning.Cmd(newApp),
snapshot.Cmd(newApp),
)

server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, appExport, addModuleInitFlags)
Expand Down
9 changes: 9 additions & 0 deletions store/snapshots/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,15 @@ func (m *Manager) RestoreChunk(chunk []byte) (bool, error) {
return false, nil
}

// RestoreLocalSnapshot restores app state from a local snapshot.
func (m *Manager) RestoreLocalSnapshot(height uint64, format uint32) error {
snapshot, ch, err := m.store.Load(height, format)
if err != nil {
return err
}
return m.restoreSnapshot(*snapshot, ch)
}

// sortedExtensionNames sort extension names for deterministic iteration.
func (m *Manager) sortedExtensionNames() []string {
names := make([]string, 0, len(m.extensions))
Expand Down

0 comments on commit 50fb51f

Please sign in to comment.