From c201963e411f93538c2197a5cd82cb33945ffbac Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Mon, 2 Nov 2020 20:10:14 +0100 Subject: [PATCH] Update x/banking and x/crisis InitChain re slow Gaia startup (#7764) * add more logs during the initialization process * initializtion: move profiling to the top of the startProcess function * x/bank InitGenesis: remove k.ValidateBalance * debug: add logs and telemetry to x/bank and x/crisis * make x/crisis AssertInvariants optional during InitGenesis * Add module init flags mechanism * update changelog * remove debug fmt.Print * fix testutil/network/ * fix log message * update test NewApp calls * review changes Co-authored-by: Aaron Craelius --- CHANGELOG.md | 6 ++++++ server/export.go | 2 +- server/export_test.go | 8 ++++---- server/start.go | 41 +++++++++++++++++++------------------ server/types/app.go | 6 +++++- server/util.go | 6 ++++-- simapp/app.go | 12 +++++++++-- simapp/app_test.go | 6 +++--- simapp/sim_bench_test.go | 4 ++-- simapp/sim_test.go | 12 +++++------ simapp/simd/cmd/root.go | 22 ++++++++++++-------- simapp/test_helpers.go | 15 ++++++++++---- testutil/network/network.go | 1 + x/bank/keeper/genesis.go | 4 ---- x/bank/module.go | 6 +++++- x/crisis/handler_test.go | 2 +- x/crisis/keeper/keeper.go | 11 +++++----- x/crisis/module.go | 30 ++++++++++++++++++++++++--- x/gov/genesis_test.go | 2 +- x/upgrade/abci_test.go | 2 +- 20 files changed, 128 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17ba0263805d..1812f7e3f680 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,12 +52,18 @@ Ref: https://keepachangelog.com/en/1.0.0/ * `MsgCreateValidator.Pubkey` type changed from `string` to `codectypes.Any`. * Deprecating and renaming `MakeEncodingConfig` to `MakeTestEncodingConfig` (both in `simapp` and `simapp/params` packages). * (tx) [\#7688](https://github.com/cosmos/cosmos-sdk/pull/7688) The gRPC simulate service method has been moved from `cosmos.base.v1beta1.simulate` to `cosmos.tx.v1beta1`, as a method in the Tx service. +* [#7764](https://github.com/cosmos/cosmos-sdk/pull/7764) Added module initialization options: + * `server/types.AppExporter` requires extra argument: `AppOptions`. + * `server.AddCommands` requires extra argument: `addStartFlags types.ModuleInitFlags` + * `x/crisis.NewAppModule` has a new attribute: `skipGenesisInvariants`. [PR](https://github.com/cosmos/cosmos-sdk/pull/7764) ### Features * (codec) [\#7519](https://github.com/cosmos/cosmos-sdk/pull/7519) `InterfaceRegistry` now inherits `jsonpb.AnyResolver`, and has a `RegisterCustomTypeURL` method to support ADR 031 packing of `Any`s. `AnyResolver` is now a required parameter to `RejectUnknownFields`. * (baseapp) [\#7519](https://github.com/cosmos/cosmos-sdk/pull/7519) Add `ServiceMsgRouter` to BaseApp to handle routing of protobuf service `Msg`s. The two new types defined in ADR 031, `sdk.ServiceMsg` and `sdk.MsgRequest` are introduced with this router. * (tx) [\#7688](https://github.com/cosmos/cosmos-sdk/pull/7688) Add a new Tx gRPC service with methods `Simulate` and `GetTx` (by hash). +* `x/crisis` has a new function: `AddModuleInitFlags`, which will register optional crisis module flags for the start command. + ### Bug Fixes diff --git a/server/export.go b/server/export.go index 3ed41a64940b..280d62da327c 100644 --- a/server/export.go +++ b/server/export.go @@ -68,7 +68,7 @@ func ExportCmd(appExporter types.AppExporter, defaultNodeHome string) *cobra.Com forZeroHeight, _ := cmd.Flags().GetBool(FlagForZeroHeight) jailAllowedAddrs, _ := cmd.Flags().GetStringSlice(FlagJailAllowedAddrs) - exported, err := appExporter(serverCtx.Logger, db, traceWriter, height, forZeroHeight, jailAllowedAddrs) + exported, err := appExporter(serverCtx.Logger, db, traceWriter, height, forZeroHeight, jailAllowedAddrs, serverCtx.Viper) if err != nil { return fmt.Errorf("error exporting state: %v", err) } diff --git a/server/export_test.go b/server/export_test.go index d804b7a15108..0971665fcfce 100644 --- a/server/export_test.go +++ b/server/export_test.go @@ -129,7 +129,7 @@ func setupApp(t *testing.T, tempDir string) (*simapp.SimApp, context.Context, *t logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) db := dbm.NewMemDB() encCfg := simapp.MakeTestEncodingConfig() - app := simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, tempDir, 0, encCfg) + app := simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, tempDir, 0, encCfg, simapp.EmptyAppOptions{}) serverCtx := server.NewDefaultContext() serverCtx.Config.RootDir = tempDir @@ -148,18 +148,18 @@ 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) (types.ExportedApp, error) { + func(_ log.Logger, _ dbm.DB, _ io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, appOptons types.AppOptions) (types.ExportedApp, error) { encCfg := simapp.MakeTestEncodingConfig() var simApp *simapp.SimApp if height != -1 { - simApp = simapp.NewSimApp(logger, db, nil, false, map[int64]bool{}, "", 0, encCfg) + simApp = simapp.NewSimApp(logger, db, nil, false, map[int64]bool{}, "", 0, encCfg, appOptons) if err := simApp.LoadHeight(height); err != nil { return types.ExportedApp{}, err } } else { - simApp = simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, "", 0, encCfg) + simApp = simapp.NewSimApp(logger, db, nil, true, map[int64]bool{}, "", 0, encCfg, appOptons) } return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) diff --git a/server/start.go b/server/start.go index 6e014de75080..2a2a1af886ee 100644 --- a/server/start.go +++ b/server/start.go @@ -193,6 +193,25 @@ func startStandAlone(ctx *Context, appCreator types.AppCreator) error { func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.AppCreator) error { cfg := ctx.Config home := cfg.RootDir + var cpuProfileCleanup func() + + if cpuProfile := ctx.Viper.GetString(flagCPUProfile); cpuProfile != "" { + f, err := os.Create(cpuProfile) + if err != nil { + return err + } + + ctx.Logger.Info("starting CPU profiler", "profile", cpuProfile) + if err := pprof.StartCPUProfile(f); err != nil { + return err + } + + cpuProfileCleanup = func() { + ctx.Logger.Info("stopping CPU profiler", "profile", cpuProfile) + pprof.StopCPUProfile() + f.Close() + } + } traceWriterFile := ctx.Viper.GetString(flagTraceStore) db, err := openDB(home) @@ -226,10 +245,12 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App if err != nil { return err } + ctx.Logger.Debug("Initialization: tmNode created") if err := tmNode.Start(); err != nil { return err } + ctx.Logger.Debug("Initialization: tmNode started") // Add the tx service to the gRPC router. app.RegisterTxService(clientCtx) @@ -273,26 +294,6 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App } } - var cpuProfileCleanup func() - - if cpuProfile := ctx.Viper.GetString(flagCPUProfile); cpuProfile != "" { - f, err := os.Create(cpuProfile) - if err != nil { - return err - } - - ctx.Logger.Info("starting CPU profiler", "profile", cpuProfile) - if err := pprof.StartCPUProfile(f); err != nil { - return err - } - - cpuProfileCleanup = func() { - ctx.Logger.Info("stopping CPU profiler", "profile", cpuProfile) - pprof.StopCPUProfile() - f.Close() - } - } - defer func() { if tmNode.IsRunning() { _ = tmNode.Stop() diff --git a/server/types/app.go b/server/types/app.go index f036f6ff093c..f6209d94ba6e 100644 --- a/server/types/app.go +++ b/server/types/app.go @@ -5,6 +5,7 @@ import ( "io" "github.com/gogo/protobuf/grpc" + "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" @@ -48,6 +49,9 @@ type ( // application using various configurations. AppCreator func(log.Logger, dbm.DB, io.Writer, AppOptions) Application + // ModuleInitFlags takes a start command and adds modules specific init flags. + ModuleInitFlags func(startCmd *cobra.Command) + // ExportedApp represents an exported app state, along with // validators, consensus params and latest app height. ExportedApp struct { @@ -63,5 +67,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) (ExportedApp, error) + AppExporter func(log.Logger, dbm.DB, io.Writer, int64, bool, []string, AppOptions) (ExportedApp, error) ) diff --git a/server/util.go b/server/util.go index b95f8ad505a1..3f66921d6617 100644 --- a/server/util.go +++ b/server/util.go @@ -201,7 +201,7 @@ func interceptConfigs(rootViper *viper.Viper) (*tmcfg.Config, error) { } // add server commands -func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator types.AppCreator, appExport types.AppExporter) { +func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator types.AppCreator, appExport types.AppExporter, addStartFlags types.ModuleInitFlags) { tendermintCmd := &cobra.Command{ Use: "tendermint", Short: "Tendermint subcommands", @@ -213,9 +213,11 @@ func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator type ShowAddressCmd(), VersionCmd(), ) + startCmd := StartCmd(appCreator, defaultNodeHome) + addStartFlags(startCmd) rootCmd.AddCommand( - StartCmd(appCreator, defaultNodeHome), + startCmd, UnsafeResetAllCmd(), flags.LineBreak, tendermintCmd, diff --git a/simapp/app.go b/simapp/app.go index 3f11216af3fa..a8c9e584be27 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -8,6 +8,7 @@ import ( "github.com/gorilla/mux" "github.com/rakyll/statik/fs" + "github.com/spf13/cast" abci "github.com/tendermint/tendermint/abci/types" tmjson "github.com/tendermint/tendermint/libs/json" "github.com/tendermint/tendermint/libs/log" @@ -197,7 +198,8 @@ func init() { // NewSimApp returns a reference to an initialized SimApp. func NewSimApp( logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, skipUpgradeHeights map[int64]bool, - homePath string, invCheckPeriod uint, encodingConfig simappparams.EncodingConfig, baseAppOptions ...func(*baseapp.BaseApp), + homePath string, invCheckPeriod uint, encodingConfig simappparams.EncodingConfig, + appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *SimApp { // TODO: Remove cdc in favor of appCodec once all modules are migrated. @@ -317,6 +319,12 @@ func NewSimApp( // If evidence needs to be handled for the app, set routes in router here and seal app.EvidenceKeeper = *evidenceKeeper + /**** Module Options ****/ + + // NOTE: we may consider parsing `appOpts` inside module constructors. For the moment + // we prefer to be more strict in what arguments the modules expect. + var skipGenesisInvariants = cast.ToBool(appOpts.Get(crisis.FlagSkipGenesisInvariants)) + // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. app.mm = module.NewManager( @@ -328,7 +336,7 @@ func NewSimApp( vesting.NewAppModule(app.AccountKeeper, app.BankKeeper), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), capability.NewAppModule(appCodec, *app.CapabilityKeeper), - crisis.NewAppModule(&app.CrisisKeeper), + crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper), mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper), slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), diff --git a/simapp/app_test.go b/simapp/app_test.go index fdc609677a5f..fef50310bff9 100644 --- a/simapp/app_test.go +++ b/simapp/app_test.go @@ -14,7 +14,7 @@ import ( func TestSimAppExport(t *testing.T) { db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig()) + app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig(), EmptyAppOptions{}) genesisState := NewDefaultGenesisState() stateBytes, err := json.MarshalIndent(genesisState, "", " ") @@ -30,7 +30,7 @@ func TestSimAppExport(t *testing.T) { app.Commit() // 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, MakeTestEncodingConfig()) + app2 := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig(), EmptyAppOptions{}) _, err = app2.ExportAppStateAndValidators(false, []string{}) require.NoError(t, err, "ExportAppStateAndValidators should not have an error") } @@ -38,7 +38,7 @@ func TestSimAppExport(t *testing.T) { // ensure that blocked addresses are properly set in bank keeper func TestBlockedAddrs(t *testing.T) { db := dbm.NewMemDB() - app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig()) + app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig(), EmptyAppOptions{}) for acc := range maccPerms { require.Equal(t, !allowedReceivingModAcc[acc], app.BankKeeper.BlockedAddr(app.AccountKeeper.GetModuleAddress(acc))) diff --git a/simapp/sim_bench_test.go b/simapp/sim_bench_test.go index 505150c450e7..7c22dcfe8a44 100644 --- a/simapp/sim_bench_test.go +++ b/simapp/sim_bench_test.go @@ -27,7 +27,7 @@ func BenchmarkFullAppSimulation(b *testing.B) { } }() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), interBlockCacheOpt()) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, interBlockCacheOpt()) // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( @@ -72,7 +72,7 @@ func BenchmarkInvariants(b *testing.B) { } }() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), interBlockCacheOpt()) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, interBlockCacheOpt()) // run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( diff --git a/simapp/sim_test.go b/simapp/sim_test.go index d20a8267c147..cc1a7cada4f5 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -68,7 +68,7 @@ func TestFullAppSimulation(t *testing.T) { require.NoError(t, os.RemoveAll(dir)) }() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), fauxMerkleModeOpt) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, fauxMerkleModeOpt) require.Equal(t, "SimApp", app.Name()) // run randomized simulation @@ -106,7 +106,7 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, os.RemoveAll(dir)) }() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), fauxMerkleModeOpt) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, fauxMerkleModeOpt) require.Equal(t, "SimApp", app.Name()) // Run randomized simulation @@ -146,7 +146,7 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() - newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), fauxMerkleModeOpt) + newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, fauxMerkleModeOpt) require.Equal(t, "SimApp", newApp.Name()) var genesisState GenesisState @@ -203,7 +203,7 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, os.RemoveAll(dir)) }() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), fauxMerkleModeOpt) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, fauxMerkleModeOpt) require.Equal(t, "SimApp", app.Name()) // Run randomized simulation @@ -248,7 +248,7 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() - newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), fauxMerkleModeOpt) + newApp := NewSimApp(log.NewNopLogger(), newDB, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, fauxMerkleModeOpt) require.Equal(t, "SimApp", newApp.Name()) newApp.InitChain(abci.RequestInitChain{ @@ -299,7 +299,7 @@ func TestAppStateDeterminism(t *testing.T) { } db := dbm.NewMemDB() - app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), interBlockCacheOpt()) + app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, FlagPeriodValue, MakeTestEncodingConfig(), EmptyAppOptions{}, interBlockCacheOpt()) fmt.Printf( "running non-determinism simulation; seed %d: %d/%d, attempt: %d/%d\n", diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index f4f6ca5897f1..2ffd39459374 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -6,10 +6,6 @@ import ( "os" "path/filepath" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/simapp/params" - "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/spf13/cast" "github.com/spf13/cobra" tmcli "github.com/tendermint/tendermint/libs/cli" @@ -22,9 +18,12 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/cosmos/cosmos-sdk/snapshots" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" @@ -32,6 +31,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" vestingcli "github.com/cosmos/cosmos-sdk/x/auth/vesting/client/cli" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" ) @@ -97,7 +97,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { debug.Cmd(), ) - server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, createSimappAndExport) + server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, createSimappAndExport, addModuleInitFlags) // add keybase, auxiliary RPC, query, and tx child commands rootCmd.AddCommand( @@ -108,6 +108,10 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { ) } +func addModuleInitFlags(startCmd *cobra.Command) { + crisis.AddModuleInitFlags(startCmd) +} + func queryCommand() *cobra.Command { cmd := &cobra.Command{ Use: "query", @@ -192,6 +196,7 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts serverty cast.ToString(appOpts.Get(flags.FlagHome)), cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), simapp.MakeTestEncodingConfig(), // Ideally, we would reuse the one created by NewRootCmd. + appOpts, baseapp.SetPruning(pruningOpts), baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), @@ -210,18 +215,19 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts serverty // and exports state. func createSimappAndExport( logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, -) (servertypes.ExportedApp, error) { + appOpts servertypes.AppOptions) (servertypes.ExportedApp, error) { + encCfg := simapp.MakeTestEncodingConfig() // Ideally, we would reuse the one created by NewRootCmd. encCfg.Marshaler = codec.NewProtoCodec(encCfg.InterfaceRegistry) var simApp *simapp.SimApp if height != -1 { - simApp = simapp.NewSimApp(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), encCfg) + simApp = simapp.NewSimApp(logger, db, traceStore, false, map[int64]bool{}, "", uint(1), encCfg, appOpts) if err := simApp.LoadHeight(height); err != nil { return servertypes.ExportedApp{}, err } } else { - simApp = simapp.NewSimApp(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), encCfg) + simApp = simapp.NewSimApp(logger, db, traceStore, true, map[int64]bool{}, "", uint(1), encCfg, appOpts) } return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) diff --git a/simapp/test_helpers.go b/simapp/test_helpers.go index de871b7c5ebd..6624c1df3fbc 100644 --- a/simapp/test_helpers.go +++ b/simapp/test_helpers.go @@ -51,7 +51,7 @@ var DefaultConsensusParams = &abci.ConsensusParams{ // Setup initializes a new SimApp. A Nop logger is set in SimApp. func Setup(isCheckTx bool) *SimApp { db := dbm.NewMemDB() - app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, MakeTestEncodingConfig()) + app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, MakeTestEncodingConfig(), EmptyAppOptions{}) if !isCheckTx { // init chain must be called to stop deliverState from being nil genesisState := NewDefaultGenesisState() @@ -79,8 +79,7 @@ func Setup(isCheckTx bool) *SimApp { // account. A Nop logger is set in SimApp. func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp { db := dbm.NewMemDB() - app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, MakeTestEncodingConfig()) - + app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, MakeTestEncodingConfig(), EmptyAppOptions{}) genesisState := NewDefaultGenesisState() // set genesis accounts @@ -160,7 +159,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs // accounts and possible balances. func SetupWithGenesisAccounts(genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *SimApp { db := dbm.NewMemDB() - app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig()) + app := NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, MakeTestEncodingConfig(), EmptyAppOptions{}) // initialize the chain with the passed in genesis accounts genesisState := NewDefaultGenesisState() @@ -435,3 +434,11 @@ func NewPubKeyFromHex(pk string) (res crypto.PubKey) { } return &ed25519.PubKey{Key: pkBytes} } + +// EmptyAppOptions is a stub implementing AppOptions +type EmptyAppOptions struct{} + +// Get implements AppOptions +func (ao EmptyAppOptions) Get(o string) interface{} { + return nil +} diff --git a/testutil/network/network.go b/testutil/network/network.go index fc50c9aa0c1b..1ee11f8c933d 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -59,6 +59,7 @@ func NewAppConstructor(encodingCfg params.EncodingConfig) AppConstructor { return simapp.NewSimApp( val.Ctx.Logger, dbm.NewMemDB(), nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0, encodingCfg, + simapp.EmptyAppOptions{}, baseapp.SetPruning(storetypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices), ) diff --git a/x/bank/keeper/genesis.go b/x/bank/keeper/genesis.go index ba1b076486b8..7397d8d5b6e6 100644 --- a/x/bank/keeper/genesis.go +++ b/x/bank/keeper/genesis.go @@ -20,10 +20,6 @@ func (k BaseKeeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { panic(err) } - if err := k.ValidateBalance(ctx, addr); err != nil { - panic(err) - } - if err := k.SetBalances(ctx, addr, balance.Coins); err != nil { panic(fmt.Errorf("error on setting balances %w", err)) } diff --git a/x/bank/module.go b/x/bank/module.go index 958d0db754a7..32f7431f26f0 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "math/rand" + "time" "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" @@ -14,6 +15,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" @@ -133,9 +135,11 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd // InitGenesis performs genesis initialization for the bank module. It returns // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { + start := time.Now() var genesisState types.GenesisState - cdc.MustUnmarshalJSON(data, &genesisState) + telemetry.MeasureSince(start, "InitGenesis", "crisis", "unmarshal") + am.keeper.InitGenesis(ctx, genesisState) return []abci.ValidatorUpdate{} } diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index 6d65b87646d5..dcde377f6d42 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -27,7 +27,7 @@ var ( func createTestApp() (*simapp.SimApp, sdk.Context, []sdk.AccAddress) { db := dbm.NewMemDB() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 1, simapp.MakeTestEncodingConfig()) + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 1, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}) ctx := app.NewContext(true, tmproto.Header{}) constantFee := sdk.NewInt64Coin(sdk.DefaultBondDenom, 10) diff --git a/x/crisis/keeper/keeper.go b/x/crisis/keeper/keeper.go index 86136981ddfa..8a78c936c3f1 100644 --- a/x/crisis/keeper/keeper.go +++ b/x/crisis/keeper/keeper.go @@ -58,7 +58,7 @@ func (k Keeper) Routes() []types.InvarRoute { return k.routes } -// Invariants returns all the registered Crisis keeper invariants. +// Invariants returns a copy of all registered Crisis keeper invariants. func (k Keeper) Invariants() []sdk.Invariant { invars := make([]sdk.Invariant, len(k.routes)) for i, route := range k.routes { @@ -74,8 +74,9 @@ func (k Keeper) AssertInvariants(ctx sdk.Context) { start := time.Now() invarRoutes := k.Routes() - - for _, ir := range invarRoutes { + n := len(invarRoutes) + for i, ir := range invarRoutes { + logger.Debug("Asserting cirisis invariants", "inv", fmt.Sprint(i, "/", n)) if res, stop := ir.Invar(ctx); stop { // TODO: Include app name as part of context to allow for this to be // variable. @@ -85,9 +86,7 @@ func (k Keeper) AssertInvariants(ctx sdk.Context) { } } - end := time.Now() - diff := end.Sub(start) - + diff := time.Since(start) logger.Info("asserted all invariants", "duration", diff, "height", ctx.BlockHeight()) } diff --git a/x/crisis/module.go b/x/crisis/module.go index 9793dc8bfc66..5d34c1ce28f9 100644 --- a/x/crisis/module.go +++ b/x/crisis/module.go @@ -3,6 +3,7 @@ package crisis import ( "encoding/json" "fmt" + "time" "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" @@ -12,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/crisis/client/cli" @@ -24,6 +26,11 @@ var ( _ module.AppModuleBasic = AppModuleBasic{} ) +// Module init related flags +const ( + FlagSkipGenesisInvariants = "x-crisis-skip-assert-invariants" +) + // AppModuleBasic defines the basic application module used by the crisis module. type AppModuleBasic struct{} @@ -83,16 +90,28 @@ type AppModule struct { // manager is created, the invariants can be properly registered and // executed. keeper *keeper.Keeper + + skipGenesisInvariants bool } -// NewAppModule creates a new AppModule object -func NewAppModule(keeper *keeper.Keeper) AppModule { +// NewAppModule creates a new AppModule object. If initChainAssertInvariants is set, +// we will call keeper.AssertInvariants during InitGenesis (it may take a significant time) +// - which doesn't impact the chain security unless 66+% of validators have a wrongly +// modified genesis file. +func NewAppModule(keeper *keeper.Keeper, skipGenesisInvariants bool) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, + + skipGenesisInvariants: skipGenesisInvariants, } } +// AddModuleInitFlags implements servertypes.ModuleInitFlags interface. +func AddModuleInitFlags(startCmd *cobra.Command) { + startCmd.Flags().Bool(FlagSkipGenesisInvariants, false, "Skip x/crisis invariants check on startup") +} + // Name returns the crisis module's name. func (AppModule) Name() string { return types.ModuleName @@ -120,10 +139,15 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // InitGenesis performs genesis initialization for the crisis module. It returns // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { + start := time.Now() var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) + telemetry.MeasureSince(start, "InitGenesis", "crisis", "unmarshal") + am.keeper.InitGenesis(ctx, &genesisState) - am.keeper.AssertInvariants(ctx) + if !am.skipGenesisInvariants { + am.keeper.AssertInvariants(ctx) + } return []abci.ValidatorUpdate{} } diff --git a/x/gov/genesis_test.go b/x/gov/genesis_test.go index f4f548c26a84..5ed4a11205e9 100644 --- a/x/gov/genesis_test.go +++ b/x/gov/genesis_test.go @@ -68,7 +68,7 @@ func TestImportExportQueues(t *testing.T) { } db := dbm.NewMemDB() - app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 0, simapp.MakeTestEncodingConfig()) + app2 := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, simapp.DefaultNodeHome, 0, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}) app2.InitChain( abci.RequestInitChain{ diff --git a/x/upgrade/abci_test.go b/x/upgrade/abci_test.go index a133cad5a29c..e2dd5c8a1200 100644 --- a/x/upgrade/abci_test.go +++ b/x/upgrade/abci_test.go @@ -40,7 +40,7 @@ var s TestSuite func setupTest(height int64, skip map[int64]bool) TestSuite { db := dbm.NewMemDB() - app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, skip, simapp.DefaultNodeHome, 0, simapp.MakeTestEncodingConfig()) + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, skip, simapp.DefaultNodeHome, 0, simapp.MakeTestEncodingConfig(), simapp.EmptyAppOptions{}) genesisState := simapp.NewDefaultGenesisState() stateBytes, err := json.MarshalIndent(genesisState, "", " ") if err != nil {