github.com/Finschia/finschia-sdk@v0.48.1/types/module/module.go (about) 1 /* 2 Package module contains application module patterns and associated "manager" functionality. 3 The module pattern has been broken down by: 4 - independent module functionality (AppModuleBasic) 5 - inter-dependent module genesis functionality (AppModuleGenesis) 6 - inter-dependent module simulation functionality (AppModuleSimulation) 7 - inter-dependent module full functionality (AppModule) 8 9 inter-dependent module functionality is module functionality which somehow 10 depends on other modules, typically through the module keeper. Many of the 11 module keepers are dependent on each other, thus in order to access the full 12 set of module functionality we need to define all the keepers/params-store/keys 13 etc. This full set of advanced functionality is defined by the AppModule interface. 14 15 Independent module functions are separated to allow for the construction of the 16 basic application structures required early on in the application definition 17 and used to enable the definition of full module functionality later in the 18 process. This separation is necessary, however we still want to allow for a 19 high level pattern for modules to follow - for instance, such that we don't 20 have to manually register all of the codecs for all the modules. This basic 21 procedure as well as other basic patterns are handled through the use of 22 BasicManager. 23 24 Lastly the interface for genesis functionality (AppModuleGenesis) has been 25 separated out from full module functionality (AppModule) so that modules which 26 are only used for genesis can take advantage of the Module patterns without 27 needlessly defining many placeholder functions 28 */ 29 package module 30 31 import ( 32 "encoding/json" 33 "fmt" 34 "sort" 35 36 "github.com/grpc-ecosystem/grpc-gateway/runtime" 37 "github.com/spf13/cobra" 38 39 ocabci "github.com/Finschia/ostracon/abci/types" 40 abci "github.com/tendermint/tendermint/abci/types" 41 42 "github.com/Finschia/finschia-sdk/client" 43 "github.com/Finschia/finschia-sdk/codec" 44 codectypes "github.com/Finschia/finschia-sdk/codec/types" 45 sdk "github.com/Finschia/finschia-sdk/types" 46 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 47 ) 48 49 // AppModuleBasic is the standard form for basic non-dependant elements of an application module. 50 type AppModuleBasic interface { 51 Name() string 52 RegisterLegacyAminoCodec(*codec.LegacyAmino) 53 RegisterInterfaces(codectypes.InterfaceRegistry) 54 55 DefaultGenesis(codec.JSONCodec) json.RawMessage 56 ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage) error 57 58 // client functionality 59 RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux) 60 GetTxCmd() *cobra.Command 61 GetQueryCmd() *cobra.Command 62 } 63 64 // BasicManager is a collection of AppModuleBasic 65 type BasicManager map[string]AppModuleBasic 66 67 // NewBasicManager creates a new BasicManager object 68 func NewBasicManager(modules ...AppModuleBasic) BasicManager { 69 moduleMap := make(map[string]AppModuleBasic) 70 for _, module := range modules { 71 moduleMap[module.Name()] = module 72 } 73 return moduleMap 74 } 75 76 // RegisterLegacyAminoCodec registers all module codecs 77 func (bm BasicManager) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { 78 for _, b := range bm { 79 b.RegisterLegacyAminoCodec(cdc) 80 } 81 } 82 83 // RegisterInterfaces registers all module interface types 84 func (bm BasicManager) RegisterInterfaces(registry codectypes.InterfaceRegistry) { 85 for _, m := range bm { 86 m.RegisterInterfaces(registry) 87 } 88 } 89 90 // DefaultGenesis provides default genesis information for all modules 91 func (bm BasicManager) DefaultGenesis(cdc codec.JSONCodec) map[string]json.RawMessage { 92 genesis := make(map[string]json.RawMessage) 93 for _, b := range bm { 94 genesis[b.Name()] = b.DefaultGenesis(cdc) 95 } 96 97 return genesis 98 } 99 100 // ValidateGenesis performs genesis state validation for all modules 101 func (bm BasicManager) ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesis map[string]json.RawMessage) error { 102 for _, b := range bm { 103 if err := b.ValidateGenesis(cdc, txEncCfg, genesis[b.Name()]); err != nil { 104 return err 105 } 106 } 107 108 return nil 109 } 110 111 // RegisterGRPCGatewayRoutes registers all module rest routes 112 func (bm BasicManager) RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) { 113 for _, b := range bm { 114 b.RegisterGRPCGatewayRoutes(clientCtx, rtr) 115 } 116 } 117 118 // AddTxCommands adds all tx commands to the rootTxCmd. 119 // 120 // TODO: Remove clientCtx argument. 121 // REF: https://github.com/cosmos/cosmos-sdk/issues/6571 122 func (bm BasicManager) AddTxCommands(rootTxCmd *cobra.Command) { 123 for _, b := range bm { 124 if cmd := b.GetTxCmd(); cmd != nil { 125 rootTxCmd.AddCommand(cmd) 126 } 127 } 128 } 129 130 // AddQueryCommands adds all query commands to the rootQueryCmd. 131 // 132 // TODO: Remove clientCtx argument. 133 // REF: https://github.com/cosmos/cosmos-sdk/issues/6571 134 func (bm BasicManager) AddQueryCommands(rootQueryCmd *cobra.Command) { 135 for _, b := range bm { 136 if cmd := b.GetQueryCmd(); cmd != nil { 137 rootQueryCmd.AddCommand(cmd) 138 } 139 } 140 } 141 142 // AppModuleGenesis is the standard form for an application module genesis functions 143 type AppModuleGenesis interface { 144 AppModuleBasic 145 146 InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate 147 ExportGenesis(sdk.Context, codec.JSONCodec) json.RawMessage 148 } 149 150 // AppModule is the standard form for an application module 151 type AppModule interface { 152 AppModuleGenesis 153 154 // registers 155 RegisterInvariants(sdk.InvariantRegistry) 156 157 // Deprecated: use RegisterServices 158 Route() sdk.Route 159 160 // Deprecated: use RegisterServices 161 QuerierRoute() string 162 163 // Deprecated: use RegisterServices 164 LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier 165 166 // RegisterServices allows a module to register services 167 RegisterServices(Configurator) 168 169 // ConsensusVersion is a sequence number for state-breaking change of the 170 // module. It should be incremented on each consensus-breaking change 171 // introduced by the module. To avoid wrong/empty versions, the initial version 172 // should be set to 1. 173 ConsensusVersion() uint64 174 } 175 176 // BeginBlockAppModule is an extension interface that contains information about the AppModule and BeginBlock. 177 type BeginBlockAppModule interface { 178 AppModule 179 BeginBlock(sdk.Context, ocabci.RequestBeginBlock) 180 } 181 182 // EndBlockAppModule is an extension interface that contains information about the AppModule and EndBlock. 183 type EndBlockAppModule interface { 184 AppModule 185 EndBlock(sdk.Context, abci.RequestEndBlock) []abci.ValidatorUpdate 186 } 187 188 // GenesisOnlyAppModule is an AppModule that only has import/export functionality 189 type GenesisOnlyAppModule struct { 190 AppModuleGenesis 191 } 192 193 // NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object 194 func NewGenesisOnlyAppModule(amg AppModuleGenesis) AppModule { 195 return GenesisOnlyAppModule{ 196 AppModuleGenesis: amg, 197 } 198 } 199 200 // RegisterInvariants is a placeholder function register no invariants 201 func (GenesisOnlyAppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} 202 203 // Route empty module message route 204 func (GenesisOnlyAppModule) Route() sdk.Route { return sdk.Route{} } 205 206 // QuerierRoute returns an empty module querier route 207 func (GenesisOnlyAppModule) QuerierRoute() string { return "" } 208 209 // LegacyQuerierHandler returns an empty module querier 210 func (gam GenesisOnlyAppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { return nil } 211 212 // RegisterServices registers all services. 213 func (gam GenesisOnlyAppModule) RegisterServices(Configurator) {} 214 215 // ConsensusVersion implements AppModule/ConsensusVersion. 216 func (gam GenesisOnlyAppModule) ConsensusVersion() uint64 { return 1 } 217 218 // BeginBlock returns an empty module begin-block 219 func (gam GenesisOnlyAppModule) BeginBlock(ctx sdk.Context, req ocabci.RequestBeginBlock) {} 220 221 // EndBlock returns an empty module end-block 222 func (GenesisOnlyAppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { 223 return []abci.ValidatorUpdate{} 224 } 225 226 // Manager defines a module manager that provides the high level utility for managing and executing 227 // operations for a group of modules 228 type Manager struct { 229 Modules map[string]AppModule 230 OrderInitGenesis []string 231 OrderExportGenesis []string 232 OrderBeginBlockers []string 233 OrderEndBlockers []string 234 OrderMigrations []string 235 } 236 237 // NewManager creates a new Manager object 238 func NewManager(modules ...AppModule) *Manager { 239 moduleMap := make(map[string]AppModule) 240 modulesStr := make([]string, 0, len(modules)) 241 for _, module := range modules { 242 moduleMap[module.Name()] = module 243 modulesStr = append(modulesStr, module.Name()) 244 } 245 246 return &Manager{ 247 Modules: moduleMap, 248 OrderInitGenesis: modulesStr, 249 OrderExportGenesis: modulesStr, 250 OrderBeginBlockers: modulesStr, 251 OrderEndBlockers: modulesStr, 252 } 253 } 254 255 // SetOrderInitGenesis sets the order of init genesis calls 256 func (m *Manager) SetOrderInitGenesis(moduleNames ...string) { 257 m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames) 258 m.OrderInitGenesis = moduleNames 259 } 260 261 // SetOrderExportGenesis sets the order of export genesis calls 262 func (m *Manager) SetOrderExportGenesis(moduleNames ...string) { 263 m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames) 264 m.OrderExportGenesis = moduleNames 265 } 266 267 // SetOrderBeginBlockers sets the order of set begin-blocker calls 268 func (m *Manager) SetOrderBeginBlockers(moduleNames ...string) { 269 m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames) 270 m.OrderBeginBlockers = moduleNames 271 } 272 273 // SetOrderEndBlockers sets the order of set end-blocker calls 274 func (m *Manager) SetOrderEndBlockers(moduleNames ...string) { 275 m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames) 276 m.OrderEndBlockers = moduleNames 277 } 278 279 // SetOrderMigrations sets the order of migrations to be run. If not set 280 // then migrations will be run with an order defined in `DefaultMigrationsOrder`. 281 func (m *Manager) SetOrderMigrations(moduleNames ...string) { 282 m.assertNoForgottenModules("SetOrderMigrations", moduleNames) 283 m.OrderMigrations = moduleNames 284 } 285 286 // RegisterInvariants registers all module invariants 287 func (m *Manager) RegisterInvariants(ir sdk.InvariantRegistry) { 288 for _, module := range m.Modules { 289 module.RegisterInvariants(ir) 290 } 291 } 292 293 // RegisterRoutes registers all module routes and module querier routes 294 func (m *Manager) RegisterRoutes(router sdk.Router, queryRouter sdk.QueryRouter, legacyQuerierCdc *codec.LegacyAmino) { 295 for _, module := range m.Modules { 296 if r := module.Route(); !r.Empty() { 297 router.AddRoute(r) 298 } 299 if r := module.QuerierRoute(); r != "" { 300 queryRouter.AddRoute(r, module.LegacyQuerierHandler(legacyQuerierCdc)) 301 } 302 } 303 } 304 305 // RegisterServices registers all module services 306 func (m *Manager) RegisterServices(cfg Configurator) { 307 for _, module := range m.Modules { 308 module.RegisterServices(cfg) 309 } 310 } 311 312 // InitGenesis performs init genesis functionality for modules 313 func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) abci.ResponseInitChain { 314 var validatorUpdates []abci.ValidatorUpdate 315 for _, moduleName := range m.OrderInitGenesis { 316 if genesisData[moduleName] == nil { 317 continue 318 } 319 320 moduleValUpdates := m.Modules[moduleName].InitGenesis(ctx, cdc, genesisData[moduleName]) 321 322 // use these validator updates if provided, the module manager assumes 323 // only one module will update the validator set 324 if len(moduleValUpdates) > 0 { 325 if len(validatorUpdates) > 0 { 326 panic("validator InitGenesis updates already set by a previous module") 327 } 328 validatorUpdates = moduleValUpdates 329 } 330 } 331 332 return abci.ResponseInitChain{ 333 Validators: validatorUpdates, 334 } 335 } 336 337 // ExportGenesis performs export genesis functionality for modules 338 func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) map[string]json.RawMessage { 339 genesisData := make(map[string]json.RawMessage) 340 for _, moduleName := range m.OrderExportGenesis { 341 genesisData[moduleName] = m.Modules[moduleName].ExportGenesis(ctx, cdc) 342 } 343 344 return genesisData 345 } 346 347 // assertNoForgottenModules checks that we didn't forget any modules in the 348 // SetOrder* functions. 349 func (m *Manager) assertNoForgottenModules(setOrderFnName string, moduleNames []string) { 350 ms := make(map[string]bool) 351 for _, m := range moduleNames { 352 ms[m] = true 353 } 354 var missing []string 355 for m := range m.Modules { 356 if !ms[m] { 357 missing = append(missing, m) 358 } 359 } 360 if len(missing) != 0 { 361 panic(fmt.Sprintf( 362 "%s: all modules must be defined when setting %s, missing: %v", setOrderFnName, setOrderFnName, missing)) 363 } 364 } 365 366 // MigrationHandler is the migration function that each module registers. 367 type MigrationHandler func(sdk.Context) error 368 369 // VersionMap is a map of moduleName -> version 370 type VersionMap map[string]uint64 371 372 // RunMigrations performs in-place store migrations for all modules. This 373 // function MUST be called insde an x/upgrade UpgradeHandler. 374 // 375 // Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from 376 // x/upgrade's store, and the function needs to return the target VersionMap 377 // that will in turn be persisted to the x/upgrade's store. In general, 378 // returning RunMigrations should be enough: 379 // 380 // Example: 381 // 382 // cfg := module.NewConfigurator(...) 383 // app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { 384 // return app.mm.RunMigrations(ctx, cfg, fromVM) 385 // }) 386 // 387 // Internally, RunMigrations will perform the following steps: 388 // - create an `updatedVM` VersionMap of module with their latest ConsensusVersion 389 // - make a diff of `fromVM` and `udpatedVM`, and for each module: 390 // - if the module's `fromVM` version is less than its `updatedVM` version, 391 // then run in-place store migrations for that module between those versions. 392 // - if the module does not exist in the `fromVM` (which means that it's a new module, 393 // because it was not in the previous x/upgrade's store), then run 394 // `InitGenesis` on that module. 395 // 396 // - return the `updatedVM` to be persisted in the x/upgrade's store. 397 // 398 // Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set) defined by 399 // `DefaultMigrationsOrder` function. 400 // 401 // As an app developer, if you wish to skip running InitGenesis for your new 402 // module "foo", you need to manually pass a `fromVM` argument to this function 403 // foo's module version set to its latest ConsensusVersion. That way, the diff 404 // between the function's `fromVM` and `udpatedVM` will be empty, hence not 405 // running anything for foo. 406 // 407 // Example: 408 // 409 // cfg := module.NewConfigurator(...) 410 // app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { 411 // // Assume "foo" is a new module. 412 // // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist 413 // // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default 414 // // run InitGenesis on foo. 415 // // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest 416 // // consensus version: 417 // fromVM["foo"] = foo.AppModule{}.ConsensusVersion() 418 // 419 // return app.mm.RunMigrations(ctx, cfg, fromVM) 420 // }) 421 // 422 // Please also refer to docs/core/upgrade.md for more information. 423 func (m Manager) RunMigrations(ctx sdk.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) { 424 c, ok := cfg.(configurator) 425 if !ok { 426 return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", configurator{}, cfg) 427 } 428 modules := m.OrderMigrations 429 if modules == nil { 430 modules = DefaultMigrationsOrder(m.ModuleNames()) 431 } 432 433 updatedVM := VersionMap{} 434 for _, moduleName := range modules { 435 module := m.Modules[moduleName] 436 fromVersion, exists := fromVM[moduleName] 437 toVersion := module.ConsensusVersion() 438 439 // Only run migrations when the module exists in the fromVM. 440 // Run InitGenesis otherwise. 441 // 442 // the module won't exist in the fromVM in two cases: 443 // 1. A new module is added. In this case we run InitGenesis with an 444 // empty genesis state. 445 // 2. An existing chain is upgrading to v043 for the first time. In this case, 446 // all modules have yet to be added to x/upgrade's VersionMap store. 447 if exists { 448 err := c.runModuleMigrations(ctx, moduleName, fromVersion, toVersion) 449 if err != nil { 450 return nil, err 451 } 452 } else { 453 cfgtor, ok := cfg.(configurator) 454 if !ok { 455 // Currently, the only implementator of Configurator (the interface) 456 // is configurator (the struct). 457 return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", configurator{}, cfg) 458 } 459 460 moduleValUpdates := module.InitGenesis(ctx, cfgtor.cdc, module.DefaultGenesis(cfgtor.cdc)) 461 ctx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName)) 462 // The module manager assumes only one module will update the 463 // validator set, and that it will not be by a new module. 464 if len(moduleValUpdates) > 0 { 465 return nil, sdkerrors.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis updates already set by a previous module") 466 } 467 } 468 469 updatedVM[moduleName] = toVersion 470 } 471 472 return updatedVM, nil 473 } 474 475 // BeginBlock performs begin block functionality for all modules. It creates a 476 // child context with an event manager to aggregate events emitted from all 477 // modules. 478 func (m *Manager) BeginBlock(ctx sdk.Context, req ocabci.RequestBeginBlock) abci.ResponseBeginBlock { 479 ctx = ctx.WithEventManager(sdk.NewEventManager()) 480 481 for _, moduleName := range m.OrderBeginBlockers { 482 module, ok := m.Modules[moduleName].(BeginBlockAppModule) 483 if ok { 484 module.BeginBlock(ctx, req) 485 } 486 } 487 488 return abci.ResponseBeginBlock{ 489 Events: ctx.EventManager().ABCIEvents(), 490 } 491 } 492 493 // EndBlock performs end block functionality for all modules. It creates a 494 // child context with an event manager to aggregate events emitted from all 495 // modules. 496 func (m *Manager) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { 497 ctx = ctx.WithEventManager(sdk.NewEventManager()) 498 validatorUpdates := []abci.ValidatorUpdate{} 499 500 for _, moduleName := range m.OrderEndBlockers { 501 module, ok := m.Modules[moduleName].(EndBlockAppModule) 502 if !ok { 503 continue 504 } 505 moduleValUpdates := module.EndBlock(ctx, req) 506 507 // use these validator updates if provided, the module manager assumes 508 // only one module will update the validator set 509 if len(moduleValUpdates) > 0 { 510 if len(validatorUpdates) > 0 { 511 panic("validator EndBlock updates already set by a previous module") 512 } 513 514 validatorUpdates = moduleValUpdates 515 } 516 } 517 518 return abci.ResponseEndBlock{ 519 ValidatorUpdates: validatorUpdates, 520 Events: ctx.EventManager().ABCIEvents(), 521 } 522 } 523 524 // GetVersionMap gets consensus version from all modules 525 func (m *Manager) GetVersionMap() VersionMap { 526 vermap := make(VersionMap) 527 for _, v := range m.Modules { 528 version := v.ConsensusVersion() 529 name := v.Name() 530 vermap[name] = version 531 } 532 533 return vermap 534 } 535 536 // ModuleNames returns list of all module names, without any particular order. 537 func (m *Manager) ModuleNames() []string { 538 ms := make([]string, len(m.Modules)) 539 i := 0 540 for m := range m.Modules { 541 ms[i] = m 542 i++ 543 } 544 return ms 545 } 546 547 // DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name, 548 // except x/auth which will run last, see: 549 // https://github.com/cosmos/cosmos-sdk/issues/10591 550 func DefaultMigrationsOrder(modules []string) []string { 551 const authName = "auth" 552 out := make([]string, 0, len(modules)) 553 hasAuth := false 554 for _, m := range modules { 555 if m == authName { 556 hasAuth = true 557 } else { 558 out = append(out, m) 559 } 560 } 561 sort.Strings(out) 562 if hasAuth { 563 out = append(out, authName) 564 } 565 return out 566 }