feat: support core API genesis in module manager (#14582)
Co-authored-by: Facundo Medica <facundomedica@gmail.com> Co-authored-by: Facundo Medica <14063057+facundomedica@users.noreply.github.com> Co-authored-by: Marko <marbar3778@yahoo.com>
This commit is contained in:
parent
8ab4389906
commit
aceadb0b7e
@ -5,9 +5,11 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
context "context"
|
||||
json "encoding/json"
|
||||
reflect "reflect"
|
||||
|
||||
appmodule "cosmossdk.io/core/appmodule"
|
||||
client "github.com/cosmos/cosmos-sdk/client"
|
||||
codec "github.com/cosmos/cosmos-sdk/codec"
|
||||
types "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
@ -239,3 +241,106 @@ func (mr *MockAppModuleWithAllExtensionsMockRecorder) ValidateGenesis(arg0, arg1
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleWithAllExtensions)(nil).ValidateGenesis), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// MockCoreAppModule is a mock of CoreAppModule interface.
|
||||
type MockCoreAppModule struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockCoreAppModuleMockRecorder
|
||||
}
|
||||
|
||||
// MockCoreAppModuleMockRecorder is the mock recorder for MockCoreAppModule.
|
||||
type MockCoreAppModuleMockRecorder struct {
|
||||
mock *MockCoreAppModule
|
||||
}
|
||||
|
||||
// NewMockCoreAppModule creates a new mock instance.
|
||||
func NewMockCoreAppModule(ctrl *gomock.Controller) *MockCoreAppModule {
|
||||
mock := &MockCoreAppModule{ctrl: ctrl}
|
||||
mock.recorder = &MockCoreAppModuleMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockCoreAppModule) EXPECT() *MockCoreAppModuleMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// DefaultGenesis mocks base method.
|
||||
func (m *MockCoreAppModule) DefaultGenesis(arg0 appmodule.GenesisTarget) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DefaultGenesis", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DefaultGenesis indicates an expected call of DefaultGenesis.
|
||||
func (mr *MockCoreAppModuleMockRecorder) DefaultGenesis(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultGenesis", reflect.TypeOf((*MockCoreAppModule)(nil).DefaultGenesis), arg0)
|
||||
}
|
||||
|
||||
// ExportGenesis mocks base method.
|
||||
func (m *MockCoreAppModule) ExportGenesis(arg0 context.Context, arg1 appmodule.GenesisTarget) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ExportGenesis", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ExportGenesis indicates an expected call of ExportGenesis.
|
||||
func (mr *MockCoreAppModuleMockRecorder) ExportGenesis(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExportGenesis", reflect.TypeOf((*MockCoreAppModule)(nil).ExportGenesis), arg0, arg1)
|
||||
}
|
||||
|
||||
// InitGenesis mocks base method.
|
||||
func (m *MockCoreAppModule) InitGenesis(arg0 context.Context, arg1 appmodule.GenesisSource) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InitGenesis", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// InitGenesis indicates an expected call of InitGenesis.
|
||||
func (mr *MockCoreAppModuleMockRecorder) InitGenesis(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitGenesis", reflect.TypeOf((*MockCoreAppModule)(nil).InitGenesis), arg0, arg1)
|
||||
}
|
||||
|
||||
// IsAppModule mocks base method.
|
||||
func (m *MockCoreAppModule) IsAppModule() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "IsAppModule")
|
||||
}
|
||||
|
||||
// IsAppModule indicates an expected call of IsAppModule.
|
||||
func (mr *MockCoreAppModuleMockRecorder) IsAppModule() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsAppModule", reflect.TypeOf((*MockCoreAppModule)(nil).IsAppModule))
|
||||
}
|
||||
|
||||
// IsOnePerModuleType mocks base method.
|
||||
func (m *MockCoreAppModule) IsOnePerModuleType() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "IsOnePerModuleType")
|
||||
}
|
||||
|
||||
// IsOnePerModuleType indicates an expected call of IsOnePerModuleType.
|
||||
func (mr *MockCoreAppModuleMockRecorder) IsOnePerModuleType() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsOnePerModuleType", reflect.TypeOf((*MockCoreAppModule)(nil).IsOnePerModuleType))
|
||||
}
|
||||
|
||||
// ValidateGenesis mocks base method.
|
||||
func (m *MockCoreAppModule) ValidateGenesis(arg0 appmodule.GenesisSource) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ValidateGenesis", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ValidateGenesis indicates an expected call of ValidateGenesis.
|
||||
func (mr *MockCoreAppModuleMockRecorder) ValidateGenesis(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockCoreAppModule)(nil).ValidateGenesis), arg0)
|
||||
}
|
||||
|
||||
163
types/module/core_module.go
Normal file
163
types/module/core_module.go
Normal file
@ -0,0 +1,163 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"cosmossdk.io/core/appmodule"
|
||||
"cosmossdk.io/core/genesis"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/spf13/cobra"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
var (
|
||||
_ AppModuleBasic = coreAppModuleBasicAdapator{}
|
||||
_ HasGenesis = coreAppModuleBasicAdapator{}
|
||||
)
|
||||
|
||||
// CoreAppModuleBasicAdaptor wraps the core API module as an AppModule that this version
|
||||
// of the SDK can use.
|
||||
func CoreAppModuleBasicAdaptor(name string, module appmodule.AppModule) AppModuleBasic {
|
||||
return coreAppModuleBasicAdapator{
|
||||
name: name,
|
||||
module: module,
|
||||
}
|
||||
}
|
||||
|
||||
type coreAppModuleBasicAdapator struct {
|
||||
name string
|
||||
module appmodule.AppModule
|
||||
}
|
||||
|
||||
// DefaultGenesis implements HasGenesis
|
||||
func (c coreAppModuleBasicAdapator) DefaultGenesis(codec.JSONCodec) json.RawMessage {
|
||||
if mod, ok := c.module.(appmodule.HasGenesis); ok {
|
||||
target := genesis.RawJSONTarget{}
|
||||
err := mod.DefaultGenesis(target.Target())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
res, err := target.JSON()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateGenesis implements HasGenesis
|
||||
func (c coreAppModuleBasicAdapator) ValidateGenesis(cdc codec.JSONCodec, txConfig client.TxEncodingConfig, bz json.RawMessage) error {
|
||||
if mod, ok := c.module.(appmodule.HasGenesis); ok {
|
||||
source, err := genesis.SourceFromRawJSON(bz)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := mod.ValidateGenesis(source); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExportGenesis implements HasGenesis
|
||||
func (c coreAppModuleBasicAdapator) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
|
||||
if module, ok := c.module.(appmodule.HasGenesis); ok {
|
||||
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
|
||||
target := genesis.RawJSONTarget{}
|
||||
err := module.ExportGenesis(ctx, target.Target())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rawJSON, err := target.JSON()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return rawJSON
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitGenesis implements HasGenesis
|
||||
func (c coreAppModuleBasicAdapator) InitGenesis(ctx sdk.Context, _ codec.JSONCodec, bz json.RawMessage) []abci.ValidatorUpdate {
|
||||
if module, ok := c.module.(appmodule.HasGenesis); ok {
|
||||
// core API genesis
|
||||
source, err := genesis.SourceFromRawJSON(bz)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = module.InitGenesis(ctx, source)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name implements AppModuleBasic
|
||||
func (c coreAppModuleBasicAdapator) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
// GetQueryCmd implements AppModuleBasic
|
||||
func (c coreAppModuleBasicAdapator) GetQueryCmd() *cobra.Command {
|
||||
if mod, ok := c.module.(interface {
|
||||
GetQueryCmd() *cobra.Command
|
||||
}); ok {
|
||||
return mod.GetQueryCmd()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTxCmd implements AppModuleBasic
|
||||
func (c coreAppModuleBasicAdapator) GetTxCmd() *cobra.Command {
|
||||
if mod, ok := c.module.(interface {
|
||||
GetTxCmd() *cobra.Command
|
||||
}); ok {
|
||||
return mod.GetTxCmd()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterGRPCGatewayRoutes implements AppModuleBasic
|
||||
func (c coreAppModuleBasicAdapator) RegisterGRPCGatewayRoutes(ctx client.Context, mux *runtime.ServeMux) {
|
||||
if mod, ok := c.module.(interface {
|
||||
RegisterGRPCGatewayRoutes(context client.Context, mux *runtime.ServeMux)
|
||||
}); ok {
|
||||
mod.RegisterGRPCGatewayRoutes(ctx, mux)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterInterfaces implements AppModuleBasic
|
||||
func (c coreAppModuleBasicAdapator) RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
||||
if mod, ok := c.module.(interface {
|
||||
RegisterInterfaces(registry codectypes.InterfaceRegistry)
|
||||
}); ok {
|
||||
mod.RegisterInterfaces(registry)
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterLegacyAminoCodec implements AppModuleBasic
|
||||
func (c coreAppModuleBasicAdapator) RegisterLegacyAminoCodec(amino *codec.LegacyAmino) {
|
||||
if mod, ok := c.module.(interface {
|
||||
RegisterLegacyAminoCodec(amino *codec.LegacyAmino)
|
||||
}); ok {
|
||||
mod.RegisterLegacyAminoCodec(amino)
|
||||
}
|
||||
}
|
||||
1
types/module/genesis.go
Normal file
1
types/module/genesis.go
Normal file
@ -0,0 +1 @@
|
||||
package module
|
||||
@ -1,6 +1,10 @@
|
||||
package module_test
|
||||
|
||||
import "github.com/cosmos/cosmos-sdk/types/module"
|
||||
import (
|
||||
"cosmossdk.io/core/appmodule"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
)
|
||||
|
||||
// AppModuleWithAllExtensions is solely here for the purpose of generating
|
||||
// mocks to be used in module tests.
|
||||
@ -13,3 +17,10 @@ type AppModuleWithAllExtensions interface {
|
||||
module.BeginBlockAppModule
|
||||
module.EndBlockAppModule
|
||||
}
|
||||
|
||||
// CoreAppModule is solely here for the purpose of generating
|
||||
// mocks to be used in module tests.
|
||||
type CoreAppModule interface {
|
||||
appmodule.AppModule
|
||||
appmodule.HasGenesis
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@ import (
|
||||
"sort"
|
||||
|
||||
"cosmossdk.io/core/appmodule"
|
||||
"cosmossdk.io/core/genesis"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/spf13/cobra"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
@ -43,7 +44,7 @@ import (
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
@ -52,7 +53,7 @@ import (
|
||||
type AppModuleBasic interface {
|
||||
HasName
|
||||
RegisterLegacyAminoCodec(*codec.LegacyAmino)
|
||||
RegisterInterfaces(codectypes.InterfaceRegistry)
|
||||
RegisterInterfaces(types.InterfaceRegistry)
|
||||
|
||||
// client functionality
|
||||
RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)
|
||||
@ -93,7 +94,7 @@ func (bm BasicManager) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
|
||||
}
|
||||
|
||||
// RegisterInterfaces registers all module interface types
|
||||
func (bm BasicManager) RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
||||
func (bm BasicManager) RegisterInterfaces(registry types.InterfaceRegistry) {
|
||||
for _, m := range bm {
|
||||
m.RegisterInterfaces(registry)
|
||||
}
|
||||
@ -101,21 +102,22 @@ func (bm BasicManager) RegisterInterfaces(registry codectypes.InterfaceRegistry)
|
||||
|
||||
// DefaultGenesis provides default genesis information for all modules
|
||||
func (bm BasicManager) DefaultGenesis(cdc codec.JSONCodec) map[string]json.RawMessage {
|
||||
genesis := make(map[string]json.RawMessage)
|
||||
genesisData := make(map[string]json.RawMessage)
|
||||
for _, b := range bm {
|
||||
if mod, ok := b.(HasGenesisBasics); ok {
|
||||
genesis[b.Name()] = mod.DefaultGenesis(cdc)
|
||||
genesisData[b.Name()] = mod.DefaultGenesis(cdc)
|
||||
}
|
||||
}
|
||||
|
||||
return genesis
|
||||
return genesisData
|
||||
}
|
||||
|
||||
// ValidateGenesis performs genesis state validation for all modules
|
||||
func (bm BasicManager) ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesis map[string]json.RawMessage) error {
|
||||
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, genesis[b.Name()]); err != nil {
|
||||
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@ -284,6 +286,9 @@ func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
|
||||
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,
|
||||
@ -297,6 +302,10 @@ func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
|
||||
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
|
||||
}
|
||||
|
||||
_, hasGenesis := module.(HasGenesis)
|
||||
return !hasGenesis
|
||||
})
|
||||
@ -307,6 +316,10 @@ func (m *Manager) SetOrderInitGenesis(moduleNames ...string) {
|
||||
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
|
||||
}
|
||||
|
||||
_, hasGenesis := module.(HasGenesis)
|
||||
return !hasGenesis
|
||||
})
|
||||
@ -371,9 +384,22 @@ func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData
|
||||
continue
|
||||
}
|
||||
|
||||
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = module.InitGenesis(ctx, source)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else if module, ok := mod.(HasGenesis); 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
|
||||
@ -407,7 +433,6 @@ func (m *Manager) ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec,
|
||||
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 {
|
||||
panic(err)
|
||||
@ -415,11 +440,29 @@ func (m *Manager) ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec,
|
||||
|
||||
channels := make(map[string]chan json.RawMessage)
|
||||
for _, moduleName := range modulesToExport {
|
||||
if module, ok := m.Modules[moduleName].(HasGenesis); ok {
|
||||
mod := m.Modules[moduleName]
|
||||
if module, ok := mod.(appmodule.HasGenesis); ok {
|
||||
// core API genesis
|
||||
channels[moduleName] = make(chan json.RawMessage)
|
||||
go func(module appmodule.HasGenesis, ch chan json.RawMessage) {
|
||||
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
|
||||
target := genesis.RawJSONTarget{}
|
||||
err := module.ExportGenesis(ctx, target.Target())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rawJSON, err := target.JSON()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ch <- rawJSON
|
||||
}(module, channels[moduleName])
|
||||
} else if module, ok := mod.(HasGenesis); ok {
|
||||
channels[moduleName] = make(chan json.RawMessage)
|
||||
go func(module HasGenesis, ch chan json.RawMessage) {
|
||||
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
|
||||
|
||||
ch <- module.ExportGenesis(ctx, cdc)
|
||||
}(module, channels[moduleName])
|
||||
}
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
package module_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"cosmossdk.io/core/appmodule"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -28,30 +31,51 @@ func TestBasicManager(t *testing.T) {
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
cdc := codec.NewProtoCodec(interfaceRegistry)
|
||||
|
||||
wantDefaultGenesis := map[string]json.RawMessage{"mockAppModuleBasic1": json.RawMessage(``)}
|
||||
// Test with a legacy module, a mock core module that doesn't return anything,
|
||||
// and a core module defined in this file
|
||||
expDefaultGenesis := map[string]json.RawMessage{
|
||||
"mockAppModuleBasic1": json.RawMessage(``),
|
||||
"mockCoreAppModule2": json.RawMessage(`null`),
|
||||
"mockCoreAppModule3": json.RawMessage(`{
|
||||
"someField": "someKey"
|
||||
}`),
|
||||
}
|
||||
|
||||
// legacy module
|
||||
mockAppModuleBasic1 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
|
||||
|
||||
mockAppModuleBasic1.EXPECT().Name().AnyTimes().Return("mockAppModuleBasic1")
|
||||
mockAppModuleBasic1.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(``))
|
||||
mockAppModuleBasic1.EXPECT().ValidateGenesis(gomock.Eq(cdc), gomock.Eq(nil), gomock.Eq(wantDefaultGenesis["mockAppModuleBasic1"])).Times(1).Return(errFoo)
|
||||
// Allow ValidateGenesis to be called any times because other module can fail before this one is called.
|
||||
mockAppModuleBasic1.EXPECT().ValidateGenesis(gomock.Eq(cdc), gomock.Eq(nil), gomock.Eq(expDefaultGenesis["mockAppModuleBasic1"])).AnyTimes().Return(nil)
|
||||
mockAppModuleBasic1.EXPECT().RegisterLegacyAminoCodec(gomock.Eq(legacyAmino)).Times(1)
|
||||
mockAppModuleBasic1.EXPECT().RegisterInterfaces(gomock.Eq(interfaceRegistry)).Times(1)
|
||||
mockAppModuleBasic1.EXPECT().GetTxCmd().Times(1).Return(nil)
|
||||
mockAppModuleBasic1.EXPECT().GetQueryCmd().Times(1).Return(nil)
|
||||
|
||||
mm := module.NewBasicManager(mockAppModuleBasic1)
|
||||
require.Equal(t, mm["mockAppModuleBasic1"], mockAppModuleBasic1)
|
||||
// mock core API module
|
||||
mockCoreAppModule2 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
mockCoreAppModule2.EXPECT().DefaultGenesis(gomock.Any()).AnyTimes().Return(nil)
|
||||
mockCoreAppModule2.EXPECT().ValidateGenesis(gomock.Any()).AnyTimes().Return(nil)
|
||||
mockAppModule2 := module.CoreAppModuleBasicAdaptor("mockCoreAppModule2", mockCoreAppModule2)
|
||||
|
||||
// mock core API module (but all methods are implemented)
|
||||
mockCoreAppModule3 := module.CoreAppModuleBasicAdaptor("mockCoreAppModule3", MockCoreAppModule{})
|
||||
|
||||
mm := module.NewBasicManager(mockAppModuleBasic1, mockAppModule2, mockCoreAppModule3)
|
||||
|
||||
require.Equal(t, mockAppModuleBasic1, mm["mockAppModuleBasic1"])
|
||||
require.Equal(t, mockAppModule2, mm["mockCoreAppModule2"])
|
||||
require.Equal(t, mockCoreAppModule3, mm["mockCoreAppModule3"])
|
||||
|
||||
mm.RegisterLegacyAminoCodec(legacyAmino)
|
||||
mm.RegisterInterfaces(interfaceRegistry)
|
||||
|
||||
require.Equal(t, wantDefaultGenesis, mm.DefaultGenesis(cdc))
|
||||
require.Equal(t, expDefaultGenesis, mm.DefaultGenesis(cdc))
|
||||
|
||||
var data map[string]string
|
||||
require.Equal(t, map[string]string(nil), data)
|
||||
|
||||
require.True(t, errors.Is(errFoo, mm.ValidateGenesis(cdc, nil, wantDefaultGenesis)))
|
||||
require.ErrorIs(t, mm.ValidateGenesis(cdc, nil, expDefaultGenesis), errFoo)
|
||||
|
||||
mockCmd := &cobra.Command{Use: "root"}
|
||||
mm.AddTxCommands(mockCmd)
|
||||
@ -59,7 +83,7 @@ func TestBasicManager(t *testing.T) {
|
||||
mm.AddQueryCommands(mockCmd)
|
||||
|
||||
// validate genesis returns nil
|
||||
require.Nil(t, module.NewBasicManager().ValidateGenesis(cdc, nil, wantDefaultGenesis))
|
||||
require.Nil(t, module.NewBasicManager().ValidateGenesis(cdc, nil, expDefaultGenesis))
|
||||
}
|
||||
|
||||
func TestGenesisOnlyAppModule(t *testing.T) {
|
||||
@ -79,28 +103,29 @@ func TestManagerOrderSetters(t *testing.T) {
|
||||
t.Cleanup(mockCtrl.Finish)
|
||||
mockAppModule1 := mock.NewMockAppModule(mockCtrl)
|
||||
mockAppModule2 := mock.NewMockAppModule(mockCtrl)
|
||||
mockAppModule3 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
|
||||
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
|
||||
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
|
||||
mm := module.NewManager(mockAppModule1, mockAppModule2)
|
||||
mm := module.NewManager(mockAppModule1, mockAppModule2, module.CoreAppModuleBasicAdaptor("module3", mockAppModule3))
|
||||
require.NotNil(t, mm)
|
||||
require.Equal(t, 2, len(mm.Modules))
|
||||
require.Equal(t, 3, len(mm.Modules))
|
||||
|
||||
require.Equal(t, []string{"module1", "module2"}, mm.OrderInitGenesis)
|
||||
mm.SetOrderInitGenesis("module2", "module1")
|
||||
require.Equal(t, []string{"module2", "module1"}, mm.OrderInitGenesis)
|
||||
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderInitGenesis)
|
||||
mm.SetOrderInitGenesis("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderInitGenesis)
|
||||
|
||||
require.Equal(t, []string{"module1", "module2"}, mm.OrderExportGenesis)
|
||||
mm.SetOrderExportGenesis("module2", "module1")
|
||||
require.Equal(t, []string{"module2", "module1"}, mm.OrderExportGenesis)
|
||||
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderExportGenesis)
|
||||
mm.SetOrderExportGenesis("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderExportGenesis)
|
||||
|
||||
require.Equal(t, []string{"module1", "module2"}, mm.OrderBeginBlockers)
|
||||
mm.SetOrderBeginBlockers("module2", "module1")
|
||||
require.Equal(t, []string{"module2", "module1"}, mm.OrderBeginBlockers)
|
||||
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderBeginBlockers)
|
||||
mm.SetOrderBeginBlockers("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderBeginBlockers)
|
||||
|
||||
require.Equal(t, []string{"module1", "module2"}, mm.OrderEndBlockers)
|
||||
mm.SetOrderEndBlockers("module2", "module1")
|
||||
require.Equal(t, []string{"module2", "module1"}, mm.OrderEndBlockers)
|
||||
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderEndBlockers)
|
||||
mm.SetOrderEndBlockers("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderEndBlockers)
|
||||
}
|
||||
|
||||
func TestManager_RegisterInvariants(t *testing.T) {
|
||||
@ -109,11 +134,13 @@ func TestManager_RegisterInvariants(t *testing.T) {
|
||||
|
||||
mockAppModule1 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
|
||||
mockAppModule2 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
|
||||
mockAppModule3 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
|
||||
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
|
||||
mm := module.NewManager(mockAppModule1, mockAppModule2)
|
||||
// TODO: This is not working for Core API modules yet
|
||||
mm := module.NewManager(mockAppModule1, mockAppModule2, module.CoreAppModuleBasicAdaptor("mockAppModule3", mockAppModule3))
|
||||
require.NotNil(t, mm)
|
||||
require.Equal(t, 2, len(mm.Modules))
|
||||
require.Equal(t, 3, len(mm.Modules))
|
||||
|
||||
// test RegisterInvariants
|
||||
mockInvariantRegistry := mock.NewMockInvariantRegistry(mockCtrl)
|
||||
@ -128,11 +155,13 @@ func TestManager_RegisterQueryServices(t *testing.T) {
|
||||
|
||||
mockAppModule1 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
|
||||
mockAppModule2 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
|
||||
mockAppModule3 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
|
||||
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
|
||||
mm := module.NewManager(mockAppModule1, mockAppModule2)
|
||||
// TODO: This is not working for Core API modules yet
|
||||
mm := module.NewManager(mockAppModule1, mockAppModule2, module.CoreAppModuleBasicAdaptor("mockAppModule3", mockAppModule3))
|
||||
require.NotNil(t, mm)
|
||||
require.Equal(t, 2, len(mm.Modules))
|
||||
require.Equal(t, 3, len(mm.Modules))
|
||||
|
||||
msgRouter := mock.NewMockServer(mockCtrl)
|
||||
queryRouter := mock.NewMockServer(mockCtrl)
|
||||
@ -151,11 +180,12 @@ func TestManager_InitGenesis(t *testing.T) {
|
||||
|
||||
mockAppModule1 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
|
||||
mockAppModule2 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
|
||||
mockAppModule3 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
|
||||
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
|
||||
mm := module.NewManager(mockAppModule1, mockAppModule2)
|
||||
mm := module.NewManager(mockAppModule1, mockAppModule2, module.CoreAppModuleBasicAdaptor("module3", mockAppModule3))
|
||||
require.NotNil(t, mm)
|
||||
require.Equal(t, 2, len(mm.Modules))
|
||||
require.Equal(t, 3, len(mm.Modules))
|
||||
|
||||
ctx := sdk.NewContext(nil, tmproto.Header{}, false, log.NewNopLogger())
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
@ -170,10 +200,19 @@ func TestManager_InitGenesis(t *testing.T) {
|
||||
genesisData = map[string]json.RawMessage{
|
||||
"module1": json.RawMessage(`{"key": "value"}`),
|
||||
"module2": json.RawMessage(`{"key": "value"}`),
|
||||
"module3": json.RawMessage(`{"key": "value"}`),
|
||||
}
|
||||
|
||||
// panic because more than one module returns validator set updates
|
||||
mockAppModule1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module1"])).Times(1).Return([]abci.ValidatorUpdate{{}})
|
||||
mockAppModule2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module2"])).Times(1).Return([]abci.ValidatorUpdate{{}})
|
||||
require.Panics(t, func() { mm.InitGenesis(ctx, cdc, genesisData) })
|
||||
|
||||
// happy path
|
||||
mockAppModule1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module1"])).Times(1).Return([]abci.ValidatorUpdate{{}})
|
||||
mockAppModule2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module2"])).Times(1).Return([]abci.ValidatorUpdate{})
|
||||
mockAppModule3.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Any()).Times(1).Return(nil)
|
||||
mm.InitGenesis(ctx, cdc, genesisData)
|
||||
}
|
||||
|
||||
func TestManager_ExportGenesis(t *testing.T) {
|
||||
@ -182,11 +221,12 @@ func TestManager_ExportGenesis(t *testing.T) {
|
||||
|
||||
mockAppModule1 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
|
||||
mockAppModule2 := mock.NewMockAppModuleWithAllExtensions(mockCtrl)
|
||||
mockCoreAppModule := MockCoreAppModule{}
|
||||
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
|
||||
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
|
||||
mm := module.NewManager(mockAppModule1, mockAppModule2)
|
||||
mm := module.NewManager(mockAppModule1, mockAppModule2, module.CoreAppModuleBasicAdaptor("mockCoreAppModule", mockCoreAppModule))
|
||||
require.NotNil(t, mm)
|
||||
require.Equal(t, 2, len(mm.Modules))
|
||||
require.Equal(t, 3, len(mm.Modules))
|
||||
|
||||
ctx := sdk.NewContext(nil, tmproto.Header{}, false, log.NewNopLogger())
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
@ -197,7 +237,11 @@ func TestManager_ExportGenesis(t *testing.T) {
|
||||
want := map[string]json.RawMessage{
|
||||
"module1": json.RawMessage(`{"key1": "value1"}`),
|
||||
"module2": json.RawMessage(`{"key2": "value2"}`),
|
||||
"mockCoreAppModule": json.RawMessage(`{
|
||||
"someField": "someKey"
|
||||
}`),
|
||||
}
|
||||
|
||||
require.Equal(t, want, mm.ExportGenesis(ctx, cdc))
|
||||
require.Equal(t, want, mm.ExportGenesisForModules(ctx, cdc, []string{}))
|
||||
require.Equal(t, map[string]json.RawMessage{"module1": json.RawMessage(`{"key1": "value1"}`)}, mm.ExportGenesisForModules(ctx, cdc, []string{"module1"}))
|
||||
@ -251,3 +295,151 @@ func TestManager_EndBlock(t *testing.T) {
|
||||
mockAppModule2.EXPECT().EndBlock(gomock.Any(), gomock.Eq(req)).Times(1).Return([]abci.ValidatorUpdate{{}})
|
||||
require.Panics(t, func() { mm.EndBlock(sdk.Context{}, req) })
|
||||
}
|
||||
|
||||
// Core API exclusive tests
|
||||
func TestCoreAPIManager(t *testing.T) {
|
||||
mockCtrl := gomock.NewController(t)
|
||||
module1 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
module2 := MockCoreAppModule{}
|
||||
mm := module.NewManagerFromMap(map[string]appmodule.AppModule{
|
||||
"module1": module1,
|
||||
"module2": module2,
|
||||
})
|
||||
|
||||
require.NotNil(t, mm)
|
||||
require.Equal(t, 2, len(mm.Modules))
|
||||
require.Equal(t, module1, mm.Modules["module1"])
|
||||
require.Equal(t, module2, mm.Modules["module2"])
|
||||
}
|
||||
|
||||
func TestCoreAPIManager_InitGenesis(t *testing.T) {
|
||||
mockCtrl := gomock.NewController(t)
|
||||
t.Cleanup(mockCtrl.Finish)
|
||||
|
||||
mockAppModule1 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
mm := module.NewManagerFromMap(map[string]appmodule.AppModule{"module1": mockAppModule1})
|
||||
require.NotNil(t, mm)
|
||||
require.Equal(t, 1, len(mm.Modules))
|
||||
|
||||
ctx := sdk.NewContext(nil, tmproto.Header{}, false, log.NewNopLogger())
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
cdc := codec.NewProtoCodec(interfaceRegistry)
|
||||
genesisData := map[string]json.RawMessage{"module1": json.RawMessage(`{"key": "value"}`)}
|
||||
|
||||
// this should panic since the validator set is empty even after init genesis
|
||||
mockAppModule1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Any()).Times(1).Return(nil)
|
||||
require.Panics(t, func() { mm.InitGenesis(ctx, cdc, genesisData) })
|
||||
|
||||
// TODO: add happy path test. We are not returning any validator updates
|
||||
}
|
||||
|
||||
func TestCoreAPIManager_ExportGenesis(t *testing.T) {
|
||||
mockAppModule1 := MockCoreAppModule{}
|
||||
mockAppModule2 := MockCoreAppModule{}
|
||||
mm := module.NewManagerFromMap(map[string]appmodule.AppModule{
|
||||
"module1": mockAppModule1,
|
||||
"module2": mockAppModule2,
|
||||
})
|
||||
require.NotNil(t, mm)
|
||||
require.Equal(t, 2, len(mm.Modules))
|
||||
|
||||
ctx := sdk.NewContext(nil, tmproto.Header{}, false, log.NewNopLogger())
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
cdc := codec.NewProtoCodec(interfaceRegistry)
|
||||
want := map[string]json.RawMessage{
|
||||
"module1": json.RawMessage(`{
|
||||
"someField": "someKey"
|
||||
}`),
|
||||
"module2": json.RawMessage(`{
|
||||
"someField": "someKey"
|
||||
}`),
|
||||
}
|
||||
|
||||
require.Equal(t, want, mm.ExportGenesis(ctx, cdc))
|
||||
require.Equal(t, want, mm.ExportGenesisForModules(ctx, cdc, []string{}))
|
||||
require.Equal(t, map[string]json.RawMessage{"module1": want["module1"]}, mm.ExportGenesisForModules(ctx, cdc, []string{"module1"}))
|
||||
require.NotEqual(t, map[string]json.RawMessage{"module1": want["module1"]}, mm.ExportGenesisForModules(ctx, cdc, []string{"module2"}))
|
||||
|
||||
require.Panics(t, func() {
|
||||
mm.ExportGenesisForModules(ctx, cdc, []string{"module1", "modulefoo"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestCoreAPIManagerOrderSetters(t *testing.T) {
|
||||
mockCtrl := gomock.NewController(t)
|
||||
t.Cleanup(mockCtrl.Finish)
|
||||
mockAppModule1 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
mockAppModule2 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
mockAppModule3 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
|
||||
mm := module.NewManagerFromMap(
|
||||
map[string]appmodule.AppModule{
|
||||
"module1": mockAppModule1,
|
||||
"module2": mockAppModule2,
|
||||
"module3": mockAppModule3,
|
||||
})
|
||||
require.NotNil(t, mm)
|
||||
require.Equal(t, 3, len(mm.Modules))
|
||||
|
||||
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderInitGenesis)
|
||||
mm.SetOrderInitGenesis("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderInitGenesis)
|
||||
|
||||
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderExportGenesis)
|
||||
mm.SetOrderExportGenesis("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderExportGenesis)
|
||||
|
||||
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderBeginBlockers)
|
||||
mm.SetOrderBeginBlockers("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderBeginBlockers)
|
||||
|
||||
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderEndBlockers)
|
||||
mm.SetOrderEndBlockers("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderEndBlockers)
|
||||
}
|
||||
|
||||
// MockCoreAppModule allows us to test functions like DefaultGenesis
|
||||
type MockCoreAppModule struct{}
|
||||
|
||||
func (MockCoreAppModule) IsOnePerModuleType() {}
|
||||
func (MockCoreAppModule) IsAppModule() {}
|
||||
func (MockCoreAppModule) DefaultGenesis(target appmodule.GenesisTarget) error {
|
||||
someFieldWriter, err := target("someField")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
someFieldWriter.Write([]byte(`"someKey"`))
|
||||
return someFieldWriter.Close()
|
||||
}
|
||||
|
||||
func (MockCoreAppModule) ValidateGenesis(src appmodule.GenesisSource) error {
|
||||
rdr, err := src("someField")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err := io.ReadAll(rdr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// this check will always fail, but it's just an example
|
||||
if string(data) != `"dummy validation"` {
|
||||
return errFoo
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (MockCoreAppModule) InitGenesis(context.Context, appmodule.GenesisSource) error { return nil }
|
||||
func (MockCoreAppModule) ExportGenesis(ctx context.Context, target appmodule.GenesisTarget) error {
|
||||
wrt, err := target("someField")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wrt.Write([]byte(`"someKey"`))
|
||||
return wrt.Close()
|
||||
}
|
||||
|
||||
var (
|
||||
_ appmodule.AppModule = MockCoreAppModule{}
|
||||
_ appmodule.HasGenesis = MockCoreAppModule{}
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user