From 880ed10a78ba54e5393a9723d58026bcda8ee8ab Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 24 May 2022 21:09:24 -0400 Subject: [PATCH] feat: start app wiring with runtime and x/params modules (#11924) * feat: start app wiring with runtime and x/params modules * WIP * WIP * docs * docs, cleanup * fixing tests * rollback unrelated changes * fix * test fixes * simplification, tests * fix tests * docs * go mod tidy * update module path * codegen * address middleware removal * update container alpha 4 * Fix cosmossdk.io/api dependency conflict - go mod tidy Co-authored-by: Matt Kocubinski --- app.go | 161 ++++++++++++++++++---------------------------------- app.yaml | 25 ++++++++ app_test.go | 10 ++-- export.go | 2 +- sim_test.go | 5 +- upgrades.go | 6 +- 6 files changed, 91 insertions(+), 118 deletions(-) create mode 100644 app.yaml diff --git a/app.go b/app.go index cb50d352bdd4..b6149141c968 100644 --- a/app.go +++ b/app.go @@ -1,7 +1,7 @@ package simapp import ( - "encoding/json" + _ "embed" "io" "net/http" "os" @@ -15,11 +15,16 @@ import ( tmos "github.com/tendermint/tendermint/libs/os" dbm "github.com/tendermint/tm-db" + "github.com/cosmos/cosmos-sdk/container" + + "cosmossdk.io/core/appconfig" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + _ "github.com/cosmos/cosmos-sdk/runtime" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" @@ -30,13 +35,11 @@ import ( "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" - "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/ante" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" "github.com/cosmos/cosmos-sdk/x/auth/posthandler" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" - authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/auth/vesting" vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" @@ -152,10 +155,10 @@ var ( // They are exported for convenience in creating helper functions, as object // capabilities aren't needed for testing. type SimApp struct { - *baseapp.BaseApp + *runtime.App legacyAmino *codec.LegacyAmino appCodec codec.Codec - interfaceRegistry types.InterfaceRegistry + interfaceRegistry codectypes.InterfaceRegistry invCheckPeriod uint @@ -182,9 +185,6 @@ type SimApp struct { GroupKeeper groupkeeper.Keeper NFTKeeper nftkeeper.Keeper - // the module manager - mm *module.Manager - // simulation manager sm *module.SimulationManager @@ -201,54 +201,64 @@ func init() { DefaultNodeHome = filepath.Join(userHomeDir, ".simapp") } +//go:embed app.yaml +var appConfigYaml []byte + +var appConfig = appconfig.LoadYAML(appConfigYaml) + // 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, appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp), ) *SimApp { - appCodec := encodingConfig.Codec - legacyAmino := encodingConfig.Amino - interfaceRegistry := encodingConfig.InterfaceRegistry + var appBuilder *runtime.AppBuilder + var paramsKeeper paramskeeper.Keeper + var appCodec codec.Codec + var legacyAmino *codec.LegacyAmino + var interfaceRegistry codectypes.InterfaceRegistry + err := container.Build(appConfig, + &appBuilder, + ¶msKeeper, + &appCodec, + &legacyAmino, + &interfaceRegistry, + ) + if err != nil { + panic(err) + } - bApp := baseapp.NewBaseApp(appName, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...) - bApp.SetCommitMultiStoreTracer(traceStore) - bApp.SetVersion(version.Version) - bApp.SetInterfaceRegistry(interfaceRegistry) + runtimeApp := appBuilder.Build(logger, db, traceStore, baseAppOptions...) keys := sdk.NewKVStoreKeys( authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, + govtypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, capabilitytypes.StoreKey, authzkeeper.StoreKey, nftkeeper.StoreKey, group.StoreKey, ) - tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) // NOTE: The testingkey is just mounted for testing purposes. Actual applications should // not include this key. memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, "testingkey") // configure state listening capabilities using AppOptions // we are doing nothing with the returned streamingServices and waitGroup in this case - if _, _, err := streaming.LoadStreamingServices(bApp, appOpts, appCodec, keys); err != nil { + if _, _, err := streaming.LoadStreamingServices(runtimeApp.BaseApp, appOpts, appCodec, keys); err != nil { tmos.Exit(err.Error()) } app := &SimApp{ - BaseApp: bApp, + App: runtimeApp, legacyAmino: legacyAmino, appCodec: appCodec, interfaceRegistry: interfaceRegistry, invCheckPeriod: invCheckPeriod, keys: keys, - tkeys: tkeys, memKeys: memKeys, } - app.ParamsKeeper = initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) - - // set the BaseApp's parameter store - bApp.SetParamStore(app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramstypes.ConsensusParamsKeyTable())) + app.ParamsKeeper = paramsKeeper + initParamsKeeper(paramsKeeper) app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) // Applications that wish to enforce statically created ScopedKeepers should call `Seal` after creating @@ -341,7 +351,7 @@ func NewSimApp( // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. - app.mm = module.NewManager( + err = app.RegisterModules( genutil.NewAppModule( app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx, encodingConfig.TxConfig, @@ -359,32 +369,13 @@ func NewSimApp( staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), upgrade.NewAppModule(app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), - params.NewAppModule(app.ParamsKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), groupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), nftmodule.NewAppModule(appCodec, app.NFTKeeper, app.AccountKeeper, app.BankKeeper, app.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. - // NOTE: staking module is required if HistoricalEntries param > 0 - // NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC) - app.mm.SetOrderBeginBlockers( - upgradetypes.ModuleName, capabilitytypes.ModuleName, minttypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, - evidencetypes.ModuleName, stakingtypes.ModuleName, - authtypes.ModuleName, banktypes.ModuleName, govtypes.ModuleName, crisistypes.ModuleName, genutiltypes.ModuleName, - authz.ModuleName, feegrant.ModuleName, nft.ModuleName, group.ModuleName, - paramstypes.ModuleName, vestingtypes.ModuleName, - ) - app.mm.SetOrderEndBlockers( - crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName, - capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, - slashingtypes.ModuleName, minttypes.ModuleName, - genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName, - feegrant.ModuleName, nft.ModuleName, group.ModuleName, - paramstypes.ModuleName, upgradetypes.ModuleName, vestingtypes.ModuleName, - ) + if err != nil { + panic(err) + } // NOTE: The genutils module must occur after staking so that pools are // properly initialized with tokens from genesis accounts. @@ -392,7 +383,7 @@ func NewSimApp( // NOTE: Capability module must occur first so that it can initialize any capabilities // so that other modules that want to create or claim capabilities afterwards in InitChain // can do so safely. - app.mm.SetOrderInitGenesis( + app.ModuleManager.SetOrderInitGenesis( capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName, slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName, crisistypes.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, authz.ModuleName, @@ -403,10 +394,10 @@ func NewSimApp( // Uncomment if you want to set a custom migration order here. // app.mm.SetOrderMigrations(custom order) - app.mm.RegisterInvariants(&app.CrisisKeeper) - app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) + app.ModuleManager.RegisterInvariants(&app.CrisisKeeper) + app.ModuleManager.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino) app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) - app.mm.RegisterServices(app.configurator) + app.ModuleManager.RegisterServices(app.configurator) // add test gRPC service for testing gRPC queries in isolation testdata_pulsar.RegisterQueryServer(app.GRPCQueryRouter(), testdata_pulsar.QueryImpl{}) @@ -425,7 +416,6 @@ func NewSimApp( staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), - params.NewAppModule(app.ParamsKeeper), evidence.NewAppModule(app.EvidenceKeeper), authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), groupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), @@ -436,13 +426,11 @@ func NewSimApp( // initialize stores app.MountKVStores(keys) - app.MountTransientStores(tkeys) app.MountMemoryStores(memKeys) // initialize BaseApp + app.SetTxDecoder(encodingConfig.TxConfig.TxDecoder()) app.SetInitChainer(app.InitChainer) - app.SetBeginBlocker(app.BeginBlocker) - app.SetEndBlocker(app.EndBlocker) app.setAnteHandler(encodingConfig.TxConfig, cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))) // In v0.46, the SDK introduces _postHandlers_. PostHandlers are like // antehandlers, but are run _after_ the `runMsgs` execution. They are also @@ -464,10 +452,9 @@ func NewSimApp( // upgrade. app.setPostHandler() - if loadLatest { - if err := app.LoadLatestVersion(); err != nil { - tmos.Exit(err.Error()) - } + err = app.Load(loadLatest) + if err != nil { + panic(err) } return app @@ -511,24 +498,10 @@ func (app *SimApp) setPostHandler() { // Name returns the name of the App func (app *SimApp) Name() string { return app.BaseApp.Name() } -// BeginBlocker application updates every begin block -func (app *SimApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock { - return app.mm.BeginBlock(ctx, req) -} - -// EndBlocker application updates every end block -func (app *SimApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { - return app.mm.EndBlock(ctx, req) -} - // InitChainer application update at chain initialization func (app *SimApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - var genesisState GenesisState - if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil { - panic(err) - } - app.UpgradeKeeper.SetModuleVersionMap(ctx, app.mm.GetVersionMap()) - return app.mm.InitGenesis(ctx, app.appCodec, genesisState) + app.UpgradeKeeper.SetModuleVersionMap(ctx, app.ModuleManager.GetVersionMap()) + return app.App.InitChainer(ctx, req) } // LoadHeight loads a particular height @@ -563,7 +536,7 @@ func (app *SimApp) AppCodec() codec.Codec { } // InterfaceRegistry returns SimApp's InterfaceRegistry -func (app *SimApp) InterfaceRegistry() types.InterfaceRegistry { +func (app *SimApp) InterfaceRegistry() codectypes.InterfaceRegistry { return app.interfaceRegistry } @@ -604,36 +577,14 @@ func (app *SimApp) SimulationManager() *module.SimulationManager { // RegisterAPIRoutes registers all application module routes with the provided // API server. func (app *SimApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { - clientCtx := apiSvr.ClientCtx - // Register new tx routes from grpc-gateway. - authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) - // Register new tendermint queries routes from grpc-gateway. - tmservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) - - // Register grpc-gateway routes for all modules. - ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + app.App.RegisterAPIRoutes(apiSvr, apiConfig) // register swagger API from root so that other applications can override easily if apiConfig.Swagger { - RegisterSwaggerAPI(clientCtx, apiSvr.Router) + RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router) } } -// RegisterTxService implements the Application.RegisterTxService method. -func (app *SimApp) RegisterTxService(clientCtx client.Context) { - authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) -} - -// RegisterTendermintService implements the Application.RegisterTendermintService method. -func (app *SimApp) RegisterTendermintService(clientCtx client.Context) { - tmservice.RegisterTendermintService( - clientCtx, - app.BaseApp.GRPCQueryRouter(), - app.interfaceRegistry, - app.Query, - ) -} - // RegisterSwaggerAPI registers swagger route with API Server func RegisterSwaggerAPI(_ client.Context, rtr *mux.Router) { statikFS, err := fs.New() @@ -655,9 +606,7 @@ func GetMaccPerms() map[string][]string { } // initParamsKeeper init params keeper and its subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { - paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) - +func initParamsKeeper(paramsKeeper paramskeeper.Keeper) { paramsKeeper.Subspace(authtypes.ModuleName) paramsKeeper.Subspace(banktypes.ModuleName) paramsKeeper.Subspace(stakingtypes.ModuleName) @@ -666,6 +615,4 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(slashingtypes.ModuleName) paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1.ParamKeyTable()) paramsKeeper.Subspace(crisistypes.ModuleName) - - return paramsKeeper } diff --git a/app.yaml b/app.yaml new file mode 100644 index 000000000000..82ceeb8450a5 --- /dev/null +++ b/app.yaml @@ -0,0 +1,25 @@ +modules: + - name: runtime + config: + "@type": cosmos.app.runtime.v1alpha1.Module + + # 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. + # NOTE: staking module is required if HistoricalEntries param > 0 + # NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC) + begin_blockers: [ upgrade, capability, mint, distribution, slashing, + evidence, staking, auth, bank, gov, crisis, genutil, + authz, feegrant, nft, group, + params, vesting ] + + end_blockers: [ crisis, gov, staking, + capability, auth, bank, distribution, + slashing, mint, + genutil, evidence, authz, + feegrant, nft, group, + params, upgrade, vesting ] + + - name: params + config: + "@type": cosmos.params.module.v1.Module diff --git a/app_test.go b/app_test.go index e5bd3365f6b6..d24348be8d74 100644 --- a/app_test.go +++ b/app_test.go @@ -89,7 +89,7 @@ func TestRunMigrations(t *testing.T) { // // The loop below is the same as calling `RegisterServices` on // ModuleManager, except that we skip x/bank. - for _, module := range app.mm.Modules { + for _, module := range app.ModuleManager.Modules { if module.Name() == banktypes.ModuleName { continue } @@ -167,7 +167,7 @@ func TestRunMigrations(t *testing.T) { // Run migrations only for bank. That's why we put the initial // version for bank as 1, and for all other modules, we put as // their latest ConsensusVersion. - _, err = app.mm.RunMigrations( + _, err = app.ModuleManager.RunMigrations( app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}), app.configurator, module.VersionMap{ "bank": 1, @@ -217,11 +217,11 @@ func TestInitGenesisOnMigration(t *testing.T) { mockModule.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(app.appCodec), gomock.Eq(mockDefaultGenesis)).Times(1).Return(nil) mockModule.EXPECT().ConsensusVersion().Times(1).Return(uint64(0)) - app.mm.Modules["mock"] = mockModule + app.ModuleManager.Modules["mock"] = mockModule // Run migrations only for "mock" module. We exclude it from // the VersionMap to simulate upgrading with a new module. - _, err := app.mm.RunMigrations(ctx, app.configurator, + _, err := app.ModuleManager.RunMigrations(ctx, app.configurator, module.VersionMap{ "bank": bank.AppModule{}.ConsensusVersion(), "auth": auth.AppModule{}.ConsensusVersion(), @@ -261,7 +261,7 @@ func TestUpgradeStateOnGenesis(t *testing.T) { // make sure the upgrade keeper has version map in state ctx := app.NewContext(false, tmproto.Header{}) vm := app.UpgradeKeeper.GetModuleVersionMap(ctx) - for v, i := range app.mm.Modules { + for v, i := range app.ModuleManager.Modules { require.Equal(t, vm[v], i.ConsensusVersion()) } } diff --git a/export.go b/export.go index 19a4a64ae56c..fd6a39c5711a 100644 --- a/export.go +++ b/export.go @@ -30,7 +30,7 @@ func (app *SimApp) ExportAppStateAndValidators( app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs) } - genState := app.mm.ExportGenesis(ctx, app.appCodec) + genState := app.ModuleManager.ExportGenesis(ctx, app.appCodec) appState, err := json.MarshalIndent(genState, "", " ") if err != nil { return servertypes.ExportedApp{}, err diff --git a/sim_test.go b/sim_test.go index bde9aa5859e4..e09df9045950 100644 --- a/sim_test.go +++ b/sim_test.go @@ -9,13 +9,14 @@ import ( "strings" "testing" - storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/simapp/helpers" "github.com/cosmos/cosmos-sdk/store" @@ -168,7 +169,7 @@ func TestAppImportExport(t *testing.T) { ctxA := app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) ctxB := newApp.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}) - newApp.mm.InitGenesis(ctxB, app.AppCodec(), genesisState) + newApp.ModuleManager.InitGenesis(ctxB, app.AppCodec(), genesisState) newApp.StoreConsensusParams(ctxB, exported.ConsensusParams) fmt.Printf("comparing stores...\n") diff --git a/upgrades.go b/upgrades.go index 2a62ae5c881c..b7a26ae80a3e 100644 --- a/upgrades.go +++ b/upgrades.go @@ -20,11 +20,11 @@ func (app SimApp) RegisterUpgradeHandlers() { func(ctx sdk.Context, plan upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { // We set fromVersion to 1 to avoid running InitGenesis for modules for // in-store migrations. - // + // // If you wish to skip any module migrations, i.e. they were already migrated // in an older version, you can use `modulename.AppModule{}.ConsensusVersion()` // instead of `1` below. - // + // // For example: // "auth": auth.AppModule{}.ConsensusVersion() fromVM := map[string]uint64{ @@ -46,7 +46,7 @@ func (app SimApp) RegisterUpgradeHandlers() { "genutil": 1, } - return app.mm.RunMigrations(ctx, app.configurator, fromVM) + return app.ModuleManager.RunMigrations(ctx, app.configurator, fromVM) }) upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()