diff --git a/UPGRADING.md b/UPGRADING.md index ff41503e2e37..fa3eefa28591 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,6 +1,7 @@ # Upgrading Cosmos SDK This guide provides instructions for upgrading to specific versions of Cosmos SDK. +Note, always read the **SimApp** section for more information on application wiring updates. ## [Unreleased] @@ -61,12 +62,14 @@ The `gogoproto.goproto_stringer = false` annotation has been removed from most p ### SimApp + + #### Module Assertions Previously, all modules were required to be set in `OrderBeginBlockers`, `OrderEndBlockers` and `OrderInitGenesis / OrderExportGenesis` in `app.go` / `app_config.go`. This is no longer the case, the assertion has been loosened to only require modules implementing, respectively, the `module.BeginBlockAppModule`, `module.EndBlockAppModule` and `module.HasGenesis` interfaces. -### Modules Keepers +#### Modules Keepers The following modules `NewKeeper` function now take a `KVStoreService` instead of a `StoreKey`: @@ -78,7 +81,7 @@ The following modules `NewKeeper` function now take a `KVStoreService` instead o * `x/feegrant` * `x/nft` -When not using depinject, the `runtime.NewKVStoreService` method can be used to create a `KVStoreService` from a `StoreKey`: +User manually wiring their chain need to use the `runtime.NewKVStoreService` method to create a `KVStoreService` from a `StoreKey`: ```diff app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper( @@ -89,19 +92,21 @@ app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper( ) ``` -The following modules `NewKeeper` function now also take a `log.Logger`: - -* `x/bank` - The following modules' `Keeper` methods now take in a `context.Context` instead of `sdk.Context`. Any module that has an interfaces for them (like "expected keepers") will need to update and re-generate mocks if needed: * `x/authz` * `x/bank` * `x/distribution` -### depinject +**Users using depinject do not need any changes, this is automatically done for them.** + +#### Logger + +The following modules `NewKeeper` function now take a `log.Logger`: + +* `x/bank` -For `depinject` users, now the logger must be supplied through the main `depinject.Inject` function instead of passing it to `appBuilder.Build`. +`depinject` users must now supply the logger through the main `depinject.Supply` function instead of passing it to `appBuilder.Build`. ```diff appConfig = depinject.Configs( @@ -118,6 +123,31 @@ appConfig = depinject.Configs( + app.App = appBuilder.Build(db, traceStore, baseAppOptions...) ``` +User manually wiring their chain need to add the logger argument when creating the keeper. + +#### Module Basics + +Previously, the `ModuleBasics` was a global variable that was used to register all modules's `AppModuleBasic` implementation. +The global variable has been removed and the basic module manager can be now created from the module manager. + +This is automatically done for depinject users, however for supplying different app module implementation, pass them via `depinject.Supply` in the main `AppConfig` (`app_config.go`): + +```go +depinject.Supply( + // supply custom module basics + map[string]module.AppModuleBasic{ + genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + govtypes.ModuleName: gov.NewAppModuleBasic( + []govclient.ProposalHandler{ + paramsclient.ProposalHandler, + }, + ), + }, + ) +``` + +Users manually wiring their chain need to use the new `module.NewBasicManagerFromManager` function, after the module manager creation, and pass a `map[string]module.AppModuleBasic` as argument for optionally overridding some module's `AppModuleBasic`. + ### Packages #### Store diff --git a/core/appmodule/module.go b/core/appmodule/module.go index ec7eb6142ffa..a701a307c974 100644 --- a/core/appmodule/module.go +++ b/core/appmodule/module.go @@ -45,7 +45,7 @@ type HasPrepareCheckState interface { PrepareCheckState(context.Context) error } -// HasPreommit is an extension interface that contains information about the AppModule and Precommit. +// HasPrecommit is an extension interface that contains information about the AppModule and Precommit. type HasPrecommit interface { AppModule Precommit(context.Context) error diff --git a/runtime/builder.go b/runtime/builder.go index 22aaf329ad6c..e340a9db7eb5 100644 --- a/runtime/builder.go +++ b/runtime/builder.go @@ -24,11 +24,7 @@ func (a *AppBuilder) DefaultGenesis() map[string]json.RawMessage { } // Build builds an *App instance. -func (a *AppBuilder) Build( - db dbm.DB, - traceStore io.Writer, - baseAppOptions ...func(*baseapp.BaseApp), -) *App { +func (a *AppBuilder) Build(db dbm.DB, traceStore io.Writer, baseAppOptions ...func(*baseapp.BaseApp)) *App { for _, option := range a.app.baseAppOptions { baseAppOptions = append(baseAppOptions, option) } @@ -42,8 +38,7 @@ func (a *AppBuilder) Build( a.app.BaseApp = bApp a.app.configurator = module.NewConfigurator(a.app.cdc, a.app.MsgServiceRouter(), a.app.GRPCQueryRouter()) - err := a.app.ModuleManager.RegisterServices(a.app.configurator) - if err != nil { + if err := a.app.ModuleManager.RegisterServices(a.app.configurator); err != nil { panic(err) } diff --git a/runtime/module.go b/runtime/module.go index 562a24aed389..09a0f0b8b708 100644 --- a/runtime/module.go +++ b/runtime/module.go @@ -67,6 +67,7 @@ func init() { ProvideMemoryStoreService, ProvideTransientStoreService, ProvideEventService, + ProvideBasicManager, ), appmodule.Invoke(SetupAppBuilder), ) @@ -91,8 +92,7 @@ func ProvideApp() ( protoTypes := protoregistry.GlobalTypes // At startup, check that all proto annotations are correct. - err = msgservice.ValidateProtoAnnotations(protoFiles) - if err != nil { + if err := msgservice.ValidateProtoAnnotations(protoFiles); err != nil { // Once we switch to using protoreflect-based antehandlers, we might // want to panic here instead of logging a warning. _, _ = fmt.Fprintln(os.Stderr, err.Error()) @@ -109,8 +109,7 @@ func ProvideApp() ( // validate the signing context to make sure that messages are properly configured // with cosmos.msg.v1.signer - err = interfaceRegistry.SigningContext().Validate() - if err != nil { + if err := interfaceRegistry.SigningContext().Validate(); err != nil { return nil, nil, nil, nil, nil, nil, nil, nil, nil, err } @@ -137,25 +136,33 @@ func ProvideApp() ( type AppInputs struct { depinject.In - AppConfig *appv1alpha1.Config - Config *runtimev1alpha1.Module - AppBuilder *AppBuilder - Modules map[string]appmodule.AppModule - BaseAppOptions []BaseAppOption - InterfaceRegistry codectypes.InterfaceRegistry - LegacyAmino *codec.LegacyAmino - Logger log.Logger + AppConfig *appv1alpha1.Config + Config *runtimev1alpha1.Module + AppBuilder *AppBuilder + Modules map[string]appmodule.AppModule + CustomModuleBasics map[string]module.AppModuleBasic `optional:"true"` + BaseAppOptions []BaseAppOption + InterfaceRegistry codectypes.InterfaceRegistry + LegacyAmino *codec.LegacyAmino + Logger log.Logger } func SetupAppBuilder(inputs AppInputs) { app := inputs.AppBuilder.app app.baseAppOptions = inputs.BaseAppOptions app.config = inputs.Config - app.ModuleManager = module.NewManagerFromMap(inputs.Modules) app.appConfig = inputs.AppConfig app.logger = inputs.Logger + app.ModuleManager = module.NewManagerFromMap(inputs.Modules) for name, mod := range inputs.Modules { + if customBasicMod, ok := inputs.CustomModuleBasics[name]; ok { + app.basicManager[name] = customBasicMod + customBasicMod.RegisterInterfaces(inputs.InterfaceRegistry) + customBasicMod.RegisterLegacyAminoCodec(inputs.LegacyAmino) + continue + } + if basicMod, ok := mod.(module.AppModuleBasic); ok { app.basicManager[name] = basicMod basicMod.RegisterInterfaces(inputs.InterfaceRegistry) @@ -229,6 +236,10 @@ func ProvideEventService() event.Service { return EventService{} } +func ProvideBasicManager(app *AppBuilder) module.BasicManager { + return app.app.basicManager +} + // globalAccAddressCodec is a temporary address codec that we will use until we // can populate it with the correct bech32 prefixes without depending on the global. type globalAccAddressCodec struct{} diff --git a/simapp/app.go b/simapp/app.go index 9e4d2f6e6c96..29e3c73a6d81 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -111,34 +111,6 @@ var ( // DefaultNodeHome default home directories for the application daemon DefaultNodeHome string - // ModuleBasics defines the module BasicManager is in charge of setting up basic, - // non-dependant module elements, such as codec registration - // and genesis verification. - ModuleBasics = module.NewBasicManager( - auth.AppModuleBasic{}, - genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), - bank.AppModuleBasic{}, - staking.AppModuleBasic{}, - mint.AppModuleBasic{}, - distr.AppModuleBasic{}, - gov.NewAppModuleBasic( - []govclient.ProposalHandler{ - paramsclient.ProposalHandler, - }, - ), - params.AppModuleBasic{}, - crisis.AppModuleBasic{}, - slashing.AppModuleBasic{}, - feegrantmodule.AppModuleBasic{}, - upgrade.AppModuleBasic{}, - evidence.AppModuleBasic{}, - authzmodule.AppModuleBasic{}, - groupmodule.AppModuleBasic{}, - vesting.AppModuleBasic{}, - nftmodule.AppModuleBasic{}, - consensus.AppModuleBasic{}, - ) - // module account permissions maccPerms = map[string][]string{ authtypes.FeeCollectorName: nil, @@ -189,7 +161,8 @@ type SimApp struct { ConsensusParamsKeeper consensusparamkeeper.Keeper // the module manager - ModuleManager *module.Manager + ModuleManager *module.Manager + BasicModuleManager module.BasicManager // simulation manager sm *module.SimulationManager @@ -216,13 +189,16 @@ func NewSimApp( appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *SimApp { - encodingConfig := makeEncodingConfig() + encodingConfig := simappparams.MakeTestEncodingConfig() appCodec := encodingConfig.Codec legacyAmino := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry txConfig := encodingConfig.TxConfig + std.RegisterLegacyAminoCodec(legacyAmino) + std.RegisterInterfaces(interfaceRegistry) + // Below we could construct and set an application specific mempool and // ABCI 1.0 PrepareProposal and ProcessProposal handlers. These defaults are // already set in the SDK's BaseApp, this shows an example of how to override @@ -404,6 +380,23 @@ func NewSimApp( consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), ) + // BasicModuleManager defines the module BasicManager is in charge of setting up basic, + // non-dependant module elements, such as codec registration and genesis verification. + // By default it is composed of all the module from the module manager. + // Additionally, app module basics can be overwritten by passing them as argument. + app.BasicModuleManager = module.NewBasicManagerFromManager( + app.ModuleManager, + map[string]module.AppModuleBasic{ + genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + govtypes.ModuleName: gov.NewAppModuleBasic( + []govclient.ProposalHandler{ + paramsclient.ProposalHandler, + }, + ), + }) + app.BasicModuleManager.RegisterLegacyAminoCodec(encodingConfig.Amino) + app.BasicModuleManager.RegisterInterfaces(encodingConfig.InterfaceRegistry) + // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. @@ -634,7 +627,7 @@ func (app *SimApp) AutoCliOpts() autocli.AppOptions { // DefaultGenesis returns a default genesis from the registered AppModuleBasic's. func (a *SimApp) DefaultGenesis() map[string]json.RawMessage { - return ModuleBasics.DefaultGenesis(a.appCodec) + return a.BasicModuleManager.DefaultGenesis(a.appCodec) } // GetKey returns the KVStoreKey for the provided store key. @@ -681,7 +674,7 @@ func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APICon nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // Register grpc-gateway routes for all modules. - ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + app.BasicModuleManager.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) // register swagger API from root so that other applications can override easily if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil { @@ -748,12 +741,3 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino return paramsKeeper } - -func makeEncodingConfig() simappparams.EncodingConfig { - encodingConfig := simappparams.MakeTestEncodingConfig() - std.RegisterLegacyAminoCodec(encodingConfig.Amino) - std.RegisterInterfaces(encodingConfig.InterfaceRegistry) - ModuleBasics.RegisterLegacyAminoCodec(encodingConfig.Amino) - ModuleBasics.RegisterInterfaces(encodingConfig.InterfaceRegistry) - return encodingConfig -} diff --git a/simapp/app_config.go b/simapp/app_config.go index cbf3c291b733..2870334d18df 100644 --- a/simapp/app_config.go +++ b/simapp/app_config.go @@ -3,6 +3,8 @@ package simapp import ( "time" + "google.golang.org/protobuf/types/known/durationpb" + runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" authmodulev1 "cosmossdk.io/api/cosmos/auth/module/v1" @@ -24,15 +26,34 @@ import ( txconfigv1 "cosmossdk.io/api/cosmos/tx/config/v1" upgrademodulev1 "cosmossdk.io/api/cosmos/upgrade/module/v1" vestingmodulev1 "cosmossdk.io/api/cosmos/vesting/module/v1" + "cosmossdk.io/depinject" + + _ "cosmossdk.io/x/evidence" // import for side-effects + _ "cosmossdk.io/x/feegrant/module" // import for side-effects + _ "cosmossdk.io/x/nft/module" // import for side-effects + _ "cosmossdk.io/x/upgrade" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/auth/vesting" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/authz/module" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/bank" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/consensus" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/crisis" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/distribution" // import for side-effects + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/gov" + _ "github.com/cosmos/cosmos-sdk/x/group/module" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/mint" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/params" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/slashing" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/staking" // import for side-effects + "cosmossdk.io/core/appconfig" evidencetypes "cosmossdk.io/x/evidence/types" + "cosmossdk.io/x/feegrant" "cosmossdk.io/x/nft" upgradetypes "cosmossdk.io/x/upgrade/types" - "google.golang.org/protobuf/types/known/durationpb" - - "cosmossdk.io/x/feegrant" - "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/types/module" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" "github.com/cosmos/cosmos-sdk/x/authz" @@ -41,9 +62,11 @@ import ( crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/group" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -74,7 +97,7 @@ var ( } // application configuration (used by depinject) - AppConfig = appconfig.Compose(&appv1alpha1.Config{ + AppConfig = depinject.Configs(appconfig.Compose(&appv1alpha1.Config{ Modules: []*appv1alpha1.ModuleConfig{ { Name: runtime.ModuleName, @@ -226,5 +249,16 @@ var ( Config: appconfig.WrapAny(&consensusmodulev1.Module{}), }, }, - }) + }), + depinject.Supply( + // supply custom module basics + map[string]module.AppModuleBasic{ + genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + govtypes.ModuleName: gov.NewAppModuleBasic( + []govclient.ProposalHandler{ + paramsclient.ProposalHandler, + }, + ), + }, + )) ) diff --git a/simapp/app_v2.go b/simapp/app_v2.go index 51d30fe00003..97859ebbb5cd 100644 --- a/simapp/app_v2.go +++ b/simapp/app_v2.go @@ -10,17 +10,11 @@ import ( "cosmossdk.io/log" dbm "github.com/cosmos/cosmos-db" - "cosmossdk.io/client/v2/autocli" "cosmossdk.io/depinject" - "cosmossdk.io/x/evidence" - evidencekeeper "cosmossdk.io/x/evidence/keeper" - nftkeeper "cosmossdk.io/x/nft/keeper" - nftmodule "cosmossdk.io/x/nft/module" - storetypes "cosmossdk.io/store/types" + evidencekeeper "cosmossdk.io/x/evidence/keeper" feegrantkeeper "cosmossdk.io/x/feegrant/keeper" - feegrantmodule "cosmossdk.io/x/feegrant/module" - "cosmossdk.io/x/upgrade" + nftkeeper "cosmossdk.io/x/nft/keeper" upgradekeeper "cosmossdk.io/x/upgrade/keeper" "github.com/cosmos/cosmos-sdk/baseapp" @@ -37,70 +31,23 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" - _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import for side-effects authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/auth/vesting" authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" - authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" - "github.com/cosmos/cosmos-sdk/x/bank" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - consensus "github.com/cosmos/cosmos-sdk/x/consensus" consensuskeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" - "github.com/cosmos/cosmos-sdk/x/crisis" crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" - distr "github.com/cosmos/cosmos-sdk/x/distribution" distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" - "github.com/cosmos/cosmos-sdk/x/gov" - govclient "github.com/cosmos/cosmos-sdk/x/gov/client" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" groupkeeper "github.com/cosmos/cosmos-sdk/x/group/keeper" - groupmodule "github.com/cosmos/cosmos-sdk/x/group/module" - "github.com/cosmos/cosmos-sdk/x/mint" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" - "github.com/cosmos/cosmos-sdk/x/params" - paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/cosmos/cosmos-sdk/x/slashing" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" - "github.com/cosmos/cosmos-sdk/x/staking" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) -var ( - // DefaultNodeHome default home directories for the application daemon - DefaultNodeHome string - - // ModuleBasics defines the module BasicManager is in charge of setting up basic, - // non-dependant module elements, such as codec registration - // and genesis verification. - ModuleBasics = module.NewBasicManager( - auth.AppModuleBasic{}, - genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), - bank.AppModuleBasic{}, - staking.AppModuleBasic{}, - mint.AppModuleBasic{}, - distr.AppModuleBasic{}, - gov.NewAppModuleBasic( - []govclient.ProposalHandler{ - paramsclient.ProposalHandler, - }, - ), - params.AppModuleBasic{}, - crisis.AppModuleBasic{}, - slashing.AppModuleBasic{}, - feegrantmodule.AppModuleBasic{}, - upgrade.AppModuleBasic{}, - evidence.AppModuleBasic{}, - authzmodule.AppModuleBasic{}, - groupmodule.AppModuleBasic{}, - vesting.AppModuleBasic{}, - nftmodule.AppModuleBasic{}, - consensus.AppModuleBasic{}, - ) -) +// DefaultNodeHome default home directories for the application daemon +var DefaultNodeHome string var ( _ runtime.AppI = (*SimApp)(nil) @@ -116,7 +63,6 @@ type SimApp struct { appCodec codec.Codec txConfig client.TxConfig interfaceRegistry codectypes.InterfaceRegistry - autoCliOpts autocli.AppOptions // keepers AccountKeeper authkeeper.AccountKeeper @@ -168,6 +114,7 @@ func NewSimApp( depinject.Supply( // supply the application options appOpts, + // supply the logger logger, // ADVANCED CONFIGURATION @@ -202,7 +149,6 @@ func NewSimApp( &app.legacyAmino, &app.txConfig, &app.interfaceRegistry, - &app.autoCliOpts, &app.AccountKeeper, &app.BankKeeper, &app.StakingKeeper, @@ -324,11 +270,6 @@ func (app *SimApp) TxConfig() client.TxConfig { return app.txConfig } -// AutoCliOpts returns the autocli options for the app. -func (app *SimApp) AutoCliOpts() autocli.AppOptions { - return app.autoCliOpts -} - // GetKey returns the KVStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index ba900be9dc54..bf287893e864 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -1,3 +1,5 @@ +//go:build app_v1 + package cmd import ( @@ -28,6 +30,7 @@ import ( servertypes "github.com/cosmos/cosmos-sdk/server/types" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/tx" txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" @@ -41,8 +44,7 @@ import ( // main function. func NewRootCmd() *cobra.Command { // we "pre"-instantiate the application for getting the injected/configured encoding configuration - // note, this is not necessary when using app wiring, as depinject can be directly used. - // for consistency between app-v1 and app-v2, we do it the same way via methods on simapp + // note, this is not necessary when using app wiring, as depinject can be directly used (see root_v2.go) tempApp := simapp.NewSimApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, simtestutil.NewAppOptionsWithFlagHome(tempDir())) encodingConfig := params.EncodingConfig{ InterfaceRegistry: tempApp.InterfaceRegistry(), @@ -101,7 +103,7 @@ func NewRootCmd() *cobra.Command { }, } - initRootCmd(rootCmd, encodingConfig) + initRootCmd(rootCmd, encodingConfig, tempApp.BasicModuleManager) if err := tempApp.AutoCliOpts().EnhanceRootCommand(rootCmd); err != nil { panic(err) @@ -179,13 +181,13 @@ lru_size = 0` return customAppTemplate, customAppConfig } -func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { +func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig, basicManager module.BasicManager) { cfg := sdk.GetConfig() cfg.Seal() rootCmd.AddCommand( - genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome), - NewTestnetCmd(simapp.ModuleBasics, banktypes.GenesisBalancesIterator{}), + genutilcli.InitCmd(basicManager, simapp.DefaultNodeHome), + NewTestnetCmd(basicManager, banktypes.GenesisBalancesIterator{}), debug.Cmd(), confixcmd.ConfigCommand(), pruning.Cmd(newApp), @@ -196,7 +198,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( rpc.StatusCommand(), - genesisCommand(encodingConfig), + genesisCommand(encodingConfig, basicManager), queryCommand(), txCommand(), keys.Commands(simapp.DefaultNodeHome), @@ -211,8 +213,8 @@ func addModuleInitFlags(startCmd *cobra.Command) { } // genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter -func genesisCommand(encodingConfig params.EncodingConfig, cmds ...*cobra.Command) *cobra.Command { - cmd := genutilcli.Commands(encodingConfig.TxConfig, simapp.ModuleBasics, simapp.DefaultNodeHome) +func genesisCommand(encodingConfig params.EncodingConfig, basicManager module.BasicManager, cmds ...*cobra.Command) *cobra.Command { + cmd := genutilcli.Commands(encodingConfig.TxConfig, basicManager, simapp.DefaultNodeHome) for _, subCmd := range cmds { cmd.AddCommand(subCmd) diff --git a/simapp/simd/cmd/root_v2.go b/simapp/simd/cmd/root_v2.go new file mode 100644 index 000000000000..db8c0298afce --- /dev/null +++ b/simapp/simd/cmd/root_v2.go @@ -0,0 +1,341 @@ +//go:build !app_v1 + +package cmd + +import ( + "errors" + "io" + "os" + + cmtcfg "github.com/cometbft/cometbft/config" + dbm "github.com/cosmos/cosmos-db" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "cosmossdk.io/client/v2/autocli" + "cosmossdk.io/depinject" + "cosmossdk.io/log" + "cosmossdk.io/simapp" + confixcmd "cosmossdk.io/tools/confix/cmd" + rosettaCmd "cosmossdk.io/tools/rosetta/cmd" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/config" + "github.com/cosmos/cosmos-sdk/client/debug" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/keys" + "github.com/cosmos/cosmos-sdk/client/pruning" + "github.com/cosmos/cosmos-sdk/client/rpc" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/server" + serverconfig "github.com/cosmos/cosmos-sdk/server/config" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" + "github.com/cosmos/cosmos-sdk/x/auth/tx" + txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config" + "github.com/cosmos/cosmos-sdk/x/auth/types" + 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" +) + +// NewRootCmd creates a new root command for simd. It is called once in the main function. +func NewRootCmd() *cobra.Command { + var ( + interfaceRegistry codectypes.InterfaceRegistry + appCodec codec.Codec + txConfig client.TxConfig + legacyAmino *codec.LegacyAmino + autoCliOpts autocli.AppOptions + moduleBasicManager module.BasicManager + ) + + if err := depinject.Inject(depinject.Configs(simapp.AppConfig, depinject.Supply(log.NewNopLogger())), + &interfaceRegistry, + &appCodec, + &txConfig, + &legacyAmino, + &autoCliOpts, + &moduleBasicManager, + ); err != nil { + panic(err) + } + + initClientCtx := client.Context{}. + WithCodec(appCodec). + WithInterfaceRegistry(interfaceRegistry). + WithLegacyAmino(legacyAmino). + WithInput(os.Stdin). + WithAccountRetriever(types.AccountRetriever{}). + WithHomeDir(simapp.DefaultNodeHome). + WithViper("") // In simapp, we don't use any prefix for env variables. + + rootCmd := &cobra.Command{ + Use: "simd", + Short: "simulation app", + PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { + // set the default command outputs + cmd.SetOut(cmd.OutOrStdout()) + cmd.SetErr(cmd.ErrOrStderr()) + + initClientCtx = initClientCtx.WithCmdContext(cmd.Context()) + initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) + if err != nil { + return err + } + + initClientCtx, err = config.ReadFromClientConfig(initClientCtx) + if err != nil { + return err + } + + // This needs to go after ReadFromClientConfig, as that function + // sets the RPC client needed for SIGN_MODE_TEXTUAL. + txConfigOpts := tx.ConfigOptions{ + TextualCoinMetadataQueryFn: txmodule.NewGRPCCoinMetadataQueryFn(initClientCtx), + } + txConfigWithTextual := tx.NewTxConfigWithOptions( + codec.NewProtoCodec(interfaceRegistry), + txConfigOpts, + ) + + initClientCtx = initClientCtx.WithTxConfig(txConfigWithTextual) + if err := client.SetCmdClientContextHandler(initClientCtx, cmd); err != nil { + return err + } + + customAppTemplate, customAppConfig := initAppConfig() + customCMTConfig := initCometBFTConfig() + + return server.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customCMTConfig) + }, + } + + initRootCmd(rootCmd, txConfig, interfaceRegistry, appCodec, moduleBasicManager) + + if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { + panic(err) + } + + return rootCmd +} + +// initCometBFTConfig helps to override default CometBFT Config values. +// return cmtcfg.DefaultConfig if no custom configuration is required for the application. +func initCometBFTConfig() *cmtcfg.Config { + cfg := cmtcfg.DefaultConfig() + + // these values put a higher strain on node memory + // cfg.P2P.MaxNumInboundPeers = 100 + // cfg.P2P.MaxNumOutboundPeers = 40 + + return cfg +} + +// initAppConfig helps to override default appConfig template and configs. +// return "", nil if no custom configuration is required for the application. +func initAppConfig() (string, interface{}) { + // The following code snippet is just for reference. + + // WASMConfig defines configuration for the wasm module. + type WASMConfig struct { + // This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries + QueryGasLimit uint64 `mapstructure:"query_gas_limit"` + + // Address defines the gRPC-web server to listen on + LruSize uint64 `mapstructure:"lru_size"` + } + + type CustomAppConfig struct { + serverconfig.Config + + WASM WASMConfig `mapstructure:"wasm"` + } + + // Optionally allow the chain developer to overwrite the SDK's default + // server config. + srvCfg := serverconfig.DefaultConfig() + // The SDK's default minimum gas price is set to "" (empty value) inside + // app.toml. If left empty by validators, the node will halt on startup. + // However, the chain developer can set a default app.toml value for their + // validators here. + // + // In summary: + // - if you leave srvCfg.MinGasPrices = "", all validators MUST tweak their + // own app.toml config, + // - if you set srvCfg.MinGasPrices non-empty, validators CAN tweak their + // own app.toml to override, or use this default value. + // + // In simapp, we set the min gas prices to 0. + srvCfg.MinGasPrices = "0stake" + // srvCfg.BaseConfig.IAVLDisableFastNode = true // disable fastnode by default + + customAppConfig := CustomAppConfig{ + Config: *srvCfg, + WASM: WASMConfig{ + LruSize: 1, + QueryGasLimit: 300000, + }, + } + + customAppTemplate := serverconfig.DefaultConfigTemplate + ` +[wasm] +# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries +query_gas_limit = 300000 +# This is the number of wasm vm instances we keep cached in memory for speed-up +# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally +lru_size = 0` + + return customAppTemplate, customAppConfig +} + +func initRootCmd( + rootCmd *cobra.Command, + txConfig client.TxConfig, + interfaceRegistry codectypes.InterfaceRegistry, + appCodec codec.Codec, + basicManager module.BasicManager, +) { + cfg := sdk.GetConfig() + cfg.Seal() + + rootCmd.AddCommand( + genutilcli.InitCmd(basicManager, simapp.DefaultNodeHome), + NewTestnetCmd(basicManager, banktypes.GenesisBalancesIterator{}), + debug.Cmd(), + confixcmd.ConfigCommand(), + pruning.Cmd(newApp), + ) + + server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, appExport, addModuleInitFlags) + + // add keybase, auxiliary RPC, query, genesis, and tx child commands + rootCmd.AddCommand( + rpc.StatusCommand(), + genesisCommand(txConfig, basicManager), + queryCommand(), + txCommand(), + keys.Commands(simapp.DefaultNodeHome), + ) + + // add rosetta + rootCmd.AddCommand(rosettaCmd.RosettaCommand(interfaceRegistry, appCodec)) +} + +func addModuleInitFlags(startCmd *cobra.Command) { + crisis.AddModuleInitFlags(startCmd) +} + +// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter +func genesisCommand(txConfig client.TxConfig, basicManager module.BasicManager, cmds ...*cobra.Command) *cobra.Command { + cmd := genutilcli.Commands(txConfig, basicManager, simapp.DefaultNodeHome) + + for _, subCmd := range cmds { + cmd.AddCommand(subCmd) + } + return cmd +} + +func queryCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "query", + Aliases: []string{"q"}, + Short: "Querying subcommands", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + rpc.ValidatorCommand(), + server.QueryBlockCmd(), + authcmd.QueryTxsByEventsCmd(), + server.QueryBlocksCmd(), + authcmd.QueryTxCmd(), + ) + + return cmd +} + +func txCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "tx", + Short: "Transactions subcommands", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + authcmd.GetSignCommand(), + authcmd.GetSignBatchCommand(), + authcmd.GetMultiSignCommand(), + authcmd.GetMultiSignBatchCmd(), + authcmd.GetValidateSignaturesCommand(), + authcmd.GetBroadcastCommand(), + authcmd.GetEncodeCommand(), + authcmd.GetDecodeCommand(), + authcmd.GetAuxToFeeCommand(), + ) + + return cmd +} + +// newApp creates the application +func newApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + appOpts servertypes.AppOptions, +) servertypes.Application { + baseappOptions := server.DefaultBaseappOptions(appOpts) + + return simapp.NewSimApp( + logger, db, traceStore, true, + appOpts, + baseappOptions..., + ) +} + +// appExport creates a new simapp (optionally at a given height) and exports state. +func appExport( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + height int64, + forZeroHeight bool, + jailAllowedAddrs []string, + appOpts servertypes.AppOptions, + modulesToExport []string, +) (servertypes.ExportedApp, error) { + // this check is necessary as we use the flag in x/upgrade. + // we can exit more gracefully by checking the flag here. + homePath, ok := appOpts.Get(flags.FlagHome).(string) + if !ok || homePath == "" { + return servertypes.ExportedApp{}, errors.New("application home not set") + } + + viperAppOpts, ok := appOpts.(*viper.Viper) + if !ok { + return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper") + } + + // overwrite the FlagInvCheckPeriod + viperAppOpts.Set(server.FlagInvCheckPeriod, 1) + appOpts = viperAppOpts + + var simApp *simapp.SimApp + if height != -1 { + simApp = simapp.NewSimApp(logger, db, traceStore, false, appOpts) + + if err := simApp.LoadHeight(height); err != nil { + return servertypes.ExportedApp{}, err + } + } else { + simApp = simapp.NewSimApp(logger, db, traceStore, true, appOpts) + } + + return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) +} diff --git a/simapp/simd/cmd/testnet_test.go b/simapp/simd/cmd/testnet_test.go index d7b05f685cbc..71ef4d304618 100644 --- a/simapp/simd/cmd/testnet_test.go +++ b/simapp/simd/cmd/testnet_test.go @@ -9,26 +9,43 @@ import ( "github.com/stretchr/testify/require" "cosmossdk.io/log" - "cosmossdk.io/simapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/types/module" moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/bank" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/consensus" + "github.com/cosmos/cosmos-sdk/x/distribution" + "github.com/cosmos/cosmos-sdk/x/genutil" genutiltest "github.com/cosmos/cosmos-sdk/x/genutil/client/testutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/cosmos/cosmos-sdk/x/mint" + "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/staking" ) func Test_TestnetCmd(t *testing.T) { + moduleBasic := module.NewBasicManager( + auth.AppModuleBasic{}, + genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + bank.AppModuleBasic{}, + staking.AppModuleBasic{}, + mint.AppModuleBasic{}, + distribution.AppModuleBasic{}, + params.AppModuleBasic{}, + consensus.AppModuleBasic{}, + ) + home := t.TempDir() - encodingConfig := moduletestutil.MakeTestEncodingConfig(staking.AppModuleBasic{}, auth.AppModuleBasic{}) + encodingConfig := moduletestutil.MakeTestEncodingConfig(auth.AppModuleBasic{}, staking.AppModuleBasic{}) logger := log.NewNopLogger() cfg, err := genutiltest.CreateDefaultCometConfig(home) require.NoError(t, err) - err = genutiltest.ExecInitCmd(simapp.ModuleBasics, home, encodingConfig.Codec) + err = genutiltest.ExecInitCmd(moduleBasic, home, encodingConfig.Codec) require.NoError(t, err) serverCtx := server.NewContext(viper.New(), cfg, logger) @@ -40,7 +57,7 @@ func Test_TestnetCmd(t *testing.T) { ctx := context.Background() ctx = context.WithValue(ctx, server.ServerContextKey, serverCtx) ctx = context.WithValue(ctx, client.ClientContextKey, &clientCtx) - cmd := testnetInitFilesCmd(simapp.ModuleBasics, banktypes.GenesisBalancesIterator{}) + cmd := testnetInitFilesCmd(moduleBasic, banktypes.GenesisBalancesIterator{}) cmd.SetArgs([]string{fmt.Sprintf("--%s=test", flags.FlagKeyringBackend), fmt.Sprintf("--output-dir=%s", home)}) err = cmd.ExecuteContext(ctx) require.NoError(t, err) diff --git a/types/module/module.go b/types/module/module.go index be144562ebbc..364724c95d5e 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -90,6 +90,25 @@ func NewBasicManager(modules ...AppModuleBasic) BasicManager { return moduleMap } +// NewBasicManagerFromManager creates a new BasicManager from a Manager +// The BasicManager will contain all AppModuleBasic from the AppModule Manager +// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map +func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic) BasicManager { + moduleMap := make(map[string]AppModuleBasic) + for name, module := range manager.Modules { + if customBasicMod, ok := customModuleBasics[name]; ok { + moduleMap[name] = customBasicMod + continue + } + + if basicMod, ok := module.(AppModuleBasic); ok { + moduleMap[name] = basicMod + } + } + + return moduleMap +} + // RegisterLegacyAminoCodec registers all module codecs func (bm BasicManager) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { for _, b := range bm {