Synopsis
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.Pre-requisite Readings
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.appmodule.AppModule/module.AppModulefor inter-dependent module functionalities (except genesis-related functionalities).- (legacy)
module.AppModuleBasicfor independent module functionalities. New modules can usemodule.CoreAppModuleBasicAdaptorinstead.
- (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.HasGenesisfor inter-dependent genesis-related module functionalities.module.HasABCIGenesisfor 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 theAppModuleandPreBlock.appmodule.HasBeginBlocker: The extension interface that contains information about theAppModuleandBeginBlock.appmodule.HasEndBlocker: The extension interface that contains information about theAppModuleandEndBlock.appmodule.HasPrecommit: The extension interface that contains information about theAppModuleandPrecommit.appmodule.HasPrepareCheckState: The extension interface that contains information about theAppModuleandPrepareCheckState.appmodule.HasService/module.HasServices: The extension interface for modules to register services.module.HasABCIEndBlock: The extension interface that contains information about theAppModule,EndBlockand 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.
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 keepers, which means there is a need for an interface where modules list their keepers 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.AppModuleBasic interface defines the independent methods modules need to implement.
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"slices"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead.
type AppModule interface {
appmodule.AppModule
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
//
// Deprecated: this will be removed in the next Cosmos SDK release.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
// HasABCIEndblock is a released typo of HasABCIEndBlock.
// Deprecated: use HasABCIEndBlock instead.
type HasABCIEndblock HasABCIEndBlock
// HasABCIEndBlock is the interface for modules that need to run code at the end of the block.
type HasABCIEndBlock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]any // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderPreBlockers []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]any)
modulesStr := make([]string, 0, len(modules))
preBlockModulesStr := make([]string, 0)
for _, module := range modules {
if _, ok := module.(appmodule.AppModule); !ok {
panic(fmt.Sprintf("module %s does not implement appmodule.AppModule", module.Name()))
}
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, module.Name())
}
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]any)
modulesStr := make([]string, 0, len(simpleModuleMap))
preBlockModulesStr := make([]string, 0)
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, name)
}
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderPreBlockers sets the order of set pre-blocker calls
func (m *Manager)
SetOrderPreBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBlock := module.(appmodule.HasPreBlocker)
return !hasBlock
})
m.OrderPreBlockers = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndBlock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
//
// Deprecated: this function is a no-op and will be removed in the next release of the Cosmos SDK.
func (m *Manager)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err)
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// PreBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was successfully executed or not.
func (m *Manager)
PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) {
paramsChanged := false
for _, moduleName := range m.OrderPreBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok {
rsp, err := module.PreBlock(ctx)
if err != nil {
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndBlock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return slices.Collect(maps.Keys(m.Modules))
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
RegisterLegacyAminoCodec(*codec.LegacyAmino): Registers theaminocodec for the module, which is used to marshal and unmarshal structs to/from[]bytein 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.
AppModuleBasic of an application are managed by the BasicManager.
HasName
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"slices"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead.
type AppModule interface {
appmodule.AppModule
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
//
// Deprecated: this will be removed in the next Cosmos SDK release.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
// HasABCIEndblock is a released typo of HasABCIEndBlock.
// Deprecated: use HasABCIEndBlock instead.
type HasABCIEndblock HasABCIEndBlock
// HasABCIEndBlock is the interface for modules that need to run code at the end of the block.
type HasABCIEndBlock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]any // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderPreBlockers []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]any)
modulesStr := make([]string, 0, len(modules))
preBlockModulesStr := make([]string, 0)
for _, module := range modules {
if _, ok := module.(appmodule.AppModule); !ok {
panic(fmt.Sprintf("module %s does not implement appmodule.AppModule", module.Name()))
}
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, module.Name())
}
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]any)
modulesStr := make([]string, 0, len(simpleModuleMap))
preBlockModulesStr := make([]string, 0)
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, name)
}
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderPreBlockers sets the order of set pre-blocker calls
func (m *Manager)
SetOrderPreBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBlock := module.(appmodule.HasPreBlocker)
return !hasBlock
})
m.OrderPreBlockers = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndBlock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
//
// Deprecated: this function is a no-op and will be removed in the next release of the Cosmos SDK.
func (m *Manager)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err)
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// PreBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was successfully executed or not.
func (m *Manager)
PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) {
paramsChanged := false
for _, moduleName := range m.OrderPreBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok {
rsp, err := module.PreBlock(ctx)
if err != nil {
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndBlock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return slices.Collect(maps.Keys(m.Modules))
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
HasNameis 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
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"slices"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead.
type AppModule interface {
appmodule.AppModule
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
//
// Deprecated: this will be removed in the next Cosmos SDK release.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
// HasABCIEndblock is a released typo of HasABCIEndBlock.
// Deprecated: use HasABCIEndBlock instead.
type HasABCIEndblock HasABCIEndBlock
// HasABCIEndBlock is the interface for modules that need to run code at the end of the block.
type HasABCIEndBlock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]any // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderPreBlockers []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]any)
modulesStr := make([]string, 0, len(modules))
preBlockModulesStr := make([]string, 0)
for _, module := range modules {
if _, ok := module.(appmodule.AppModule); !ok {
panic(fmt.Sprintf("module %s does not implement appmodule.AppModule", module.Name()))
}
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, module.Name())
}
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]any)
modulesStr := make([]string, 0, len(simpleModuleMap))
preBlockModulesStr := make([]string, 0)
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, name)
}
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderPreBlockers sets the order of set pre-blocker calls
func (m *Manager)
SetOrderPreBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBlock := module.(appmodule.HasPreBlocker)
return !hasBlock
})
m.OrderPreBlockers = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndBlock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
//
// Deprecated: this function is a no-op and will be removed in the next release of the Cosmos SDK.
func (m *Manager)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err)
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// PreBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was successfully executed or not.
func (m *Manager)
PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) {
paramsChanged := false
for _, moduleName := range m.OrderPreBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok {
rsp, err := module.PreBlock(ctx)
if err != nil {
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndBlock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return slices.Collect(maps.Keys(m.Modules))
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
DefaultGenesis(codec.JSONCodec): Returns a defaultGenesisStatefor the module, marshalled tojson.RawMessage. The defaultGenesisStateneed to be defined by the module developer and is primarily used for testing.ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage): Used to validate theGenesisStatedefined by a module, given in itsjson.RawMessageform. It will usually unmarshall thejsonbefore running a customValidateGenesisfunction defined by the module developer.
module.HasGenesis
HasGenesis is an extension interface for allowing modules to implement genesis functionalities.
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"golang.org/x/exp/maps"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
type AppModule interface {
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
type HasABCIEndblock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// genesisOnlyModule is an interface need to return GenesisOnlyAppModule struct in order to wrap two interfaces
type genesisOnlyModule interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
genesisOnlyModule
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg genesisOnlyModule)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
genesisOnlyModule: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]interface{
} // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]interface{
})
modulesStr := make([]string, 0, len(modules))
for _, module := range modules {
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]interface{
})
modulesStr := make([]string, 0, len(simpleModuleMap))
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndblock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
func (m *Manager)
RegisterInvariants(ir sdk.InvariantRegistry) {
for _, module := range m.Modules {
if module, ok := module.(HasInvariants); ok {
module.RegisterInvariants(ir)
}
}
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, res.err
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
m := m
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
module1, ok := m.Modules[moduleName].(HasGenesis)
if ok {
module1.InitGenesis(sdkCtx, c.cdc, module1.DefaultGenesis(c.cdc))
}
if module2, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module2.InitGenesis(sdkCtx, c.cdc, module1.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// RunMigrationBeginBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was executed or not and an error if fails.
func (m *Manager)
RunMigrationBeginBlock(ctx sdk.Context) (bool, error) {
for _, moduleName := range m.OrderBeginBlockers {
if mod, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if _, ok := mod.(appmodule.UpgradeModule); ok {
err := mod.BeginBlock(ctx)
return err == nil, err
}
}
}
return false, nil
}
// BeginBlock performs begin block functionality for non-upgrade modules. It creates a
// child context with an event manager to aggregate events emitted from non-upgrade
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if _, ok := module.(appmodule.UpgradeModule); !ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndblock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
name := name
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return maps.Keys(m.Modules)
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
module.HasABCIGenesis
HasABCIGenesis is an extension interface for allowing modules to implement genesis functionalities and returns validator set updates.
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"golang.org/x/exp/maps"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
type AppModule interface {
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
type HasABCIEndblock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// genesisOnlyModule is an interface need to return GenesisOnlyAppModule struct in order to wrap two interfaces
type genesisOnlyModule interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
genesisOnlyModule
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg genesisOnlyModule)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
genesisOnlyModule: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]interface{
} // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]interface{
})
modulesStr := make([]string, 0, len(modules))
for _, module := range modules {
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]interface{
})
modulesStr := make([]string, 0, len(simpleModuleMap))
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndblock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
func (m *Manager)
RegisterInvariants(ir sdk.InvariantRegistry) {
for _, module := range m.Modules {
if module, ok := module.(HasInvariants); ok {
module.RegisterInvariants(ir)
}
}
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, res.err
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
m := m
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
module1, ok := m.Modules[moduleName].(HasGenesis)
if ok {
module1.InitGenesis(sdkCtx, c.cdc, module1.DefaultGenesis(c.cdc))
}
if module2, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module2.InitGenesis(sdkCtx, c.cdc, module1.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// RunMigrationBeginBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was executed or not and an error if fails.
func (m *Manager)
RunMigrationBeginBlock(ctx sdk.Context) (bool, error) {
for _, moduleName := range m.OrderBeginBlockers {
if mod, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if _, ok := mod.(appmodule.UpgradeModule); ok {
err := mod.BeginBlock(ctx)
return err == nil, err
}
}
}
return false, nil
}
// BeginBlock performs begin block functionality for non-upgrade modules. It creates a
// child context with an event manager to aggregate events emitted from non-upgrade
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if _, ok := module.(appmodule.UpgradeModule); !ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndblock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
name := name
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return maps.Keys(m.Modules)
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
appmodule.HasGenesis
appmodule.HasGenesis is experimental and should be considered unstable, it is recommended to not use this interface at this time.Copy
Ask AI
package appmodule
import (
"context"
"io"
)
// HasGenesis is the extension interface that modules should implement to handle
// genesis data and state initialization.
// WARNING: This interface is experimental and may change at any time.
type HasGenesis interface {
AppModule
// DefaultGenesis writes the default genesis for this module to the target.
DefaultGenesis(GenesisTarget)
error
// ValidateGenesis validates the genesis data read from the source.
ValidateGenesis(GenesisSource)
error
// InitGenesis initializes module state from the genesis source.
InitGenesis(context.Context, GenesisSource)
error
// ExportGenesis exports module state to the genesis target.
ExportGenesis(context.Context, GenesisTarget)
error
}
// GenesisSource is a source for genesis data in JSON format. It may abstract over a
// single JSON object or separate files for each field in a JSON object that can
// be streamed over. Modules should open a separate io.ReadCloser for each field that
// is required. When fields represent arrays they can efficiently be streamed
// over. If there is no data for a field, this function should return nil, nil. It is
// important that the caller closes the reader when done with it.
type GenesisSource = func(field string) (io.ReadCloser, error)
// GenesisTarget is a target for writing genesis data in JSON format. It may
// abstract over a single JSON object or JSON in separate files that can be
// streamed over. Modules should open a separate io.WriteCloser for each field
// and should prefer writing fields as arrays when possible to support efficient
// iteration. It is important the caller closers the writer AND checks the error
// when done with it. It is expected that a stream of JSON data is written
// to the writer.
type GenesisTarget = func(field string) (io.WriteCloser, error)
AppModule
The AppModule interface defines a module. Modules can declare their functionalities by implementing extensions interfaces.
AppModules are managed by the module manager, which checks which extension interfaces are implemented by the module.
appmodule.AppModule
Copy
Ask AI
package appmodule
import (
"context"
"google.golang.org/grpc"
"cosmossdk.io/depinject"
)
// AppModule is a tag interface for app module implementations to use as a basis
// for extension interfaces. It provides no functionality itself, but is the
// type that all valid app modules should provide so that they can be identified
// by other modules (usually via depinject)
as app modules.
type AppModule interface {
depinject.OnePerModuleType
// IsAppModule is a dummy method to tag a struct as implementing an AppModule.
IsAppModule()
}
// HasServices is the extension interface that modules should implement to register
// implementations of services defined in .proto files.
type HasServices interface {
AppModule
// RegisterServices registers the module's services with the app's service
// registrar.
//
// Two types of services are currently supported:
// - read-only gRPC query services, which are the default.
// - transaction message services, which must have the protobuf service
// option "cosmos.msg.v1.service" (defined in "cosmos/msg/v1/service.proto")
// set to true.
//
// The service registrar will figure out which type of service you are
// implementing based on the presence (or absence)
of protobuf options. You
// do not need to specify this in golang code.
RegisterServices(grpc.ServiceRegistrar)
error
}
// HasPrepareCheckState is an extension interface that contains information about the AppModule
// and PrepareCheckState.
type HasPrepareCheckState interface {
AppModule
PrepareCheckState(context.Context)
error
}
// HasPrecommit is an extension interface that contains information about the AppModule and Precommit.
type HasPrecommit interface {
AppModule
Precommit(context.Context)
error
}
// HasBeginBlocker is the extension interface that modules should implement to run
// custom logic before transaction processing in a block.
type HasBeginBlocker interface {
AppModule
// BeginBlock is a method that will be run before transactions are processed in
// a block.
BeginBlock(context.Context)
error
}
// HasEndBlocker is the extension interface that modules should implement to run
// custom logic after transaction processing in a block.
type HasEndBlocker interface {
AppModule
// EndBlock is a method that will be run after transactions are processed in
// a block.
EndBlock(context.Context)
error
}
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.Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"slices"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead.
type AppModule interface {
appmodule.AppModule
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
//
// Deprecated: this will be removed in the next Cosmos SDK release.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
// HasABCIEndblock is a released typo of HasABCIEndBlock.
// Deprecated: use HasABCIEndBlock instead.
type HasABCIEndblock HasABCIEndBlock
// HasABCIEndBlock is the interface for modules that need to run code at the end of the block.
type HasABCIEndBlock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]any // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderPreBlockers []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]any)
modulesStr := make([]string, 0, len(modules))
preBlockModulesStr := make([]string, 0)
for _, module := range modules {
if _, ok := module.(appmodule.AppModule); !ok {
panic(fmt.Sprintf("module %s does not implement appmodule.AppModule", module.Name()))
}
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, module.Name())
}
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]any)
modulesStr := make([]string, 0, len(simpleModuleMap))
preBlockModulesStr := make([]string, 0)
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, name)
}
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderPreBlockers sets the order of set pre-blocker calls
func (m *Manager)
SetOrderPreBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBlock := module.(appmodule.HasPreBlocker)
return !hasBlock
})
m.OrderPreBlockers = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndBlock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
//
// Deprecated: this function is a no-op and will be removed in the next release of the Cosmos SDK.
func (m *Manager)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err)
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// PreBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was successfully executed or not.
func (m *Manager)
PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) {
paramsChanged := false
for _, moduleName := range m.OrderPreBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok {
rsp, err := module.PreBlock(ctx)
if err != nil {
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndBlock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return slices.Collect(maps.Keys(m.Modules))
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
HasInvariants
This interface defines one method. It allows to checks if a module can register invariants.
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"slices"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead.
type AppModule interface {
appmodule.AppModule
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
//
// Deprecated: this will be removed in the next Cosmos SDK release.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
// HasABCIEndblock is a released typo of HasABCIEndBlock.
// Deprecated: use HasABCIEndBlock instead.
type HasABCIEndblock HasABCIEndBlock
// HasABCIEndBlock is the interface for modules that need to run code at the end of the block.
type HasABCIEndBlock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]any // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderPreBlockers []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]any)
modulesStr := make([]string, 0, len(modules))
preBlockModulesStr := make([]string, 0)
for _, module := range modules {
if _, ok := module.(appmodule.AppModule); !ok {
panic(fmt.Sprintf("module %s does not implement appmodule.AppModule", module.Name()))
}
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, module.Name())
}
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]any)
modulesStr := make([]string, 0, len(simpleModuleMap))
preBlockModulesStr := make([]string, 0)
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, name)
}
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderPreBlockers sets the order of set pre-blocker calls
func (m *Manager)
SetOrderPreBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBlock := module.(appmodule.HasPreBlocker)
return !hasBlock
})
m.OrderPreBlockers = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndBlock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
//
// Deprecated: this function is a no-op and will be removed in the next release of the Cosmos SDK.
func (m *Manager)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err)
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// PreBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was successfully executed or not.
func (m *Manager)
PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) {
paramsChanged := false
for _, moduleName := range m.OrderPreBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok {
rsp, err := module.PreBlock(ctx)
if err != nil {
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndBlock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return slices.Collect(maps.Keys(m.Modules))
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
RegisterInvariants(sdk.InvariantRegistry): Registers theinvariantsof the module. If an invariant deviates from its predicted value, theInvariantRegistrytriggers 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
Copy
Ask AI
package appmodule
import (
"context"
"google.golang.org/grpc"
"cosmossdk.io/depinject"
)
// AppModule is a tag interface for app module implementations to use as a basis
// for extension interfaces. It provides no functionality itself, but is the
// type that all valid app modules should provide so that they can be identified
// by other modules (usually via depinject)
as app modules.
type AppModule interface {
depinject.OnePerModuleType
// IsAppModule is a dummy method to tag a struct as implementing an AppModule.
IsAppModule()
}
// HasServices is the extension interface that modules should implement to register
// implementations of services defined in .proto files.
type HasServices interface {
AppModule
// RegisterServices registers the module's services with the app's service
// registrar.
//
// Two types of services are currently supported:
// - read-only gRPC query services, which are the default.
// - transaction message services, which must have the protobuf service
// option "cosmos.msg.v1.service" (defined in "cosmos/msg/v1/service.proto")
// set to true.
//
// The service registrar will figure out which type of service you are
// implementing based on the presence (or absence)
of protobuf options. You
// do not need to specify this in golang code.
RegisterServices(grpc.ServiceRegistrar)
error
}
// HasPrepareCheckState is an extension interface that contains information about the AppModule
// and PrepareCheckState.
type HasPrepareCheckState interface {
AppModule
PrepareCheckState(context.Context)
error
}
// HasPrecommit is an extension interface that contains information about the AppModule and Precommit.
type HasPrecommit interface {
AppModule
Precommit(context.Context)
error
}
// HasBeginBlocker is the extension interface that modules should implement to run
// custom logic before transaction processing in a block.
type HasBeginBlocker interface {
AppModule
// BeginBlock is a method that will be run before transactions are processed in
// a block.
BeginBlock(context.Context)
error
}
// HasEndBlocker is the extension interface that modules should implement to run
// custom logic after transaction processing in a block.
type HasEndBlocker interface {
AppModule
// EndBlock is a method that will be run after transactions are processed in
// a block.
EndBlock(context.Context)
error
}
module.HasServices
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"slices"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead.
type AppModule interface {
appmodule.AppModule
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
//
// Deprecated: this will be removed in the next Cosmos SDK release.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
// HasABCIEndblock is a released typo of HasABCIEndBlock.
// Deprecated: use HasABCIEndBlock instead.
type HasABCIEndblock HasABCIEndBlock
// HasABCIEndBlock is the interface for modules that need to run code at the end of the block.
type HasABCIEndBlock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]any // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderPreBlockers []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]any)
modulesStr := make([]string, 0, len(modules))
preBlockModulesStr := make([]string, 0)
for _, module := range modules {
if _, ok := module.(appmodule.AppModule); !ok {
panic(fmt.Sprintf("module %s does not implement appmodule.AppModule", module.Name()))
}
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, module.Name())
}
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]any)
modulesStr := make([]string, 0, len(simpleModuleMap))
preBlockModulesStr := make([]string, 0)
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, name)
}
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderPreBlockers sets the order of set pre-blocker calls
func (m *Manager)
SetOrderPreBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBlock := module.(appmodule.HasPreBlocker)
return !hasBlock
})
m.OrderPreBlockers = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndBlock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
//
// Deprecated: this function is a no-op and will be removed in the next release of the Cosmos SDK.
func (m *Manager)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err)
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// PreBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was successfully executed or not.
func (m *Manager)
PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) {
paramsChanged := false
for _, moduleName := range m.OrderPreBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok {
rsp, err := module.PreBlock(ctx)
if err != nil {
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndBlock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return slices.Collect(maps.Keys(m.Modules))
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
RegisterServices(Configurator): Allows a module to register services.
HasConsensusVersion
This interface defines one method for checking a module consensus version.
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"slices"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead.
type AppModule interface {
appmodule.AppModule
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
//
// Deprecated: this will be removed in the next Cosmos SDK release.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
// HasABCIEndblock is a released typo of HasABCIEndBlock.
// Deprecated: use HasABCIEndBlock instead.
type HasABCIEndblock HasABCIEndBlock
// HasABCIEndBlock is the interface for modules that need to run code at the end of the block.
type HasABCIEndBlock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]any // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderPreBlockers []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]any)
modulesStr := make([]string, 0, len(modules))
preBlockModulesStr := make([]string, 0)
for _, module := range modules {
if _, ok := module.(appmodule.AppModule); !ok {
panic(fmt.Sprintf("module %s does not implement appmodule.AppModule", module.Name()))
}
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, module.Name())
}
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]any)
modulesStr := make([]string, 0, len(simpleModuleMap))
preBlockModulesStr := make([]string, 0)
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, name)
}
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderPreBlockers sets the order of set pre-blocker calls
func (m *Manager)
SetOrderPreBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBlock := module.(appmodule.HasPreBlocker)
return !hasBlock
})
m.OrderPreBlockers = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndBlock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
//
// Deprecated: this function is a no-op and will be removed in the next release of the Cosmos SDK.
func (m *Manager)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err)
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// PreBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was successfully executed or not.
func (m *Manager)
PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) {
paramsChanged := false
for _, moduleName := range m.OrderPreBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok {
rsp, err := module.PreBlock(ctx)
if err != nil {
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndBlock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return slices.Collect(maps.Keys(m.Modules))
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
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.
Copy
Ask AI
package appmodule
import (
"context"
"google.golang.org/grpc"
"cosmossdk.io/depinject"
)
// AppModule is a tag interface for app module implementations to use as a basis
// for extension interfaces. It provides no functionality itself, but is the
// type that all valid app modules should provide so that they can be identified
// by other modules (usually via depinject)
as app modules.
type AppModule interface {
depinject.OnePerModuleType
// IsAppModule is a dummy method to tag a struct as implementing an AppModule.
IsAppModule()
}
// HasServices is the extension interface that modules should implement to register
// implementations of services defined in .proto files.
type HasServices interface {
AppModule
// RegisterServices registers the module's services with the app's service
// registrar.
//
// Two types of services are currently supported:
// - read-only gRPC query services, which are the default.
// - transaction message services, which must have the protobuf service
// option "cosmos.msg.v1.service" (defined in "cosmos/msg/v1/service.proto")
// set to true.
//
// The service registrar will figure out which type of service you are
// implementing based on the presence (or absence)
of protobuf options. You
// do not need to specify this in golang code.
RegisterServices(grpc.ServiceRegistrar)
error
}
// HasPrepareCheckState is an extension interface that contains information about the AppModule
// and PrepareCheckState.
type HasPrepareCheckState interface {
AppModule
PrepareCheckState(context.Context)
error
}
// HasPrecommit is an extension interface that contains information about the AppModule and Precommit.
type HasPrecommit interface {
AppModule
Precommit(context.Context)
error
}
// ResponsePreBlock represents the response from the PreBlock method.
// It can modify consensus parameters in storage and signal the caller through the return value.
// When it returns ConsensusParamsChanged=true, the caller must refresh the consensus parameter in the finalize context.
// The new context (ctx)
must be passed to all the other lifecycle methods.
type ResponsePreBlock interface {
IsConsensusParamsChanged()
bool
}
// HasPreBlocker is the extension interface that modules should implement to run
// custom logic before BeginBlock.
type HasPreBlocker interface {
AppModule
// PreBlock is method that will be run before BeginBlock.
PreBlock(context.Context) (ResponsePreBlock, error)
}
// HasBeginBlocker is the extension interface that modules should implement to run
// custom logic before transaction processing in a block.
type HasBeginBlocker interface {
AppModule
// BeginBlock is a method that will be run before transactions are processed in
// a block.
BeginBlock(context.Context)
error
}
// HasEndBlocker is the extension interface that modules should implement to run
// custom logic after transaction processing in a block.
type HasEndBlocker interface {
AppModule
// EndBlock is a method that will be run after transactions are processed in
// a block.
EndBlock(context.Context)
error
}
// UpgradeModule is the extension interface that upgrade module should implement to differentiate
// it from other modules, migration handler need ensure the upgrade module's migration is executed
// before the rest of the modules.
type UpgradeModule interface {
IsUpgradeModule()
}
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
Copy
Ask AI
package appmodule
import (
"context"
"google.golang.org/grpc"
"cosmossdk.io/depinject"
)
// AppModule is a tag interface for app module implementations to use as a basis
// for extension interfaces. It provides no functionality itself, but is the
// type that all valid app modules should provide so that they can be identified
// by other modules (usually via depinject)
as app modules.
type AppModule interface {
depinject.OnePerModuleType
// IsAppModule is a dummy method to tag a struct as implementing an AppModule.
IsAppModule()
}
// HasServices is the extension interface that modules should implement to register
// implementations of services defined in .proto files.
type HasServices interface {
AppModule
// RegisterServices registers the module's services with the app's service
// registrar.
//
// Two types of services are currently supported:
// - read-only gRPC query services, which are the default.
// - transaction message services, which must have the protobuf service
// option "cosmos.msg.v1.service" (defined in "cosmos/msg/v1/service.proto")
// set to true.
//
// The service registrar will figure out which type of service you are
// implementing based on the presence (or absence)
of protobuf options. You
// do not need to specify this in golang code.
RegisterServices(grpc.ServiceRegistrar)
error
}
// HasPrepareCheckState is an extension interface that contains information about the AppModule
// and PrepareCheckState.
type HasPrepareCheckState interface {
AppModule
PrepareCheckState(context.Context)
error
}
// HasPrecommit is an extension interface that contains information about the AppModule and Precommit.
type HasPrecommit interface {
AppModule
Precommit(context.Context)
error
}
// ResponsePreBlock represents the response from the PreBlock method.
// It can modify consensus parameters in storage and signal the caller through the return value.
// When it returns ConsensusParamsChanged=true, the caller must refresh the consensus parameter in the finalize context.
// The new context (ctx)
must be passed to all the other lifecycle methods.
type ResponsePreBlock interface {
IsConsensusParamsChanged()
bool
}
// HasPreBlocker is the extension interface that modules should implement to run
// custom logic before BeginBlock.
type HasPreBlocker interface {
AppModule
// PreBlock is method that will be run before BeginBlock.
PreBlock(context.Context) (ResponsePreBlock, error)
}
// HasBeginBlocker is the extension interface that modules should implement to run
// custom logic before transaction processing in a block.
type HasBeginBlocker interface {
AppModule
// BeginBlock is a method that will be run before transactions are processed in
// a block.
BeginBlock(context.Context)
error
}
// HasEndBlocker is the extension interface that modules should implement to run
// custom logic after transaction processing in a block.
type HasEndBlocker interface {
AppModule
// EndBlock is a method that will be run after transactions are processed in
// a block.
EndBlock(context.Context)
error
}
// UpgradeModule is the extension interface that upgrade module should implement to differentiate
// it from other modules, migration handler need ensure the upgrade module's migration is executed
// before the rest of the modules.
type UpgradeModule interface {
IsUpgradeModule()
}
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.
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"slices"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead.
type AppModule interface {
appmodule.AppModule
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
//
// Deprecated: this will be removed in the next Cosmos SDK release.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
// HasABCIEndblock is a released typo of HasABCIEndBlock.
// Deprecated: use HasABCIEndBlock instead.
type HasABCIEndblock HasABCIEndBlock
// HasABCIEndBlock is the interface for modules that need to run code at the end of the block.
type HasABCIEndBlock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]any // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderPreBlockers []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]any)
modulesStr := make([]string, 0, len(modules))
preBlockModulesStr := make([]string, 0)
for _, module := range modules {
if _, ok := module.(appmodule.AppModule); !ok {
panic(fmt.Sprintf("module %s does not implement appmodule.AppModule", module.Name()))
}
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, module.Name())
}
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]any)
modulesStr := make([]string, 0, len(simpleModuleMap))
preBlockModulesStr := make([]string, 0)
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, name)
}
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderPreBlockers sets the order of set pre-blocker calls
func (m *Manager)
SetOrderPreBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBlock := module.(appmodule.HasPreBlocker)
return !hasBlock
})
m.OrderPreBlockers = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndBlock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
//
// Deprecated: this function is a no-op and will be removed in the next release of the Cosmos SDK.
func (m *Manager)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err)
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// PreBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was successfully executed or not.
func (m *Manager)
PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) {
paramsChanged := false
for _, moduleName := range m.OrderPreBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok {
rsp, err := module.PreBlock(ctx)
if err != nil {
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndBlock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return slices.Collect(maps.Keys(m.Modules))
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
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. thestakingmodule).
HasPrecommit
HasPrecommit is an extension interface from appmodule.AppModule. All modules that have a Precommit method implement this interface.
Copy
Ask AI
package appmodule
import (
"context"
"google.golang.org/grpc"
"cosmossdk.io/depinject"
)
// AppModule is a tag interface for app module implementations to use as a basis
// for extension interfaces. It provides no functionality itself, but is the
// type that all valid app modules should provide so that they can be identified
// by other modules (usually via depinject)
as app modules.
type AppModule interface {
depinject.OnePerModuleType
// IsAppModule is a dummy method to tag a struct as implementing an AppModule.
IsAppModule()
}
// HasServices is the extension interface that modules should implement to register
// implementations of services defined in .proto files.
type HasServices interface {
AppModule
// RegisterServices registers the module's services with the app's service
// registrar.
//
// Two types of services are currently supported:
// - read-only gRPC query services, which are the default.
// - transaction message services, which must have the protobuf service
// option "cosmos.msg.v1.service" (defined in "cosmos/msg/v1/service.proto")
// set to true.
//
// The service registrar will figure out which type of service you are
// implementing based on the presence (or absence)
of protobuf options. You
// do not need to specify this in golang code.
RegisterServices(grpc.ServiceRegistrar)
error
}
// HasPrepareCheckState is an extension interface that contains information about the AppModule
// and PrepareCheckState.
type HasPrepareCheckState interface {
AppModule
PrepareCheckState(context.Context)
error
}
// HasPrecommit is an extension interface that contains information about the AppModule and Precommit.
type HasPrecommit interface {
AppModule
Precommit(context.Context)
error
}
// ResponsePreBlock represents the response from the PreBlock method.
// It can modify consensus parameters in storage and signal the caller through the return value.
// When it returns ConsensusParamsChanged=true, the caller must refresh the consensus parameter in the finalize context.
// The new context (ctx)
must be passed to all the other lifecycle methods.
type ResponsePreBlock interface {
IsConsensusParamsChanged()
bool
}
// HasPreBlocker is the extension interface that modules should implement to run
// custom logic before BeginBlock.
type HasPreBlocker interface {
AppModule
// PreBlock is method that will be run before BeginBlock.
PreBlock(context.Context) (ResponsePreBlock, error)
}
// HasBeginBlocker is the extension interface that modules should implement to run
// custom logic before transaction processing in a block.
type HasBeginBlocker interface {
AppModule
// BeginBlock is a method that will be run before transactions are processed in
// a block.
BeginBlock(context.Context)
error
}
// HasEndBlocker is the extension interface that modules should implement to run
// custom logic after transaction processing in a block.
type HasEndBlocker interface {
AppModule
// EndBlock is a method that will be run after transactions are processed in
// a block.
EndBlock(context.Context)
error
}
// UpgradeModule is the extension interface that upgrade module should implement to differentiate
// it from other modules, migration handler need ensure the upgrade module's migration is executed
// before the rest of the modules.
type UpgradeModule interface {
IsUpgradeModule()
}
Precommit(context.Context): This method gives module developers the option to implement logic that is automatically triggered during [Commit'](../../learn/advanced/00-baseapp.md#commit) of each block using the [finalizeblockstate](../../learn/advanced/00-baseapp.md#state-updates) 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.
Copy
Ask AI
package appmodule
import (
"context"
"google.golang.org/grpc"
"cosmossdk.io/depinject"
)
// AppModule is a tag interface for app module implementations to use as a basis
// for extension interfaces. It provides no functionality itself, but is the
// type that all valid app modules should provide so that they can be identified
// by other modules (usually via depinject)
as app modules.
type AppModule interface {
depinject.OnePerModuleType
// IsAppModule is a dummy method to tag a struct as implementing an AppModule.
IsAppModule()
}
// HasServices is the extension interface that modules should implement to register
// implementations of services defined in .proto files.
type HasServices interface {
AppModule
// RegisterServices registers the module's services with the app's service
// registrar.
//
// Two types of services are currently supported:
// - read-only gRPC query services, which are the default.
// - transaction message services, which must have the protobuf service
// option "cosmos.msg.v1.service" (defined in "cosmos/msg/v1/service.proto")
// set to true.
//
// The service registrar will figure out which type of service you are
// implementing based on the presence (or absence)
of protobuf options. You
// do not need to specify this in golang code.
RegisterServices(grpc.ServiceRegistrar)
error
}
// HasPrepareCheckState is an extension interface that contains information about the AppModule
// and PrepareCheckState.
type HasPrepareCheckState interface {
AppModule
PrepareCheckState(context.Context)
error
}
// HasPrecommit is an extension interface that contains information about the AppModule and Precommit.
type HasPrecommit interface {
AppModule
Precommit(context.Context)
error
}
// ResponsePreBlock represents the response from the PreBlock method.
// It can modify consensus parameters in storage and signal the caller through the return value.
// When it returns ConsensusParamsChanged=true, the caller must refresh the consensus parameter in the finalize context.
// The new context (ctx)
must be passed to all the other lifecycle methods.
type ResponsePreBlock interface {
IsConsensusParamsChanged()
bool
}
// HasPreBlocker is the extension interface that modules should implement to run
// custom logic before BeginBlock.
type HasPreBlocker interface {
AppModule
// PreBlock is method that will be run before BeginBlock.
PreBlock(context.Context) (ResponsePreBlock, error)
}
// HasBeginBlocker is the extension interface that modules should implement to run
// custom logic before transaction processing in a block.
type HasBeginBlocker interface {
AppModule
// BeginBlock is a method that will be run before transactions are processed in
// a block.
BeginBlock(context.Context)
error
}
// HasEndBlocker is the extension interface that modules should implement to run
// custom logic after transaction processing in a block.
type HasEndBlocker interface {
AppModule
// EndBlock is a method that will be run after transactions are processed in
// a block.
EndBlock(context.Context)
error
}
// UpgradeModule is the extension interface that upgrade module should implement to differentiate
// it from other modules, migration handler need ensure the upgrade module's migration is executed
// before the rest of the modules.
type UpgradeModule interface {
IsUpgradeModule()
}
PrepareCheckState(context.Context): This method gives module developers the option to implement logic that is automatically triggered during [Commit'](../../learn/advanced/00-baseapp.md#commit) of each block using the [checkState](../../learn/advanced/00-baseapp.md#state-updates) 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 calledmodule.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.
Copy
Ask AI
// example
type AppModule struct {
AppModuleBasic
keeper Keeper
}
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:
Copy
Ask AI
type AppModuleBasic struct{
}
Module Managers
Module managers are used to manage collections ofAppModuleBasic and AppModule.
BasicManager
The BasicManager is a structure that lists all the AppModuleBasic of an application:
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"slices"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead.
type AppModule interface {
appmodule.AppModule
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
//
// Deprecated: this will be removed in the next Cosmos SDK release.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
// HasABCIEndblock is a released typo of HasABCIEndBlock.
// Deprecated: use HasABCIEndBlock instead.
type HasABCIEndblock HasABCIEndBlock
// HasABCIEndBlock is the interface for modules that need to run code at the end of the block.
type HasABCIEndBlock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]any // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderPreBlockers []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]any)
modulesStr := make([]string, 0, len(modules))
preBlockModulesStr := make([]string, 0)
for _, module := range modules {
if _, ok := module.(appmodule.AppModule); !ok {
panic(fmt.Sprintf("module %s does not implement appmodule.AppModule", module.Name()))
}
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, module.Name())
}
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]any)
modulesStr := make([]string, 0, len(simpleModuleMap))
preBlockModulesStr := make([]string, 0)
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, name)
}
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderPreBlockers sets the order of set pre-blocker calls
func (m *Manager)
SetOrderPreBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBlock := module.(appmodule.HasPreBlocker)
return !hasBlock
})
m.OrderPreBlockers = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndBlock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
//
// Deprecated: this function is a no-op and will be removed in the next release of the Cosmos SDK.
func (m *Manager)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err)
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// PreBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was successfully executed or not.
func (m *Manager)
PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) {
paramsChanged := false
for _, moduleName := range m.OrderPreBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok {
rsp, err := module.PreBlock(ctx)
if err != nil {
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndBlock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return slices.Collect(maps.Keys(m.Modules))
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
NewBasicManager(modules ...AppModuleBasic): Constructor function. It takes a list of the application’sAppModuleBasicand builds a newBasicManager. This function is generally called in theinit()function ofapp.goto 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 newBasicManagerfrom aManager. TheBasicManagerwill contain allAppModuleBasicfrom theAppModulemanager usingCoreAppModuleBasicAdaptorwhenever possible. Module’sAppModuleBasiccan be overridden by passing a custom AppModuleBasic mapRegisterLegacyAminoCodec(cdc *codec.LegacyAmino): Registers thecodec.LegacyAminos 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 theHasGenesisBasicsinterfaces.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 theHasGenesisBasicsinterface.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.gofunction 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.gofunction 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:
Copy
Ask AI
/*
Package module contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module simulation functionality (AppModuleSimulation)
- inter-dependent module full functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
BasicManager.
Lastly the interface for genesis functionality (HasGenesis & HasABCIGenesis)
has been
separated out from full module functionality (AppModule)
so that modules which
are only used for genesis can take advantage of the Module patterns without
needlessly defining many placeholder functions
*/
package module
import (
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"slices"
"sort"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/genesis"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(types.InterfaceRegistry)
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
}
// HasName allows the module to provide its own name for legacy purposes.
// Newer apps should specify the name for their modules using a map
// using NewManagerFromMap.
type HasName interface {
Name()
string
}
// HasGenesisBasics is the legacy interface for stateless genesis methods.
type HasGenesisBasics interface {
DefaultGenesis(codec.JSONCodec)
json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)
error
}
// BasicManager is a collection of AppModuleBasic
type BasicManager map[string]AppModuleBasic
// NewBasicManager creates a new BasicManager object
func NewBasicManager(modules ...AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for _, module := range modules {
moduleMap[module.Name()] = module
}
return moduleMap
}
// NewBasicManagerFromManager creates a new BasicManager from a Manager
// The BasicManager will contain all AppModuleBasic from the AppModule Manager
// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map
func NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)
BasicManager {
moduleMap := make(map[string]AppModuleBasic)
for name, module := range manager.Modules {
if customBasicMod, ok := customModuleBasics[name]; ok {
moduleMap[name] = customBasicMod
continue
}
if appModule, ok := module.(appmodule.AppModule); ok {
moduleMap[name] = CoreAppModuleBasicAdaptor(name, appModule)
continue
}
if basicMod, ok := module.(AppModuleBasic); ok {
moduleMap[name] = basicMod
}
}
return moduleMap
}
// RegisterLegacyAminoCodec registers all module codecs
func (bm BasicManager)
RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
for _, b := range bm {
b.RegisterLegacyAminoCodec(cdc)
}
}
// RegisterInterfaces registers all module interface types
func (bm BasicManager)
RegisterInterfaces(registry types.InterfaceRegistry) {
for _, m := range bm {
m.RegisterInterfaces(registry)
}
}
// DefaultGenesis provides default genesis information for all modules
func (bm BasicManager)
DefaultGenesis(cdc codec.JSONCodec)
map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range bm {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
}
}
return genesisData
}
// ValidateGenesis performs genesis state validation for all modules
func (bm BasicManager)
ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage)
error {
for _, b := range bm {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
return err
}
}
}
return nil
}
// RegisterGRPCGatewayRoutes registers all module rest routes
func (bm BasicManager)
RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) {
for _, b := range bm {
b.RegisterGRPCGatewayRoutes(clientCtx, rtr)
}
}
// AddTxCommands adds all tx commands to the rootTxCmd.
func (bm BasicManager)
AddTxCommands(rootTxCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetTxCmd() *cobra.Command
}); ok {
if cmd := mod.GetTxCmd(); cmd != nil {
rootTxCmd.AddCommand(cmd)
}
}
}
}
// AddQueryCommands adds all query commands to the rootQueryCmd.
func (bm BasicManager)
AddQueryCommands(rootQueryCmd *cobra.Command) {
for _, b := range bm {
if mod, ok := b.(interface {
GetQueryCmd() *cobra.Command
}); ok {
if cmd := mod.GetQueryCmd(); cmd != nil {
rootQueryCmd.AddCommand(cmd)
}
}
}
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec)
json.RawMessage
}
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead.
type AppModule interface {
appmodule.AppModule
AppModuleBasic
}
// HasInvariants is the interface for registering invariants.
//
// Deprecated: this will be removed in the next Cosmos SDK release.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// HasServices is the interface for modules to register services.
type HasServices interface {
// RegisterServices allows a module to register services.
RegisterServices(Configurator)
}
// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion interface {
// ConsensusVersion is a sequence number for state-breaking change of the
// module. It should be incremented on each consensus-breaking change
// introduced by the module. To avoid wrong/empty versions, the initial version
// should be set to 1.
ConsensusVersion()
uint64
}
// HasABCIEndblock is a released typo of HasABCIEndBlock.
// Deprecated: use HasABCIEndBlock instead.
type HasABCIEndblock HasABCIEndBlock
// HasABCIEndBlock is the interface for modules that need to run code at the end of the block.
type HasABCIEndBlock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
}
var (
_ appmodule.AppModule = (*GenesisOnlyAppModule)(nil)
_ AppModuleBasic = (*GenesisOnlyAppModule)(nil)
)
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasABCIGenesis
}
// GenesisOnlyAppModule is an AppModule that only has import/export functionality
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis)
GenesisOnlyAppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
func (GenesisOnlyAppModule)
IsOnePerModuleType() {
}
// IsAppModule implements the appmodule.AppModule interface.
func (GenesisOnlyAppModule)
IsAppModule() {
}
// RegisterInvariants is a placeholder function register no invariants
func (GenesisOnlyAppModule)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (gam GenesisOnlyAppModule)
ConsensusVersion()
uint64 {
return 1
}
// Manager defines a module manager that provides the high level utility for managing and executing
// operations for a group of modules
type Manager struct {
Modules map[string]any // interface{
}
is used now to support the legacy AppModule as well as new core appmodule.AppModule.
OrderInitGenesis []string
OrderExportGenesis []string
OrderPreBlockers []string
OrderBeginBlockers []string
OrderEndBlockers []string
OrderPrepareCheckStaters []string
OrderPrecommiters []string
OrderMigrations []string
}
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]any)
modulesStr := make([]string, 0, len(modules))
preBlockModulesStr := make([]string, 0)
for _, module := range modules {
if _, ok := module.(appmodule.AppModule); !ok {
panic(fmt.Sprintf("module %s does not implement appmodule.AppModule", module.Name()))
}
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, module.Name())
}
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// NewManagerFromMap creates a new Manager object from a map of module names to module implementations.
// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API.
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
simpleModuleMap := make(map[string]any)
modulesStr := make([]string, 0, len(simpleModuleMap))
preBlockModulesStr := make([]string, 0)
for name, module := range moduleMap {
simpleModuleMap[name] = module
modulesStr = append(modulesStr, name)
if _, ok := module.(appmodule.HasPreBlocker); ok {
preBlockModulesStr = append(preBlockModulesStr, name)
}
}
// Sort the modules by name. Given that we are using a map above we can't guarantee the order.
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderPreBlockers: preBlockModulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager)
SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderInitGenesis = moduleNames
}
// SetOrderExportGenesis sets the order of export genesis calls
func (m *Manager)
SetOrderExportGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis {
return !hasGenesis
}
if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis {
return !hasABCIGenesis
}
_, hasGenesis := module.(HasGenesis)
return !hasGenesis
})
m.OrderExportGenesis = moduleNames
}
// SetOrderPreBlockers sets the order of set pre-blocker calls
func (m *Manager)
SetOrderPreBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBlock := module.(appmodule.HasPreBlocker)
return !hasBlock
})
m.OrderPreBlockers = moduleNames
}
// SetOrderBeginBlockers sets the order of set begin-blocker calls
func (m *Manager)
SetOrderBeginBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasBeginBlock := module.(appmodule.HasBeginBlocker)
return !hasBeginBlock
})
m.OrderBeginBlockers = moduleNames
}
// SetOrderEndBlockers sets the order of set end-blocker calls
func (m *Manager)
SetOrderEndBlockers(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock {
return !hasEndBlock
}
_, hasABCIEndBlock := module.(HasABCIEndBlock)
return !hasABCIEndBlock
})
m.OrderEndBlockers = moduleNames
}
// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls
func (m *Manager)
SetOrderPrepareCheckStaters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState)
return !hasPrepareCheckState
})
m.OrderPrepareCheckStaters = moduleNames
}
// SetOrderPrecommiters sets the order of set precommiter calls
func (m *Manager)
SetOrderPrecommiters(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames,
func(moduleName string)
bool {
module := m.Modules[moduleName]
_, hasPrecommit := module.(appmodule.HasPrecommit)
return !hasPrecommit
})
m.OrderPrecommiters = moduleNames
}
// SetOrderMigrations sets the order of migrations to be run. If not set
// then migrations will be run with an order defined in `DefaultMigrationsOrder`.
func (m *Manager)
SetOrderMigrations(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil)
m.OrderMigrations = moduleNames
}
// RegisterInvariants registers all module invariants
//
// Deprecated: this function is a no-op and will be removed in the next release of the Cosmos SDK.
func (m *Manager)
RegisterInvariants(_ sdk.InvariantRegistry) {
}
// RegisterServices registers all module services
func (m *Manager)
RegisterServices(cfg Configurator)
error {
for _, module := range m.Modules {
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
if module, ok := module.(appmodule.HasServices); ok {
err := module.RegisterServices(cfg)
if err != nil {
return err
}
}
if cfg.Error() != nil {
return cfg.Error()
}
}
return nil
}
// InitGenesis performs init genesis functionality for modules. Exactly one
// module must return a non-empty validator set update to correctly initialize
// the chain.
func (m *Manager)
InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) {
var validatorUpdates []abci.ValidatorUpdate
ctx.Logger().Info("initializing blockchain state from genesis.json")
for _, moduleName := range m.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
mod := m.Modules[moduleName]
// we might get an adapted module, a native core API module or a legacy module
if module, ok := mod.(appmodule.HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
if err != nil {
return &abci.ResponseInitChain{
}, err
}
err = module.InitGenesis(ctx, source)
if err != nil {
return &abci.ResponseInitChain{
}, err
}
}
else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return &abci.ResponseInitChain{
}, errors.New("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
}
// a chain must initialize with a non-empty validator set
if len(validatorUpdates) == 0 {
return &abci.ResponseInitChain{
}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction)
}
return &abci.ResponseInitChain{
Validators: validatorUpdates,
}, nil
}
// ExportGenesis performs export genesis functionality for modules
func (m *Manager)
ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, cdc, []string{
})
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *Manager)
ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
// verify modules exists in app, so that we don't panic in the middle of an export
if err := m.checkModulesExists(modulesToExport); err != nil {
return nil, err
}
type genesisResult struct {
bz json.RawMessage
err error
}
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{
}
err := module.ExportGenesis(ctx, target.Target())
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
rawJSON, err := target.JSON()
if err != nil {
ch <- genesisResult{
nil, err
}
return
}
ch <- genesisResult{
rawJSON, nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
else if module, ok := mod.(HasABCIGenesis); ok {
channels[moduleName] = make(chan genesisResult)
go func(module HasABCIGenesis, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
ch <- genesisResult{
module.ExportGenesis(ctx, cdc), nil
}
}(module, channels[moduleName])
}
}
genesisData := make(map[string]json.RawMessage)
for moduleName := range channels {
res := <-channels[moduleName]
if res.err != nil {
return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err)
}
genesisData[moduleName] = res.bz
}
return genesisData, nil
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *Manager)
checkModulesExists(moduleName []string)
error {
for _, name := range moduleName {
if _, ok := m.Modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
}
}
return nil
}
// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *Manager)
assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string)
bool) {
ms := make(map[string]bool)
for _, m := range moduleNames {
ms[m] = true
}
var missing []string
for m := range m.Modules {
if pass != nil && pass(m) {
continue
}
if !ms[m] {
missing = append(missing, m)
}
}
if len(missing) != 0 {
sort.Strings(missing)
panic(fmt.Sprintf(
"all modules must be defined when setting %s, missing: %v", setOrderFnName, missing))
}
}
// MigrationHandler is the migration function that each module registers.
type MigrationHandler func(sdk.Context)
error
// VersionMap is a map of moduleName -> version
type VersionMap map[string]uint64
// RunMigrations performs in-place store migrations for all modules. This
// function MUST be called insde an x/upgrade UpgradeHandler.
//
// Recall that in an upgrade handler, the `fromVM` VersionMap is retrieved from
// x/upgrade's store, and the function needs to return the target VersionMap
// that will in turn be persisted to the x/upgrade's store. In general,
// returning RunMigrations should be enough:
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Internally, RunMigrations will perform the following steps:
// - create an `updatedVM` VersionMap of module with their latest ConsensusVersion
// - make a diff of `fromVM` and `udpatedVM`, and for each module:
// - if the module's `fromVM` version is less than its `updatedVM` version,
// then run in-place store migrations for that module between those versions.
// - if the module does not exist in the `fromVM` (which means that it's a new module,
// because it was not in the previous x/upgrade's store), then run
// `InitGenesis` on that module.
//
// - return the `updatedVM` to be persisted in the x/upgrade's store.
//
// Migrations are run in an order defined by `Manager.OrderMigrations` or (if not set)
defined by
// `DefaultMigrationsOrder` function.
//
// As an app developer, if you wish to skip running InitGenesis for your new
// module "foo", you need to manually pass a `fromVM` argument to this function
// foo's module version set to its latest ConsensusVersion. That way, the diff
// between the function's `fromVM` and `udpatedVM` will be empty, hence not
// running anything for foo.
//
// Example:
//
// cfg := module.NewConfigurator(...)
// app.UpgradeKeeper.SetUpgradeHandler("my-plan", func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) {
// // Assume "foo" is a new module.
// // `fromVM` is fetched from existing x/upgrade store. Since foo didn't exist
// // before this upgrade, `v, exists := fromVM["foo"]; exists == false`, and RunMigration will by default
// // run InitGenesis on foo.
// // To skip running foo's InitGenesis, you need set `fromVM`'s foo to its latest
// // consensus version:
// fromVM["foo"] = foo.AppModule{
}.ConsensusVersion()
//
// return app.mm.RunMigrations(ctx, cfg, fromVM)
//
})
//
// Please also refer to https://docs.cosmos.network/main/core/upgrade for more information.
func (m Manager)
RunMigrations(ctx context.Context, cfg Configurator, fromVM VersionMap) (VersionMap, error) {
c, ok := cfg.(*configurator)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expected %T, got %T", &configurator{
}, cfg)
}
modules := m.OrderMigrations
if modules == nil {
modules = DefaultMigrationsOrder(m.ModuleNames())
}
sdkCtx := sdk.UnwrapSDKContext(ctx)
updatedVM := VersionMap{
}
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := uint64(0)
if module, ok := module.(HasConsensusVersion); ok {
toVersion = module.ConsensusVersion()
}
// We run migration if the module is specified in `fromVM`.
// Otherwise we run InitGenesis.
//
// The module won't exist in the fromVM in two cases:
// 1. A new module is added. In this case we run InitGenesis with an
// empty genesis state.
// 2. An existing chain is upgrading from version < 0.43 to v0.43+ for the first time.
// In this case, all modules have yet to be added to x/upgrade's VersionMap store.
if exists {
err := c.runModuleMigrations(sdkCtx, moduleName, fromVersion, toVersion)
if err != nil {
return nil, err
}
}
else {
sdkCtx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
return nil, errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
updatedVM[moduleName] = toVersion
}
return updatedVM, nil
}
// PreBlock performs begin block functionality for upgrade module.
// It takes the current context as a parameter and returns a boolean value
// indicating whether the migration was successfully executed or not.
func (m *Manager)
PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) {
paramsChanged := false
for _, moduleName := range m.OrderPreBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasPreBlocker); ok {
rsp, err := module.PreBlock(ctx)
if err != nil {
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
for _, moduleName := range m.OrderBeginBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasBeginBlocker); ok {
if err := module.BeginBlock(ctx); err != nil {
return sdk.BeginBlock{
}, err
}
}
}
return sdk.BeginBlock{
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// EndBlock performs end block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.
func (m *Manager)
EndBlock(ctx sdk.Context) (sdk.EndBlock, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
validatorUpdates := []abci.ValidatorUpdate{
}
for _, moduleName := range m.OrderEndBlockers {
if module, ok := m.Modules[moduleName].(appmodule.HasEndBlocker); ok {
err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
}
else if module, ok := m.Modules[moduleName].(HasABCIEndBlock); ok {
moduleValUpdates, err := module.EndBlock(ctx)
if err != nil {
return sdk.EndBlock{
}, err
}
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
return sdk.EndBlock{
}, errors.New("validator EndBlock updates already set by a previous module")
}
for _, updates := range moduleValUpdates {
validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{
PubKey: updates.PubKey,
Power: updates.Power
})
}
}
}
else {
continue
}
}
return sdk.EndBlock{
ValidatorUpdates: validatorUpdates,
Events: ctx.EventManager().ABCIEvents(),
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager)
Precommit(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(appmodule.HasPrecommit)
if !ok {
continue
}
if err := module.Precommit(ctx); err != nil {
return err
}
}
return nil
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager)
PrepareCheckState(ctx sdk.Context)
error {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(appmodule.HasPrepareCheckState)
if !ok {
continue
}
if err := module.PrepareCheckState(ctx); err != nil {
return err
}
}
return nil
}
// GetVersionMap gets consensus version from all modules
func (m *Manager)
GetVersionMap()
VersionMap {
vermap := make(VersionMap)
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
vermap[name] = version
}
return vermap
}
// ModuleNames returns list of all module names, without any particular order.
func (m *Manager)
ModuleNames() []string {
return slices.Collect(maps.Keys(m.Modules))
}
// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name,
// except x/auth which will run last, see:
// https://github.com/cosmos/cosmos-sdk/issues/10591
func DefaultMigrationsOrder(modules []string) []string {
const authName = "auth"
out := make([]string, 0, len(modules))
hasAuth := false
for _, m := range modules {
if m == authName {
hasAuth = true
}
else {
out = append(out, m)
}
}
sort.Strings(out)
if hasAuth {
out = append(out, authName)
}
return out
}
NewManager(modules ...AppModule): Constructor function. It takes a list of the application’sAppModules and builds a newManager. It is generally called from the application’s main constructor function.SetOrderInitGenesis(moduleNames ...string): Sets the order in which theInitGenesisfunction 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, thegenutilmodule must occur afterstakingmodule so that the pools are properly initialized with tokens from genesis accounts, thegenutilsmodule must also occur afterauthso that it can access the params from auth, IBC’scapabilitymodule should be initialized before all other modules so that it can initialize any capabilities.SetOrderExportGenesis(moduleNames ...string): Sets the order in which theExportGenesisfunction 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 theHasInvariantsinterface.RegisterServices(cfg Configurator): Registers the services of modules implementing theHasServicesinterface.InitGenesis(ctx context.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage): Calls theInitGenesisfunction of each module when the application is first started, in the order defined inOrderInitGenesis. Returns anabci.ResponseInitChainto the underlying consensus engine, which can contain validator updates.ExportGenesis(ctx context.Context, cdc codec.JSONCodec): Calls theExportGenesisfunction 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 fromBaseAppand, in turn, calls theBeginBlockfunction of each modules implementing theappmodule.HasBeginBlockerinterface, 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 fromBaseAppand, in turn, calls theEndBlockfunction of each modules implementing theappmodule.HasEndBlockerinterface, in the order defined inOrderEndBlockers. It creates a child context with an event manager to aggregate events emitted from all modules. The function returns anabciwhich 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 fromBaseAppand, in turn, calls theEndBlockfunction of each modules implementing themodule.HasABCIEndBlockinterface, in the order defined inOrderEndBlockers. It creates a child context with an event manager to aggregate events emitted from all modules. The function returns anabciwhich contains the aforementioned events, as well as validator set updates (if any).Precommit(ctx context.Context): DuringCommit, this function is called fromBaseAppimmediately before thedeliverStateis written to the underlyingrootMultiStoreand, in turn calls thePrecommitfunction of each modules implementing theHasPrecommitinterface, in the order defined inOrderPrecommiters. It creates a child context where the underlyingCacheMultiStoreis that of the newly committed block’sfinalizeblockstate.PrepareCheckState(ctx context.Context): DuringCommit, this function is called fromBaseAppimmediately after thedeliverStateis written to the underlyingrootMultiStoreand, in turn calls thePrepareCheckStatefunction of each module implementing theHasPrepareCheckStateinterface, in the order defined inOrderPrepareCheckStaters. It creates a child context where the underlyingCacheMultiStoreis that of the next block’scheckState. Writes to this state will be present in thecheckStateof the next block, and therefore this method can be used to prepare thecheckStatefor the next block.
simapp:
Copy
Ask AI
//go:build app_v1
package simapp
import (
"encoding/json"
"fmt"
"io"
"maps"
abci "github.com/cometbft/cometbft/abci/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/gogoproto/proto"
"github.com/spf13/cast"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
"cosmossdk.io/client/v2/autocli"
clienthelpers "cosmossdk.io/client/v2/helpers"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/log"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/x/circuit"
circuitkeeper "cosmossdk.io/x/circuit/keeper"
circuittypes "cosmossdk.io/x/circuit/types"
"cosmossdk.io/x/evidence"
evidencekeeper "cosmossdk.io/x/evidence/keeper"
evidencetypes "cosmossdk.io/x/evidence/types"
"cosmossdk.io/x/feegrant"
feegrantkeeper "cosmossdk.io/x/feegrant/keeper"
feegrantmodule "cosmossdk.io/x/feegrant/module"
"cosmossdk.io/x/nft"
nftkeeper "cosmossdk.io/x/nft/keeper"
nftmodule "cosmossdk.io/x/nft/module"
"cosmossdk.io/x/tx/signing"
"cosmossdk.io/x/upgrade"
upgradekeeper "cosmossdk.io/x/upgrade/keeper"
upgradetypes "cosmossdk.io/x/upgrade/types"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/runtime"
runtimeservices "github.com/cosmos/cosmos-sdk/runtime/services"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/std"
testdata_pulsar "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
sigtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
"github.com/cosmos/cosmos-sdk/x/auth/posthandler"
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
txmodule "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
"github.com/cosmos/cosmos-sdk/x/authz"
authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module"
"github.com/cosmos/cosmos-sdk/x/bank"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
consensus "github.com/cosmos/cosmos-sdk/x/consensus"
consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper"
consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
"github.com/cosmos/cosmos-sdk/x/epochs"
epochskeeper "github.com/cosmos/cosmos-sdk/x/epochs/keeper"
epochstypes "github.com/cosmos/cosmos-sdk/x/epochs/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"github.com/cosmos/cosmos-sdk/x/gov"
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
"github.com/cosmos/cosmos-sdk/x/group"
groupkeeper "github.com/cosmos/cosmos-sdk/x/group/keeper"
groupmodule "github.com/cosmos/cosmos-sdk/x/group/module"
"github.com/cosmos/cosmos-sdk/x/mint"
mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
"github.com/cosmos/cosmos-sdk/x/protocolpool"
protocolpoolkeeper "github.com/cosmos/cosmos-sdk/x/protocolpool/keeper"
protocolpooltypes "github.com/cosmos/cosmos-sdk/x/protocolpool/types"
"github.com/cosmos/cosmos-sdk/x/slashing"
slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
)
const appName = "SimApp"
var (
// DefaultNodeHome default home directories for the application daemon
DefaultNodeHome string
// module account permissions
maccPerms = map[string][]string{
authtypes.FeeCollectorName: nil,
distrtypes.ModuleName: nil,
minttypes.ModuleName: {
authtypes.Minter
},
stakingtypes.BondedPoolName: {
authtypes.Burner, authtypes.Staking
},
stakingtypes.NotBondedPoolName: {
authtypes.Burner, authtypes.Staking
},
govtypes.ModuleName: {
authtypes.Burner
},
nft.ModuleName: nil,
protocolpooltypes.ModuleName: nil,
protocolpooltypes.ProtocolPoolEscrowAccount: nil
}
)
var (
_ runtime.AppI = (*SimApp)(nil)
_ servertypes.Application = (*SimApp)(nil)
)
// SimApp extends an ABCI application, but with most of its parameters exported.
// They are exported for convenience in creating helper functions, as object
// capabilities aren't needed for testing.
type SimApp struct {
*baseapp.BaseApp
legacyAmino *codec.LegacyAmino
appCodec codec.Codec
txConfig client.TxConfig
interfaceRegistry types.InterfaceRegistry
// keys to access the substores
keys map[string]*storetypes.KVStoreKey
// essential keepers
AccountKeeper authkeeper.AccountKeeper
BankKeeper bankkeeper.BaseKeeper
StakingKeeper *stakingkeeper.Keeper
SlashingKeeper slashingkeeper.Keeper
MintKeeper mintkeeper.Keeper
DistrKeeper distrkeeper.Keeper
GovKeeper govkeeper.Keeper
UpgradeKeeper *upgradekeeper.Keeper
EvidenceKeeper evidencekeeper.Keeper
ConsensusParamsKeeper consensusparamkeeper.Keeper
CircuitKeeper circuitkeeper.Keeper
// supplementary keepers
FeeGrantKeeper feegrantkeeper.Keeper
GroupKeeper groupkeeper.Keeper
AuthzKeeper authzkeeper.Keeper
NFTKeeper nftkeeper.Keeper
EpochsKeeper epochskeeper.Keeper
ProtocolPoolKeeper protocolpoolkeeper.Keeper
// the module manager
ModuleManager *module.Manager
BasicModuleManager module.BasicManager
// simulation manager
sm *module.SimulationManager
// module configurator
configurator module.Configurator
}
func init() {
var err error
DefaultNodeHome, err = clienthelpers.GetNodeHomeDirectory(".simapp")
if err != nil {
panic(err)
}
}
// NewSimApp returns a reference to an initialized SimApp.
func NewSimApp(
logger log.Logger,
db dbm.DB,
traceStore io.Writer,
loadLatest bool,
appOpts servertypes.AppOptions,
baseAppOptions ...func(*baseapp.BaseApp),
) *SimApp {
interfaceRegistry, _ := types.NewInterfaceRegistryWithOptions(types.InterfaceRegistryOptions{
ProtoFiles: proto.HybridResolver,
SigningOptions: signing.Options{
AddressCodec: address.Bech32Codec{
Bech32Prefix: sdk.GetConfig().GetBech32AccountAddrPrefix(),
},
ValidatorAddressCodec: address.Bech32Codec{
Bech32Prefix: sdk.GetConfig().GetBech32ValidatorAddrPrefix(),
},
},
})
appCodec := codec.NewProtoCodec(interfaceRegistry)
legacyAmino := codec.NewLegacyAmino()
txConfig := tx.NewTxConfig(appCodec, tx.DefaultSignModes)
if err := interfaceRegistry.SigningContext().Validate(); err != nil {
panic(err)
}
std.RegisterLegacyAminoCodec(legacyAmino)
std.RegisterInterfaces(interfaceRegistry)
// Below we could construct and set an application specific mempool and
// ABCI 1.0 PrepareProposal and ProcessProposal handlers. These defaults are
// already set in the SDK's BaseApp, this shows an example of how to override
// them.
//
// Example:
//
// bApp := baseapp.NewBaseApp(...)
// nonceMempool := mempool.NewSenderNonceMempool()
// abciPropHandler := NewDefaultProposalHandler(nonceMempool, bApp)
//
// bApp.SetMempool(nonceMempool)
// bApp.SetPrepareProposal(abciPropHandler.PrepareProposalHandler())
// bApp.SetProcessProposal(abciPropHandler.ProcessProposalHandler())
//
// Alternatively, you can construct BaseApp options, append those to
// baseAppOptions and pass them to NewBaseApp.
//
// Example:
//
// prepareOpt = func(app *baseapp.BaseApp) {
// abciPropHandler := baseapp.NewDefaultProposalHandler(nonceMempool, app)
// app.SetPrepareProposal(abciPropHandler.PrepareProposalHandler())
//
}
// baseAppOptions = append(baseAppOptions, prepareOpt)
// create and set dummy vote extension handler
voteExtOp := func(bApp *baseapp.BaseApp) {
voteExtHandler := NewVoteExtensionHandler()
voteExtHandler.SetHandlers(bApp)
}
baseAppOptions = append(baseAppOptions, voteExtOp, baseapp.SetOptimisticExecution())
bApp := baseapp.NewBaseApp(appName, logger, db, txConfig.TxDecoder(), baseAppOptions...)
bApp.SetCommitMultiStoreTracer(traceStore)
bApp.SetVersion(version.Version)
bApp.SetInterfaceRegistry(interfaceRegistry)
bApp.SetTxEncoder(txConfig.TxEncoder())
keys := storetypes.NewKVStoreKeys(
authtypes.StoreKey,
banktypes.StoreKey,
stakingtypes.StoreKey,
minttypes.StoreKey,
distrtypes.StoreKey,
slashingtypes.StoreKey,
govtypes.StoreKey,
consensusparamtypes.StoreKey,
upgradetypes.StoreKey,
feegrant.StoreKey,
evidencetypes.StoreKey,
circuittypes.StoreKey,
authzkeeper.StoreKey,
nftkeeper.StoreKey,
group.StoreKey,
epochstypes.StoreKey,
protocolpooltypes.StoreKey,
)
// register streaming services
if err := bApp.RegisterStreamingServices(appOpts, keys); err != nil {
panic(err)
}
app := &SimApp{
BaseApp: bApp,
legacyAmino: legacyAmino,
appCodec: appCodec,
txConfig: txConfig,
interfaceRegistry: interfaceRegistry,
keys: keys,
}
// set the BaseApp's parameter store
app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[consensusparamtypes.StoreKey]),
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
runtime.EventService{
},
)
bApp.SetParamStore(app.ConsensusParamsKeeper.ParamsStore)
// add keepers
app.AccountKeeper = authkeeper.NewAccountKeeper(
appCodec,
runtime.NewKVStoreService(keys[authtypes.StoreKey]),
authtypes.ProtoBaseAccount,
maccPerms,
authcodec.NewBech32Codec(sdk.Bech32MainPrefix),
sdk.Bech32MainPrefix,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
authkeeper.WithUnorderedTransactions(true),
)
app.BankKeeper = bankkeeper.NewBaseKeeper(
appCodec,
runtime.NewKVStoreService(keys[banktypes.StoreKey]),
app.AccountKeeper,
BlockedAddresses(),
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
logger,
)
// optional: enable sign mode textual by overwriting the default tx config (after setting the bank keeper)
enabledSignModes := append(tx.DefaultSignModes, sigtypes.SignMode_SIGN_MODE_TEXTUAL)
txConfigOpts := tx.ConfigOptions{
EnabledSignModes: enabledSignModes,
TextualCoinMetadataQueryFn: txmodule.NewBankKeeperCoinMetadataQueryFn(app.BankKeeper),
}
txConfig, err := tx.NewTxConfigWithOptions(
appCodec,
txConfigOpts,
)
if err != nil {
panic(err)
}
app.txConfig = txConfig
app.StakingKeeper = stakingkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[stakingtypes.StoreKey]),
app.AccountKeeper,
app.BankKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
authcodec.NewBech32Codec(sdk.Bech32PrefixValAddr),
authcodec.NewBech32Codec(sdk.Bech32PrefixConsAddr),
)
app.MintKeeper = mintkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[minttypes.StoreKey]),
app.StakingKeeper,
app.AccountKeeper,
app.BankKeeper,
authtypes.FeeCollectorName,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
// mintkeeper.WithMintFn(mintkeeper.DefaultMintFn(minttypes.DefaultInflationCalculationFn)), custom mintFn can be added here
)
app.ProtocolPoolKeeper = protocolpoolkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[protocolpooltypes.StoreKey]),
app.AccountKeeper,
app.BankKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
app.DistrKeeper = distrkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[distrtypes.StoreKey]),
app.AccountKeeper,
app.BankKeeper,
app.StakingKeeper,
authtypes.FeeCollectorName,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
distrkeeper.WithExternalCommunityPool(app.ProtocolPoolKeeper),
)
app.SlashingKeeper = slashingkeeper.NewKeeper(
appCodec,
legacyAmino,
runtime.NewKVStoreService(keys[slashingtypes.StoreKey]),
app.StakingKeeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
app.FeeGrantKeeper = feegrantkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[feegrant.StoreKey]),
app.AccountKeeper,
)
// register the staking hooks
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
app.StakingKeeper.SetHooks(
stakingtypes.NewMultiStakingHooks(
app.DistrKeeper.Hooks(),
app.SlashingKeeper.Hooks(),
),
)
app.CircuitKeeper = circuitkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[circuittypes.StoreKey]),
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
app.AccountKeeper.AddressCodec(),
)
app.BaseApp.SetCircuitBreaker(&app.CircuitKeeper)
app.AuthzKeeper = authzkeeper.NewKeeper(
runtime.NewKVStoreService(keys[authzkeeper.StoreKey]),
appCodec,
app.MsgServiceRouter(),
app.AccountKeeper,
)
groupConfig := group.DefaultConfig()
/*
Example of setting group params:
groupConfig.MaxMetadataLen = 1000
*/
app.GroupKeeper = groupkeeper.NewKeeper(
keys[group.StoreKey],
appCodec,
app.MsgServiceRouter(),
app.AccountKeeper,
groupConfig,
)
// get skipUpgradeHeights from the app options
skipUpgradeHeights := map[int64]bool{
}
for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) {
skipUpgradeHeights[int64(h)] = true
}
homePath := cast.ToString(appOpts.Get(flags.FlagHome))
// set the governance module account as the authority for conducting upgrades
app.UpgradeKeeper = upgradekeeper.NewKeeper(
skipUpgradeHeights,
runtime.NewKVStoreService(keys[upgradetypes.StoreKey]),
appCodec,
homePath,
app.BaseApp,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
// Register the proposal types
// Deprecated: Avoid adding new handlers, instead use the new proposal flow
// by granting the governance module the right to execute the message.
// See: https://docs.cosmos.network/main/modules/gov#proposal-messages
govRouter := govv1beta1.NewRouter()
govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler)
govConfig := govtypes.DefaultConfig()
/*
Example of setting gov params:
govConfig.MaxMetadataLen = 10000
*/
govKeeper := govkeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[govtypes.StoreKey]),
app.AccountKeeper,
app.BankKeeper,
app.StakingKeeper,
app.DistrKeeper,
app.MsgServiceRouter(),
govConfig,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
// govkeeper.WithCustomCalculateVoteResultsAndVotingPowerFn(...), // Add if you want to use a custom vote calculation function.
)
// Set legacy router for backwards compatibility with gov v1beta1
govKeeper.SetLegacyRouter(govRouter)
app.GovKeeper = *govKeeper.SetHooks(
govtypes.NewMultiGovHooks(
// register the governance hooks
),
)
app.NFTKeeper = nftkeeper.NewKeeper(
runtime.NewKVStoreService(keys[nftkeeper.StoreKey]),
appCodec,
app.AccountKeeper,
app.BankKeeper,
)
// create evidence keeper with router
evidenceKeeper := evidencekeeper.NewKeeper(
appCodec,
runtime.NewKVStoreService(keys[evidencetypes.StoreKey]),
app.StakingKeeper,
app.SlashingKeeper,
app.AccountKeeper.AddressCodec(),
runtime.ProvideCometInfoService(),
)
// If evidence needs to be handled for the app, set routes in router here and seal
app.EvidenceKeeper = *evidenceKeeper
app.EpochsKeeper = epochskeeper.NewKeeper(
runtime.NewKVStoreService(keys[epochstypes.StoreKey]),
appCodec,
)
app.EpochsKeeper.SetHooks(
epochstypes.NewMultiEpochHooks(
// insert epoch hooks receivers here
),
)
/**** Module Options ****/
// NOTE: Any module instantiated in the module manager that is later modified
// must be passed by reference here.
app.ModuleManager = module.NewManager(
genutil.NewAppModule(
app.AccountKeeper, app.StakingKeeper, app,
txConfig,
),
auth.NewAppModule(appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, nil),
vesting.NewAppModule(app.AccountKeeper, app.BankKeeper),
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper, nil),
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, nil),
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil, nil),
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, nil, app.interfaceRegistry),
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, nil),
staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, nil),
upgrade.NewAppModule(app.UpgradeKeeper, app.AccountKeeper.AddressCodec()),
evidence.NewAppModule(app.EvidenceKeeper),
authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
groupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
nftmodule.NewAppModule(appCodec, app.NFTKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper),
circuit.NewAppModule(appCodec, app.CircuitKeeper),
epochs.NewAppModule(app.EpochsKeeper),
protocolpool.NewAppModule(app.ProtocolPoolKeeper, app.AccountKeeper, app.BankKeeper),
)
// BasicModuleManager defines the module BasicManager is in charge of setting up basic,
// non-dependant module elements, such as codec registration and genesis verification.
// By default it is composed of all the module from the module manager.
// Additionally, app module basics can be overwritten by passing them as argument.
app.BasicModuleManager = module.NewBasicManagerFromManager(
app.ModuleManager,
map[string]module.AppModuleBasic{
genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
govtypes.ModuleName: gov.NewAppModuleBasic(
[]govclient.ProposalHandler{
},
),
})
app.BasicModuleManager.RegisterLegacyAminoCodec(legacyAmino)
app.BasicModuleManager.RegisterInterfaces(interfaceRegistry)
// NOTE: upgrade module is required to be prioritized
app.ModuleManager.SetOrderPreBlockers(
upgradetypes.ModuleName,
authtypes.ModuleName,
)
// During begin block slashing happens after distr.BeginBlocker so that
// there is nothing left over in the validator fee pool, so as to keep the
// CanWithdrawInvariant invariant.
// NOTE: staking module is required if HistoricalEntries param > 0
app.ModuleManager.SetOrderBeginBlockers(
minttypes.ModuleName,
distrtypes.ModuleName,
protocolpooltypes.ModuleName,
slashingtypes.ModuleName,
evidencetypes.ModuleName,
stakingtypes.ModuleName,
genutiltypes.ModuleName,
authz.ModuleName,
epochstypes.ModuleName,
)
app.ModuleManager.SetOrderEndBlockers(
govtypes.ModuleName,
stakingtypes.ModuleName,
genutiltypes.ModuleName,
feegrant.ModuleName,
group.ModuleName,
protocolpooltypes.ModuleName,
)
// NOTE: The genutils module must occur after staking so that pools are
// properly initialized with tokens from genesis accounts.
// NOTE: The genutils module must also occur after auth so that it can access the params from auth.
genesisModuleOrder := []string{
authtypes.ModuleName,
banktypes.ModuleName,
distrtypes.ModuleName,
stakingtypes.ModuleName,
slashingtypes.ModuleName,
govtypes.ModuleName,
minttypes.ModuleName,
genutiltypes.ModuleName,
evidencetypes.ModuleName,
authz.ModuleName,
feegrant.ModuleName,
nft.ModuleName,
group.ModuleName,
upgradetypes.ModuleName,
vestingtypes.ModuleName,
consensusparamtypes.ModuleName,
circuittypes.ModuleName,
epochstypes.ModuleName,
protocolpooltypes.ModuleName,
}
exportModuleOrder := []string{
consensusparamtypes.ModuleName,
authtypes.ModuleName,
protocolpooltypes.ModuleName, // Must be exported before bank
banktypes.ModuleName,
distrtypes.ModuleName,
stakingtypes.ModuleName,
slashingtypes.ModuleName,
govtypes.ModuleName,
minttypes.ModuleName,
genutiltypes.ModuleName,
evidencetypes.ModuleName,
authz.ModuleName,
feegrant.ModuleName,
nft.ModuleName,
group.ModuleName,
upgradetypes.ModuleName,
vestingtypes.ModuleName,
circuittypes.ModuleName,
epochstypes.ModuleName,
}
app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...)
app.ModuleManager.SetOrderExportGenesis(exportModuleOrder...)
// Uncomment if you want to set a custom migration order here.
// app.ModuleManager.SetOrderMigrations(custom order)
app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter())
err = app.ModuleManager.RegisterServices(app.configurator)
if err != nil {
panic(err)
}
// RegisterUpgradeHandlers is used for registering any on-chain upgrades.
// Make sure it's called after `app.ModuleManager` and `app.configurator` are set.
app.RegisterUpgradeHandlers()
autocliv1.RegisterQueryServer(app.GRPCQueryRouter(), runtimeservices.NewAutoCLIQueryService(app.ModuleManager.Modules))
reflectionSvc, err := runtimeservices.NewReflectionService()
if err != nil {
panic(err)
}
reflectionv1.RegisterReflectionServiceServer(app.GRPCQueryRouter(), reflectionSvc)
// add test gRPC service for testing gRPC queries in isolation
testdata_pulsar.RegisterQueryServer(app.GRPCQueryRouter(), testdata_pulsar.QueryImpl{
})
// create the simulation manager and define the order of the modules for deterministic simulations
//
// NOTE: this is not required apps that don't use the simulator for fuzz testing
// transactions
overrideModules := map[string]module.AppModuleSimulation{
authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, nil),
}
app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules)
app.sm.RegisterStoreDecoders()
// initialize stores
app.MountKVStores(keys)
// initialize BaseApp
app.SetInitChainer(app.InitChainer)
app.SetPreBlocker(app.PreBlocker)
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.setAnteHandler(txConfig)
// In v0.46, the SDK introduces _postHandlers_. PostHandlers are like
// antehandlers, but are run _after_ the `runMsgs` execution. They are also
// defined as a chain, and have the same signature as antehandlers.
//
// In baseapp, postHandlers are run in the same store branch as `runMsgs`,
// meaning that both `runMsgs` and `postHandler` state will be committed if
// both are successful, and both will be reverted if any of the two fails.
//
// The SDK exposes a default postHandlers chain
//
// Please note that changing any of the anteHandler or postHandler chain is
// likely to be a state-machine breaking change, which needs a coordinated
// upgrade.
app.setPostHandler()
if loadLatest {
if err := app.LoadLatestVersion(); err != nil {
panic(fmt.Errorf("error loading last version: %w", err))
}
}
return app
}
func (app *SimApp)
setAnteHandler(txConfig client.TxConfig) {
anteHandler, err := NewAnteHandler(
HandlerOptions{
ante.HandlerOptions{
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
SignModeHandler: txConfig.SignModeHandler(),
FeegrantKeeper: app.FeeGrantKeeper,
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
SigVerifyOptions: []ante.SigVerificationDecoratorOption{
// change below as needed.
ante.WithUnorderedTxGasCost(ante.DefaultUnorderedTxGasCost),
ante.WithMaxUnorderedTxTimeoutDuration(ante.DefaultMaxTimeoutDuration),
},
},
&app.CircuitKeeper,
},
)
if err != nil {
panic(err)
}
// Set the AnteHandler for the app
app.SetAnteHandler(anteHandler)
}
func (app *SimApp)
setPostHandler() {
postHandler, err := posthandler.NewPostHandler(
posthandler.HandlerOptions{
},
)
if err != nil {
panic(err)
}
app.SetPostHandler(postHandler)
}
// Name returns the name of the App
func (app *SimApp)
Name()
string {
return app.BaseApp.Name()
}
// PreBlocker application updates every pre block
func (app *SimApp)
PreBlocker(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
return app.ModuleManager.PreBlock(ctx)
}
// BeginBlocker application updates every begin block
func (app *SimApp)
BeginBlocker(ctx sdk.Context) (sdk.BeginBlock, error) {
return app.ModuleManager.BeginBlock(ctx)
}
// EndBlocker application updates every end block
func (app *SimApp)
EndBlocker(ctx sdk.Context) (sdk.EndBlock, error) {
return app.ModuleManager.EndBlock(ctx)
}
func (a *SimApp)
Configurator()
module.Configurator {
return a.configurator
}
// InitChainer application update at chain initialization
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 {
panic(err)
}
app.UpgradeKeeper.SetModuleVersionMap(ctx, app.ModuleManager.GetVersionMap())
return app.ModuleManager.InitGenesis(ctx, app.appCodec, genesisState)
}
// LoadHeight loads a particular height
func (app *SimApp)
LoadHeight(height int64)
error {
return app.LoadVersion(height)
}
// LegacyAmino returns SimApp's amino codec.
//
// NOTE: This is solely to be used for testing purposes as it may be desirable
// for modules to register their own custom testing types.
func (app *SimApp)
LegacyAmino() *codec.LegacyAmino {
return app.legacyAmino
}
// AppCodec returns SimApp's app codec.
//
// NOTE: This is solely to be used for testing purposes as it may be desirable
// for modules to register their own custom testing types.
func (app *SimApp)
AppCodec()
codec.Codec {
return app.appCodec
}
// InterfaceRegistry returns SimApp's InterfaceRegistry
func (app *SimApp)
InterfaceRegistry()
types.InterfaceRegistry {
return app.interfaceRegistry
}
// TxConfig returns SimApp's TxConfig
func (app *SimApp)
TxConfig()
client.TxConfig {
return app.txConfig
}
// AutoCliOpts returns the autocli options for the app.
func (app *SimApp)
AutoCliOpts()
autocli.AppOptions {
modules := make(map[string]appmodule.AppModule, 0)
for _, m := range app.ModuleManager.Modules {
if moduleWithName, ok := m.(module.HasName); ok {
moduleName := moduleWithName.Name()
if appModule, ok := moduleWithName.(appmodule.AppModule); ok {
modules[moduleName] = appModule
}
}
}
return autocli.AppOptions{
Modules: modules,
ModuleOptions: runtimeservices.ExtractAutoCLIOptions(app.ModuleManager.Modules),
AddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32AccountAddrPrefix()),
ValidatorAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ValidatorAddrPrefix()),
ConsensusAddressCodec: authcodec.NewBech32Codec(sdk.GetConfig().GetBech32ConsensusAddrPrefix()),
}
}
// DefaultGenesis returns a default genesis from the registered AppModuleBasic's.
func (a *SimApp)
DefaultGenesis()
map[string]json.RawMessage {
return a.BasicModuleManager.DefaultGenesis(a.appCodec)
}
// GetKey returns the KVStoreKey for the provided store key.
//
// NOTE: This is solely to be used for testing purposes.
func (app *SimApp)
GetKey(storeKey string) *storetypes.KVStoreKey {
return app.keys[storeKey]
}
// GetStoreKeys returns all the stored store keys.
func (app *SimApp)
GetStoreKeys() []storetypes.StoreKey {
keys := make([]storetypes.StoreKey, 0, len(app.keys))
for _, key := range app.keys {
keys = append(keys, key)
}
return keys
}
// SimulationManager implements the SimulationApp interface
func (app *SimApp)
SimulationManager() *module.SimulationManager {
return app.sm
}
// RegisterAPIRoutes registers all application module routes with the provided
// API server.
func (app *SimApp)
RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
clientCtx := apiSvr.ClientCtx
// Register new tx routes from grpc-gateway.
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// Register new CometBFT queries routes from grpc-gateway.
cmtservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// Register node gRPC service for grpc-gateway.
nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// Register grpc-gateway routes for all modules.
app.BasicModuleManager.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
// register swagger API from root so that other applications can override easily
if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil {
panic(err)
}
}
// RegisterTxService implements the Application.RegisterTxService method.
func (app *SimApp)
RegisterTxService(clientCtx client.Context) {
authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry)
}
// RegisterTendermintService implements the Application.RegisterTendermintService method.
func (app *SimApp)
RegisterTendermintService(clientCtx client.Context) {
cmtApp := server.NewCometABCIWrapper(app)
cmtservice.RegisterTendermintService(
clientCtx,
app.BaseApp.GRPCQueryRouter(),
app.interfaceRegistry,
cmtApp.Query,
)
}
func (app *SimApp)
RegisterNodeService(clientCtx client.Context, cfg config.Config) {
nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter(), cfg)
}
// GetMaccPerms returns a copy of the module account permissions
//
// NOTE: This is solely to be used for testing purposes.
func GetMaccPerms()
map[string][]string {
return maps.Clone(maccPerms)
}
// BlockedAddresses returns all the app's blocked account addresses.
func BlockedAddresses()
map[string]bool {
modAccAddrs := make(map[string]bool)
for acc := range GetMaccPerms() {
modAccAddrs[authtypes.NewModuleAddress(acc).String()] = true
}
// allow the following addresses to receive funds
delete(modAccAddrs, authtypes.NewModuleAddress(govtypes.ModuleName).String())
return modAccAddrs
}
runtime (the package that powers app di):
Copy
Ask AI
package runtime
import (
"fmt"
"os"
"slices"
"github.com/cosmos/gogoproto/proto"
"google.golang.org/protobuf/reflect/protodesc"
"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"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/comet"
"cosmossdk.io/core/event"
"cosmossdk.io/core/genesis"
"cosmossdk.io/core/header"
"cosmossdk.io/core/store"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/x/tx/signing"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/std"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/types/msgservice"
)
type appModule struct {
app *App
}
func (m appModule)
RegisterServices(configurator module.Configurator) {
err := m.app.registerRuntimeServices(configurator)
if err != nil {
panic(err)
}
}
func (m appModule)
IsOnePerModuleType() {
}
func (m appModule)
IsAppModule() {
}
var (
_ appmodule.AppModule = appModule{
}
_ module.HasServices = appModule{
}
)
// BaseAppOption is a depinject.AutoGroupType which can be used to pass
// BaseApp options into the depinject. It should be used carefully.
type BaseAppOption func(*baseapp.BaseApp)
// IsManyPerContainerType indicates that this is a depinject.ManyPerContainerType.
func (b BaseAppOption)
IsManyPerContainerType() {
}
func init() {
appmodule.Register(&runtimev1alpha1.Module{
},
appmodule.Provide(
ProvideApp,
ProvideInterfaceRegistry,
ProvideKVStoreKey,
ProvideTransientStoreKey,
ProvideMemoryStoreKey,
ProvideGenesisTxHandler,
ProvideKVStoreService,
ProvideMemoryStoreService,
ProvideTransientStoreService,
ProvideEventService,
ProvideHeaderInfoService,
ProvideCometInfoService,
ProvideBasicManager,
ProvideAddressCodec,
),
appmodule.Invoke(SetupAppBuilder),
)
}
func ProvideApp(interfaceRegistry codectypes.InterfaceRegistry) (
codec.Codec,
*codec.LegacyAmino,
*AppBuilder,
*baseapp.MsgServiceRouter,
*baseapp.GRPCQueryRouter,
appmodule.AppModule,
protodesc.Resolver,
protoregistry.MessageTypeResolver,
error,
) {
protoFiles := proto.HybridResolver
protoTypes := protoregistry.GlobalTypes
// At startup, check that all proto annotations are correct.
if err := msgservice.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())
}
amino := codec.NewLegacyAmino()
std.RegisterInterfaces(interfaceRegistry)
std.RegisterLegacyAminoCodec(amino)
cdc := codec.NewProtoCodec(interfaceRegistry)
msgServiceRouter := baseapp.NewMsgServiceRouter()
grpcQueryRouter := baseapp.NewGRPCQueryRouter()
app := &App{
storeKeys: nil,
interfaceRegistry: interfaceRegistry,
cdc: cdc,
amino: amino,
basicManager: module.BasicManager{
},
msgServiceRouter: msgServiceRouter,
grpcQueryRouter: grpcQueryRouter,
}
appBuilder := &AppBuilder{
app
}
return cdc, amino, appBuilder, msgServiceRouter, grpcQueryRouter, appModule{
app
}, protoFiles, protoTypes, nil
}
type AppInputs struct {
depinject.In
AppConfig *appv1alpha1.Config `optional:"true"`
Config *runtimev1alpha1.Module
AppBuilder *AppBuilder
Modules map[string]appmodule.AppModule
CustomModuleBasics map[string]module.AppModuleBasic `optional:"true"`
BaseAppOptions []BaseAppOption
InterfaceRegistry codectypes.InterfaceRegistry
LegacyAmino *codec.LegacyAmino
Logger log.Logger
}
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)
for name, mod := range inputs.Modules {
if customBasicMod, ok := inputs.CustomModuleBasics[name]; ok {
app.basicManager[name] = customBasicMod
customBasicMod.RegisterInterfaces(inputs.InterfaceRegistry)
customBasicMod.RegisterLegacyAminoCodec(inputs.LegacyAmino)
continue
}
coreAppModuleBasic := module.CoreAppModuleBasicAdaptor(name, mod)
app.basicManager[name] = coreAppModuleBasic
coreAppModuleBasic.RegisterInterfaces(inputs.InterfaceRegistry)
coreAppModuleBasic.RegisterLegacyAminoCodec(inputs.LegacyAmino)
}
}
func ProvideInterfaceRegistry(addressCodec address.Codec, validatorAddressCodec ValidatorAddressCodec, customGetSigners []signing.CustomGetSigner) (codectypes.InterfaceRegistry, error) {
signingOptions := signing.Options{
AddressCodec: addressCodec,
ValidatorAddressCodec: validatorAddressCodec,
}
for _, signer := range customGetSigners {
signingOptions.DefineCustomGetSigners(signer.MsgType, signer.Fn)
}
interfaceRegistry, err := codectypes.NewInterfaceRegistryWithOptions(codectypes.InterfaceRegistryOptions{
ProtoFiles: proto.HybridResolver,
SigningOptions: signingOptions,
})
if err != nil {
return nil, err
}
if err := interfaceRegistry.SigningContext().Validate(); err != nil {
return nil, err
}
return interfaceRegistry, nil
}
func registerStoreKey(wrapper *AppBuilder, key storetypes.StoreKey) {
wrapper.app.storeKeys = append(wrapper.app.storeKeys, key)
}
func storeKeyOverride(config *runtimev1alpha1.Module, moduleName string) *runtimev1alpha1.StoreKeyConfig {
for _, cfg := range config.OverrideStoreKeys {
if cfg.ModuleName == moduleName {
return cfg
}
}
return nil
}
func ProvideKVStoreKey(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) *storetypes.KVStoreKey {
if slices.Contains(config.SkipStoreKeys, key.Name()) {
return nil
}
override := storeKeyOverride(config, key.Name())
var storeKeyName string
if override != nil {
storeKeyName = override.KvStoreKey
}
else {
storeKeyName = key.Name()
}
storeKey := storetypes.NewKVStoreKey(storeKeyName)
registerStoreKey(app, storeKey)
return storeKey
}
func ProvideTransientStoreKey(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) *storetypes.TransientStoreKey {
if slices.Contains(config.SkipStoreKeys, key.Name()) {
return nil
}
storeKey := storetypes.NewTransientStoreKey(fmt.Sprintf("transient:%s", key.Name()))
registerStoreKey(app, storeKey)
return storeKey
}
func ProvideMemoryStoreKey(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) *storetypes.MemoryStoreKey {
if slices.Contains(config.SkipStoreKeys, key.Name()) {
return nil
}
storeKey := storetypes.NewMemoryStoreKey(fmt.Sprintf("memory:%s", key.Name()))
registerStoreKey(app, storeKey)
return storeKey
}
func ProvideGenesisTxHandler(appBuilder *AppBuilder)
genesis.TxHandler {
return appBuilder.app
}
func ProvideKVStoreService(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder)
store.KVStoreService {
storeKey := ProvideKVStoreKey(config, key, app)
return kvStoreService{
key: storeKey
}
}
func ProvideMemoryStoreService(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder)
store.MemoryStoreService {
storeKey := ProvideMemoryStoreKey(config, key, app)
return memStoreService{
key: storeKey
}
}
func ProvideTransientStoreService(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder)
store.TransientStoreService {
storeKey := ProvideTransientStoreKey(config, key, app)
return transientStoreService{
key: storeKey
}
}
func ProvideEventService()
event.Service {
return EventService{
}
}
func ProvideCometInfoService()
comet.BlockInfoService {
return cometInfoService{
}
}
func ProvideHeaderInfoService(app *AppBuilder)
header.Service {
return headerInfoService{
}
}
func ProvideBasicManager(app *AppBuilder)
module.BasicManager {
return app.app.basicManager
}
type (
// ValidatorAddressCodec is an alias for address.Codec for validator addresses.
ValidatorAddressCodec address.Codec
// ConsensusAddressCodec is an alias for address.Codec for validator consensus addresses.
ConsensusAddressCodec address.Codec
)
type AddressCodecInputs struct {
depinject.In
AuthConfig *authmodulev1.Module `optional:"true"`
StakingConfig *stakingmodulev1.Module `optional:"true"`
AddressCodecFactory func()
address.Codec `optional:"true"`
ValidatorAddressCodecFactory func()
ValidatorAddressCodec `optional:"true"`
ConsensusAddressCodecFactory func()
ConsensusAddressCodec `optional:"true"`
}
// ProvideAddressCodec provides an address.Codec to the container for any
// modules that want to do address string <> bytes conversion.
func ProvideAddressCodec(in AddressCodecInputs) (address.Codec, ValidatorAddressCodec, ConsensusAddressCodec) {
if in.AddressCodecFactory != nil && in.ValidatorAddressCodecFactory != nil && in.ConsensusAddressCodecFactory != nil {
return in.AddressCodecFactory(), in.ValidatorAddressCodecFactory(), in.ConsensusAddressCodecFactory()
}
if in.AuthConfig == nil || in.AuthConfig.Bech32Prefix == "" {
panic("auth config bech32 prefix cannot be empty if no custom address codec is provided")
}
if in.StakingConfig == nil {
in.StakingConfig = &stakingmodulev1.Module{
}
}
if in.StakingConfig.Bech32PrefixValidator == "" {
in.StakingConfig.Bech32PrefixValidator = fmt.Sprintf("%svaloper", in.AuthConfig.Bech32Prefix)
}
if in.StakingConfig.Bech32PrefixConsensus == "" {
in.StakingConfig.Bech32PrefixConsensus = fmt.Sprintf("%svalcons", in.AuthConfig.Bech32Prefix)
}
return addresscodec.NewBech32Codec(in.AuthConfig.Bech32Prefix),
addresscodec.NewBech32Codec(in.StakingConfig.Bech32PrefixValidator),
addresscodec.NewBech32Codec(in.StakingConfig.Bech32PrefixConsensus)
}
Copy
Ask AI
package runtime
import (
"fmt"
"os"
"slices"
"github.com/cosmos/gogoproto/proto"
"google.golang.org/protobuf/reflect/protodesc"
"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"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/comet"
"cosmossdk.io/core/event"
"cosmossdk.io/core/genesis"
"cosmossdk.io/core/header"
"cosmossdk.io/core/store"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/x/tx/signing"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/std"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/types/msgservice"
)
type appModule struct {
app *App
}
func (m appModule)
RegisterServices(configurator module.Configurator) {
err := m.app.registerRuntimeServices(configurator)
if err != nil {
panic(err)
}
}
func (m appModule)
IsOnePerModuleType() {
}
func (m appModule)
IsAppModule() {
}
var (
_ appmodule.AppModule = appModule{
}
_ module.HasServices = appModule{
}
)
// BaseAppOption is a depinject.AutoGroupType which can be used to pass
// BaseApp options into the depinject. It should be used carefully.
type BaseAppOption func(*baseapp.BaseApp)
// IsManyPerContainerType indicates that this is a depinject.ManyPerContainerType.
func (b BaseAppOption)
IsManyPerContainerType() {
}
func init() {
appmodule.Register(&runtimev1alpha1.Module{
},
appmodule.Provide(
ProvideApp,
ProvideInterfaceRegistry,
ProvideKVStoreKey,
ProvideTransientStoreKey,
ProvideMemoryStoreKey,
ProvideGenesisTxHandler,
ProvideKVStoreService,
ProvideMemoryStoreService,
ProvideTransientStoreService,
ProvideEventService,
ProvideHeaderInfoService,
ProvideCometInfoService,
ProvideBasicManager,
ProvideAddressCodec,
),
appmodule.Invoke(SetupAppBuilder),
)
}
func ProvideApp(interfaceRegistry codectypes.InterfaceRegistry) (
codec.Codec,
*codec.LegacyAmino,
*AppBuilder,
*baseapp.MsgServiceRouter,
*baseapp.GRPCQueryRouter,
appmodule.AppModule,
protodesc.Resolver,
protoregistry.MessageTypeResolver,
error,
) {
protoFiles := proto.HybridResolver
protoTypes := protoregistry.GlobalTypes
// At startup, check that all proto annotations are correct.
if err := msgservice.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())
}
amino := codec.NewLegacyAmino()
std.RegisterInterfaces(interfaceRegistry)
std.RegisterLegacyAminoCodec(amino)
cdc := codec.NewProtoCodec(interfaceRegistry)
msgServiceRouter := baseapp.NewMsgServiceRouter()
grpcQueryRouter := baseapp.NewGRPCQueryRouter()
app := &App{
storeKeys: nil,
interfaceRegistry: interfaceRegistry,
cdc: cdc,
amino: amino,
basicManager: module.BasicManager{
},
msgServiceRouter: msgServiceRouter,
grpcQueryRouter: grpcQueryRouter,
}
appBuilder := &AppBuilder{
app
}
return cdc, amino, appBuilder, msgServiceRouter, grpcQueryRouter, appModule{
app
}, protoFiles, protoTypes, nil
}
type AppInputs struct {
depinject.In
AppConfig *appv1alpha1.Config `optional:"true"`
Config *runtimev1alpha1.Module
AppBuilder *AppBuilder
Modules map[string]appmodule.AppModule
CustomModuleBasics map[string]module.AppModuleBasic `optional:"true"`
BaseAppOptions []BaseAppOption
InterfaceRegistry codectypes.InterfaceRegistry
LegacyAmino *codec.LegacyAmino
Logger log.Logger
}
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)
for name, mod := range inputs.Modules {
if customBasicMod, ok := inputs.CustomModuleBasics[name]; ok {
app.basicManager[name] = customBasicMod
customBasicMod.RegisterInterfaces(inputs.InterfaceRegistry)
customBasicMod.RegisterLegacyAminoCodec(inputs.LegacyAmino)
continue
}
coreAppModuleBasic := module.CoreAppModuleBasicAdaptor(name, mod)
app.basicManager[name] = coreAppModuleBasic
coreAppModuleBasic.RegisterInterfaces(inputs.InterfaceRegistry)
coreAppModuleBasic.RegisterLegacyAminoCodec(inputs.LegacyAmino)
}
}
func ProvideInterfaceRegistry(addressCodec address.Codec, validatorAddressCodec ValidatorAddressCodec, customGetSigners []signing.CustomGetSigner) (codectypes.InterfaceRegistry, error) {
signingOptions := signing.Options{
AddressCodec: addressCodec,
ValidatorAddressCodec: validatorAddressCodec,
}
for _, signer := range customGetSigners {
signingOptions.DefineCustomGetSigners(signer.MsgType, signer.Fn)
}
interfaceRegistry, err := codectypes.NewInterfaceRegistryWithOptions(codectypes.InterfaceRegistryOptions{
ProtoFiles: proto.HybridResolver,
SigningOptions: signingOptions,
})
if err != nil {
return nil, err
}
if err := interfaceRegistry.SigningContext().Validate(); err != nil {
return nil, err
}
return interfaceRegistry, nil
}
func registerStoreKey(wrapper *AppBuilder, key storetypes.StoreKey) {
wrapper.app.storeKeys = append(wrapper.app.storeKeys, key)
}
func storeKeyOverride(config *runtimev1alpha1.Module, moduleName string) *runtimev1alpha1.StoreKeyConfig {
for _, cfg := range config.OverrideStoreKeys {
if cfg.ModuleName == moduleName {
return cfg
}
}
return nil
}
func ProvideKVStoreKey(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) *storetypes.KVStoreKey {
if slices.Contains(config.SkipStoreKeys, key.Name()) {
return nil
}
override := storeKeyOverride(config, key.Name())
var storeKeyName string
if override != nil {
storeKeyName = override.KvStoreKey
}
else {
storeKeyName = key.Name()
}
storeKey := storetypes.NewKVStoreKey(storeKeyName)
registerStoreKey(app, storeKey)
return storeKey
}
func ProvideTransientStoreKey(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) *storetypes.TransientStoreKey {
if slices.Contains(config.SkipStoreKeys, key.Name()) {
return nil
}
storeKey := storetypes.NewTransientStoreKey(fmt.Sprintf("transient:%s", key.Name()))
registerStoreKey(app, storeKey)
return storeKey
}
func ProvideMemoryStoreKey(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder) *storetypes.MemoryStoreKey {
if slices.Contains(config.SkipStoreKeys, key.Name()) {
return nil
}
storeKey := storetypes.NewMemoryStoreKey(fmt.Sprintf("memory:%s", key.Name()))
registerStoreKey(app, storeKey)
return storeKey
}
func ProvideGenesisTxHandler(appBuilder *AppBuilder)
genesis.TxHandler {
return appBuilder.app
}
func ProvideKVStoreService(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder)
store.KVStoreService {
storeKey := ProvideKVStoreKey(config, key, app)
return kvStoreService{
key: storeKey
}
}
func ProvideMemoryStoreService(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder)
store.MemoryStoreService {
storeKey := ProvideMemoryStoreKey(config, key, app)
return memStoreService{
key: storeKey
}
}
func ProvideTransientStoreService(config *runtimev1alpha1.Module, key depinject.ModuleKey, app *AppBuilder)
store.TransientStoreService {
storeKey := ProvideTransientStoreKey(config, key, app)
return transientStoreService{
key: storeKey
}
}
func ProvideEventService()
event.Service {
return EventService{
}
}
func ProvideCometInfoService()
comet.BlockInfoService {
return cometInfoService{
}
}
func ProvideHeaderInfoService(app *AppBuilder)
header.Service {
return headerInfoService{
}
}
func ProvideBasicManager(app *AppBuilder)
module.BasicManager {
return app.app.basicManager
}
type (
// ValidatorAddressCodec is an alias for address.Codec for validator addresses.
ValidatorAddressCodec address.Codec
// ConsensusAddressCodec is an alias for address.Codec for validator consensus addresses.
ConsensusAddressCodec address.Codec
)
type AddressCodecInputs struct {
depinject.In
AuthConfig *authmodulev1.Module `optional:"true"`
StakingConfig *stakingmodulev1.Module `optional:"true"`
AddressCodecFactory func()
address.Codec `optional:"true"`
ValidatorAddressCodecFactory func()
ValidatorAddressCodec `optional:"true"`
ConsensusAddressCodecFactory func()
ConsensusAddressCodec `optional:"true"`
}
// ProvideAddressCodec provides an address.Codec to the container for any
// modules that want to do address string <> bytes conversion.
func ProvideAddressCodec(in AddressCodecInputs) (address.Codec, ValidatorAddressCodec, ConsensusAddressCodec) {
if in.AddressCodecFactory != nil && in.ValidatorAddressCodecFactory != nil && in.ConsensusAddressCodecFactory != nil {
return in.AddressCodecFactory(), in.ValidatorAddressCodecFactory(), in.ConsensusAddressCodecFactory()
}
if in.AuthConfig == nil || in.AuthConfig.Bech32Prefix == "" {
panic("auth config bech32 prefix cannot be empty if no custom address codec is provided")
}
if in.StakingConfig == nil {
in.StakingConfig = &stakingmodulev1.Module{
}
}
if in.StakingConfig.Bech32PrefixValidator == "" {
in.StakingConfig.Bech32PrefixValidator = fmt.Sprintf("%svaloper", in.AuthConfig.Bech32Prefix)
}
if in.StakingConfig.Bech32PrefixConsensus == "" {
in.StakingConfig.Bech32PrefixConsensus = fmt.Sprintf("%svalcons", in.AuthConfig.Bech32Prefix)
}
return addresscodec.NewBech32Codec(in.AuthConfig.Bech32Prefix),
addresscodec.NewBech32Codec(in.StakingConfig.Bech32PrefixValidator),
addresscodec.NewBech32Codec(in.StakingConfig.Bech32PrefixConsensus)
}