github.com/cosmos/cosmos-sdk@v0.50.10/runtime/app.go (about) 1 package runtime 2 3 import ( 4 "encoding/json" 5 "fmt" 6 7 abci "github.com/cometbft/cometbft/abci/types" 8 "golang.org/x/exp/slices" 9 10 runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" 11 appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" 12 "cosmossdk.io/core/appmodule" 13 "cosmossdk.io/log" 14 storetypes "cosmossdk.io/store/types" 15 16 "github.com/cosmos/cosmos-sdk/baseapp" 17 "github.com/cosmos/cosmos-sdk/client" 18 "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" 19 nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" 20 "github.com/cosmos/cosmos-sdk/codec" 21 codectypes "github.com/cosmos/cosmos-sdk/codec/types" 22 "github.com/cosmos/cosmos-sdk/server" 23 "github.com/cosmos/cosmos-sdk/server/api" 24 "github.com/cosmos/cosmos-sdk/server/config" 25 servertypes "github.com/cosmos/cosmos-sdk/server/types" 26 sdk "github.com/cosmos/cosmos-sdk/types" 27 "github.com/cosmos/cosmos-sdk/types/module" 28 authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" 29 ) 30 31 // App is a wrapper around BaseApp and ModuleManager that can be used in hybrid 32 // app.go/app config scenarios or directly as a servertypes.Application instance. 33 // To get an instance of *App, *AppBuilder must be requested as a dependency 34 // in a container which declares the runtime module and the AppBuilder.Build() 35 // method must be called. 36 // 37 // App can be used to create a hybrid app.go setup where some configuration is 38 // done declaratively with an app config and the rest of it is done the old way. 39 // See simapp/app.go for an example of this setup. 40 type App struct { 41 *baseapp.BaseApp 42 43 ModuleManager *module.Manager 44 configurator module.Configurator 45 config *runtimev1alpha1.Module 46 storeKeys []storetypes.StoreKey 47 interfaceRegistry codectypes.InterfaceRegistry 48 cdc codec.Codec 49 amino *codec.LegacyAmino 50 basicManager module.BasicManager 51 baseAppOptions []BaseAppOption 52 msgServiceRouter *baseapp.MsgServiceRouter 53 grpcQueryRouter *baseapp.GRPCQueryRouter 54 appConfig *appv1alpha1.Config 55 logger log.Logger 56 // initChainer is the init chainer function defined by the app config. 57 // this is only required if the chain wants to add special InitChainer logic. 58 initChainer sdk.InitChainer 59 } 60 61 // RegisterModules registers the provided modules with the module manager and 62 // the basic module manager. This is the primary hook for integrating with 63 // modules which are not registered using the app config. 64 func (a *App) RegisterModules(modules ...module.AppModule) error { 65 for _, appModule := range modules { 66 name := appModule.Name() 67 if _, ok := a.ModuleManager.Modules[name]; ok { 68 return fmt.Errorf("AppModule named %q already exists", name) 69 } 70 71 if _, ok := a.basicManager[name]; ok { 72 return fmt.Errorf("AppModuleBasic named %q already exists", name) 73 } 74 75 a.ModuleManager.Modules[name] = appModule 76 a.basicManager[name] = appModule 77 appModule.RegisterInterfaces(a.interfaceRegistry) 78 appModule.RegisterLegacyAminoCodec(a.amino) 79 80 if module, ok := appModule.(module.HasServices); ok { 81 module.RegisterServices(a.configurator) 82 } else if module, ok := appModule.(appmodule.HasServices); ok { 83 if err := module.RegisterServices(a.configurator); err != nil { 84 return err 85 } 86 } 87 } 88 89 return nil 90 } 91 92 // RegisterStores registers the provided store keys. 93 // This method should only be used for registering extra stores 94 // wiich is necessary for modules that not registered using the app config. 95 // To be used in combination of RegisterModules. 96 func (a *App) RegisterStores(keys ...storetypes.StoreKey) error { 97 a.storeKeys = append(a.storeKeys, keys...) 98 a.MountStores(keys...) 99 100 return nil 101 } 102 103 // Load finishes all initialization operations and loads the app. 104 func (a *App) Load(loadLatest bool) error { 105 if len(a.config.InitGenesis) != 0 { 106 a.ModuleManager.SetOrderInitGenesis(a.config.InitGenesis...) 107 if a.initChainer == nil { 108 a.SetInitChainer(a.InitChainer) 109 } 110 } 111 112 if len(a.config.ExportGenesis) != 0 { 113 a.ModuleManager.SetOrderExportGenesis(a.config.ExportGenesis...) 114 } else if len(a.config.InitGenesis) != 0 { 115 a.ModuleManager.SetOrderExportGenesis(a.config.InitGenesis...) 116 } 117 118 if len(a.config.PreBlockers) != 0 { 119 a.ModuleManager.SetOrderPreBlockers(a.config.PreBlockers...) 120 if a.BaseApp.PreBlocker() == nil { 121 a.SetPreBlocker(a.PreBlocker) 122 } 123 } 124 125 if len(a.config.BeginBlockers) != 0 { 126 a.ModuleManager.SetOrderBeginBlockers(a.config.BeginBlockers...) 127 a.SetBeginBlocker(a.BeginBlocker) 128 } 129 130 if len(a.config.EndBlockers) != 0 { 131 a.ModuleManager.SetOrderEndBlockers(a.config.EndBlockers...) 132 a.SetEndBlocker(a.EndBlocker) 133 } 134 135 if len(a.config.Precommiters) != 0 { 136 a.ModuleManager.SetOrderPrecommiters(a.config.Precommiters...) 137 a.SetPrecommiter(a.Precommiter) 138 } 139 140 if len(a.config.PrepareCheckStaters) != 0 { 141 a.ModuleManager.SetOrderPrepareCheckStaters(a.config.PrepareCheckStaters...) 142 a.SetPrepareCheckStater(a.PrepareCheckStater) 143 } 144 145 if len(a.config.OrderMigrations) != 0 { 146 a.ModuleManager.SetOrderMigrations(a.config.OrderMigrations...) 147 } 148 149 if loadLatest { 150 if err := a.LoadLatestVersion(); err != nil { 151 return err 152 } 153 } 154 155 return nil 156 } 157 158 // PreBlocker application updates every pre block 159 func (a *App) PreBlocker(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) { 160 return a.ModuleManager.PreBlock(ctx) 161 } 162 163 // BeginBlocker application updates every begin block 164 func (a *App) BeginBlocker(ctx sdk.Context) (sdk.BeginBlock, error) { 165 return a.ModuleManager.BeginBlock(ctx) 166 } 167 168 // EndBlocker application updates every end block 169 func (a *App) EndBlocker(ctx sdk.Context) (sdk.EndBlock, error) { 170 return a.ModuleManager.EndBlock(ctx) 171 } 172 173 // Precommiter application updates every commit 174 func (a *App) Precommiter(ctx sdk.Context) { 175 a.ModuleManager.Precommit(ctx) 176 } 177 178 // PrepareCheckStater application updates every commit 179 func (a *App) PrepareCheckStater(ctx sdk.Context) { 180 a.ModuleManager.PrepareCheckState(ctx) 181 } 182 183 // InitChainer initializes the chain. 184 func (a *App) InitChainer(ctx sdk.Context, req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { 185 var genesisState map[string]json.RawMessage 186 if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil { 187 panic(err) 188 } 189 return a.ModuleManager.InitGenesis(ctx, a.cdc, genesisState) 190 } 191 192 // RegisterAPIRoutes registers all application module routes with the provided 193 // API server. 194 func (a *App) RegisterAPIRoutes(apiSvr *api.Server, _ config.APIConfig) { 195 clientCtx := apiSvr.ClientCtx 196 // Register new tx routes from grpc-gateway. 197 authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) 198 199 // Register new CometBFT queries routes from grpc-gateway. 200 cmtservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) 201 202 // Register node gRPC service for grpc-gateway. 203 nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) 204 205 // Register grpc-gateway routes for all modules. 206 a.basicManager.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) 207 } 208 209 // RegisterTxService implements the Application.RegisterTxService method. 210 func (a *App) RegisterTxService(clientCtx client.Context) { 211 authtx.RegisterTxService(a.GRPCQueryRouter(), clientCtx, a.Simulate, a.interfaceRegistry) 212 } 213 214 // RegisterTendermintService implements the Application.RegisterTendermintService method. 215 func (a *App) RegisterTendermintService(clientCtx client.Context) { 216 cmtApp := server.NewCometABCIWrapper(a) 217 cmtservice.RegisterTendermintService( 218 clientCtx, 219 a.GRPCQueryRouter(), 220 a.interfaceRegistry, 221 cmtApp.Query, 222 ) 223 } 224 225 // RegisterNodeService registers the node gRPC service on the app gRPC router. 226 func (a *App) RegisterNodeService(clientCtx client.Context, cfg config.Config) { 227 nodeservice.RegisterNodeService(clientCtx, a.GRPCQueryRouter(), cfg) 228 } 229 230 // Configurator returns the app's configurator. 231 func (a *App) Configurator() module.Configurator { 232 return a.configurator 233 } 234 235 // LoadHeight loads a particular height 236 func (a *App) LoadHeight(height int64) error { 237 return a.LoadVersion(height) 238 } 239 240 // DefaultGenesis returns a default genesis from the registered AppModuleBasic's. 241 func (a *App) DefaultGenesis() map[string]json.RawMessage { 242 return a.basicManager.DefaultGenesis(a.cdc) 243 } 244 245 // GetStoreKeys returns all the stored store keys. 246 func (a *App) GetStoreKeys() []storetypes.StoreKey { 247 return a.storeKeys 248 } 249 250 // SetInitChainer sets the init chainer function 251 // It wraps `BaseApp.SetInitChainer` to allow setting a custom init chainer from an app. 252 func (a *App) SetInitChainer(initChainer sdk.InitChainer) { 253 a.initChainer = initChainer 254 a.BaseApp.SetInitChainer(initChainer) 255 } 256 257 // UnsafeFindStoreKey fetches a registered StoreKey from the App in linear time. 258 // 259 // NOTE: This should only be used in testing. 260 func (a *App) UnsafeFindStoreKey(storeKey string) storetypes.StoreKey { 261 i := slices.IndexFunc(a.storeKeys, func(s storetypes.StoreKey) bool { return s.Name() == storeKey }) 262 if i == -1 { 263 return nil 264 } 265 266 return a.storeKeys[i] 267 } 268 269 var _ servertypes.Application = &App{}