Overview
The Module Manager orchestrates the lifecycle of all modules in a Cosmos SDK application, handling initialization, genesis operations, begin/end block execution, and migrations.Core Types
Manager
type Manager struct {
Modules map[string]interface{}
OrderInitGenesis []string
OrderExportGenesis []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
types/module/module.go
Manager handles module lifecycle operations in a specific order.
AppModule Interface
type AppModule interface {
AppModuleBasic
// RegisterServices allows a module to register services
RegisterServices(Configurator)
// ConsensusVersion is a sequence number for state-breaking change
ConsensusVersion() uint64
}
types/module/module.go
AppModuleBasic Interface
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
types/module/module.go:60-66
Basic, non-dependent module functionality.
HasGenesis Interface
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec) json.RawMessage
}
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec) json.RawMessage
}
types/module/module.go:190-200
Creating a Manager
NewManager
func NewManager(modules ...AppModule) *Manager
// Usage
app.ModuleManager = module.NewManager(
auth.NewAppModule(app.AccountKeeper),
bank.NewAppModule(app.BankKeeper, app.AccountKeeper),
staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
distribution.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper),
// ... other modules
)
NewManagerFromMap
func NewManagerFromMap(modules map[string]appmodule.AppModule) *Manager
// Used with runtime/depinject
app.ModuleManager = module.NewManagerFromMap(moduleMap)
types/module/module.go
Setting Module Order
SetOrderInitGenesis
func (m *Manager) SetOrderInitGenesis(moduleNames ...string)
// Example
app.ModuleManager.SetOrderInitGenesis(
authtypes.ModuleName,
banktypes.ModuleName,
stakingtypes.ModuleName,
distrtypes.ModuleName,
govtypes.ModuleName,
minttypes.ModuleName,
)
SetOrderExportGenesis
func (m *Manager) SetOrderExportGenesis(moduleNames ...string)
app.ModuleManager.SetOrderExportGenesis(
authtypes.ModuleName,
banktypes.ModuleName,
stakingtypes.ModuleName,
// ...
)
SetOrderBeginBlockers
func (m *Manager) SetOrderBeginBlockers(moduleNames ...string)
app.ModuleManager.SetOrderBeginBlockers(
minttypes.ModuleName, // Mint new tokens first
distrtypes.ModuleName, // Then distribute rewards
slashingtypes.ModuleName, // Apply slashing
stakingtypes.ModuleName, // Process staking
)
SetOrderEndBlockers
func (m *Manager) SetOrderEndBlockers(moduleNames ...string)
app.ModuleManager.SetOrderEndBlockers(
stakingtypes.ModuleName, // Process validator updates
govtypes.ModuleName, // Execute passed proposals
)
Module Operations
InitGenesis
func (m *Manager) InitGenesis(
ctx sdk.Context,
cdc codec.JSONCodec,
genesisData map[string]json.RawMessage,
) abci.ResponseInitChain
// Called in app.InitChainer
func (app *App) InitChainer(
ctx sdk.Context,
req *abci.RequestInitChain,
) (*abci.ResponseInitChain, error) {
var genesisState GenesisState
if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil {
return nil, err
}
return app.ModuleManager.InitGenesis(ctx, app.appCodec, genesisState), nil
}
ExportGenesis
func (m *Manager) ExportGenesis(
ctx sdk.Context,
cdc codec.JSONCodec,
) map[string]json.RawMessage
// Export current state
func (app *App) ExportAppStateAndValidators(
forZeroHeight bool,
jailAllowedAddrs []string,
) (servertypes.ExportedApp, error) {
ctx := app.NewContext(true)
if forZeroHeight {
// Prepare for zero height export
app.prepForZeroHeightGenesis(ctx, jailAllowedAddrs)
}
genState := app.ModuleManager.ExportGenesis(ctx, app.appCodec)
appState, err := json.MarshalIndent(genState, "", " ")
if err != nil {
return servertypes.ExportedApp{}, err
}
validators, err := staking.WriteValidators(ctx, app.StakingKeeper)
return servertypes.ExportedApp{
AppState: appState,
Validators: validators,
Height: app.LastBlockHeight(),
ConsensusParams: app.BaseApp.GetConsensusParams(ctx),
}, err
}
RegisterServices
func (m *Manager) RegisterServices(cfg Configurator)
// Called during app initialization
func (app *App) RegisterServices() {
app.configurator = module.NewConfigurator(
app.appCodec,
app.MsgServiceRouter(),
app.GRPCQueryRouter(),
)
app.ModuleManager.RegisterServices(app.configurator)
}
Configurator
type Configurator interface {
// MsgServer returns a gRPC message server
MsgServer() grpc.Server
// QueryServer returns a gRPC query server
QueryServer() grpc.Server
// RegisterMigration registers an in-place store migration
RegisterMigration(
moduleName string,
fromVersion uint64,
handler MigrationHandler,
) error
}
type MigrationHandler func(sdk.Context) error
Module Migrations
Registering Migrations
package mymodule
import (
"github.com/cosmos/cosmos-sdk/types/module"
)
func (am AppModule) RegisterServices(cfg module.Configurator) {
// Register msg and query servers
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
// Register migrations
err := cfg.RegisterMigration(
types.ModuleName,
1, // from version
func(ctx sdk.Context) error {
return keeper.MigrateV1ToV2(ctx, am.keeper)
},
)
if err != nil {
panic(err)
}
err = cfg.RegisterMigration(
types.ModuleName,
2, // from version
func(ctx sdk.Context) error {
return keeper.MigrateV2ToV3(ctx, am.keeper)
},
)
if err != nil {
panic(err)
}
}
func (am AppModule) ConsensusVersion() uint64 {
return 3 // current version
}
Running Migrations
func (m *Manager) RunMigrations(
ctx sdk.Context,
cfg Configurator,
fromVM VersionMap,
) (VersionMap, error)
// In upgrade handler
func (app *App) RegisterUpgradeHandlers() {
app.UpgradeKeeper.SetUpgradeHandler(
"v2",
func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// Run all module migrations
return app.ModuleManager.RunMigrations(ctx, app.configurator, fromVM)
},
)
}
Usage in SimApp
package simapp
import (
"github.com/cosmos/cosmos-sdk/types/module"
)
func NewSimApp(
logger log.Logger,
db dbm.DB,
// ...
) *SimApp {
// ... create keepers ...
// Create module manager
app.ModuleManager = module.NewManager(
auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts),
vesting.NewAppModule(app.AccountKeeper, app.BankKeeper),
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper),
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper),
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
upgrade.NewAppModule(app.UpgradeKeeper),
)
// Set order of operations
app.ModuleManager.SetOrderInitGenesis(
authtypes.ModuleName,
banktypes.ModuleName,
distrtypes.ModuleName,
stakingtypes.ModuleName,
slashingtypes.ModuleName,
govtypes.ModuleName,
minttypes.ModuleName,
upgradetypes.ModuleName,
)
app.ModuleManager.SetOrderBeginBlockers(
minttypes.ModuleName,
distrtypes.ModuleName,
slashingtypes.ModuleName,
stakingtypes.ModuleName,
)
app.ModuleManager.SetOrderEndBlockers(
govtypes.ModuleName,
stakingtypes.ModuleName,
)
// Register services
app.configurator = module.NewConfigurator(
app.appCodec,
app.MsgServiceRouter(),
app.GRPCQueryRouter(),
)
app.ModuleManager.RegisterServices(app.configurator)
// Set init chainer, begin blocker, end blocker
app.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
return app
}
func (app *SimApp) InitChainer(
ctx sdk.Context,
req *abci.RequestInitChain,
) (*abci.ResponseInitChain, error) {
var genesisState GenesisState
if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil {
return nil, err
}
return app.ModuleManager.InitGenesis(ctx, app.appCodec, genesisState), nil
}
func (app *SimApp) BeginBlocker(
ctx sdk.Context,
) (sdk.BeginBlock, error) {
return app.ModuleManager.BeginBlock(ctx)
}
func (app *SimApp) EndBlocker(
ctx sdk.Context,
) (sdk.EndBlock, error) {
return app.ModuleManager.EndBlock(ctx)
}
Related APIs
- BaseApp - Application lifecycle
- Runtime - Dependency injection
- Keeper Patterns - Module state management