Skip to content

Commit

Permalink
Support for snapshots export command (#9563)
Browse files Browse the repository at this point in the history
closes: #9100 
closes: #9425

## Description
Until we have better layering of the snapshots extensions in cosmos-sdk, this replaces the implementation of the `snapshots export` command to initiate the snapshot creation through our front-running mechanism used for state-sync.

Drive-by cleanup of the root command as well to address #9425

### Security Considerations
None,

### Scaling Considerations
None

### Documentation Considerations
Communicate to validators that we fixed the command and that it's usable as expected with any cosmos chain.

### Testing Considerations
Added an integration test since this only modifies the command line handling

Manually tested with the following
```
cd packages/cosmic-swingset
make scenario2-setup
make scenario2-run-chain
# wait until there are blocks, then kill
agd --home t1/n0 snapshots export
rm -rf t1/n0/data/application.db t1/n0/data/agoric
# the above removes app state without removing cometbft state as that cannot
# be restored easily in a single node chain
agd --home t1/n0 snapshot restore $snapshot_height 2
make scenario2-run-chain
# verify blocks are being produced
```

### Upgrade Considerations
Since we replace the upstream sdk command handling, any future changes upstream would have to be reflected in the override.
  • Loading branch information
mergify[bot] authored and mhofman committed Jun 23, 2024
2 parents a56e3ae + 99e83af commit b385872
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
diff --git a/dist/upgrade-test-scripts/env_setup.sh b/dist/upgrade-test-scripts/env_setup.sh
index 617a0fbe7efdfa457e28fc52806dba1b323930d8..25f52a6cf133dca830bd0dcd47c91700e6a8effe 100755
--- a/dist/upgrade-test-scripts/env_setup.sh
+++ b/dist/upgrade-test-scripts/env_setup.sh
@@ -100,7 +100,7 @@ killAgd() {
AGD_PID=$(cat $HOME/.agoric/agd.pid)
kill $AGD_PID
rm $HOME/.agoric/agd.pid
- wait $AGD_PID || true
+ tail --pid=$AGD_PID -f /dev/null || true
}

provisionSmartWallet() {
2 changes: 1 addition & 1 deletion a3p-integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"doctor": "yarn synthetic-chain doctor"
},
"dependencies": {
"@agoric/synthetic-chain": "^0.1.0",
"@agoric/synthetic-chain": "patch:@agoric/synthetic-chain@npm%3A0.1.0#~/.yarn/patches/@agoric-synthetic-chain-npm-0.1.0-148de716a6.patch",
"@types/better-sqlite3": "^7.6.9"
},
"packageManager": "yarn@4.2.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

source /usr/src/upgrade-test-scripts/env_setup.sh

set -e

killAgd
agd snapshots export
SNAPSHOT_DETAILS=$(agd snapshots list | head -n1 | sed -E 's/height: ([0-9]+) format: ([0-9]+) chunks: [0-9]+/\1 \2/')
echo found snapshot $SNAPSHOT_DETAILS
rm -rf /root/.agoric/data/application.db /root/.agoric/data/agoric
agd snapshots restore $SNAPSHOT_DETAILS

startAgd
2 changes: 2 additions & 0 deletions a3p-integration/proposals/z:acceptance/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ GLOBIGNORE=initial.test.js
yarn ava ./*.test.js

./create-kread-item-test.sh

./state-sync-snapshots-test.sh
18 changes: 16 additions & 2 deletions a3p-integration/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ __metadata:
version: 8
cacheKey: 10c0

"@agoric/synthetic-chain@npm:^0.1.0":
"@agoric/synthetic-chain@npm:0.1.0":
version: 0.1.0
resolution: "@agoric/synthetic-chain@npm:0.1.0"
dependencies:
Expand All @@ -19,6 +19,20 @@ __metadata:
languageName: node
linkType: hard

"@agoric/synthetic-chain@patch:@agoric/synthetic-chain@npm%3A0.1.0#~/.yarn/patches/@agoric-synthetic-chain-npm-0.1.0-148de716a6.patch":
version: 0.1.0
resolution: "@agoric/synthetic-chain@patch:@agoric/synthetic-chain@npm%3A0.1.0#~/.yarn/patches/@agoric-synthetic-chain-npm-0.1.0-148de716a6.patch::version=0.1.0&hash=4a65eb"
dependencies:
"@endo/zip": "npm:^1.0.1"
better-sqlite3: "npm:^9.4.0"
chalk: "npm:^5.3.0"
execa: "npm:^8.0.1"
bin:
synthetic-chain: dist/cli/cli.js
checksum: 10c0/e974038161b1a9570912a02d9366c6680bc13ee3dfd0e49d06e5ce5e93dbcddf04d1d4cd453af0969bf29ccfe96ce3e141a214539722449add90b13f0785f1f7
languageName: node
linkType: hard

"@endo/zip@npm:^1.0.1":
version: 1.0.1
resolution: "@endo/zip@npm:1.0.1"
Expand Down Expand Up @@ -990,7 +1004,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "root-workspace-0b6124@workspace:."
dependencies:
"@agoric/synthetic-chain": "npm:^0.1.0"
"@agoric/synthetic-chain": "patch:@agoric/synthetic-chain@npm%3A0.1.0#~/.yarn/patches/@agoric-synthetic-chain-npm-0.1.0-148de716a6.patch"
"@types/better-sqlite3": "npm:^7.6.9"
languageName: unknown
linkType: soft
Expand Down
147 changes: 103 additions & 44 deletions golang/cosmos/daemon/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

serverconfig "github.com/cosmos/cosmos-sdk/server/config"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/client/debug"
Expand All @@ -19,9 +18,6 @@ import (
"github.com/cosmos/cosmos-sdk/client/snapshot"
"github.com/cosmos/cosmos-sdk/server"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/snapshots"
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/auth/types"
Expand All @@ -39,6 +35,7 @@ import (
gaia "github.com/Agoric/agoric-sdk/golang/cosmos/app"
"github.com/Agoric/agoric-sdk/golang/cosmos/app/params"
"github.com/Agoric/agoric-sdk/golang/cosmos/vm"
swingsetkeeper "github.com/Agoric/agoric-sdk/golang/cosmos/x/swingset/keeper"
)

var AppName = "agd"
Expand Down Expand Up @@ -142,16 +139,27 @@ func initRootCmd(sender vm.Sender, rootCmd *cobra.Command, encodingConfig params
testnetCmd(gaia.ModuleBasics, banktypes.GenesisBalancesIterator{}),
debug.Cmd(),
config.Cmd(),
pruning.Cmd(ac.newApp, gaia.DefaultNodeHome),
snapshot.Cmd(ac.newApp),
pruning.Cmd(ac.newSnapshotsApp, gaia.DefaultNodeHome),
snapshot.Cmd(ac.newSnapshotsApp),
)

server.AddCommands(rootCmd, gaia.DefaultNodeHome, ac.newApp, ac.appExport, addModuleInitFlags)

for _, command := range rootCmd.Commands() {
if command.Name() == "export" {
switch command.Name() {
case "export":
addAgoricVMFlags(command)
extendCosmosExportCommand(command)
break
case "snapshots":
for _, subCommand := range command.Commands() {
switch subCommand.Name() {
case "restore":
addAgoricVMFlags(subCommand)
case "export":
addAgoricVMFlags(subCommand)
replaceCosmosSnapshotExportCommand(subCommand, ac)
}
}
}
}

Expand Down Expand Up @@ -264,22 +272,13 @@ func (ac appCreator) newApp(
}
}

var cache sdk.MultiStorePersistentCache

if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) {
cache = store.NewCommitKVStoreCacheManager()
}
baseappOptions := server.DefaultBaseappOptions(appOpts)

skipUpgradeHeights := make(map[int64]bool)
for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) {
skipUpgradeHeights[int64(h)] = true
}

pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts)
if err != nil {
panic(err)
}

homePath := cast.ToString(appOpts.Get(flags.FlagHome))

// Set a default value for FlagSwingStoreExportDir based on the homePath
Expand All @@ -289,39 +288,41 @@ func (ac appCreator) newApp(
viper.Set(gaia.FlagSwingStoreExportDir, filepath.Join(homePath, "config", ExportedSwingStoreDirectoryName))
}

snapshotDir := filepath.Join(homePath, "data", "snapshots")
snapshotDB, err := dbm.NewDB("metadata", dbm.GoLevelDBBackend, snapshotDir)
if err != nil {
panic(err)
}
snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir)
if err != nil {
panic(err)
}
snapshotOptions := snapshottypes.NewSnapshotOptions(
cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval)),
cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent)),
return gaia.NewAgoricApp(
ac.sender, ac.agdServer,
logger, db, traceStore, true, skipUpgradeHeights,
homePath,
cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)),
ac.encCfg,
appOpts,
baseappOptions...,
)
}

func (ac appCreator) newSnapshotsApp(
logger log.Logger,
db dbm.DB,
traceStore io.Writer,
appOpts servertypes.AppOptions,
) servertypes.Application {
if OnExportHook != nil {
if err := OnExportHook(ac.agdServer, logger, appOpts); err != nil {
panic(err)
}
}

baseappOptions := server.DefaultBaseappOptions(appOpts)

homePath := cast.ToString(appOpts.Get(flags.FlagHome))

return gaia.NewAgoricApp(
ac.sender, ac.agdServer,
logger, db, traceStore, true, skipUpgradeHeights,
logger, db, traceStore, true, map[int64]bool{},
homePath,
cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)),
ac.encCfg,
appOpts,
baseapp.SetPruning(pruningOpts),
baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))),
baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))),
baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))),
baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))),
baseapp.SetInterBlockCache(cache),
baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))),
baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))),
baseapp.SetSnapshot(snapshotStore, snapshotOptions),
baseapp.SetIAVLCacheSize(cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize))),
baseapp.SetIAVLDisableFastNode(cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))),
baseapp.SetIAVLLazyLoading(cast.ToBool(appOpts.Get(server.FlagIAVLLazyLoading))),
baseappOptions...,
)
}

Expand All @@ -342,7 +343,6 @@ const (
// cosmos-sdk to add a required "export-dir" command-line flag, and create the
// genesis export in the specified directory if the VM is running.
func extendCosmosExportCommand(cmd *cobra.Command) {
addAgoricVMFlags(cmd)
cmd.Flags().String(FlagExportDir, "", "The directory where to create the genesis export")
err := cmd.MarkFlagRequired(FlagExportDir)
if err != nil {
Expand Down Expand Up @@ -443,3 +443,62 @@ func (ac appCreator) appExport(

return gaiaApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs)
}

// replaceCosmosSnapshotExportCommand monkey-patches the "snapshots export" command
// added by cosmos-sdk and replaces its implementation with one suitable for
// our modifications to the cosmos snapshots process
func replaceCosmosSnapshotExportCommand(cmd *cobra.Command, ac appCreator) {
// Copy of RunE is cosmos-sdk/client/snapshot/export.go
replacedRunE := func(cmd *cobra.Command, args []string) error {
ctx := server.GetServerContextFromCmd(cmd)

height, err := cmd.Flags().GetInt64("height")
if err != nil {
return err
}

home := ctx.Config.RootDir
dataDir := filepath.Join(home, "data")
db, err := dbm.NewDB("application", server.GetAppDBBackend(ctx.Viper), dataDir)
if err != nil {
return err
}

app := ac.newSnapshotsApp(ctx.Logger, db, nil, ctx.Viper)
gaiaApp := app.(*gaia.GaiaApp)

if height == 0 {
height = app.CommitMultiStore().LastCommitID().Version
}

cmd.Printf("Exporting snapshot for height %d\n", height)

err = gaiaApp.SwingSetSnapshotter.InitiateSnapshot(height)
if err != nil {
return err
}

err = swingsetkeeper.WaitUntilSwingStoreExportDone()
if err != nil {
return err
}

snapshotList, err := app.SnapshotManager().List()
if err != nil {
return err
}

snapshotHeight := uint64(height)

for _, snapshot := range snapshotList {
if snapshot.Height == snapshotHeight {
cmd.Printf("Snapshot created at height %d, format %d, chunks %d\n", snapshot.Height, snapshot.Format, snapshot.Chunks)
break
}
}

return nil
}

cmd.RunE = replacedRunE
}

0 comments on commit b385872

Please sign in to comment.