From 53f49f9c26dc80461108c535b1bf0c77098e2d3f Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Thu, 25 Jul 2024 23:43:19 +0200 Subject: [PATCH 1/4] fix(runtime): remove `appv1alpha1.Config` from runtime (#21042) (cherry picked from commit 502450cd1ef0b6bd77807922091893611c370c5d) # Conflicts: # runtime/module.go # runtime/v2/app.go # runtime/v2/module.go --- runtime/app.go | 2 - runtime/module.go | 17 ++- runtime/v2/app.go | 123 +++++++++++++++++++++ runtime/v2/module.go | 248 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 387 insertions(+), 3 deletions(-) create mode 100644 runtime/v2/app.go create mode 100644 runtime/v2/module.go diff --git a/runtime/app.go b/runtime/app.go index 55b44aaa0d34..1a845c72763e 100644 --- a/runtime/app.go +++ b/runtime/app.go @@ -8,7 +8,6 @@ import ( "golang.org/x/exp/slices" runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" - appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" "cosmossdk.io/core/appmodule" "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" @@ -51,7 +50,6 @@ type App struct { baseAppOptions []BaseAppOption msgServiceRouter *baseapp.MsgServiceRouter grpcQueryRouter *baseapp.GRPCQueryRouter - appConfig *appv1alpha1.Config logger log.Logger // initChainer is the init chainer function defined by the app config. // this is only required if the chain wants to add special InitChainer logic. diff --git a/runtime/module.go b/runtime/module.go index 9ab1bbf40816..b326206b368e 100644 --- a/runtime/module.go +++ b/runtime/module.go @@ -9,10 +9,16 @@ import ( "google.golang.org/protobuf/reflect/protoregistry" runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" +<<<<<<< HEAD appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" authmodulev1 "cosmossdk.io/api/cosmos/auth/module/v1" stakingmodulev1 "cosmossdk.io/api/cosmos/staking/module/v1" "cosmossdk.io/core/address" +======= + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" + "cosmossdk.io/core/app" +>>>>>>> 502450cd1 (fix(runtime): remove `appv1alpha1.Config` from runtime (#21042)) "cosmossdk.io/core/appmodule" "cosmossdk.io/core/comet" "cosmossdk.io/core/event" @@ -127,6 +133,7 @@ func ProvideApp(interfaceRegistry codectypes.InterfaceRegistry) ( type AppInputs struct { depinject.In +<<<<<<< HEAD AppConfig *appv1alpha1.Config Config *runtimev1alpha1.Module AppBuilder *AppBuilder @@ -136,13 +143,21 @@ type AppInputs struct { InterfaceRegistry codectypes.InterfaceRegistry LegacyAmino *codec.LegacyAmino Logger log.Logger +======= + Logger log.Logger + Config *runtimev1alpha1.Module + AppBuilder *AppBuilder + ModuleManager *module.Manager + BaseAppOptions []BaseAppOption + InterfaceRegistry codectypes.InterfaceRegistry + LegacyAmino legacy.Amino +>>>>>>> 502450cd1 (fix(runtime): remove `appv1alpha1.Config` from runtime (#21042)) } func SetupAppBuilder(inputs AppInputs) { app := inputs.AppBuilder.app app.baseAppOptions = inputs.BaseAppOptions app.config = inputs.Config - app.appConfig = inputs.AppConfig app.logger = inputs.Logger app.ModuleManager = module.NewManagerFromMap(inputs.Modules) diff --git a/runtime/v2/app.go b/runtime/v2/app.go new file mode 100644 index 000000000000..56632590b4f9 --- /dev/null +++ b/runtime/v2/app.go @@ -0,0 +1,123 @@ +package runtime + +import ( + "encoding/json" + "errors" + + gogoproto "github.com/cosmos/gogoproto/proto" + "golang.org/x/exp/slices" + + runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2" + "cosmossdk.io/core/legacy" + "cosmossdk.io/core/log" + "cosmossdk.io/core/registry" + "cosmossdk.io/core/transaction" + "cosmossdk.io/server/v2/appmanager" + "cosmossdk.io/server/v2/stf" +) + +// App is a wrapper around AppManager and ModuleManager that can be used in hybrid +// app.go/app config scenarios or directly as a servertypes.Application instance. +// To get an instance of *App, *AppBuilder must be requested as a dependency +// in a container which declares the runtime module and the AppBuilder.Build() +// method must be called. +// +// 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[T transaction.Tx] struct { + *appmanager.AppManager[T] + + // app manager dependencies + stf *stf.STF[T] + msgRouterBuilder *stf.MsgRouterBuilder + queryRouterBuilder *stf.MsgRouterBuilder + db Store + + // app configuration + logger log.Logger + config *runtimev2.Module + + // modules configuration + storeKeys []string + interfaceRegistrar registry.InterfaceRegistrar + amino legacy.Amino + moduleManager *MM[T] + + // GRPCQueryDecoders maps gRPC method name to a function that decodes the request + // bytes into a gogoproto.Message, which then can be passed to appmanager. + GRPCQueryDecoders map[string]func(requestBytes []byte) (gogoproto.Message, error) +} + +// Name returns the app name. +func (a *App[T]) Name() string { + return a.config.AppName +} + +// Logger returns the app logger. +func (a *App[T]) Logger() log.Logger { + return a.logger +} + +// ModuleManager returns the module manager. +func (a *App[T]) ModuleManager() *MM[T] { + return a.moduleManager +} + +// DefaultGenesis returns a default genesis from the registered modules. +func (a *App[T]) DefaultGenesis() map[string]json.RawMessage { + return a.moduleManager.DefaultGenesis() +} + +// LoadLatest loads the latest version. +func (a *App[T]) LoadLatest() error { + return a.db.LoadLatestVersion() +} + +// LoadHeight loads a particular height +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[T]) Close() error { + return nil +} + +// GetStoreKeys returns all the app store keys. +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[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") + } + + return a.storeKeys[i], nil +} + +// GetStore returns the app store. +func (a *App[T]) GetStore() Store { + return a.db +} + +// GetLogger returns the app logger. +func (a *App[T]) GetLogger() log.Logger { + return a.logger +} + +func (a *App[T]) ExecuteGenesisTx(_ []byte) error { + panic("App.ExecuteGenesisTx not supported in runtime/v2") +} + +func (a *App[T]) GetAppManager() *appmanager.AppManager[T] { + return a.AppManager +} + +func (a *App[T]) GetGRPCQueryDecoders() map[string]func(requestBytes []byte) (gogoproto.Message, error) { + return a.GRPCQueryDecoders +} diff --git a/runtime/v2/module.go b/runtime/v2/module.go new file mode 100644 index 000000000000..588584d06500 --- /dev/null +++ b/runtime/v2/module.go @@ -0,0 +1,248 @@ +package runtime + +import ( + "fmt" + "os" + "slices" + + "github.com/cosmos/gogoproto/proto" + "github.com/spf13/viper" + "google.golang.org/grpc" + "google.golang.org/protobuf/reflect/protodesc" + "google.golang.org/protobuf/reflect/protoregistry" + + runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2" + appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" + autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" + reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" + "cosmossdk.io/core/app" + "cosmossdk.io/core/appmodule" + appmodulev2 "cosmossdk.io/core/appmodule/v2" + "cosmossdk.io/core/comet" + "cosmossdk.io/core/genesis" + "cosmossdk.io/core/legacy" + "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" + "cosmossdk.io/server/v2/stf" +) + +var ( + _ appmodulev2.AppModule = appModule[transaction.Tx]{} + _ appmodule.HasServices = appModule[transaction.Tx]{} +) + +type appModule[T transaction.Tx] struct { + app *App[T] +} + +func (m appModule[T]) IsOnePerModuleType() {} +func (m appModule[T]) IsAppModule() {} + +func (m appModule[T]) RegisterServices(registar grpc.ServiceRegistrar) error { + autoCliQueryService, err := services.NewAutoCLIQueryService(m.app.moduleManager.modules) + if err != nil { + return err + } + + autocliv1.RegisterQueryServer(registar, autoCliQueryService) + + reflectionSvc, err := services.NewReflectionService() + if err != nil { + return err + } + reflectionv1.RegisterReflectionServiceServer(registar, reflectionSvc) + + return nil +} + +func (m appModule[T]) AutoCLIOptions() *autocliv1.ModuleOptions { + return &autocliv1.ModuleOptions{ + Query: &autocliv1.ServiceCommandDescriptor{ + Service: appv1alpha1.Query_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "Config", + Short: "Query the current app config", + }, + }, + SubCommands: map[string]*autocliv1.ServiceCommandDescriptor{ + "autocli": { + Service: autocliv1.Query_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "AppOptions", + Short: "Query the custom autocli options", + }, + }, + }, + "reflection": { + Service: reflectionv1.ReflectionService_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "FileDescriptors", + Short: "Query the app's protobuf file descriptors", + }, + }, + }, + }, + }, + } +} + +func init() { + appconfig.Register(&runtimev2.Module{}, + appconfig.Provide( + ProvideAppBuilder[transaction.Tx], + ProvideEnvironment[transaction.Tx], + ProvideModuleManager[transaction.Tx], + ProvideGenesisTxHandler[transaction.Tx], + ProvideCometService, + ProvideAppVersionModifier[transaction.Tx], + ), + appconfig.Invoke(SetupAppBuilder), + ) +} + +func ProvideAppBuilder[T transaction.Tx]( + interfaceRegistrar registry.InterfaceRegistrar, + amino legacy.Amino, +) ( + *AppBuilder[T], + *stf.MsgRouterBuilder, + appmodulev2.AppModule, + protodesc.Resolver, + protoregistry.MessageTypeResolver, +) { + protoFiles := proto.HybridResolver + protoTypes := protoregistry.GlobalTypes + + // At startup, check that all proto annotations are correct. + if err := validateProtoAnnotations(protoFiles); err != nil { + // Once we switch to using protoreflect-based ante handlers, we might + // want to panic here instead of logging a warning. + _, _ = fmt.Fprintln(os.Stderr, err.Error()) + } + + msgRouterBuilder := stf.NewMsgRouterBuilder() + app := &App[T]{ + storeKeys: nil, + interfaceRegistrar: interfaceRegistrar, + amino: amino, + msgRouterBuilder: msgRouterBuilder, + queryRouterBuilder: stf.NewMsgRouterBuilder(), // TODO dedicated query router + } + appBuilder := &AppBuilder[T]{app: app} + + return appBuilder, msgRouterBuilder, appModule[T]{app}, protoFiles, protoTypes +} + +type AppInputs struct { + depinject.In + + Config *runtimev2.Module + AppBuilder *AppBuilder[transaction.Tx] + ModuleManager *MM[transaction.Tx] + InterfaceRegistrar registry.InterfaceRegistrar + LegacyAmino legacy.Amino + Logger log.Logger + Viper *viper.Viper `optional:"true"` +} + +func SetupAppBuilder(inputs AppInputs) { + app := inputs.AppBuilder.app + app.config = inputs.Config + app.logger = inputs.Logger + app.moduleManager = inputs.ModuleManager + app.moduleManager.RegisterInterfaces(inputs.InterfaceRegistrar) + app.moduleManager.RegisterLegacyAminoCodec(inputs.LegacyAmino) + + if inputs.Viper != nil { + inputs.AppBuilder.viper = inputs.Viper + } +} + +func ProvideModuleManager[T transaction.Tx]( + logger log.Logger, + config *runtimev2.Module, + modules map[string]appmodulev2.AppModule, +) *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[T transaction.Tx](logger log.Logger, config *runtimev2.Module, key depinject.ModuleKey, appBuilder *AppBuilder[T]) ( + appmodulev2.Environment, + store.KVStoreService, + store.MemoryStoreService, +) { + var ( + kvService store.KVStoreService = failingStoreService{} + memKvService store.MemoryStoreService = failingStoreService{} + ) + + // skips modules that have no store + if !slices.Contains(config.SkipStoreKeys, key.Name()) { + var kvStoreKey string + storeKeyOverride := storeKeyOverride(config, key.Name()) + if storeKeyOverride != nil { + kvStoreKey = storeKeyOverride.KvStoreKey + } else { + kvStoreKey = key.Name() + } + + registerStoreKey(appBuilder, kvStoreKey) + kvService = stf.NewKVStoreService([]byte(kvStoreKey)) + + memStoreKey := fmt.Sprintf("memory:%s", key.Name()) + registerStoreKey(appBuilder, memStoreKey) + memKvService = stf.NewMemoryStoreService([]byte(memStoreKey)) + } + + env := appmodulev2.Environment{ + Logger: logger, + BranchService: stf.BranchService{}, + EventService: stf.NewEventService(), + GasService: stf.NewGasMeterService(), + HeaderService: stf.HeaderService{}, + QueryRouterService: stf.NewQueryRouterService(), + MsgRouterService: stf.NewMsgRouterService([]byte(key.Name())), + TransactionService: services.NewContextAwareTransactionService(), + KVStoreService: kvService, + MemStoreService: memKvService, + } + + return env, kvService, memKvService +} + +func registerStoreKey[T transaction.Tx](wrapper *AppBuilder[T], key string) { + wrapper.app.storeKeys = append(wrapper.app.storeKeys, key) +} + +func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.StoreKeyConfig { + for _, cfg := range config.OverrideStoreKeys { + if cfg.ModuleName == moduleName { + return cfg + } + } + + return nil +} + +func ProvideGenesisTxHandler[T transaction.Tx](appBuilder *AppBuilder[T]) genesis.TxHandler { + return appBuilder.app +} + +func ProvideCometService() comet.Service { + return &services.ContextAwareCometInfoService{} +} + +// 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[T transaction.Tx](app *AppBuilder[T]) app.VersionModifier { + return nil +} From 0aee1661f76aeea2dff1ec2f2b73d8943ada4ef9 Mon Sep 17 00:00:00 2001 From: marbar3778 Date: Fri, 26 Jul 2024 08:48:53 +0200 Subject: [PATCH 2/4] fix conflicts --- runtime/module.go | 18 ---- runtime/services.go | 2 - runtime/v2/app.go | 123 --------------------- runtime/v2/module.go | 248 ------------------------------------------- 4 files changed, 391 deletions(-) delete mode 100644 runtime/v2/app.go delete mode 100644 runtime/v2/module.go diff --git a/runtime/module.go b/runtime/module.go index b326206b368e..92e9ea763c69 100644 --- a/runtime/module.go +++ b/runtime/module.go @@ -9,16 +9,9 @@ import ( "google.golang.org/protobuf/reflect/protoregistry" runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" -<<<<<<< HEAD - appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" authmodulev1 "cosmossdk.io/api/cosmos/auth/module/v1" stakingmodulev1 "cosmossdk.io/api/cosmos/staking/module/v1" "cosmossdk.io/core/address" -======= - autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" - reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" - "cosmossdk.io/core/app" ->>>>>>> 502450cd1 (fix(runtime): remove `appv1alpha1.Config` from runtime (#21042)) "cosmossdk.io/core/appmodule" "cosmossdk.io/core/comet" "cosmossdk.io/core/event" @@ -133,8 +126,6 @@ func ProvideApp(interfaceRegistry codectypes.InterfaceRegistry) ( type AppInputs struct { depinject.In -<<<<<<< HEAD - AppConfig *appv1alpha1.Config Config *runtimev1alpha1.Module AppBuilder *AppBuilder Modules map[string]appmodule.AppModule @@ -143,15 +134,6 @@ type AppInputs struct { InterfaceRegistry codectypes.InterfaceRegistry LegacyAmino *codec.LegacyAmino Logger log.Logger -======= - Logger log.Logger - Config *runtimev1alpha1.Module - AppBuilder *AppBuilder - ModuleManager *module.Manager - BaseAppOptions []BaseAppOption - InterfaceRegistry codectypes.InterfaceRegistry - LegacyAmino legacy.Amino ->>>>>>> 502450cd1 (fix(runtime): remove `appv1alpha1.Config` from runtime (#21042)) } func SetupAppBuilder(inputs AppInputs) { diff --git a/runtime/services.go b/runtime/services.go index 5dcd2bf3427d..e7dc9c1bc3fb 100644 --- a/runtime/services.go +++ b/runtime/services.go @@ -3,7 +3,6 @@ package runtime import ( "context" - appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" "cosmossdk.io/core/comet" @@ -15,7 +14,6 @@ import ( ) func (a *App) registerRuntimeServices(cfg module.Configurator) error { - appv1alpha1.RegisterQueryServer(cfg.QueryServer(), services.NewAppQueryService(a.appConfig)) autocliv1.RegisterQueryServer(cfg.QueryServer(), services.NewAutoCLIQueryService(a.ModuleManager.Modules)) reflectionSvc, err := services.NewReflectionService() diff --git a/runtime/v2/app.go b/runtime/v2/app.go deleted file mode 100644 index 56632590b4f9..000000000000 --- a/runtime/v2/app.go +++ /dev/null @@ -1,123 +0,0 @@ -package runtime - -import ( - "encoding/json" - "errors" - - gogoproto "github.com/cosmos/gogoproto/proto" - "golang.org/x/exp/slices" - - runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2" - "cosmossdk.io/core/legacy" - "cosmossdk.io/core/log" - "cosmossdk.io/core/registry" - "cosmossdk.io/core/transaction" - "cosmossdk.io/server/v2/appmanager" - "cosmossdk.io/server/v2/stf" -) - -// App is a wrapper around AppManager and ModuleManager that can be used in hybrid -// app.go/app config scenarios or directly as a servertypes.Application instance. -// To get an instance of *App, *AppBuilder must be requested as a dependency -// in a container which declares the runtime module and the AppBuilder.Build() -// method must be called. -// -// 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[T transaction.Tx] struct { - *appmanager.AppManager[T] - - // app manager dependencies - stf *stf.STF[T] - msgRouterBuilder *stf.MsgRouterBuilder - queryRouterBuilder *stf.MsgRouterBuilder - db Store - - // app configuration - logger log.Logger - config *runtimev2.Module - - // modules configuration - storeKeys []string - interfaceRegistrar registry.InterfaceRegistrar - amino legacy.Amino - moduleManager *MM[T] - - // GRPCQueryDecoders maps gRPC method name to a function that decodes the request - // bytes into a gogoproto.Message, which then can be passed to appmanager. - GRPCQueryDecoders map[string]func(requestBytes []byte) (gogoproto.Message, error) -} - -// Name returns the app name. -func (a *App[T]) Name() string { - return a.config.AppName -} - -// Logger returns the app logger. -func (a *App[T]) Logger() log.Logger { - return a.logger -} - -// ModuleManager returns the module manager. -func (a *App[T]) ModuleManager() *MM[T] { - return a.moduleManager -} - -// DefaultGenesis returns a default genesis from the registered modules. -func (a *App[T]) DefaultGenesis() map[string]json.RawMessage { - return a.moduleManager.DefaultGenesis() -} - -// LoadLatest loads the latest version. -func (a *App[T]) LoadLatest() error { - return a.db.LoadLatestVersion() -} - -// LoadHeight loads a particular height -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[T]) Close() error { - return nil -} - -// GetStoreKeys returns all the app store keys. -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[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") - } - - return a.storeKeys[i], nil -} - -// GetStore returns the app store. -func (a *App[T]) GetStore() Store { - return a.db -} - -// GetLogger returns the app logger. -func (a *App[T]) GetLogger() log.Logger { - return a.logger -} - -func (a *App[T]) ExecuteGenesisTx(_ []byte) error { - panic("App.ExecuteGenesisTx not supported in runtime/v2") -} - -func (a *App[T]) GetAppManager() *appmanager.AppManager[T] { - return a.AppManager -} - -func (a *App[T]) GetGRPCQueryDecoders() map[string]func(requestBytes []byte) (gogoproto.Message, error) { - return a.GRPCQueryDecoders -} diff --git a/runtime/v2/module.go b/runtime/v2/module.go deleted file mode 100644 index 588584d06500..000000000000 --- a/runtime/v2/module.go +++ /dev/null @@ -1,248 +0,0 @@ -package runtime - -import ( - "fmt" - "os" - "slices" - - "github.com/cosmos/gogoproto/proto" - "github.com/spf13/viper" - "google.golang.org/grpc" - "google.golang.org/protobuf/reflect/protodesc" - "google.golang.org/protobuf/reflect/protoregistry" - - runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2" - appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" - autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" - reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" - "cosmossdk.io/core/app" - "cosmossdk.io/core/appmodule" - appmodulev2 "cosmossdk.io/core/appmodule/v2" - "cosmossdk.io/core/comet" - "cosmossdk.io/core/genesis" - "cosmossdk.io/core/legacy" - "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" - "cosmossdk.io/server/v2/stf" -) - -var ( - _ appmodulev2.AppModule = appModule[transaction.Tx]{} - _ appmodule.HasServices = appModule[transaction.Tx]{} -) - -type appModule[T transaction.Tx] struct { - app *App[T] -} - -func (m appModule[T]) IsOnePerModuleType() {} -func (m appModule[T]) IsAppModule() {} - -func (m appModule[T]) RegisterServices(registar grpc.ServiceRegistrar) error { - autoCliQueryService, err := services.NewAutoCLIQueryService(m.app.moduleManager.modules) - if err != nil { - return err - } - - autocliv1.RegisterQueryServer(registar, autoCliQueryService) - - reflectionSvc, err := services.NewReflectionService() - if err != nil { - return err - } - reflectionv1.RegisterReflectionServiceServer(registar, reflectionSvc) - - return nil -} - -func (m appModule[T]) AutoCLIOptions() *autocliv1.ModuleOptions { - return &autocliv1.ModuleOptions{ - Query: &autocliv1.ServiceCommandDescriptor{ - Service: appv1alpha1.Query_ServiceDesc.ServiceName, - RpcCommandOptions: []*autocliv1.RpcCommandOptions{ - { - RpcMethod: "Config", - Short: "Query the current app config", - }, - }, - SubCommands: map[string]*autocliv1.ServiceCommandDescriptor{ - "autocli": { - Service: autocliv1.Query_ServiceDesc.ServiceName, - RpcCommandOptions: []*autocliv1.RpcCommandOptions{ - { - RpcMethod: "AppOptions", - Short: "Query the custom autocli options", - }, - }, - }, - "reflection": { - Service: reflectionv1.ReflectionService_ServiceDesc.ServiceName, - RpcCommandOptions: []*autocliv1.RpcCommandOptions{ - { - RpcMethod: "FileDescriptors", - Short: "Query the app's protobuf file descriptors", - }, - }, - }, - }, - }, - } -} - -func init() { - appconfig.Register(&runtimev2.Module{}, - appconfig.Provide( - ProvideAppBuilder[transaction.Tx], - ProvideEnvironment[transaction.Tx], - ProvideModuleManager[transaction.Tx], - ProvideGenesisTxHandler[transaction.Tx], - ProvideCometService, - ProvideAppVersionModifier[transaction.Tx], - ), - appconfig.Invoke(SetupAppBuilder), - ) -} - -func ProvideAppBuilder[T transaction.Tx]( - interfaceRegistrar registry.InterfaceRegistrar, - amino legacy.Amino, -) ( - *AppBuilder[T], - *stf.MsgRouterBuilder, - appmodulev2.AppModule, - protodesc.Resolver, - protoregistry.MessageTypeResolver, -) { - protoFiles := proto.HybridResolver - protoTypes := protoregistry.GlobalTypes - - // At startup, check that all proto annotations are correct. - if err := validateProtoAnnotations(protoFiles); err != nil { - // Once we switch to using protoreflect-based ante handlers, we might - // want to panic here instead of logging a warning. - _, _ = fmt.Fprintln(os.Stderr, err.Error()) - } - - msgRouterBuilder := stf.NewMsgRouterBuilder() - app := &App[T]{ - storeKeys: nil, - interfaceRegistrar: interfaceRegistrar, - amino: amino, - msgRouterBuilder: msgRouterBuilder, - queryRouterBuilder: stf.NewMsgRouterBuilder(), // TODO dedicated query router - } - appBuilder := &AppBuilder[T]{app: app} - - return appBuilder, msgRouterBuilder, appModule[T]{app}, protoFiles, protoTypes -} - -type AppInputs struct { - depinject.In - - Config *runtimev2.Module - AppBuilder *AppBuilder[transaction.Tx] - ModuleManager *MM[transaction.Tx] - InterfaceRegistrar registry.InterfaceRegistrar - LegacyAmino legacy.Amino - Logger log.Logger - Viper *viper.Viper `optional:"true"` -} - -func SetupAppBuilder(inputs AppInputs) { - app := inputs.AppBuilder.app - app.config = inputs.Config - app.logger = inputs.Logger - app.moduleManager = inputs.ModuleManager - app.moduleManager.RegisterInterfaces(inputs.InterfaceRegistrar) - app.moduleManager.RegisterLegacyAminoCodec(inputs.LegacyAmino) - - if inputs.Viper != nil { - inputs.AppBuilder.viper = inputs.Viper - } -} - -func ProvideModuleManager[T transaction.Tx]( - logger log.Logger, - config *runtimev2.Module, - modules map[string]appmodulev2.AppModule, -) *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[T transaction.Tx](logger log.Logger, config *runtimev2.Module, key depinject.ModuleKey, appBuilder *AppBuilder[T]) ( - appmodulev2.Environment, - store.KVStoreService, - store.MemoryStoreService, -) { - var ( - kvService store.KVStoreService = failingStoreService{} - memKvService store.MemoryStoreService = failingStoreService{} - ) - - // skips modules that have no store - if !slices.Contains(config.SkipStoreKeys, key.Name()) { - var kvStoreKey string - storeKeyOverride := storeKeyOverride(config, key.Name()) - if storeKeyOverride != nil { - kvStoreKey = storeKeyOverride.KvStoreKey - } else { - kvStoreKey = key.Name() - } - - registerStoreKey(appBuilder, kvStoreKey) - kvService = stf.NewKVStoreService([]byte(kvStoreKey)) - - memStoreKey := fmt.Sprintf("memory:%s", key.Name()) - registerStoreKey(appBuilder, memStoreKey) - memKvService = stf.NewMemoryStoreService([]byte(memStoreKey)) - } - - env := appmodulev2.Environment{ - Logger: logger, - BranchService: stf.BranchService{}, - EventService: stf.NewEventService(), - GasService: stf.NewGasMeterService(), - HeaderService: stf.HeaderService{}, - QueryRouterService: stf.NewQueryRouterService(), - MsgRouterService: stf.NewMsgRouterService([]byte(key.Name())), - TransactionService: services.NewContextAwareTransactionService(), - KVStoreService: kvService, - MemStoreService: memKvService, - } - - return env, kvService, memKvService -} - -func registerStoreKey[T transaction.Tx](wrapper *AppBuilder[T], key string) { - wrapper.app.storeKeys = append(wrapper.app.storeKeys, key) -} - -func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.StoreKeyConfig { - for _, cfg := range config.OverrideStoreKeys { - if cfg.ModuleName == moduleName { - return cfg - } - } - - return nil -} - -func ProvideGenesisTxHandler[T transaction.Tx](appBuilder *AppBuilder[T]) genesis.TxHandler { - return appBuilder.app -} - -func ProvideCometService() comet.Service { - return &services.ContextAwareCometInfoService{} -} - -// 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[T transaction.Tx](app *AppBuilder[T]) app.VersionModifier { - return nil -} From 59deba60721aa0144f6019d69c27fefd07b8320e Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 26 Jul 2024 09:07:52 +0200 Subject: [PATCH 3/4] cl --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1ea94db8fc0..e48783a88e8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [#20939](https://github.com/cosmos/cosmos-sdk/pull/20939) Fix collection reverse iterator to include `pagination.key` in the result. * (client/grpc) [#20969](https://github.com/cosmos/cosmos-sdk/pull/20969) Fix `node.NewQueryServer` method not setting `cfg`. * (testutil/integration) [#21006](https://github.com/cosmos/cosmos-sdk/pull/21006) Fix `NewIntegrationApp` method not writing default genesis to state +* (runtime) [#21080](https://github.com/cosmos/cosmos-sdk/pull/21080) Fix `app.yaml` / `app.json` incompatibility with `depinject v1.0.0` ## [v0.50.8](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.8) - 2024-07-15 From a7d8f6b8cf22650e3cfcad1b83ab01b012126df8 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 26 Jul 2024 10:11:54 +0200 Subject: [PATCH 4/4] updates --- runtime/app.go | 2 ++ runtime/module.go | 3 +++ runtime/services.go | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/runtime/app.go b/runtime/app.go index 1a845c72763e..55b44aaa0d34 100644 --- a/runtime/app.go +++ b/runtime/app.go @@ -8,6 +8,7 @@ import ( "golang.org/x/exp/slices" runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" + appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" "cosmossdk.io/core/appmodule" "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" @@ -50,6 +51,7 @@ type App struct { baseAppOptions []BaseAppOption msgServiceRouter *baseapp.MsgServiceRouter grpcQueryRouter *baseapp.GRPCQueryRouter + appConfig *appv1alpha1.Config logger log.Logger // initChainer is the init chainer function defined by the app config. // this is only required if the chain wants to add special InitChainer logic. diff --git a/runtime/module.go b/runtime/module.go index 92e9ea763c69..d7d46cc75b90 100644 --- a/runtime/module.go +++ b/runtime/module.go @@ -9,6 +9,7 @@ import ( "google.golang.org/protobuf/reflect/protoregistry" runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" + appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" authmodulev1 "cosmossdk.io/api/cosmos/auth/module/v1" stakingmodulev1 "cosmossdk.io/api/cosmos/staking/module/v1" "cosmossdk.io/core/address" @@ -126,6 +127,7 @@ func ProvideApp(interfaceRegistry codectypes.InterfaceRegistry) ( type AppInputs struct { depinject.In + AppConfig *appv1alpha1.Config `optional:"true"` Config *runtimev1alpha1.Module AppBuilder *AppBuilder Modules map[string]appmodule.AppModule @@ -140,6 +142,7 @@ func SetupAppBuilder(inputs AppInputs) { app := inputs.AppBuilder.app app.baseAppOptions = inputs.BaseAppOptions app.config = inputs.Config + app.appConfig = inputs.AppConfig app.logger = inputs.Logger app.ModuleManager = module.NewManagerFromMap(inputs.Modules) diff --git a/runtime/services.go b/runtime/services.go index e7dc9c1bc3fb..3730b4a2af92 100644 --- a/runtime/services.go +++ b/runtime/services.go @@ -3,6 +3,7 @@ package runtime import ( "context" + appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" "cosmossdk.io/core/comet" @@ -14,6 +15,11 @@ import ( ) func (a *App) registerRuntimeServices(cfg module.Configurator) error { + // no app config service if user is using app.yaml / app.json + // it is as in v0.52, this whole query service does not exist at all. + if a.appConfig != nil { + appv1alpha1.RegisterQueryServer(cfg.QueryServer(), services.NewAppQueryService(a.appConfig)) + } autocliv1.RegisterQueryServer(cfg.QueryServer(), services.NewAutoCLIQueryService(a.ModuleManager.Modules)) reflectionSvc, err := services.NewReflectionService()