From c94a4d71a1c9e65d8566f8d695db58812f10b8b2 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 4 Oct 2022 13:06:30 +0300 Subject: [PATCH] feat!: specify module to export (#13437) --- CHANGELOG.md | 1 + server/export.go | 5 ++++- server/export_test.go | 4 ++-- server/types/app.go | 2 +- simapp/app_test.go | 2 +- simapp/export.go | 6 ++---- simapp/sim_test.go | 4 ++-- simapp/simd/cmd/root.go | 3 ++- simapp/types.go | 4 +--- simapp/utils.go | 2 +- types/module/module.go | 32 ++++++++++++++++++++++++++++++-- types/module/module_test.go | 6 +++++- 12 files changed, 52 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac88e96e0371..860fcfbc604e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* [#13437](https://github.com/cosmos/cosmos-sdk/pull/13437) Add new flag `--modules-to-export` in `simd export` command to export only selected modules. * (grpc) [#13485](https://github.com/cosmos/cosmos-sdk/pull/13485) Implement a new gRPC query, `/cosmos/base/node/v1beta1/config`, which provides operator configuration. Applications that wish to expose operator minimum gas prices via gRPC should have their application implement the `ApplicationQueryService` interface (see `SimApp#RegisterNodeService` as an example). * [#13557](https://github.com/cosmos/cosmos-sdk/pull/#13557) - Add `GenSignedMockTx`. This can be used as workaround for #12437 revertion. `v0.46+` contains as well a `GenSignedMockTx` that behaves the same way. * (x/auth) [#13612](https://github.com/cosmos/cosmos-sdk/pull/13612) Add `Query/ModuleAccountByName` endpoint for accessing the module account info by module name. diff --git a/server/export.go b/server/export.go index df40f11ec61f..28fb7a462f78 100644 --- a/server/export.go +++ b/server/export.go @@ -20,6 +20,7 @@ const ( FlagHeight = "height" FlagForZeroHeight = "for-zero-height" FlagJailAllowedAddrs = "jail-allowed-addrs" + FlagModulesToExport = "modules-to-export" ) // ExportCmd dumps app state to JSON. @@ -67,8 +68,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) } @@ -121,6 +123,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/export_test.go b/server/export_test.go index 67dd95444ed1..2a53ad542723 100644 --- a/server/export_test.go +++ b/server/export_test.go @@ -148,7 +148,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, appOptons types.AppOptions) (types.ExportedApp, error) { + func(_ log.Logger, _ dbm.DB, _ io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, appOptons types.AppOptions, modulesToExport []string) (types.ExportedApp, error) { encCfg := simapp.MakeTestEncodingConfig() var simApp *simapp.SimApp @@ -162,7 +162,7 @@ func setupApp(t *testing.T, tempDir string) (*simapp.SimApp, context.Context, *t simApp = simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, "", 0, encCfg, appOptons) } - return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) }, tempDir) ctx := context.Background() diff --git a/server/types/app.go b/server/types/app.go index 03ec6cdfc177..f8e6ba6977ec 100644 --- a/server/types/app.go +++ b/server/types/app.go @@ -89,5 +89,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 56c6dc1485ad..be918cf6409a 100644 --- a/simapp/app_test.go +++ b/simapp/app_test.go @@ -63,7 +63,7 @@ func TestSimAppExportAndBlockedAddrs(t *testing.T) { // Making a new app object with the db, so that initchain hasn't been called app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{}) - _, 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 e6a0525fba40..10dbfda6892e 100644 --- a/simapp/export.go +++ b/simapp/export.go @@ -15,9 +15,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()}) @@ -29,7 +27,7 @@ func (app *SimApp) ExportAppStateAndValidators( app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs) } - genState := app.mm.ExportGenesis(ctx, app.appCodec) + genState := app.mm.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 7db09cee432f..ad1c7ea3b664 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -132,7 +132,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") @@ -235,7 +235,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 08331b9c9c07..53f52f37022e 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -286,6 +286,7 @@ func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, a func (a appCreator) appExport( logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, appOpts servertypes.AppOptions, + modulesToExport []string, ) (servertypes.ExportedApp, error) { var simApp *simapp.SimApp homePath, ok := appOpts.Get(flags.FlagHome).(string) @@ -303,5 +304,5 @@ func (a appCreator) appExport( simApp = simapp.NewSimApp(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), a.encCfg, appOpts) } - return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) } diff --git a/simapp/types.go b/simapp/types.go index 0e190af1bc93..9eaa88e70add 100644 --- a/simapp/types.go +++ b/simapp/types.go @@ -32,9 +32,7 @@ type App 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) // All the registered module account addreses. ModuleAccountAddrs() map[string]bool diff --git a/simapp/utils.go b/simapp/utils.go index 09edfcfdd5d9..9b2c452cf895 100644 --- a/simapp/utils.go +++ b/simapp/utils.go @@ -79,7 +79,7 @@ func CheckExportSimulation( ) 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 22c05983a81e..035bdc464394 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -342,10 +342,27 @@ 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 { + if moduleName == "interchainaccounts" { + genesisData[moduleName] = m.Modules[moduleName].DefaultGenesis(cdc) + } else { + 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 { if moduleName == "interchainaccounts" { genesisData[moduleName] = m.Modules[moduleName].DefaultGenesis(cdc) } else { @@ -356,6 +373,17 @@ func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) map[string 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 7e880b4b1003..b349eb0b7601 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -238,7 +238,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) {