refactor!: migrate to core appmodule.AppModule extension interfaces (#13794)

This commit is contained in:
Aaron Craelius
2022-11-14 21:23:55 +00:00
committed by GitHub
parent 14c582f30e
commit ec27c5384b
34 changed files with 909 additions and 490 deletions
+15
View File
@@ -0,0 +1,15 @@
package module_test
import "github.com/cosmos/cosmos-sdk/types/module"
// AppModuleWithAllExtensions is solely here for the purpose of generating
// mocks to be used in module tests.
type AppModuleWithAllExtensions interface {
module.AppModule
module.HasServices
module.HasGenesis
module.HasInvariants
module.HasConsensusVersion
module.BeginBlockAppModule
module.EndBlockAppModule
}
+104 -32
View File
@@ -33,6 +33,7 @@ import (
"fmt"
"sort"
"cosmossdk.io/core/appmodule"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
@@ -47,12 +48,11 @@ import (
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
Name() string
HasName
RegisterLegacyAminoCodec(*codec.LegacyAmino)
RegisterInterfaces(codectypes.InterfaceRegistry)
DefaultGenesis(codec.JSONCodec) json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage) error
HasGenesisBasics
// client functionality
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
@@ -60,6 +60,19 @@ type AppModuleBasic interface {
GetQueryCmd() *cobra.Command
}
// 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
@@ -143,21 +156,36 @@ func (bm BasicManager) AddQueryCommands(rootQueryCmd *cobra.Command) {
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
HasGenesis
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(sdk.Context, codec.JSONCodec) json.RawMessage
}
// AppModule is the standard form for an application module
// AppModule is the form for an application module. Most of
// its functionality has been moved to extension interfaces.
type AppModule interface {
AppModuleGenesis
AppModuleBasic
}
// registers
// HasInvariants is the interface for registering invariants.
type HasInvariants interface {
// RegisterInvariants registers module invariants.
RegisterInvariants(sdk.InvariantRegistry)
}
// RegisterServices allows a module to register services
// 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
@@ -183,12 +211,18 @@ type GenesisOnlyAppModule struct {
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis) AppModule {
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) {}
@@ -212,7 +246,7 @@ func (GenesisOnlyAppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []ab
// 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]AppModule
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
@@ -220,9 +254,9 @@ type Manager struct {
OrderMigrations []string
}
// NewManager creates a new Manager object
// NewManager creates a new Manager object.
func NewManager(modules ...AppModule) *Manager {
moduleMap := make(map[string]AppModule)
moduleMap := make(map[string]interface{})
modulesStr := make([]string, 0, len(modules))
for _, module := range modules {
moduleMap[module.Name()] = module
@@ -238,6 +272,25 @@ func NewManager(modules ...AppModule) *Manager {
}
}
// 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)
}
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// SetOrderInitGenesis sets the order of init genesis calls
func (m *Manager) SetOrderInitGenesis(moduleNames ...string) {
m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames)
@@ -273,7 +326,9 @@ func (m *Manager) SetOrderMigrations(moduleNames ...string) {
func (m *Manager) RegisterInvariants(ir sdk.InvariantRegistry) {
modules := maps.Values(m.Modules)
for _, module := range modules {
module.RegisterInvariants(ir)
if module, ok := module.(HasInvariants); ok {
module.RegisterInvariants(ir)
}
}
}
@@ -281,7 +336,9 @@ func (m *Manager) RegisterInvariants(ir sdk.InvariantRegistry) {
func (m *Manager) RegisterServices(cfg Configurator) {
modules := maps.Values(m.Modules)
for _, module := range modules {
module.RegisterServices(cfg)
if module, ok := module.(HasServices); ok {
module.RegisterServices(cfg)
}
}
}
@@ -295,17 +352,20 @@ func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData
if genesisData[moduleName] == nil {
continue
}
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := m.Modules[moduleName].InitGenesis(ctx, cdc, genesisData[moduleName])
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", 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 {
panic("validator InitGenesis updates already set by a previous module")
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 {
panic("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
validatorUpdates = moduleValUpdates
}
}
@@ -329,7 +389,9 @@ func (m *Manager) ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec,
genesisData := make(map[string]json.RawMessage)
if len(modulesToExport) == 0 {
for _, moduleName := range m.OrderExportGenesis {
genesisData[moduleName] = m.Modules[moduleName].ExportGenesis(ctx, cdc)
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
genesisData[moduleName] = module.ExportGenesis(ctx, cdc)
}
}
return genesisData
@@ -341,7 +403,9 @@ func (m *Manager) ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec,
}
for _, moduleName := range modulesToExport {
genesisData[moduleName] = m.Modules[moduleName].ExportGenesis(ctx, cdc)
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
genesisData[moduleName] = module.ExportGenesis(ctx, cdc)
}
}
return genesisData
@@ -450,7 +514,10 @@ func (m Manager) RunMigrations(ctx sdk.Context, cfg Configurator, fromVM Version
for _, moduleName := range modules {
module := m.Modules[moduleName]
fromVersion, exists := fromVM[moduleName]
toVersion := module.ConsensusVersion()
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.
@@ -467,11 +534,13 @@ func (m Manager) RunMigrations(ctx sdk.Context, cfg Configurator, fromVM Version
}
} else {
ctx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName))
moduleValUpdates := module.InitGenesis(ctx, 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, sdkerrors.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
moduleValUpdates := module.InitGenesis(ctx, 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, sdkerrors.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module")
}
}
}
@@ -533,9 +602,12 @@ func (m *Manager) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) abci.Respo
// GetVersionMap gets consensus version from all modules
func (m *Manager) GetVersionMap() VersionMap {
vermap := make(VersionMap)
for _, v := range m.Modules {
version := v.ConsensusVersion()
name := v.Name()
for name, v := range m.Modules {
version := uint64(0)
if v, ok := v.(HasConsensusVersion); ok {
version = v.ConsensusVersion()
}
name := name
vermap[name] = version
}
+2 -2
View File
@@ -17,7 +17,7 @@ type TestSuite struct {
func (s TestSuite) TestAssertNoForgottenModules() {
m := Manager{
Modules: map[string]AppModule{"a": nil, "b": nil},
Modules: map[string]interface{}{"a": nil, "b": nil},
}
tcs := []struct {
name string
@@ -39,7 +39,7 @@ func (s TestSuite) TestAssertNoForgottenModules() {
func (s TestSuite) TestModuleNames() {
m := Manager{
Modules: map[string]AppModule{"a": nil, "b": nil},
Modules: map[string]interface{}{"a": nil, "b": nil},
}
ms := m.ModuleNames()
sort.Strings(ms)
+8 -8
View File
@@ -107,8 +107,8 @@ func TestManager_RegisterInvariants(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockAppModule1 := mock.NewMockAppModule(mockCtrl)
mockAppModule2 := mock.NewMockAppModule(mockCtrl)
mockAppModule1 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
mockAppModule2 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
mm := module.NewManager(mockAppModule1, mockAppModule2)
@@ -126,8 +126,8 @@ func TestManager_RegisterQueryServices(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockAppModule1 := mock.NewMockAppModule(mockCtrl)
mockAppModule2 := mock.NewMockAppModule(mockCtrl)
mockAppModule1 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
mockAppModule2 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
mm := module.NewManager(mockAppModule1, mockAppModule2)
@@ -149,8 +149,8 @@ func TestManager_InitGenesis(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockAppModule1 := mock.NewMockAppModule(mockCtrl)
mockAppModule2 := mock.NewMockAppModule(mockCtrl)
mockAppModule1 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
mockAppModule2 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
mm := module.NewManager(mockAppModule1, mockAppModule2)
@@ -180,8 +180,8 @@ func TestManager_ExportGenesis(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockAppModule1 := mock.NewMockAppModule(mockCtrl)
mockAppModule2 := mock.NewMockAppModule(mockCtrl)
mockAppModule1 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
mockAppModule2 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
mm := module.NewManager(mockAppModule1, mockAppModule2)
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"time"
sdkmath "cosmossdk.io/math"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/simulation"
@@ -51,7 +52,7 @@ func NewSimulationManager(modules ...AppModuleSimulation) *SimulationManager {
// with the same moduleName.
// Then it attempts to cast every provided AppModule into an AppModuleSimulation.
// If the cast succeeds, its included, otherwise it is excluded.
func NewSimulationManagerFromAppModules(modules map[string]AppModule, overrideModules map[string]AppModuleSimulation) *SimulationManager {
func NewSimulationManagerFromAppModules(modules map[string]interface{}, overrideModules map[string]AppModuleSimulation) *SimulationManager {
simModules := []AppModuleSimulation{}
appModuleNamesSorted := make([]string, 0, len(modules))
for moduleName := range modules {