diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 9c7eb51809..fe47826896 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -119,6 +119,9 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci } // custom logic for export -func (app *GaiaApp) ExportStake() stake.GenesisState { - return app.stakeKeeper.WriteGenesis(app.NewContext(true, abci.Header{})) +func (app *GaiaApp) ExportGenesis() GenesisState { + return GenesisState{ + Accounts: []GenesisAccount{}, + StakeData: app.stakeKeeper.WriteGenesis(app.NewContext(true, abci.Header{})), + } } diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index ca9b72cdf2..36b7099523 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -12,8 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/server" - stake "github.com/cosmos/cosmos-sdk/x/stake" - stakecmd "github.com/cosmos/cosmos-sdk/x/stake/commands" + "github.com/cosmos/cosmos-sdk/wire" ) func main() { @@ -26,6 +25,7 @@ func main() { } server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), generateApp) + server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), generateApp, exportApp) // prepare and add flags executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome) @@ -41,3 +41,16 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { bapp := app.NewGaiaApp(logger, db) return bapp, nil } + +func exportApp(rootDir string, logger log.Logger) (interface{}, *wire.Codec, error) { + dataDir := filepath.Join(rootDir, "data") + db, err := dbm.NewGoLevelDB("gaia", dataDir) + if err != nil { + return nil, nil, err + } + bapp := app.NewGaiaApp(log.NewNopLogger(), db) + if err != nil { + return nil, nil, err + } + return bapp.ExportGenesis(), app.MakeCodec(), nil +} diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index a1ec9a38bf..c85ff44413 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -119,3 +119,8 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) } return abci.ResponseInitChain{} } + +// Custom logic for state export +func (app *BasecoinApp) ExportGenesis() types.GenesisState { + return types.GenesisState{} +} diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 8d14821c6a..5a165735ef 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/examples/basecoin/app" "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/wire" ) func main() { @@ -25,7 +26,7 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, generateApp) + server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, generateApp, exportApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.basecoind") @@ -42,3 +43,13 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { bapp := app.NewBasecoinApp(logger, db) return bapp, nil } + +func exportApp(rootDir string, logger log.Logger) (interface{}, *wire.Codec, error) { + dataDir := filepath.Join(rootDir, "data") + db, err := dbm.NewGoLevelDB("basecoin", dataDir) + if err != nil { + return nil, nil, err + } + bapp := app.NewBasecoinApp(logger, db) + return bapp.ExportGenesis(), nil, nil +} diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index aabd4c41c5..516e3b6755 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -36,6 +36,9 @@ type DemocoinApp struct { capKeyIBCStore *sdk.KVStoreKey capKeyStakingStore *sdk.KVStoreKey + // keepers + powKeeper pow.Keeper + // Manage getting and setting accounts accountMapper sdk.AccountMapper } @@ -66,19 +69,19 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { // Add handlers. coinKeeper := bank.NewKeeper(app.accountMapper) coolKeeper := cool.NewKeeper(app.capKeyMainStore, coinKeeper, app.RegisterCodespace(cool.DefaultCodespace)) - powKeeper := pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), coinKeeper, app.RegisterCodespace(pow.DefaultCodespace)) + app.powKeeper = pow.NewKeeper(app.capKeyPowStore, pow.NewConfig("pow", int64(1)), coinKeeper, app.RegisterCodespace(pow.DefaultCodespace)) ibcMapper := ibc.NewMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace)) stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper, app.RegisterCodespace(simplestake.DefaultCodespace)) app.Router(). AddRoute("bank", bank.NewHandler(coinKeeper)). AddRoute("cool", cool.NewHandler(coolKeeper)). - AddRoute("pow", powKeeper.Handler). + AddRoute("pow", app.powKeeper.Handler). AddRoute("sketchy", sketchy.NewHandler()). AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper)). AddRoute("simplestake", simplestake.NewHandler(stakeKeeper)) // Initialize BaseApp. - app.SetInitChainer(app.initChainerFn(coolKeeper, powKeeper)) + app.SetInitChainer(app.initChainerFn(coolKeeper, app.powKeeper)) app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyPowStore, app.capKeyIBCStore, app.capKeyStakingStore) app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.BurnFeeHandler)) err := app.LoadLatestVersion(app.capKeyMainStore) @@ -142,3 +145,13 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep return abci.ResponseInitChain{} } } + +// Custom logic for state export +func (app *DemocoinApp) ExportGenesis() types.GenesisState { + ctx := app.NewContext(true, abci.Header{}) + return types.GenesisState{ + Accounts: []*types.GenesisAccount{}, + POWGenesis: app.powKeeper.WriteGenesis(ctx), + CoolGenesis: cool.Genesis{}, + } +} diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index afca80bce3..738420e8de 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -32,6 +32,12 @@ func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso key := "cool" value := json.RawMessage(`{ "trend": "ice-cold" + }`) + appState, err = server.AppendJSON(cdc, appState, key, value) + key = "pow" + value = json.RawMessage(`{ + "difficulty": 1, + "count": 0 }`) appState, err = server.AppendJSON(cdc, appState, key, value) return @@ -46,6 +52,16 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { return bapp, nil } +func exportApp(rootDir string, logger log.Logger) (interface{}, *wire.Codec, error) { + dataDir := filepath.Join(rootDir, "data") + db, err := dbm.NewGoLevelDB("democoin", dataDir) + if err != nil { + return nil, nil, err + } + bapp := app.NewDemocoinApp(logger, db) + return bapp.ExportGenesis(), nil, nil +} + func main() { cdc := app.MakeCodec() ctx := server.NewDefaultContext() @@ -56,7 +72,7 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - server.AddCommands(ctx, cdc, rootCmd, CoolAppInit, generateApp) + server.AddCommands(ctx, cdc, rootCmd, CoolAppInit, generateApp, exportApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.democoind") diff --git a/server/export.go b/server/export.go new file mode 100644 index 0000000000..9430eeb48a --- /dev/null +++ b/server/export.go @@ -0,0 +1,48 @@ +package server + +import ( + "fmt" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/tendermint/tmlibs/log" + + "github.com/cosmos/cosmos-sdk/wire" +) + +// AppExporter dumps all app state to JSON-serializable structure +type AppExporter func(home string, log log.Logger) (interface{}, *wire.Codec, error) + +// ExportCmd dumps app state to JSON +func ExportCmd(app AppExporter, ctx *Context) *cobra.Command { + export := exportCmd{ + appExporter: app, + context: ctx, + } + cmd := &cobra.Command{ + Use: "export", + Short: "Export state to JSON", + RunE: export.run, + } + return cmd +} + +type exportCmd struct { + appExporter AppExporter + context *Context +} + +func (e exportCmd) run(cmd *cobra.Command, args []string) error { + home := viper.GetString("home") + genesis, cdc, err := e.appExporter(home, e.context.Logger) + if err != nil { + return errors.Errorf("Error exporting state: %v\n", err) + } + output, err := wire.MarshalJSONIndent(cdc, genesis) + if err != nil { + return errors.Errorf("Error marshalling state: %v\n", err) + } + fmt.Println(string(output)) + return nil +} diff --git a/server/util.go b/server/util.go index ed91f30489..6e7c56af0d 100644 --- a/server/util.go +++ b/server/util.go @@ -68,7 +68,8 @@ func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error func AddCommands( ctx *Context, cdc *wire.Codec, rootCmd *cobra.Command, appInit AppInit, - appCreator AppCreator) { + appCreator AppCreator, appExporter AppExporter, + context *Context) { rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level") @@ -78,6 +79,8 @@ func AddCommands( UnsafeResetAllCmd(ctx), ShowNodeIDCmd(ctx), ShowValidatorCmd(ctx), + ExportCmd(appExporter, context), + UnsafeResetAllCmd(context), version.VersionCmd, ) } diff --git a/x/stake/commands/export.go b/x/stake/commands/export.go deleted file mode 100644 index 679aa5d1a7..0000000000 --- a/x/stake/commands/export.go +++ /dev/null @@ -1,31 +0,0 @@ -package commands - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/wire" // XXX fix - "github.com/cosmos/cosmos-sdk/x/stake" -) - -// get the command to export state -func GetCmdExport(export func() (stake.GenesisState, error), cdc *wire.Codec) *cobra.Command { - cmd := &cobra.Command{ - Use: "export-stake", - Short: "Export stake module state as JSON to stdout", - RunE: func(cmd *cobra.Command, args []string) error { - genesis, err := export() - if err != nil { - return err - } - output, err := wire.MarshalJSONIndent(cdc, genesis) - if err != nil { - return err - } - fmt.Println(string(output)) - return nil - }, - } - return cmd -}