diff --git a/CHANGELOG.md b/CHANGELOG.md index 99eb76e0b56b..37d4f1654db0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features -* [#13435](https://github.com/cosmos/cosmos-sdk/pull/13435) extend error context when a simulation fails. +* [#13437](https://github.com/cosmos/cosmos-sdk/pull/13437) Add new flag `--modules-to-export` in `simd export` command to export only selected modules. +* [#13435](https://github.com/cosmos/cosmos-sdk/pull/13435) Extend error context when a simulation fails. * [#13298](https://github.com/cosmos/cosmos-sdk/pull/13298) Add `AddGenesisAccount` helper func in x/auth module which helps adding accounts to genesis state. * (x/authz) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) Add an allow list, an optional list of addresses allowed to receive bank assets via authz MsgSend grant. * (sdk.Coins) [#12627](https://github.com/cosmos/cosmos-sdk/pull/12627) Make a Denoms method on sdk.Coins. @@ -97,6 +98,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* [#13437](https://github.com/cosmos/cosmos-sdk/pull/13437) Add a list of modules to export argument in `ExportAppStateAndValidators` and `ExportGenesis`. * (x/slashing) [#13427](https://github.com/cosmos/cosmos-sdk/pull/13427) Move `x/slashing/testslashing` to `x/slashing/testutil` for consistency with other modules. * (x/staking) [#13427](https://github.com/cosmos/cosmos-sdk/pull/13427) Move `x/staking/teststaking` to `x/staking/testutil` for consistency with other modules. * (simapp) [#13402](https://github.com/cosmos/cosmos-sdk/pull/13402) Move simulation flags to `x/simulation/client/cli`. diff --git a/UPGRADING.md b/UPGRADING.md index 159d3c4136c2..e086c4bdc30c 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -34,6 +34,11 @@ The constructor, `NewSimApp` has been simplified: `simapp.MakeTestEncodingConfig()` was deprecated and has been removed. Instead you can use the `TestEncodingConfig` from the `types/module/testutil` package. This means you can replace your usage of `simapp.MakeTestEncodingConfig` in tests to `moduletestutil.MakeTestEncodingConfig`, which takes a series of relevant `AppModuleBasic` as input (the module being tested and any potential dependencies). +#### Export + +`ExportAppStateAndValidators` takes an extra argument, `modulesToExport`, which is a list of module names to export. +That argument should be passed to the module maanager `ExportGenesis` method. + ### Protobuf The SDK has migrated from `gogo/protobuf` (which is currently unmaintained), to our own maintained fork, [`cosmos/gogoproto`](https://github.com/cosmos/gogoproto). diff --git a/runtime/types.go b/runtime/types.go index b5abc22059cf..fb7c65d82f62 100644 --- a/runtime/types.go +++ b/runtime/types.go @@ -32,9 +32,7 @@ type AppI interface { LoadHeight(height int64) error // Exports the state of the application for a genesis file. - ExportAppStateAndValidators( - forZeroHeight bool, jailAllowedAddrs []string, - ) (types.ExportedApp, error) + ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs []string, modulesToExport []string) (types.ExportedApp, error) // Helper for the simulation framework. SimulationManager() *module.SimulationManager diff --git a/server/export.go b/server/export.go index a50501284d8d..80415679a709 100644 --- a/server/export.go +++ b/server/export.go @@ -19,6 +19,7 @@ const ( FlagHeight = "height" FlagForZeroHeight = "for-zero-height" FlagJailAllowedAddrs = "jail-allowed-addrs" + FlagModulesToExport = "modules-to-export" ) // ExportCmd dumps app state to JSON. @@ -65,8 +66,9 @@ func ExportCmd(appExporter types.AppExporter, defaultNodeHome string) *cobra.Com height, _ := cmd.Flags().GetInt64(FlagHeight) forZeroHeight, _ := cmd.Flags().GetBool(FlagForZeroHeight) jailAllowedAddrs, _ := cmd.Flags().GetStringSlice(FlagJailAllowedAddrs) + modulesToExport, _ := cmd.Flags().GetStringSlice(FlagModulesToExport) - exported, err := appExporter(serverCtx.Logger, db, traceWriter, height, forZeroHeight, jailAllowedAddrs, serverCtx.Viper) + exported, err := appExporter(serverCtx.Logger, db, traceWriter, height, forZeroHeight, jailAllowedAddrs, serverCtx.Viper, modulesToExport) if err != nil { return fmt.Errorf("error exporting state: %v", err) } @@ -113,6 +115,7 @@ func ExportCmd(appExporter types.AppExporter, defaultNodeHome string) *cobra.Com cmd.Flags().Int64(FlagHeight, -1, "Export state from a particular height (-1 means latest height)") cmd.Flags().Bool(FlagForZeroHeight, false, "Export state to start at height zero (perform preproccessing)") cmd.Flags().StringSlice(FlagJailAllowedAddrs, []string{}, "Comma-separated list of operator addresses of jailed validators to unjail") + cmd.Flags().StringSlice(FlagModulesToExport, []string{}, "Comma-separated list of modules to export. If empty, will export all modules") return cmd } diff --git a/server/types/app.go b/server/types/app.go index d727e2c81509..09026095e4bf 100644 --- a/server/types/app.go +++ b/server/types/app.go @@ -80,5 +80,5 @@ type ( // AppExporter is a function that dumps all app state to // JSON-serializable structure and returns the current validator set. - AppExporter func(log.Logger, dbm.DB, io.Writer, int64, bool, []string, AppOptions) (ExportedApp, error) + AppExporter func(log.Logger, dbm.DB, io.Writer, int64, bool, []string, AppOptions, []string) (ExportedApp, error) ) diff --git a/simapp/app_test.go b/simapp/app_test.go index b27f9b272619..af92cbe077a0 100644 --- a/simapp/app_test.go +++ b/simapp/app_test.go @@ -60,7 +60,7 @@ func TestSimAppExportAndBlockedAddrs(t *testing.T) { logger2 := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) // Making a new app object with the db, so that initchain hasn't been called app2 := NewSimApp(logger2, db, nil, true, simtestutil.NewAppOptionsWithFlagHome(DefaultNodeHome)) - _, err := app2.ExportAppStateAndValidators(false, []string{}) + _, err := app2.ExportAppStateAndValidators(false, []string{}, []string{}) require.NoError(t, err, "ExportAppStateAndValidators should not have an error") } diff --git a/simapp/export.go b/simapp/export.go index d47e23a80f0f..60aecc5a05b0 100644 --- a/simapp/export.go +++ b/simapp/export.go @@ -16,9 +16,7 @@ import ( // ExportAppStateAndValidators exports the state of the application for a genesis // file. -func (app *SimApp) ExportAppStateAndValidators( - forZeroHeight bool, jailAllowedAddrs []string, -) (servertypes.ExportedApp, error) { +func (app *SimApp) ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs []string, modulesToExport []string) (servertypes.ExportedApp, error) { // as if they could withdraw from the start of the next block ctx := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) @@ -30,7 +28,7 @@ func (app *SimApp) ExportAppStateAndValidators( app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs) } - genState := app.ModuleManager.ExportGenesis(ctx, app.appCodec) + genState := app.ModuleManager.ExportGenesis(ctx, app.appCodec, modulesToExport) appState, err := json.MarshalIndent(genState, "", " ") if err != nil { return servertypes.ExportedApp{}, err diff --git a/simapp/sim_test.go b/simapp/sim_test.go index bfa4bd2d352e..53d65ea9b6b8 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -156,7 +156,7 @@ func TestAppImportExport(t *testing.T) { fmt.Printf("exporting genesis...\n") - exported, err := app.ExportAppStateAndValidators(false, []string{}) + exported, err := app.ExportAppStateAndValidators(false, []string{}, []string{}) require.NoError(t, err) fmt.Printf("importing genesis...\n") @@ -277,7 +277,7 @@ func TestAppSimulationAfterImport(t *testing.T) { fmt.Printf("exporting genesis...\n") - exported, err := app.ExportAppStateAndValidators(true, []string{}) + exported, err := app.ExportAppStateAndValidators(true, []string{}, []string{}) require.NoError(t, err) fmt.Printf("importing genesis...\n") diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 11719637d73e..7590217c7083 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -318,6 +318,7 @@ func appExport( forZeroHeight bool, jailAllowedAddrs []string, appOpts servertypes.AppOptions, + modulesToExport []string, ) (servertypes.ExportedApp, error) { var simApp *simapp.SimApp @@ -347,5 +348,5 @@ func appExport( simApp = simapp.NewSimApp(logger, db, traceStore, true, appOpts) } - return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) } diff --git a/tests/e2e/server/export_test.go b/tests/e2e/server/export_test.go index 633106e61473..b994d87706f8 100644 --- a/tests/e2e/server/export_test.go +++ b/tests/e2e/server/export_test.go @@ -157,7 +157,7 @@ func setupApp(t *testing.T, tempDir string) (*simapp.SimApp, context.Context, *t app.Commit() cmd := server.ExportCmd( - func(_ log.Logger, _ dbm.DB, _ io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, appOptions types.AppOptions) (types.ExportedApp, error) { + func(_ log.Logger, _ dbm.DB, _ io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, appOptions types.AppOptions, modulesToExport []string) (types.ExportedApp, error) { var simApp *simapp.SimApp if height != -1 { simApp = simapp.NewSimApp(logger, db, nil, false, appOptions) @@ -169,7 +169,7 @@ func setupApp(t *testing.T, tempDir string) (*simapp.SimApp, context.Context, *t simApp = simapp.NewSimApp(logger, db, nil, true, appOptions) } - return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) }, tempDir) ctx := context.Background() diff --git a/testutil/sims/simulation_helpers.go b/testutil/sims/simulation_helpers.go index 420171b05ceb..4132007c0906 100644 --- a/testutil/sims/simulation_helpers.go +++ b/testutil/sims/simulation_helpers.go @@ -72,7 +72,7 @@ func SimulationOperations(app runtime.AppI, cdc codec.JSONCodec, config simtypes func CheckExportSimulation(app runtime.AppI, config simtypes.Config, params simtypes.Params) error { if config.ExportStatePath != "" { fmt.Println("exporting app state...") - exported, err := app.ExportAppStateAndValidators(false, nil) + exported, err := app.ExportAppStateAndValidators(false, nil, nil) if err != nil { return err } diff --git a/types/module/module.go b/types/module/module.go index 2955fcbbd0cd..f693e0824b17 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -320,15 +320,39 @@ func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData } // ExportGenesis performs export genesis functionality for modules -func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) map[string]json.RawMessage { +func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) map[string]json.RawMessage { genesisData := make(map[string]json.RawMessage) - for _, moduleName := range m.OrderExportGenesis { + if len(modulesToExport) == 0 { + for _, moduleName := range m.OrderExportGenesis { + genesisData[moduleName] = m.Modules[moduleName].ExportGenesis(ctx, cdc) + } + + return genesisData + } + + // verify modules exists in app, so that we don't panic in the middle of an export + if err := m.checkModulesExists(modulesToExport); err != nil { + panic(err) + } + + for _, moduleName := range modulesToExport { genesisData[moduleName] = m.Modules[moduleName].ExportGenesis(ctx, cdc) } return genesisData } +// checkModulesExists verifies that all modules in the list exist in the app +func (m *Manager) checkModulesExists(moduleName []string) error { + for _, name := range moduleName { + if _, ok := m.Modules[name]; !ok { + return fmt.Errorf("module %s does not exist", name) + } + } + + return nil +} + // assertNoForgottenModules checks that we didn't forget any modules in the // SetOrder* functions. func (m *Manager) assertNoForgottenModules(setOrderFnName string, moduleNames []string) { diff --git a/types/module/module_test.go b/types/module/module_test.go index 202f0a01d957..c8be39e32068 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -198,7 +198,11 @@ func TestManager_ExportGenesis(t *testing.T) { "module1": json.RawMessage(`{"key1": "value1"}`), "module2": json.RawMessage(`{"key2": "value2"}`), } - require.Equal(t, want, mm.ExportGenesis(ctx, cdc)) + require.Equal(t, want, mm.ExportGenesis(ctx, cdc, []string{})) + + require.Panics(t, func() { + mm.ExportGenesis(ctx, cdc, []string{"module1", "modulefoo"}) + }) } func TestManager_BeginBlock(t *testing.T) {