Module Manager
Cosmos SDK modules need to implement the AppModule
interfaces, in order to be managed by the application's module manager. The module manager plays an important role in message
and query
routing, and allows application developers to set the order of execution of a variety of functions like PreBlocker
and BeginBlocker
and EndBlocker
.
Application Module Interfaces
Application module interfaces exist to facilitate the composition of modules together to form a functional Cosmos SDK application.
It is recommended to implement interfaces from the Core API appmodule
package. This makes modules less dependent on the SDK.
For legacy reason modules can still implement interfaces from the SDK module
package.
There are 2 main application module interfaces:
appmodule.AppModule
/module.AppModule
for inter-dependent module functionalities (except genesis-related functionalities).- (legacy)
module.AppModuleBasic
for independent module functionalities. New modules can usemodule.CoreAppModuleBasicAdaptor
instead.
The above interfaces are mostly embedding smaller interfaces (extension interfaces), that defines specific functionalities:
- (legacy)
module.HasName
: Allows the module to provide its own name for legacy purposes. - (legacy)
module.HasGenesisBasics
: The legacy interface for stateless genesis methods. module.HasGenesis
for inter-dependent genesis-related module functionalities.module.HasABCIGenesis
for inter-dependent genesis-related module functionalities.appmodule.HasGenesis
/module.HasGenesis
: The extension interface for stateful genesis methods.appmodule.HasPreBlocker
: The extension interface that contains information about theAppModule
andPreBlock
.appmodule.HasBeginBlocker
: The extension interface that contains information about theAppModule
andBeginBlock
.appmodule.HasEndBlocker
: The extension interface that contains information about theAppModule
andEndBlock
.appmodule.HasPrecommit
: The extension interface that contains information about theAppModule
andPrecommit
.appmodule.HasPrepareCheckState
: The extension interface that contains information about theAppModule
andPrepareCheckState
.appmodule.HasService
/module.HasServices
: The extension interface for modules to register services.module.HasABCIEndBlock
: The extension interface that contains information about theAppModule
,EndBlock
and returns an updated validator set.- (legacy)
module.HasInvariants
: The extension interface for registering invariants. - (legacy)
module.HasConsensusVersion
: The extension interface for declaring a module consensus version.
The AppModuleBasic
interface exists to define independent methods of the module, i.e. those that do not depend on other modules in the application. This allows for the construction of the basic application structure early in the application definition, generally in the init()
function of the main application file.
The AppModule
interface exists to define inter-dependent module methods. Many modules need to interact with other modules, typically through keeper
s, which means there is a need for an interface where modules list their keeper
s and other methods that require a reference to another module's object. AppModule
interface extension, such as HasBeginBlocker
and HasEndBlocker
, also enables the module manager to set the order of execution between module's methods like BeginBlock
and EndBlock
, which is important in cases where the order of execution between modules matters in the context of the application.
The usage of extension interfaces allows modules to define only the functionalities they need. For example, a module that does not need an EndBlock
does not need to define the HasEndBlocker
interface and thus the EndBlock
method. AppModule
and AppModuleGenesis
are voluntarily small interfaces, that can take advantage of the Module
patterns without having to define many placeholder functions.
AppModuleBasic
Use module.CoreAppModuleBasicAdaptor
instead for creating an AppModuleBasic
from an appmodule.AppModule
.
The AppModuleBasic
interface defines the independent methods modules need to implement.
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L56-L66
Let us go through the methods:
RegisterLegacyAminoCodec(*codec.LegacyAmino)
: Registers theamino
codec for the module, which is used to marshal and unmarshal structs to/from[]byte
in order to persist them in the module'sKVStore
.RegisterInterfaces(codectypes.InterfaceRegistry)
: Registers a module's interface types and their concrete implementations asproto.Message
.RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
: Registers gRPC routes for the module.
All the AppModuleBasic
of an application are managed by the BasicManager
.
HasName
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L71-L73
HasName
is an interface that has a methodName()
. This method returns the name of the module as astring
.
Genesis
For easily creating an AppModule
that only has genesis functionalities, use module.GenesisOnlyAppModule
.
module.HasGenesisBasics
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L76-L79
Let us go through the methods:
DefaultGenesis(codec.JSONCodec)
: Returns a defaultGenesisState
for the module, marshalled tojson.RawMessage
. The defaultGenesisState
need to be defined by the module developer and is primarily used for testing.ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
: Used to validate theGenesisState
defined by a module, given in itsjson.RawMessage
form. It will usually unmarshall thejson
before running a customValidateGenesis
function defined by the module developer.
module.HasGenesis
HasGenesis
is an extension interface for allowing modules to implement genesis functionalities.
https://github.com/cosmos/cosmos-sdk/blob/6ce2505/types/module/module.go#L184-L189
module.HasABCIGenesis
HasABCIGenesis
is an extension interface for allowing modules to implement genesis functionalities and returns validator set updates.
https://github.com/cosmos/cosmos-sdk/blob/6ce2505/types/module/module.go#L191-L196
appmodule.HasGenesis
appmodule.HasGenesis
is experimental and should be considered unstable, it is recommended to not use this interface at this time.
https://github.com/cosmos/cosmos-sdk/blob/6ce2505/core/appmodule/genesis.go#L8-L25
AppModule
The AppModule
interface defines a module. Modules can declare their functionalities by implementing extensions interfaces.
AppModule
s are managed by the module manager, which checks which extension interfaces are implemented by the module.
appmodule.AppModule
https://github.com/cosmos/cosmos-sdk/blob/6afece6/core/appmodule/module.go#L11-L20
module.AppModule
Previously the module.AppModule
interface was containing all the methods that are defined in the extensions interfaces. This was leading to much boilerplate for modules that did not need all the functionalities.
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L195-L199
HasInvariants
This interface defines one method. It allows to checks if a module can register invariants.
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L202-L205
RegisterInvariants(sdk.InvariantRegistry)
: Registers theinvariants
of the module. If an invariant deviates from its predicted value, theInvariantRegistry
triggers appropriate logic (most often the chain will be halted).
HasServices
This interface defines one method. It allows to checks if a module can register invariants.
appmodule.HasService
https://github.com/cosmos/cosmos-sdk/blob/6afece6/core/appmodule/module.go#L22-L40
module.HasServices
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L208-L211
RegisterServices(Configurator)
: Allows a module to register services.
HasConsensusVersion
This interface defines one method for checking a module consensus version.
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L214-L220
ConsensusVersion() uint64
: Returns the consensus version of the module.
HasPreBlocker
The HasPreBlocker
is an extension interface from appmodule.AppModule
. All modules that have an PreBlock
method implement this interface.
HasBeginBlocker
The HasBeginBlocker
is an extension interface from appmodule.AppModule
. All modules that have an BeginBlock
method implement this interface.
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/core/appmodule/module.go#L56-L63
BeginBlock(context.Context) error
: This method gives module developers the option to implement logic that is automatically triggered at the beginning of each block.
HasEndBlocker
The HasEndBlocker
is an extension interface from appmodule.AppModule
. All modules that have an EndBlock
method implement this interface. If a module need to return validator set updates (staking), they can use HasABCIEndBlock
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/core/appmodule/module.go#L66-L72
EndBlock(context.Context) error
: This method gives module developers the option to implement logic that is automatically triggered at the end of each block.
HasABCIEndBlock
The HasABCIEndBlock
is an extension interface from module.AppModule
. All modules that have an EndBlock
which return validator set updates implement this interface.
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L222-L225
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
: This method gives module developers the option to inform the underlying consensus engine of validator set changes (e.g. thestaking
module).
HasPrecommit
HasPrecommit
is an extension interface from appmodule.AppModule
. All modules that have a Precommit
method implement this interface.
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/core/appmodule/module.go#L49-L52
Precommit(context.Context)
: This method gives module developers the option to implement logic that is automatically triggered during `Commit' of each block using thefinalizeblockstate
of the block to be committed. Implement empty if no logic needs to be triggered duringCommit
of each block for this module.
HasPrepareCheckState
HasPrepareCheckState
is an extension interface from appmodule.AppModule
. All modules that have a PrepareCheckState
method implement this interface.
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/core/appmodule/module.go#L49-L52
PrepareCheckState(context.Context)
: This method gives module developers the option to implement logic that is automatically triggered during `Commit' of each block using thecheckState
of the next block. Implement empty if no logic needs to be triggered duringCommit
of each block for this module.
Implementing the Application Module Interfaces
Typically, the various application module interfaces are implemented in a file called module.go
, located in the module's folder (e.g. ./x/module/module.go
).
Almost every module needs to implement the AppModuleBasic
and AppModule
interfaces. If the module is only used for genesis, it will implement AppModuleGenesis
instead of AppModule
. The concrete type that implements the interface can add parameters that are required for the implementation of the various methods of the interface. For example, the Route()
function often calls a NewMsgServerImpl(k keeper)
function defined in keeper/msg_server.go
and therefore needs to pass the module's keeper
as a parameter.
// example
type AppModule struct {
AppModuleBasic
keeper Keeper
}
In the example above, you can see that the AppModule
concrete type references an AppModuleBasic
, and not an AppModuleGenesis
. That is because AppModuleGenesis
only needs to be implemented in modules that focus on genesis-related functionalities. In most modules, the concrete AppModule
type will have a reference to an AppModuleBasic
and implement the two added methods of AppModuleGenesis
directly in the AppModule
type.
If no parameter is required (which is often the case for AppModuleBasic
), just declare an empty concrete type like so:
type AppModuleBasic struct{}
Module Managers
Module managers are used to manage collections of AppModuleBasic
and AppModule
.
BasicManager
The BasicManager
is a structure that lists all the AppModuleBasic
of an application:
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L82
It implements the following methods:
NewBasicManager(modules ...AppModuleBasic)
: Constructor function. It takes a list of the application'sAppModuleBasic
and builds a newBasicManager
. This function is generally called in theinit()
function ofapp.go
to quickly initialize the independent elements of the application's modules (click here to see an example).NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
: Contructor function. It creates a newBasicManager
from aManager
. TheBasicManager
will contain allAppModuleBasic
from theAppModule
manager usingCoreAppModuleBasicAdaptor
whenever possible. Module'sAppModuleBasic
can be overridden by passing a custom AppModuleBasic mapRegisterLegacyAminoCodec(cdc *codec.LegacyAmino)
: Registers thecodec.LegacyAmino
s of each of the application'sAppModuleBasic
. This function is usually called early on in the application's construction.RegisterInterfaces(registry codectypes.InterfaceRegistry)
: Registers interface types and implementations of each of the application'sAppModuleBasic
.DefaultGenesis(cdc codec.JSONCodec)
: Provides default genesis information for modules in the application by calling theDefaultGenesis(cdc codec.JSONCodec)
function of each module. It only calls the modules that implements theHasGenesisBasics
interfaces.ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesis map[string]json.RawMessage)
: Validates the genesis information modules by calling theValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
function of modules implementing theHasGenesisBasics
interface.RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux)
: Registers gRPC routes for modules.AddTxCommands(rootTxCmd *cobra.Command)
: Adds modules' transaction commands (defined asGetTxCmd() *cobra.Command
) to the application'srootTxCommand
. This function is usually called function from themain.go
function of the application's command-line interface.AddQueryCommands(rootQueryCmd *cobra.Command)
: Adds modules' query commands (defined asGetQueryCmd() *cobra.Command
) to the application'srootQueryCommand
. This function is usually called function from themain.go
function of the application's command-line interface.
Manager
The Manager
is a structure that holds all the AppModule
of an application, and defines the order of execution between several key components of these modules:
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L267-L276
The module manager is used throughout the application whenever an action on a collection of modules is required. It implements the following methods:
NewManager(modules ...AppModule)
: Constructor function. It takes a list of the application'sAppModule
s and builds a newManager
. It is generally called from the application's main constructor function.SetOrderInitGenesis(moduleNames ...string)
: Sets the order in which theInitGenesis
function of each module will be called when the application is first started. This function is generally called from the application's main constructor function. To initialize modules successfully, module dependencies should be considered. For example, thegenutil
module must occur afterstaking
module so that the pools are properly initialized with tokens from genesis accounts, thegenutils
module must also occur afterauth
so that it can access the params from auth, IBC'scapability
module should be initialized before all other modules so that it can initialize any capabilities.SetOrderExportGenesis(moduleNames ...string)
: Sets the order in which theExportGenesis
function of each module will be called in case of an export. This function is generally called from the application's main constructor function.SetOrderPreBlockers(moduleNames ...string)
: Sets the order in which thePreBlock()
function of each module will be called beforeBeginBlock()
of all modules. This function is generally called from the application's main constructor function.SetOrderBeginBlockers(moduleNames ...string)
: Sets the order in which theBeginBlock()
function of each module will be called at the beginning of each block. This function is generally called from the application's main constructor function.SetOrderEndBlockers(moduleNames ...string)
: Sets the order in which theEndBlock()
function of each module will be called at the end of each block. This function is generally called from the application's main constructor function.SetOrderPrecommiters(moduleNames ...string)
: Sets the order in which thePrecommit()
function of each module will be called during commit of each block. This function is generally called from the application's main constructor function.SetOrderPrepareCheckStaters(moduleNames ...string)
: Sets the order in which thePrepareCheckState()
function of each module will be called during commit of each block. This function is generally called from the application's main constructor function.SetOrderMigrations(moduleNames ...string)
: Sets the order of migrations to be run. If not set then migrations will be run with an order defined inDefaultMigrationsOrder
.RegisterInvariants(ir sdk.InvariantRegistry)
: Registers the invariants of module implementing theHasInvariants
interface.RegisterServices(cfg Configurator)
: Registers the services of modules implementing theHasServices
interface.InitGenesis(ctx context.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage)
: Calls theInitGenesis
function of each module when the application is first started, in the order defined inOrderInitGenesis
. Returns anabci.ResponseInitChain
to the underlying consensus engine, which can contain validator updates.ExportGenesis(ctx context.Context, cdc codec.JSONCodec)
: Calls theExportGenesis
function of each module, in the order defined inOrderExportGenesis
. The export constructs a genesis file from a previously existing state, and is mainly used when a hard-fork upgrade of the chain is required.ExportGenesisForModules(ctx context.Context, cdc codec.JSONCodec, modulesToExport []string)
: Behaves the same asExportGenesis
, except takes a list of modules to export.BeginBlock(ctx context.Context) error
: At the beginning of each block, this function is called fromBaseApp
and, in turn, calls theBeginBlock
function of each modules implementing theappmodule.HasBeginBlocker
interface, in the order defined inOrderBeginBlockers
. It creates a child context with an event manager to aggregate events emitted from each modules.EndBlock(ctx context.Context) error
: At the end of each block, this function is called fromBaseApp
and, in turn, calls theEndBlock
function of each modules implementing theappmodule.HasEndBlocker
interface, in the order defined inOrderEndBlockers
. It creates a child context with an event manager to aggregate events emitted from all modules. The function returns anabci
which contains the aforementioned events, as well as validator set updates (if any).EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
: At the end of each block, this function is called fromBaseApp
and, in turn, calls theEndBlock
function of each modules implementing themodule.HasABCIEndBlock
interface, in the order defined inOrderEndBlockers
. It creates a child context with an event manager to aggregate events emitted from all modules. The function returns anabci
which contains the aforementioned events, as well as validator set updates (if any).Precommit(ctx context.Context)
: DuringCommit
, this function is called fromBaseApp
immediately before thedeliverState
is written to the underlyingrootMultiStore
and, in turn calls thePrecommit
function of each modules implementing theHasPrecommit
interface, in the order defined inOrderPrecommiters
. It creates a child context where the underlyingCacheMultiStore
is that of the newly committed block'sfinalizeblockstate
.PrepareCheckState(ctx context.Context)
: DuringCommit
, this function is called fromBaseApp
immediately after thedeliverState
is written to the underlyingrootMultiStore
and, in turn calls thePrepareCheckState
function of each module implementing theHasPrepareCheckState
interface, in the order defined inOrderPrepareCheckStaters
. It creates a child context where the underlyingCacheMultiStore
is that of the next block'scheckState
. Writes to this state will be present in thecheckState
of the next block, and therefore this method can be used to prepare thecheckState
for the next block.
Here's an example of a concrete integration within an simapp
:
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/simapp/app.go#L411-L434
This is the same example from runtime
(the package that powers app di):
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/runtime/module.go#L61
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/runtime/module.go#L82