diff --git a/runtime/v2/app.go b/runtime/v2/app.go index 3f7f042e6a..59ede48711 100644 --- a/runtime/v2/app.go +++ b/runtime/v2/app.go @@ -19,7 +19,7 @@ import ( "cosmossdk.io/server/v2/stf" ) -var _ AppI[transaction.Tx] = (*App)(nil) +var _ AppI[transaction.Tx] = (*App[transaction.Tx])(nil) // AppI is an interface that defines the methods required by the App. type AppI[T transaction.Tx] interface { @@ -33,7 +33,7 @@ type AppI[T transaction.Tx] interface { QueryWithState(ctx context.Context, state store.ReaderMap, request transaction.Msg) (transaction.Msg, error) Logger() log.Logger - ModuleManager() *MM + ModuleManager() *MM[T] Close() error } @@ -46,11 +46,11 @@ type AppI[T transaction.Tx] interface { // App can be used to create a hybrid app.go setup where some configuration is // done declaratively with an app config and the rest of it is done the old way. // See simapp/app_v2.go for an example of this setup. -type App struct { - *appmanager.AppManager[transaction.Tx] +type App[T transaction.Tx] struct { + *appmanager.AppManager[T] // app manager dependencies - stf *stf.STF[transaction.Tx] + stf *stf.STF[T] msgRouterBuilder *stf.MsgRouterBuilder queryRouterBuilder *stf.MsgRouterBuilder db Store @@ -64,47 +64,47 @@ type App struct { storeKeys []string interfaceRegistrar registry.InterfaceRegistrar amino legacy.Amino - moduleManager *MM + moduleManager *MM[T] } // Logger returns the app logger. -func (a *App) Logger() log.Logger { +func (a *App[T]) Logger() log.Logger { return a.logger } // ModuleManager returns the module manager. -func (a *App) ModuleManager() *MM { +func (a *App[T]) ModuleManager() *MM[T] { return a.moduleManager } // DefaultGenesis returns a default genesis from the registered modules. -func (a *App) DefaultGenesis() map[string]json.RawMessage { +func (a *App[T]) DefaultGenesis() map[string]json.RawMessage { return a.moduleManager.DefaultGenesis() } // LoadLatest loads the latest version. -func (a *App) LoadLatest() error { +func (a *App[T]) LoadLatest() error { return a.db.LoadLatestVersion() } // LoadHeight loads a particular height -func (a *App) LoadHeight(height uint64) error { +func (a *App[T]) LoadHeight(height uint64) error { return a.db.LoadVersion(height) } // Close is called in start cmd to gracefully cleanup resources. -func (a *App) Close() error { +func (a *App[T]) Close() error { return nil } // GetStoreKeys returns all the app store keys. -func (a *App) GetStoreKeys() []string { +func (a *App[T]) GetStoreKeys() []string { return a.storeKeys } // UnsafeFindStoreKey fetches a registered StoreKey from the App in linear time. // NOTE: This should only be used in testing. -func (a *App) UnsafeFindStoreKey(storeKey string) (string, error) { +func (a *App[T]) UnsafeFindStoreKey(storeKey string) (string, error) { i := slices.IndexFunc(a.storeKeys, func(s string) bool { return s == storeKey }) if i == -1 { return "", errors.New("store key not found") @@ -114,19 +114,19 @@ func (a *App) UnsafeFindStoreKey(storeKey string) (string, error) { } // GetStore returns the app store. -func (a *App) GetStore() Store { +func (a *App[T]) GetStore() Store { return a.db } // GetLogger returns the app logger. -func (a *App) GetLogger() log.Logger { +func (a *App[T]) GetLogger() log.Logger { return a.logger } -func (a *App) ExecuteGenesisTx(_ []byte) error { +func (a *App[T]) ExecuteGenesisTx(_ []byte) error { panic("App.ExecuteGenesisTx not supported in runtime/v2") } -func (a *App) GetAppManager() *appmanager.AppManager[transaction.Tx] { +func (a *App[T]) GetAppManager() *appmanager.AppManager[T] { return a.AppManager } diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index e3728a2ec0..0bdf5992d6 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -19,24 +19,24 @@ import ( // AppBuilder is a type that is injected into a container by the runtime/v2 module // (as *AppBuilder) which can be used to create an app which is compatible with // the existing app.go initialization conventions. -type AppBuilder struct { - app *App +type AppBuilder[T transaction.Tx] struct { + app *App[T] storeOptions *rootstore.FactoryOptions // the following fields are used to overwrite the default branch func(state store.ReaderMap) store.WriterMap - txValidator func(ctx context.Context, tx transaction.Tx) error - postTxExec func(ctx context.Context, tx transaction.Tx, success bool) error + txValidator func(ctx context.Context, tx T) error + postTxExec func(ctx context.Context, tx T, success bool) error } // DefaultGenesis returns a default genesis from the registered AppModule's. -func (a *AppBuilder) DefaultGenesis() map[string]json.RawMessage { +func (a *AppBuilder[T]) DefaultGenesis() map[string]json.RawMessage { return a.app.moduleManager.DefaultGenesis() } // RegisterModules registers the provided modules with the module manager. // This is the primary hook for integrating with modules which are not registered using the app config. -func (a *AppBuilder) RegisterModules(modules ...appmodulev2.AppModule) error { +func (a *AppBuilder[T]) RegisterModules(modules ...appmodulev2.AppModule) error { for _, appModule := range modules { if mod, ok := appModule.(appmodule.HasName); ok { name := mod.Name() @@ -62,7 +62,7 @@ func (a *AppBuilder) RegisterModules(modules ...appmodulev2.AppModule) error { // This method should only be used for registering extra stores // wiich is necessary for modules that not registered using the app config. // To be used in combination of RegisterModules. -func (a *AppBuilder) RegisterStores(keys ...string) { +func (a *AppBuilder[T]) RegisterStores(keys ...string) { a.app.storeKeys = append(a.app.storeKeys, keys...) if a.storeOptions != nil { a.storeOptions.StoreKeys = append(a.storeOptions.StoreKeys, keys...) @@ -70,7 +70,7 @@ func (a *AppBuilder) RegisterStores(keys ...string) { } // Build builds an *App instance. -func (a *AppBuilder) Build(opts ...AppBuilderOption) (*App, error) { +func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { for _, opt := range opts { opt(a) } @@ -87,7 +87,7 @@ func (a *AppBuilder) Build(opts ...AppBuilderOption) (*App, error) { // default post tx exec if a.postTxExec == nil { - a.postTxExec = func(ctx context.Context, tx transaction.Tx, success bool) error { + a.postTxExec = func(ctx context.Context, tx T, success bool) error { return nil } } @@ -98,7 +98,7 @@ func (a *AppBuilder) Build(opts ...AppBuilderOption) (*App, error) { endBlocker, valUpdate := a.app.moduleManager.EndBlock() - stf, err := stf.NewSTF[transaction.Tx]( + stf, err := stf.NewSTF[T]( a.app.logger.With("module", "stf"), a.app.msgRouterBuilder, a.app.queryRouterBuilder, @@ -122,7 +122,7 @@ func (a *AppBuilder) Build(opts ...AppBuilderOption) (*App, error) { } a.app.db = rs - appManagerBuilder := appmanager.Builder[transaction.Tx]{ + appManagerBuilder := appmanager.Builder[T]{ STF: a.app.stf, DB: a.app.db, ValidateTxGasLimit: a.app.config.GasConfig.ValidateTxGasLimit, @@ -155,33 +155,33 @@ func (a *AppBuilder) Build(opts ...AppBuilderOption) (*App, error) { } // AppBuilderOption is a function that can be passed to AppBuilder.Build to customize the resulting app. -type AppBuilderOption func(*AppBuilder) +type AppBuilderOption[T transaction.Tx] func(*AppBuilder[T]) // AppBuilderWithBranch sets a custom branch implementation for the app. -func AppBuilderWithBranch(branch func(state store.ReaderMap) store.WriterMap) AppBuilderOption { - return func(a *AppBuilder) { +func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) store.WriterMap) AppBuilderOption[T] { + return func(a *AppBuilder[T]) { a.branch = branch } } // AppBuilderWithTxValidator sets the tx validator for the app. // It overrides all default tx validators defined by modules. -func AppBuilderWithTxValidator(txValidators func(ctx context.Context, tx transaction.Tx) error) AppBuilderOption { - return func(a *AppBuilder) { +func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.Context, tx T) error) AppBuilderOption[T] { + return func(a *AppBuilder[T]) { a.txValidator = txValidators } } // AppBuilderWithPostTxExec sets logic that will be executed after each transaction. // When not provided, a no-op function will be used. -func AppBuilderWithPostTxExec( +func AppBuilderWithPostTxExec[T transaction.Tx]( postTxExec func( ctx context.Context, - tx transaction.Tx, + tx T, success bool, ) error, -) AppBuilderOption { - return func(a *AppBuilder) { +) AppBuilderOption[T] { + return func(a *AppBuilder[T]) { a.postTxExec = postTxExec } } diff --git a/runtime/v2/manager.go b/runtime/v2/manager.go index 6f0b8ca2e5..5fa423330e 100644 --- a/runtime/v2/manager.go +++ b/runtime/v2/manager.go @@ -25,7 +25,7 @@ import ( "cosmossdk.io/server/v2/stf" ) -type MM struct { +type MM[T transaction.Tx] struct { logger log.Logger config *runtimev2.Module modules map[string]appmodulev2.AppModule @@ -34,11 +34,11 @@ type MM struct { // NewModuleManager is the constructor for the module manager // It handles all the interactions between the modules and the application -func NewModuleManager( +func NewModuleManager[T transaction.Tx]( logger log.Logger, config *runtimev2.Module, modules map[string]appmodulev2.AppModule, -) *MM { +) *MM[T] { // good defaults for the module manager order modulesName := maps.Keys(modules) if len(config.PreBlockers) == 0 { @@ -63,7 +63,7 @@ func NewModuleManager( config.OrderMigrations = defaultMigrationsOrder(modulesName) } - mm := &MM{ + mm := &MM[T]{ logger: logger, config: config, modules: modules, @@ -78,12 +78,12 @@ func NewModuleManager( } // Modules returns the modules registered in the module manager -func (m *MM) Modules() map[string]appmodulev2.AppModule { +func (m *MM[T]) Modules() map[string]appmodulev2.AppModule { return m.modules } // RegisterLegacyAminoCodec registers all module codecs -func (m *MM) RegisterLegacyAminoCodec(cdc legacy.Amino) { +func (m *MM[T]) RegisterLegacyAminoCodec(cdc legacy.Amino) { for _, b := range m.modules { if mod, ok := b.(appmodule.HasAminoCodec); ok { mod.RegisterLegacyAminoCodec(cdc) @@ -92,7 +92,7 @@ func (m *MM) RegisterLegacyAminoCodec(cdc legacy.Amino) { } // RegisterInterfaces registers all module interface types -func (m *MM) RegisterInterfaces(registry registry.InterfaceRegistrar) { +func (m *MM[T]) RegisterInterfaces(registry registry.InterfaceRegistrar) { for _, b := range m.modules { if mod, ok := b.(appmodulev2.HasRegisterInterfaces); ok { mod.RegisterInterfaces(registry) @@ -101,7 +101,7 @@ func (m *MM) RegisterInterfaces(registry registry.InterfaceRegistrar) { } // DefaultGenesis provides default genesis information for all modules -func (m *MM) DefaultGenesis() map[string]json.RawMessage { +func (m *MM[T]) DefaultGenesis() map[string]json.RawMessage { genesisData := make(map[string]json.RawMessage) for name, b := range m.modules { if mod, ok := b.(appmodule.HasGenesisBasics); ok { @@ -117,7 +117,7 @@ func (m *MM) DefaultGenesis() map[string]json.RawMessage { } // ValidateGenesis performs genesis state validation for all modules -func (m *MM) ValidateGenesis(genesisData map[string]json.RawMessage) error { +func (m *MM[T]) ValidateGenesis(genesisData map[string]json.RawMessage) error { for name, b := range m.modules { if mod, ok := b.(appmodule.HasGenesisBasics); ok { if err := mod.ValidateGenesis(genesisData[mod.Name()]); err != nil { @@ -134,7 +134,7 @@ func (m *MM) ValidateGenesis(genesisData map[string]json.RawMessage) error { } // InitGenesisJSON performs init genesis functionality for modules from genesis data in JSON format -func (m *MM) InitGenesisJSON( +func (m *MM[T]) InitGenesisJSON( ctx context.Context, genesisData map[string]json.RawMessage, txHandler func(json.RawMessage) error, @@ -190,7 +190,7 @@ func (m *MM) InitGenesisJSON( } // ExportGenesisForModules performs export genesis functionality for modules -func (m *MM) ExportGenesisForModules( +func (m *MM[T]) ExportGenesisForModules( ctx context.Context, modulesToExport ...string, ) (map[string]json.RawMessage, error) { @@ -247,7 +247,7 @@ func (m *MM) ExportGenesisForModules( } // checkModulesExists verifies that all modules in the list exist in the app -func (m *MM) checkModulesExists(moduleName []string) error { +func (m *MM[T]) checkModulesExists(moduleName []string) error { for _, name := range moduleName { if _, ok := m.modules[name]; !ok { return fmt.Errorf("module %s does not exist", name) @@ -258,7 +258,7 @@ func (m *MM) checkModulesExists(moduleName []string) error { } // BeginBlock runs the begin-block logic of all modules -func (m *MM) BeginBlock() func(ctx context.Context) error { +func (m *MM[T]) BeginBlock() func(ctx context.Context) error { return func(ctx context.Context) error { for _, moduleName := range m.config.BeginBlockers { if module, ok := m.modules[moduleName].(appmodulev2.HasBeginBlocker); ok { @@ -278,7 +278,7 @@ type hasABCIEndBlock interface { } // EndBlock runs the end-block logic of all modules and tx validator updates -func (m *MM) EndBlock() ( +func (m *MM[T]) EndBlock() ( endBlockFunc func(ctx context.Context) error, valUpdateFunc func(ctx context.Context) ([]appmodulev2.ValidatorUpdate, error), ) { @@ -336,8 +336,8 @@ func (m *MM) EndBlock() ( } // PreBlocker runs the pre-block logic of all modules -func (m *MM) PreBlocker() func(ctx context.Context, txs []transaction.Tx) error { - return func(ctx context.Context, txs []transaction.Tx) error { +func (m *MM[T]) PreBlocker() func(ctx context.Context, txs []T) error { + return func(ctx context.Context, txs []T) error { for _, moduleName := range m.config.PreBlockers { if module, ok := m.modules[moduleName].(appmodulev2.HasPreBlocker); ok { if err := module.PreBlock(ctx); err != nil { @@ -351,10 +351,10 @@ func (m *MM) PreBlocker() func(ctx context.Context, txs []transaction.Tx) error } // TxValidators validates incoming transactions -func (m *MM) TxValidators() func(ctx context.Context, tx transaction.Tx) error { - return func(ctx context.Context, tx transaction.Tx) error { +func (m *MM[T]) TxValidators() func(ctx context.Context, tx T) error { + return func(ctx context.Context, tx T) error { for _, moduleName := range m.config.TxValidators { - if module, ok := m.modules[moduleName].(appmodulev2.HasTxValidator[transaction.Tx]); ok { + if module, ok := m.modules[moduleName].(appmodulev2.HasTxValidator[T]); ok { if err := module.TxValidator(ctx, tx); err != nil { return fmt.Errorf("failed to run tx validator for %s: %w", moduleName, err) } @@ -367,7 +367,7 @@ func (m *MM) TxValidators() func(ctx context.Context, tx transaction.Tx) error { // TODO write as descriptive godoc as module manager v1. // TODO include feedback from https://github.com/cosmos/cosmos-sdk/issues/15120 -func (m *MM) RunMigrations(ctx context.Context, fromVM appmodulev2.VersionMap) (appmodulev2.VersionMap, error) { +func (m *MM[T]) RunMigrations(ctx context.Context, fromVM appmodulev2.VersionMap) (appmodulev2.VersionMap, error) { updatedVM := appmodulev2.VersionMap{} for _, moduleName := range m.config.OrderMigrations { module := m.modules[moduleName] @@ -417,7 +417,7 @@ func (m *MM) RunMigrations(ctx context.Context, fromVM appmodulev2.VersionMap) ( } // RegisterServices registers all module services. -func (m *MM) RegisterServices(app *App) error { +func (m *MM[T]) RegisterServices(app *App[T]) error { for _, module := range m.modules { // register msg + query if services, ok := module.(appmodule.HasServices); ok { @@ -441,7 +441,7 @@ func (m *MM) RegisterServices(app *App) error { // validateConfig validates the module manager configuration // it asserts that all modules are defined in the configuration and that no modules are forgotten -func (m *MM) validateConfig() error { +func (m *MM[T]) validateConfig() error { if err := m.assertNoForgottenModules("PreBlockers", m.config.PreBlockers, func(moduleName string) bool { module := m.modules[moduleName] _, hasBlock := module.(appmodulev2.HasPreBlocker) @@ -472,7 +472,7 @@ func (m *MM) validateConfig() error { if err := m.assertNoForgottenModules("TxValidators", m.config.TxValidators, func(moduleName string) bool { module := m.modules[moduleName] - _, hasTxValidator := module.(appmodulev2.HasTxValidator[transaction.Tx]) + _, hasTxValidator := module.(appmodulev2.HasTxValidator[T]) return !hasTxValidator }); err != nil { return err @@ -520,7 +520,7 @@ func (m *MM) validateConfig() error { // assertNoForgottenModules checks that we didn't forget any modules in the *runtimev2.Module config. // `pass` is a closure which allows one to omit modules from `moduleNames`. // If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion. -func (m *MM) assertNoForgottenModules( +func (m *MM[T]) assertNoForgottenModules( setOrderFnName string, moduleNames []string, pass func(moduleName string) bool, @@ -549,7 +549,7 @@ func (m *MM) assertNoForgottenModules( return nil } -func registerServices(s appmodule.HasServices, app *App, registry *protoregistry.Files) error { +func registerServices[T transaction.Tx](s appmodule.HasServices, app *App[T], registry *protoregistry.Files) error { c := &configurator{ stfQueryRouter: app.queryRouterBuilder, stfMsgRouter: app.msgRouterBuilder, diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 85f739954d..ffc5632f94 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -23,6 +23,7 @@ import ( "cosmossdk.io/core/log" "cosmossdk.io/core/registry" "cosmossdk.io/core/store" + "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" "cosmossdk.io/depinject/appconfig" "cosmossdk.io/runtime/v2/services" @@ -31,18 +32,18 @@ import ( ) var ( - _ appmodulev2.AppModule = appModule{} - _ appmodule.HasServices = appModule{} + _ appmodulev2.AppModule = appModule[transaction.Tx]{} + _ appmodule.HasServices = appModule[transaction.Tx]{} ) -type appModule struct { - app *App +type appModule[T transaction.Tx] struct { + app *App[T] } -func (m appModule) IsOnePerModuleType() {} -func (m appModule) IsAppModule() {} +func (m appModule[T]) IsOnePerModuleType() {} +func (m appModule[T]) IsAppModule() {} -func (m appModule) RegisterServices(registar grpc.ServiceRegistrar) error { +func (m appModule[T]) RegisterServices(registar grpc.ServiceRegistrar) error { autoCliQueryService, err := services.NewAutoCLIQueryService(m.app.moduleManager.modules) if err != nil { return err @@ -59,7 +60,7 @@ func (m appModule) RegisterServices(registar grpc.ServiceRegistrar) error { return nil } -func (m appModule) AutoCLIOptions() *autocliv1.ModuleOptions { +func (m appModule[T]) AutoCLIOptions() *autocliv1.ModuleOptions { return &autocliv1.ModuleOptions{ Query: &autocliv1.ServiceCommandDescriptor{ Service: appv1alpha1.Query_ServiceDesc.ServiceName, @@ -96,22 +97,22 @@ func (m appModule) AutoCLIOptions() *autocliv1.ModuleOptions { func init() { appconfig.Register(&runtimev2.Module{}, appconfig.Provide( - ProvideAppBuilder, - ProvideEnvironment, - ProvideModuleManager, - ProvideGenesisTxHandler, + ProvideAppBuilder[transaction.Tx], + ProvideEnvironment[transaction.Tx], + ProvideModuleManager[transaction.Tx], + ProvideGenesisTxHandler[transaction.Tx], ProvideCometService, - ProvideAppVersionModifier, + ProvideAppVersionModifier[transaction.Tx], ), appconfig.Invoke(SetupAppBuilder), ) } -func ProvideAppBuilder( +func ProvideAppBuilder[T transaction.Tx]( interfaceRegistrar registry.InterfaceRegistrar, amino legacy.Amino, ) ( - *AppBuilder, + *AppBuilder[T], *stf.MsgRouterBuilder, appmodulev2.AppModule, protodesc.Resolver, @@ -128,16 +129,16 @@ func ProvideAppBuilder( } msgRouterBuilder := stf.NewMsgRouterBuilder() - app := &App{ + app := &App[T]{ storeKeys: nil, interfaceRegistrar: interfaceRegistrar, amino: amino, msgRouterBuilder: msgRouterBuilder, queryRouterBuilder: stf.NewMsgRouterBuilder(), // TODO dedicated query router } - appBuilder := &AppBuilder{app: app} + appBuilder := &AppBuilder[T]{app: app} - return appBuilder, msgRouterBuilder, appModule{app}, protoFiles, protoTypes + return appBuilder, msgRouterBuilder, appModule[T]{app}, protoFiles, protoTypes } type AppInputs struct { @@ -145,8 +146,8 @@ type AppInputs struct { AppConfig *appv1alpha1.Config Config *runtimev2.Module - AppBuilder *AppBuilder - ModuleManager *MM + AppBuilder *AppBuilder[transaction.Tx] + ModuleManager *MM[transaction.Tx] InterfaceRegistrar registry.InterfaceRegistrar LegacyAmino legacy.Amino Logger log.Logger @@ -169,16 +170,16 @@ func SetupAppBuilder(inputs AppInputs) { } } -func ProvideModuleManager( +func ProvideModuleManager[T transaction.Tx]( logger log.Logger, config *runtimev2.Module, modules map[string]appmodulev2.AppModule, -) *MM { - return NewModuleManager(logger, config, modules) +) *MM[T] { + return NewModuleManager[T](logger, config, modules) } // ProvideEnvironment provides the environment for keeper modules, while maintaining backward compatibility and provide services directly as well. -func ProvideEnvironment(logger log.Logger, config *runtimev2.Module, key depinject.ModuleKey, appBuilder *AppBuilder) ( +func ProvideEnvironment[T transaction.Tx](logger log.Logger, config *runtimev2.Module, key depinject.ModuleKey, appBuilder *AppBuilder[T]) ( appmodulev2.Environment, store.KVStoreService, store.MemoryStoreService, @@ -222,7 +223,7 @@ func ProvideEnvironment(logger log.Logger, config *runtimev2.Module, key depinje return env, kvService, memKvService } -func registerStoreKey(wrapper *AppBuilder, key string) { +func registerStoreKey[T transaction.Tx](wrapper *AppBuilder[T], key string) { wrapper.app.storeKeys = append(wrapper.app.storeKeys, key) } @@ -236,7 +237,7 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St return nil } -func ProvideGenesisTxHandler(appBuilder *AppBuilder) genesis.TxHandler { +func ProvideGenesisTxHandler[T transaction.Tx](appBuilder *AppBuilder[T]) genesis.TxHandler { return appBuilder.app } @@ -246,6 +247,6 @@ func ProvideCometService() comet.Service { // ProvideAppVersionModifier returns nil, `app.VersionModifier` is a feature of BaseApp and neither used nor required for runtim/v2. // nil is acceptable, see: https://github.com/cosmos/cosmos-sdk/blob/0a6ee406a02477ae8ccbfcbe1b51fc3930087f4c/x/upgrade/keeper/keeper.go#L438 -func ProvideAppVersionModifier(app *AppBuilder) app.VersionModifier { +func ProvideAppVersionModifier[T transaction.Tx](app *AppBuilder[T]) app.VersionModifier { return nil } diff --git a/server/v2/api/grpc/server.go b/server/v2/api/grpc/server.go index 7b9d62e316..8521fedfa8 100644 --- a/server/v2/api/grpc/server.go +++ b/server/v2/api/grpc/server.go @@ -23,7 +23,7 @@ import ( const serverName = "grpc-server" -type GRPCServer struct { +type GRPCServer[AppT serverv2.AppI[T], T transaction.Tx] struct { logger log.Logger config *Config @@ -35,13 +35,13 @@ type GRPCService interface { RegisterGRPCServer(gogogrpc.Server) } -func New() *GRPCServer { - return &GRPCServer{} +func New[AppT serverv2.AppI[T], T transaction.Tx]() *GRPCServer[AppT, T] { + return &GRPCServer[AppT, T]{} } // Init returns a correctly configured and initialized gRPC server. // Note, the caller is responsible for starting the server. -func (g *GRPCServer) Init(appI serverv2.AppI[transaction.Tx], v *viper.Viper, logger log.Logger) error { +func (g *GRPCServer[AppT, T]) Init(appI AppT, v *viper.Viper, logger log.Logger) error { cfg := DefaultConfig() if v != nil { if err := v.Sub(serverName).Unmarshal(&cfg); err != nil { @@ -68,11 +68,11 @@ func (g *GRPCServer) Init(appI serverv2.AppI[transaction.Tx], v *viper.Viper, lo return nil } -func (g *GRPCServer) Name() string { +func (g *GRPCServer[AppT, T]) Name() string { return serverName } -func (g *GRPCServer) Start(ctx context.Context) error { +func (g *GRPCServer[AppT, T]) Start(ctx context.Context) error { listener, err := net.Listen("tcp", g.config.Address) if err != nil { return fmt.Errorf("failed to listen on address %s: %w", g.config.Address, err) @@ -95,14 +95,14 @@ func (g *GRPCServer) Start(ctx context.Context) error { return err } -func (g *GRPCServer) Stop(ctx context.Context) error { +func (g *GRPCServer[AppT, T]) Stop(ctx context.Context) error { g.logger.Info("stopping gRPC server...", "address", g.config.Address) g.grpcSrv.GracefulStop() return nil } -func (g *GRPCServer) Config() any { +func (g *GRPCServer[AppT, T]) Config() any { if g.config == nil || g.config == (&Config{}) { return DefaultConfig() } diff --git a/server/v2/cometbft/commands.go b/server/v2/cometbft/commands.go index b635ca505c..58d728fcbf 100644 --- a/server/v2/cometbft/commands.go +++ b/server/v2/cometbft/commands.go @@ -29,7 +29,7 @@ import ( "github.com/cosmos/cosmos-sdk/version" ) -func (s *CometBFTServer[T]) rpcClient(cmd *cobra.Command) (rpc.CometRPC, error) { +func (s *CometBFTServer[AppT, T]) rpcClient(cmd *cobra.Command) (rpc.CometRPC, error) { if s.config.Standalone { client, err := rpchttp.New(client.GetConfigFromCmd(cmd).RPC.ListenAddress) if err != nil { @@ -52,7 +52,7 @@ func (s *CometBFTServer[T]) rpcClient(cmd *cobra.Command) (rpc.CometRPC, error) } // StatusCommand returns the command to return the status of the network. -func (s *CometBFTServer[T]) StatusCommand() *cobra.Command { +func (s *CometBFTServer[AppT, T]) StatusCommand() *cobra.Command { cmd := &cobra.Command{ Use: "status", Short: "Query remote node for status", @@ -83,7 +83,7 @@ func (s *CometBFTServer[T]) StatusCommand() *cobra.Command { } // ShowNodeIDCmd - ported from CometBFT, dump node ID to stdout -func (s *CometBFTServer[T]) ShowNodeIDCmd() *cobra.Command { +func (s *CometBFTServer[AppT, T]) ShowNodeIDCmd() *cobra.Command { return &cobra.Command{ Use: "show-node-id", Short: "Show this node's ID", @@ -101,7 +101,7 @@ func (s *CometBFTServer[T]) ShowNodeIDCmd() *cobra.Command { } // ShowValidatorCmd - ported from CometBFT, show this node's validator info -func (s *CometBFTServer[T]) ShowValidatorCmd() *cobra.Command { +func (s *CometBFTServer[AppT, T]) ShowValidatorCmd() *cobra.Command { cmd := cobra.Command{ Use: "show-validator", Short: "Show this node's CometBFT validator info", @@ -135,7 +135,7 @@ func (s *CometBFTServer[T]) ShowValidatorCmd() *cobra.Command { } // ShowAddressCmd - show this node's validator address -func (s *CometBFTServer[T]) ShowAddressCmd() *cobra.Command { +func (s *CometBFTServer[AppT, T]) ShowAddressCmd() *cobra.Command { cmd := &cobra.Command{ Use: "show-address", Short: "Shows this node's CometBFT validator consensus address", @@ -154,7 +154,7 @@ func (s *CometBFTServer[T]) ShowAddressCmd() *cobra.Command { } // VersionCmd prints CometBFT and ABCI version numbers. -func (s *CometBFTServer[T]) VersionCmd() *cobra.Command { +func (s *CometBFTServer[AppT, T]) VersionCmd() *cobra.Command { return &cobra.Command{ Use: "version", Short: "Print CometBFT libraries' version", @@ -182,7 +182,7 @@ func (s *CometBFTServer[T]) VersionCmd() *cobra.Command { } // QueryBlocksCmd returns a command to search through blocks by events. -func (s *CometBFTServer[T]) QueryBlocksCmd() *cobra.Command { +func (s *CometBFTServer[AppT, T]) QueryBlocksCmd() *cobra.Command { cmd := &cobra.Command{ Use: "blocks", Short: "Query for paginated blocks that match a set of events", @@ -232,7 +232,7 @@ for. Each module documents its respective events under 'xx_events.md'. } // QueryBlockCmd implements the default command for a Block query. -func (s *CometBFTServer[T]) QueryBlockCmd() *cobra.Command { +func (s *CometBFTServer[AppT, T]) QueryBlockCmd() *cobra.Command { cmd := &cobra.Command{ Use: "block --type=[height|hash] [height|hash]", Short: "Query for a committed block by height, hash, or event(s)", @@ -319,7 +319,7 @@ $ %s query block --%s=%s } // QueryBlockResultsCmd implements the default command for a BlockResults query. -func (s *CometBFTServer[T]) QueryBlockResultsCmd() *cobra.Command { +func (s *CometBFTServer[AppT, T]) QueryBlockResultsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "block-results [height]", Short: "Query for a committed block's results by height", @@ -384,7 +384,7 @@ func parseOptionalHeight(heightStr string) (*int64, error) { return &tmp, nil } -func (s *CometBFTServer[T]) BootstrapStateCmd() *cobra.Command { +func (s *CometBFTServer[AppT, T]) BootstrapStateCmd() *cobra.Command { cmd := &cobra.Command{ Use: "bootstrap-state", Short: "Bootstrap CometBFT state at an arbitrary block height using a light client", @@ -414,7 +414,7 @@ func (s *CometBFTServer[T]) BootstrapStateCmd() *cobra.Command { func printOutput(cmd *cobra.Command, out []byte) error { // Get flags output - outFlag, err := cmd.Flags().GetString(flags.FlagOutput) + outFlag, err := cmd.Flags().GetString(flags.FlagOutput) if err != nil { return err } diff --git a/server/v2/cometbft/server.go b/server/v2/cometbft/server.go index e48a58c5e3..b0a9e8eaf2 100644 --- a/server/v2/cometbft/server.go +++ b/server/v2/cometbft/server.go @@ -45,11 +45,15 @@ const ( FlagTrace = "trace" ) -var _ serverv2.ServerComponent[transaction.Tx] = (*CometBFTServer[transaction.Tx])(nil) -var _ serverv2.HasCLICommands = (*CometBFTServer[transaction.Tx])(nil) -var _ serverv2.HasStartFlags = (*CometBFTServer[transaction.Tx])(nil) +var ( + _ serverv2.ServerComponent[ + serverv2.AppI[transaction.Tx], transaction.Tx, + ] = (*CometBFTServer[serverv2.AppI[transaction.Tx], transaction.Tx])(nil) + _ serverv2.HasCLICommands = (*CometBFTServer[serverv2.AppI[transaction.Tx], transaction.Tx])(nil) + _ serverv2.HasStartFlags = (*CometBFTServer[serverv2.AppI[transaction.Tx], transaction.Tx])(nil) +) -type CometBFTServer[T transaction.Tx] struct { +type CometBFTServer[AppT serverv2.AppI[T], T transaction.Tx] struct { Node *node.Node App *Consensus[T] logger log.Logger @@ -65,14 +69,14 @@ type App[T transaction.Tx] interface { GetStore() types.Store } -func New[T transaction.Tx](txCodec transaction.Codec[T]) *CometBFTServer[T] { +func New[AppT serverv2.AppI[T], T transaction.Tx](txCodec transaction.Codec[T]) *CometBFTServer[AppT, T] { consensus := &Consensus[T]{txCodec: txCodec} - return &CometBFTServer[T]{ + return &CometBFTServer[AppT, T]{ App: consensus, } } -func (s *CometBFTServer[T]) Init(appI serverv2.AppI[T], v *viper.Viper, logger log.Logger) error { +func (s *CometBFTServer[AppT, T]) Init(appI AppT, v *viper.Viper, logger log.Logger) error { store := appI.GetStore().(types.Store) cfg := Config{CmtConfig: GetConfigFromViper(v), ConsensusAuthority: appI.GetConsensusAuthority()} @@ -109,11 +113,11 @@ func (s *CometBFTServer[T]) Init(appI serverv2.AppI[T], v *viper.Viper, logger l return nil } -func (s *CometBFTServer[T]) Name() string { +func (s *CometBFTServer[AppT, T]) Name() string { return "cometbft" } -func (s *CometBFTServer[T]) Start(ctx context.Context) error { +func (s *CometBFTServer[AppT, T]) Start(ctx context.Context) error { viper := ctx.Value(corectx.ViperContextKey{}).(*viper.Viper) cometConfig := GetConfigFromViper(viper) @@ -152,7 +156,7 @@ func (s *CometBFTServer[T]) Start(ctx context.Context) error { return s.Node.Start() } -func (s *CometBFTServer[T]) Stop(context.Context) error { +func (s *CometBFTServer[AppT, T]) Stop(context.Context) error { if s.Node != nil && s.Node.IsRunning() { return s.Node.Stop() } @@ -198,7 +202,7 @@ func getGenDocProvider(cfg *cmtcfg.Config) func() (node.ChecksummedGenesisDoc, e } } -func (s *CometBFTServer[T]) StartCmdFlags() *pflag.FlagSet { +func (s *CometBFTServer[AppT, T]) StartCmdFlags() *pflag.FlagSet { flags := pflag.NewFlagSet("cometbft", pflag.ExitOnError) flags.Bool(flagWithComet, true, "Run abci app embedded in-process with CometBFT") flags.String(flagAddress, "tcp://127.0.0.1:26658", "Listen address") @@ -213,7 +217,7 @@ func (s *CometBFTServer[T]) StartCmdFlags() *pflag.FlagSet { return flags } -func (s *CometBFTServer[T]) CLICommands() serverv2.CLIConfig { +func (s *CometBFTServer[AppT, T]) CLICommands() serverv2.CLIConfig { return serverv2.CLIConfig{ Commands: []*cobra.Command{ s.StatusCommand(), @@ -230,7 +234,7 @@ func (s *CometBFTServer[T]) CLICommands() serverv2.CLIConfig { } } -func (s *CometBFTServer[T]) WriteDefaultConfigAt(configPath string) error { +func (s *CometBFTServer[AppT, T]) WriteDefaultConfigAt(configPath string) error { cometConfig := cmtcfg.DefaultConfig() cmtcfg.WriteConfigFile(filepath.Join(configPath, "config.toml"), cometConfig) return nil diff --git a/server/v2/commands.go b/server/v2/commands.go index 2cddedbc4b..b5b6e5533e 100644 --- a/server/v2/commands.go +++ b/server/v2/commands.go @@ -33,7 +33,12 @@ func Execute(rootCmd *cobra.Command, envPrefix, defaultHome string) error { return rootCmd.Execute() } -func Commands(rootCmd *cobra.Command, newApp AppCreator[transaction.Tx], logger log.Logger, components ...ServerComponent[transaction.Tx]) (CLIConfig, error) { +func Commands[AppT AppI[T], T transaction.Tx]( + rootCmd *cobra.Command, + newApp AppCreator[AppT, T], + logger log.Logger, + components ...ServerComponent[AppT, T], +) (CLIConfig, error) { if len(components) == 0 { return CLIConfig{}, errors.New("no components provided") } @@ -94,7 +99,12 @@ func Commands(rootCmd *cobra.Command, newApp AppCreator[transaction.Tx], logger return cmds, nil } -func AddCommands(rootCmd *cobra.Command, newApp AppCreator[transaction.Tx], logger log.Logger, components ...ServerComponent[transaction.Tx]) error { +func AddCommands[AppT AppI[T], T transaction.Tx]( + rootCmd *cobra.Command, + newApp AppCreator[AppT, T], + logger log.Logger, + components ...ServerComponent[AppT, T], +) error { cmds, err := Commands(rootCmd, newApp, logger, components...) if err != nil { return err @@ -125,7 +135,7 @@ func AddCommands(rootCmd *cobra.Command, newApp AppCreator[transaction.Tx], logg } // configHandle writes the default config to the home directory if it does not exist and sets the server context -func configHandle(s *Server, home string, cmd *cobra.Command) error { +func configHandle[AppT AppI[T], T transaction.Tx](s *Server[AppT, T], home string, cmd *cobra.Command) error { configDir := filepath.Join(home, "config") // we need to check app.toml as the config folder can already exist for the client.toml diff --git a/server/v2/server.go b/server/v2/server.go index f565c6a4c1..762488e5fa 100644 --- a/server/v2/server.go +++ b/server/v2/server.go @@ -18,12 +18,12 @@ import ( ) // ServerComponent is a server module that can be started and stopped. -type ServerComponent[T transaction.Tx] interface { +type ServerComponent[AppT AppI[T], T transaction.Tx] interface { Name() string Start(context.Context) error Stop(context.Context) error - Init(AppI[T], *viper.Viper, log.Logger) error + Init(AppT, *viper.Viper, log.Logger) error } // HasCLICommands is a server module that has CLI commands. @@ -41,7 +41,7 @@ type HasStartFlags interface { StartCmdFlags() *pflag.FlagSet } -var _ ServerComponent[transaction.Tx] = (*Server)(nil) +var _ ServerComponent[AppI[transaction.Tx], transaction.Tx] = (*Server[AppI[transaction.Tx], transaction.Tx])(nil) // Configs returns a viper instance of the config file func ReadConfig(configPath string) (*viper.Viper, error) { @@ -63,24 +63,26 @@ func ReadConfig(configPath string) (*viper.Viper, error) { return v, nil } -type Server struct { +type Server[AppT AppI[T], T transaction.Tx] struct { logger log.Logger - components []ServerComponent[transaction.Tx] + components []ServerComponent[AppT, T] } -func NewServer(logger log.Logger, components ...ServerComponent[transaction.Tx]) *Server { - return &Server{ +func NewServer[AppT AppI[T], T transaction.Tx]( + logger log.Logger, components ...ServerComponent[AppT, T], +) *Server[AppT, T] { + return &Server[AppT, T]{ logger: logger, components: components, } } -func (s *Server) Name() string { +func (s *Server[AppT, T]) Name() string { return "server" } // Start starts all components concurrently. -func (s *Server) Start(ctx context.Context) error { +func (s *Server[AppT, T]) Start(ctx context.Context) error { s.logger.Info("starting servers...") g, ctx := errgroup.WithContext(ctx) @@ -104,7 +106,7 @@ func (s *Server) Start(ctx context.Context) error { } // Stop stops all components concurrently. -func (s *Server) Stop(ctx context.Context) error { +func (s *Server[AppT, T]) Stop(ctx context.Context) error { s.logger.Info("stopping servers...") g, ctx := errgroup.WithContext(ctx) @@ -119,7 +121,7 @@ func (s *Server) Stop(ctx context.Context) error { } // CLICommands returns all CLI commands of all components. -func (s *Server) CLICommands() CLIConfig { +func (s *Server[AppT, T]) CLICommands() CLIConfig { compart := func(name string, cmds ...*cobra.Command) *cobra.Command { if len(cmds) == 1 && strings.HasPrefix(cmds[0].Use, name) { return cmds[0] @@ -147,7 +149,7 @@ func (s *Server) CLICommands() CLIConfig { } // Configs returns all configs of all server components. -func (s *Server) Configs() map[string]any { +func (s *Server[AppT, T]) Configs() map[string]any { cfgs := make(map[string]any) for _, mod := range s.components { if configmod, ok := mod.(HasConfig); ok { @@ -160,8 +162,8 @@ func (s *Server) Configs() map[string]any { } // Configs returns all configs of all server components. -func (s *Server) Init(appI AppI[transaction.Tx], v *viper.Viper, logger log.Logger) error { - var components []ServerComponent[transaction.Tx] +func (s *Server[AppT, T]) Init(appI AppT, v *viper.Viper, logger log.Logger) error { + var components []ServerComponent[AppT, T] for _, mod := range s.components { mod := mod if err := mod.Init(appI, v, logger); err != nil { @@ -177,7 +179,7 @@ func (s *Server) Init(appI AppI[transaction.Tx], v *viper.Viper, logger log.Logg // WriteConfig writes the config to the given path. // Note: it does not use viper.WriteConfigAs because we do not want to store flag values in the config. -func (s *Server) WriteConfig(configPath string) error { +func (s *Server[AppT, T]) WriteConfig(configPath string) error { cfgs := s.Configs() b, err := toml.Marshal(cfgs) if err != nil { @@ -206,7 +208,7 @@ func (s *Server) WriteConfig(configPath string) error { } // Flags returns all flags of all server components. -func (s *Server) StartFlags() []*pflag.FlagSet { +func (s *Server[AppT, T]) StartFlags() []*pflag.FlagSet { flags := []*pflag.FlagSet{} for _, mod := range s.components { if startmod, ok := mod.(HasStartFlags); ok { diff --git a/server/v2/server_test.go b/server/v2/server_test.go index 22a76fa538..6ad73cffa4 100644 --- a/server/v2/server_test.go +++ b/server/v2/server_test.go @@ -58,7 +58,7 @@ func TestServer(t *testing.T) { } logger := log.NewLogger(os.Stdout) - grpcServer := grpc.New() + grpcServer := grpc.New[serverv2.AppI[transaction.Tx], transaction.Tx]() if err := grpcServer.Init(&mockApp[transaction.Tx]{}, v, logger); err != nil { t.Log(err) t.Fail() diff --git a/server/v2/types.go b/server/v2/types.go index 034f333db7..1a22abf8e1 100644 --- a/server/v2/types.go +++ b/server/v2/types.go @@ -9,7 +9,7 @@ import ( "cosmossdk.io/server/v2/appmanager" ) -type AppCreator[T transaction.Tx] func(log.Logger, *viper.Viper) AppI[T] +type AppCreator[AppT AppI[T], T transaction.Tx] func(log.Logger, *viper.Viper) AppT type AppI[T transaction.Tx] interface { GetAppManager() *appmanager.AppManager[T] diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index bbcf4b66c4..b1e05095d9 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -10,6 +10,7 @@ import ( coreapp "cosmossdk.io/core/app" "cosmossdk.io/core/legacy" "cosmossdk.io/core/log" + "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" "cosmossdk.io/runtime/v2" serverv2 "cosmossdk.io/server/v2" @@ -48,8 +49,8 @@ var DefaultNodeHome string // SimApp extends an ABCI application, but with most of its parameters exported. // They are exported for convenience in creating helper functions, as object // capabilities aren't needed for testing. -type SimApp struct { - *runtime.App +type SimApp[T transaction.Tx] struct { + *runtime.App[T] legacyAmino legacy.Amino appCodec codec.Codec txConfig client.TxConfig @@ -91,18 +92,18 @@ func AppConfig() depinject.Config { } // NewSimApp returns a reference to an initialized SimApp. -func NewSimApp( +func NewSimApp[T transaction.Tx]( logger log.Logger, viper *viper.Viper, -) *SimApp { +) *SimApp[T] { viper.Set(serverv2.FlagHome, DefaultNodeHome) // TODO possibly set earlier when viper is created scRawDb, err := db.NewGoLevelDB("application", filepath.Join(DefaultNodeHome, "data"), nil) if err != nil { panic(err) } var ( - app = &SimApp{} - appBuilder *runtime.AppBuilder + app = &SimApp[T]{} + appBuilder *runtime.AppBuilder[T] // merge the AppConfig and other configuration in one config appConfig = depinject.Configs( @@ -231,26 +232,26 @@ func NewSimApp( // // NOTE: This is solely to be used for testing purposes as it may be desirable // for modules to register their own custom testing types. -func (app *SimApp) AppCodec() codec.Codec { +func (app *SimApp[T]) AppCodec() codec.Codec { return app.appCodec } // InterfaceRegistry returns SimApp's InterfaceRegistry. -func (app *SimApp) InterfaceRegistry() coreapp.InterfaceRegistry { +func (app *SimApp[T]) InterfaceRegistry() coreapp.InterfaceRegistry { return app.interfaceRegistry } // TxConfig returns SimApp's TxConfig. -func (app *SimApp) TxConfig() client.TxConfig { +func (app *SimApp[T]) TxConfig() client.TxConfig { return app.txConfig } // GetConsensusAuthority gets the consensus authority. -func (app *SimApp) GetConsensusAuthority() string { +func (app *SimApp[T]) GetConsensusAuthority() string { return app.ConsensusParamsKeeper.GetAuthority() } // GetStore gets the app store. -func (app *SimApp) GetStore() any { +func (app *SimApp[T]) GetStore() any { return app.App.GetStore() } diff --git a/simapp/v2/export.go b/simapp/v2/export.go index f4d9218518..41b8d94e9e 100644 --- a/simapp/v2/export.go +++ b/simapp/v2/export.go @@ -5,6 +5,6 @@ import ( ) // ExportAppStateAndValidators exports the state of the application for a genesis file. -func (app *SimApp) ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs, modulesToExport []string) (servertypes.ExportedApp, error) { +func (app *SimApp[T]) ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs, modulesToExport []string) (servertypes.ExportedApp, error) { panic("not implemented") } diff --git a/simapp/v2/simdv2/cmd/commands.go b/simapp/v2/simdv2/cmd/commands.go index b4b186c0f0..ea7f252b5d 100644 --- a/simapp/v2/simdv2/cmd/commands.go +++ b/simapp/v2/simdv2/cmd/commands.go @@ -32,30 +32,56 @@ import ( genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ) -var _ transaction.Codec[transaction.Tx] = &temporaryTxDecoder{} +var _ transaction.Codec[transaction.Tx] = &temporaryTxDecoder[transaction.Tx]{} -type temporaryTxDecoder struct { +type temporaryTxDecoder[T transaction.Tx] struct { txConfig client.TxConfig } // Decode implements transaction.Codec. -func (t *temporaryTxDecoder) Decode(bz []byte) (transaction.Tx, error) { - return t.txConfig.TxDecoder()(bz) +func (t *temporaryTxDecoder[T]) Decode(bz []byte) (T, error) { + var out T + tx, err := t.txConfig.TxDecoder()(bz) + if err != nil { + return out, err + } + + var ok bool + out, ok = tx.(T) + if !ok { + return out, errors.New("unexpected Tx type") + } + + return out, nil } // DecodeJSON implements transaction.Codec. -func (t *temporaryTxDecoder) DecodeJSON(bz []byte) (transaction.Tx, error) { - return t.txConfig.TxJSONDecoder()(bz) +func (t *temporaryTxDecoder[T]) DecodeJSON(bz []byte) (T, error) { + var out T + tx, err := t.txConfig.TxJSONDecoder()(bz) + if err != nil { + return out, err + } + + var ok bool + out, ok = tx.(T) + if !ok { + return out, errors.New("unexpected Tx type") + } + + return out, nil } -func newApp(logger log.Logger, viper *viper.Viper) serverv2.AppI[transaction.Tx] { - return simapp.NewSimApp(logger, viper) +func newApp[AppT serverv2.AppI[T], T transaction.Tx]( + logger log.Logger, viper *viper.Viper, +) AppT { + return serverv2.AppI[T](simapp.NewSimApp[T](logger, viper)).(AppT) } -func initRootCmd( +func initRootCmd[AppT serverv2.AppI[T], T transaction.Tx]( rootCmd *cobra.Command, txConfig client.TxConfig, - moduleManager *runtimev2.MM, + moduleManager *runtimev2.MM[T], ) { cfg := sdk.GetConfig() cfg.Seal() @@ -78,8 +104,8 @@ func initRootCmd( rootCmd, newApp, logger, - cometbft.New(&temporaryTxDecoder{txConfig}), - grpc.New(), + cometbft.New[AppT, T](&temporaryTxDecoder[T]{txConfig}), + grpc.New[AppT, T](), ); err != nil { panic(err) } @@ -87,7 +113,7 @@ func initRootCmd( // add keybase, auxiliary RPC, query, genesis, and tx child commands rootCmd.AddCommand( server.StatusCommand(), - genesisCommand(txConfig, moduleManager, appExport), + genesisCommand[T](txConfig, moduleManager, appExport[T]), queryCommand(), txCommand(), keys.Commands(), @@ -96,9 +122,9 @@ func initRootCmd( } // genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter -func genesisCommand( +func genesisCommand[T transaction.Tx]( txConfig client.TxConfig, - moduleManager *runtimev2.MM, + moduleManager *runtimev2.MM[T], appExport func(logger log.Logger, height int64, forZeroHeight bool, @@ -171,7 +197,7 @@ func txCommand() *cobra.Command { } // appExport creates a new simapp (optionally at a given height) and exports state. -func appExport( +func appExport[T transaction.Tx]( logger log.Logger, height int64, forZeroHeight bool, @@ -182,15 +208,15 @@ func appExport( // overwrite the FlagInvCheckPeriod viper.Set(server.FlagInvCheckPeriod, 1) - var simApp *simapp.SimApp + var simApp *simapp.SimApp[T] if height != -1 { - simApp = simapp.NewSimApp(logger, viper) + simApp = simapp.NewSimApp[T](logger, viper) if err := simApp.LoadHeight(uint64(height)); err != nil { return servertypes.ExportedApp{}, err } } else { - simApp = simapp.NewSimApp(logger, viper) + simApp = simapp.NewSimApp[T](logger, viper) } return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go index 51c873be57..aff106a95a 100644 --- a/simapp/v2/simdv2/cmd/root_di.go +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -8,9 +8,11 @@ import ( "cosmossdk.io/client/v2/autocli" "cosmossdk.io/core/address" "cosmossdk.io/core/legacy" + "cosmossdk.io/core/transaction" "cosmossdk.io/depinject" "cosmossdk.io/log" "cosmossdk.io/runtime/v2" + serverv2 "cosmossdk.io/server/v2" "cosmossdk.io/simapp/v2" "cosmossdk.io/x/auth/tx" authtxconfig "cosmossdk.io/x/auth/tx/config" @@ -24,10 +26,10 @@ import ( ) // NewRootCmd creates a new root command for simd. It is called once in the main function. -func NewRootCmd() *cobra.Command { +func NewRootCmd[AppT serverv2.AppI[T], T transaction.Tx]() *cobra.Command { var ( autoCliOpts autocli.AppOptions - moduleManager *runtime.MM + moduleManager *runtime.MM[T] clientCtx client.Context ) @@ -83,7 +85,7 @@ func NewRootCmd() *cobra.Command { }, } - initRootCmd(rootCmd, clientCtx.TxConfig, moduleManager) + initRootCmd[AppT, T](rootCmd, clientCtx.TxConfig, moduleManager) if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { panic(err) } diff --git a/simapp/v2/simdv2/cmd/root_test.go b/simapp/v2/simdv2/cmd/root_test.go index 84d63769b0..ebca74ba70 100644 --- a/simapp/v2/simdv2/cmd/root_test.go +++ b/simapp/v2/simdv2/cmd/root_test.go @@ -6,6 +6,8 @@ import ( "github.com/stretchr/testify/require" + "cosmossdk.io/core/transaction" + serverv2 "cosmossdk.io/server/v2" "cosmossdk.io/simapp/v2" "cosmossdk.io/simapp/v2/simdv2/cmd" @@ -15,7 +17,7 @@ import ( ) func TestInitCmd(t *testing.T) { - rootCmd := cmd.NewRootCmd() + rootCmd := cmd.NewRootCmd[serverv2.AppI[transaction.Tx], transaction.Tx]() rootCmd.SetArgs([]string{ "init", // Test the init cmd "simapp-test", // Moniker @@ -28,7 +30,7 @@ func TestInitCmd(t *testing.T) { func TestHomeFlagRegistration(t *testing.T) { homeDir := "/tmp/foo" - rootCmd := cmd.NewRootCmd() + rootCmd := cmd.NewRootCmd[serverv2.AppI[transaction.Tx], transaction.Tx]() rootCmd.SetArgs([]string{ "query", fmt.Sprintf("--%s", flags.FlagHome), diff --git a/simapp/v2/simdv2/main.go b/simapp/v2/simdv2/main.go index 5766d6e9d8..e41ba6ffc1 100644 --- a/simapp/v2/simdv2/main.go +++ b/simapp/v2/simdv2/main.go @@ -4,13 +4,14 @@ import ( "fmt" "os" + "cosmossdk.io/core/transaction" serverv2 "cosmossdk.io/server/v2" "cosmossdk.io/simapp/v2" "cosmossdk.io/simapp/v2/simdv2/cmd" ) func main() { - rootCmd := cmd.NewRootCmd() + rootCmd := cmd.NewRootCmd[serverv2.AppI[transaction.Tx], transaction.Tx]() if err := serverv2.Execute(rootCmd, "", simapp.DefaultNodeHome); err != nil { fmt.Fprintln(rootCmd.OutOrStderr(), err) os.Exit(1) diff --git a/simapp/v2/upgrades.go b/simapp/v2/upgrades.go index d024ac0967..4c76d0d78a 100644 --- a/simapp/v2/upgrades.go +++ b/simapp/v2/upgrades.go @@ -20,7 +20,7 @@ import ( // v0.50.x to v0.51.x. const UpgradeName = "v050-to-v051" -func (app *SimApp) RegisterUpgradeHandlers() { +func (app *SimApp[T]) RegisterUpgradeHandlers() { app.UpgradeKeeper.SetUpgradeHandler( UpgradeName, func(ctx context.Context, _ upgradetypes.Plan, fromVM appmodule.VersionMap) (appmodule.VersionMap, error) {