refactor(modules): adopt appmodulev2.Hasgenesis (#19627)

Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
Marko
2024-03-11 10:22:16 +00:00
committed by GitHub
co-authored by Julien Robert
parent d4e52069f7
commit d2e40963ed
72 changed files with 686 additions and 694 deletions
+36 -16
View File
@@ -43,8 +43,8 @@ type coreAppModuleAdaptor struct {
}
// DefaultGenesis implements HasGenesis
func (c coreAppModuleAdaptor) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
if mod, ok := c.module.(appmodule.HasGenesis); ok {
func (c coreAppModuleAdaptor) DefaultGenesis() json.RawMessage {
if mod, ok := c.module.(appmodule.HasGenesisAuto); ok {
target := genesis.RawJSONTarget{}
err := mod.DefaultGenesis(target.Target())
if err != nil {
@@ -60,15 +60,19 @@ func (c coreAppModuleAdaptor) DefaultGenesis(cdc codec.JSONCodec) json.RawMessag
}
if mod, ok := c.module.(HasGenesisBasics); ok {
return mod.DefaultGenesis(cdc)
return mod.DefaultGenesis()
}
if mod, ok := c.module.(HasGenesis); ok {
return mod.DefaultGenesis()
}
return nil
}
// ValidateGenesis implements HasGenesis
func (c coreAppModuleAdaptor) ValidateGenesis(cdc codec.JSONCodec, txConfig client.TxEncodingConfig, bz json.RawMessage) error {
if mod, ok := c.module.(appmodule.HasGenesis); ok {
func (c coreAppModuleAdaptor) ValidateGenesis(bz json.RawMessage) error {
if mod, ok := c.module.(appmodule.HasGenesisAuto); ok {
source, err := genesis.SourceFromRawJSON(bz)
if err != nil {
return err
@@ -80,15 +84,19 @@ func (c coreAppModuleAdaptor) ValidateGenesis(cdc codec.JSONCodec, txConfig clie
}
if mod, ok := c.module.(HasGenesisBasics); ok {
return mod.ValidateGenesis(cdc, txConfig, bz)
return mod.ValidateGenesis(bz)
}
if mod, ok := c.module.(HasGenesis); ok {
return mod.ValidateGenesis(bz)
}
return nil
}
// ExportGenesis implements HasGenesis
func (c coreAppModuleAdaptor) ExportGenesis(ctx context.Context, cdc codec.JSONCodec) json.RawMessage {
if module, ok := c.module.(appmodule.HasGenesis); ok {
func (c coreAppModuleAdaptor) ExportGenesis(ctx context.Context) json.RawMessage {
if module, ok := c.module.(appmodule.HasGenesisAuto); ok {
ctx := sdk.UnwrapSDKContext(ctx).WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{}
err := module.ExportGenesis(ctx, target.Target())
@@ -104,16 +112,24 @@ func (c coreAppModuleAdaptor) ExportGenesis(ctx context.Context, cdc codec.JSONC
return rawJSON
}
if mod, ok := c.module.(HasABCIGenesis); ok {
return mod.ExportGenesis(ctx)
}
if mod, ok := c.module.(HasGenesis); ok {
return mod.ExportGenesis(ctx, cdc)
eg, err := mod.ExportGenesis(ctx)
if err != nil {
panic(err)
}
return eg
}
return nil
}
// InitGenesis implements HasGenesis
func (c coreAppModuleAdaptor) InitGenesis(ctx context.Context, cdc codec.JSONCodec, bz json.RawMessage) []abci.ValidatorUpdate {
if module, ok := c.module.(appmodule.HasGenesis); ok {
func (c coreAppModuleAdaptor) InitGenesis(ctx context.Context, bz json.RawMessage) []abci.ValidatorUpdate {
if module, ok := c.module.(appmodule.HasGenesisAuto); ok {
// core API genesis
source, err := genesis.SourceFromRawJSON(bz)
if err != nil {
@@ -126,12 +142,16 @@ func (c coreAppModuleAdaptor) InitGenesis(ctx context.Context, cdc codec.JSONCod
}
}
if mod, ok := c.module.(HasGenesis); ok {
mod.InitGenesis(ctx, cdc, bz)
return nil
}
if mod, ok := c.module.(HasABCIGenesis); ok {
return mod.InitGenesis(ctx, cdc, bz)
return mod.InitGenesis(ctx, bz)
}
if mod, ok := c.module.(HasGenesis); ok {
err := mod.InitGenesis(ctx, bz)
if err != nil {
panic(err)
}
}
return nil
}
+6 -5
View File
@@ -2,6 +2,7 @@ package module_test
import (
"cosmossdk.io/core/appmodule"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"github.com/cosmos/cosmos-sdk/types/module"
)
@@ -11,7 +12,7 @@ import (
type AppModuleWithAllExtensions interface {
module.AppModule
module.HasServices
module.HasGenesis
appmodulev2.HasGenesis
module.HasInvariants
module.HasConsensusVersion
module.HasABCIEndBlock
@@ -32,10 +33,10 @@ type AppModuleWithAllExtensionsABCI interface {
// CoreAppModule is solely here for the purpose of generating
// mocks to be used in module tests.
type CoreAppModule interface {
appmodule.AppModule
appmodule.HasGenesis
appmodule.HasBeginBlocker
appmodule.HasEndBlocker
appmodulev2.AppModule
appmodule.HasGenesisAuto
appmodulev2.HasBeginBlocker
appmodulev2.HasEndBlocker
appmodule.HasPrecommit
appmodule.HasPrepareCheckState
}
+40 -33
View File
@@ -32,6 +32,7 @@ import (
"golang.org/x/exp/maps"
"cosmossdk.io/core/appmodule"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/genesis"
"cosmossdk.io/core/registry"
errorsmod "cosmossdk.io/errors"
@@ -45,8 +46,9 @@ import (
// Deprecated: use the embed extension interfaces instead, when needed.
type AppModuleBasic interface {
appmodulev2.HasRegisterInterfaces
HasName
HasRegisterInterfaces
HasGRPCGateway
HasAminoCodec
}
@@ -55,10 +57,10 @@ type AppModuleBasic interface {
// its functionality has been moved to extension interfaces.
// Deprecated: use appmodule.AppModule with a combination of extension interfaces interfaces instead.
type AppModule interface {
appmodule.AppModule
HasName
HasRegisterInterfaces
appmodulev2.AppModule
appmodulev2.HasRegisterInterfaces
}
// HasName allows the module to provide its own name for legacy purposes.
@@ -72,8 +74,8 @@ type HasName interface {
type HasGenesisBasics interface {
HasName
DefaultGenesis(codec.JSONCodec) json.RawMessage
ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage) error
DefaultGenesis() json.RawMessage
ValidateGenesis(json.RawMessage) error
}
// HasAminoCodec is the interface for modules that have amino codec registration.
@@ -83,7 +85,7 @@ type HasAminoCodec interface {
}
// HasRegisterInterfaces is the interface for modules to register their msg types.
type HasRegisterInterfaces appmodule.HasRegisterInterfaces
type HasRegisterInterfaces appmodulev2.HasRegisterInterfaces
// HasGRPCGateway is the interface for modules to register their gRPC gateway routes.
type HasGRPCGateway interface {
@@ -91,17 +93,13 @@ type HasGRPCGateway interface {
}
// HasGenesis is the extension interface for stateful genesis methods.
type HasGenesis interface {
HasGenesisBasics
InitGenesis(context.Context, codec.JSONCodec, json.RawMessage)
ExportGenesis(context.Context, codec.JSONCodec) json.RawMessage
}
type HasGenesis = appmodulev2.HasGenesis
// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates.
type HasABCIGenesis interface {
HasGenesisBasics
InitGenesis(context.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(context.Context, codec.JSONCodec) json.RawMessage
InitGenesis(context.Context, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(context.Context) json.RawMessage
}
// HasInvariants is the interface for registering invariants.
@@ -207,7 +205,7 @@ 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 {
if _, hasGenesis := module.(appmodule.HasGenesisAuto); hasGenesis {
return !hasGenesis
}
@@ -225,7 +223,7 @@ 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 {
if _, hasGenesis := module.(appmodule.HasGenesisAuto); hasGenesis {
return !hasGenesis
}
@@ -324,11 +322,11 @@ func (m *Manager) RegisterInterfaces(registry registry.LegacyRegistry) {
}
// DefaultGenesis provides default genesis information for all modules
func (m *Manager) DefaultGenesis(cdc codec.JSONCodec) map[string]json.RawMessage {
func (m *Manager) DefaultGenesis() map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, b := range m.Modules {
if mod, ok := b.(HasGenesisBasics); ok {
genesisData[mod.Name()] = mod.DefaultGenesis(cdc)
genesisData[mod.Name()] = mod.DefaultGenesis()
} else if mod, ok := b.(HasName); ok {
genesisData[mod.Name()] = []byte("{}")
}
@@ -338,11 +336,11 @@ func (m *Manager) DefaultGenesis(cdc codec.JSONCodec) map[string]json.RawMessage
}
// ValidateGenesis performs genesis state validation for all modules
func (m *Manager) ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage) error {
func (m *Manager) ValidateGenesis(genesisData map[string]json.RawMessage) error {
for _, b := range m.Modules {
// first check if the module is an adapted Core API Module
if mod, ok := b.(HasGenesisBasics); ok {
if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[mod.Name()]); err != nil {
if err := mod.ValidateGenesis(genesisData[mod.Name()]); err != nil {
return err
}
}
@@ -427,7 +425,7 @@ func (m *Manager) RegisterServices(cfg Configurator) error {
// 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) {
func (m *Manager) InitGenesis(ctx sdk.Context, _ 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 {
@@ -437,7 +435,7 @@ func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData
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 {
if module, ok := mod.(appmodule.HasGenesisAuto); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
// core API genesis
source, err := genesis.SourceFromRawJSON(genesisData[moduleName])
@@ -451,10 +449,12 @@ func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData
}
} else if module, ok := mod.(HasGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
module.InitGenesis(ctx, cdc, genesisData[moduleName])
if err := module.InitGenesis(ctx, genesisData[moduleName]); err != nil {
return &abci.ResponseInitChain{}, err
}
} else if module, ok := mod.(HasABCIGenesis); ok {
ctx.Logger().Debug("running initialization for module", "module", moduleName)
moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName])
moduleValUpdates := module.InitGenesis(ctx, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
@@ -478,12 +478,12 @@ func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData
}
// 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{})
func (m *Manager) ExportGenesis(ctx sdk.Context) (map[string]json.RawMessage, error) {
return m.ExportGenesisForModules(ctx, []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) {
func (m *Manager) ExportGenesisForModules(ctx sdk.Context, modulesToExport []string) (map[string]json.RawMessage, error) {
if len(modulesToExport) == 0 {
modulesToExport = m.OrderExportGenesis
}
@@ -500,10 +500,10 @@ func (m *Manager) ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec,
channels := make(map[string]chan genesisResult)
for _, moduleName := range modulesToExport {
mod := m.Modules[moduleName]
if module, ok := mod.(appmodule.HasGenesis); ok {
if module, ok := mod.(appmodule.HasGenesisAuto); ok {
// core API genesis
channels[moduleName] = make(chan genesisResult)
go func(module appmodule.HasGenesis, ch chan genesisResult) {
go func(module appmodule.HasGenesisAuto, ch chan genesisResult) {
ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions
target := genesis.RawJSONTarget{}
err := module.ExportGenesis(ctx, target.Target())
@@ -524,13 +524,18 @@ func (m *Manager) ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec,
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}
jm, err := module.ExportGenesis(ctx)
if err != nil {
ch <- genesisResult{nil, err}
return
}
ch <- genesisResult{jm, 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}
ch <- genesisResult{module.ExportGenesis(ctx), nil}
}(module, channels[moduleName])
}
}
@@ -678,10 +683,12 @@ func (m Manager) RunMigrations(ctx context.Context, cfg Configurator, fromVM Ver
} 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 err := module.InitGenesis(sdkCtx, module.DefaultGenesis()); err != nil {
return nil, err
}
}
if module, ok := m.Modules[moduleName].(HasABCIGenesis); ok {
moduleValUpdates := module.InitGenesis(sdkCtx, c.cdc, module.DefaultGenesis(c.cdc))
moduleValUpdates := module.InitGenesis(sdkCtx, module.DefaultGenesis())
// The module manager assumes only one module will update the
// validator set, and it can't be a new module.
if len(moduleValUpdates) > 0 {
+20 -24
View File
@@ -177,7 +177,7 @@ func TestManager_InitGenesis(t *testing.T) {
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.Eq(cdc), gomock.Eq(genesisData["module1"])).Times(1)
mockAppModule1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(genesisData["module1"])).Times(1)
_, err := mm.InitGenesis(ctx, cdc, genesisData)
require.ErrorContains(t, err, "validator set is empty after InitGenesis")
@@ -194,16 +194,16 @@ func TestManager_InitGenesis(t *testing.T) {
mockAppModuleABCI2.EXPECT().Name().Times(2).Return("module2")
mmABCI := module.NewManager(mockAppModuleABCI1, mockAppModuleABCI2)
// panic because more than one module returns validator set updates
mockAppModuleABCI1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module1"])).Times(1).Return([]abci.ValidatorUpdate{{}})
mockAppModuleABCI2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(cdc), gomock.Eq(genesisData["module2"])).Times(1).Return([]abci.ValidatorUpdate{{}})
mockAppModuleABCI1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(genesisData["module1"])).Times(1).Return([]abci.ValidatorUpdate{{}})
mockAppModuleABCI2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(genesisData["module2"])).Times(1).Return([]abci.ValidatorUpdate{{}})
_, err = mmABCI.InitGenesis(ctx, cdc, genesisData)
require.ErrorContains(t, err, "validator InitGenesis updates already set by a previous module")
// happy path
mm2 := module.NewManager(mockAppModuleABCI1, mockAppModule2, module.CoreAppModuleAdaptor("module3", mockAppModule3))
mockAppModuleABCI1.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)
mockAppModuleABCI1.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(genesisData["module1"])).Times(1).Return([]abci.ValidatorUpdate{{}})
mockAppModule2.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Eq(genesisData["module2"])).Times(1)
mockAppModule3.EXPECT().InitGenesis(gomock.Eq(ctx), gomock.Any()).Times(1).Return(nil)
_, err = mm2.InitGenesis(ctx, cdc, genesisData)
require.NoError(t, err)
@@ -223,10 +223,8 @@ func TestManager_ExportGenesis(t *testing.T) {
require.Equal(t, 3, len(mm.Modules))
ctx := sdk.NewContext(nil, false, log.NewNopLogger())
interfaceRegistry := types.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(interfaceRegistry)
mockAppModule1.EXPECT().ExportGenesis(gomock.Eq(ctx), gomock.Eq(cdc)).AnyTimes().Return(json.RawMessage(`{"key1": "value1"}`))
mockAppModule2.EXPECT().ExportGenesis(gomock.Eq(ctx), gomock.Eq(cdc)).AnyTimes().Return(json.RawMessage(`{"key2": "value2"}`))
mockAppModule1.EXPECT().ExportGenesis(gomock.Eq(ctx)).AnyTimes().Return(json.RawMessage(`{"key1": "value1"}`), nil)
mockAppModule2.EXPECT().ExportGenesis(gomock.Eq(ctx)).AnyTimes().Return(json.RawMessage(`{"key2": "value2"}`), nil)
want := map[string]json.RawMessage{
"module1": json.RawMessage(`{"key1": "value1"}`),
@@ -236,23 +234,23 @@ func TestManager_ExportGenesis(t *testing.T) {
}`),
}
res, err := mm.ExportGenesis(ctx, cdc)
res, err := mm.ExportGenesis(ctx)
require.NoError(t, err)
require.Equal(t, want, res)
res, err = mm.ExportGenesisForModules(ctx, cdc, []string{})
res, err = mm.ExportGenesisForModules(ctx, []string{})
require.NoError(t, err)
require.Equal(t, want, res)
res, err = mm.ExportGenesisForModules(ctx, cdc, []string{"module1"})
res, err = mm.ExportGenesisForModules(ctx, []string{"module1"})
require.NoError(t, err)
require.Equal(t, map[string]json.RawMessage{"module1": json.RawMessage(`{"key1": "value1"}`)}, res)
res, err = mm.ExportGenesisForModules(ctx, cdc, []string{"module2"})
res, err = mm.ExportGenesisForModules(ctx, []string{"module2"})
require.NoError(t, err)
require.NotEqual(t, map[string]json.RawMessage{"module1": json.RawMessage(`{"key1": "value1"}`)}, res)
_, err = mm.ExportGenesisForModules(ctx, cdc, []string{"module1", "modulefoo"})
_, err = mm.ExportGenesisForModules(ctx, []string{"module1", "modulefoo"})
require.Error(t, err)
}
@@ -333,8 +331,6 @@ func TestCoreAPIManager_ExportGenesis(t *testing.T) {
require.Equal(t, 2, len(mm.Modules))
ctx := sdk.NewContext(nil, false, log.NewNopLogger())
interfaceRegistry := types.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(interfaceRegistry)
want := map[string]json.RawMessage{
"module1": json.RawMessage(`{
"someField": "someKey"
@@ -344,23 +340,23 @@ func TestCoreAPIManager_ExportGenesis(t *testing.T) {
}`),
}
res, err := mm.ExportGenesis(ctx, cdc)
res, err := mm.ExportGenesis(ctx)
require.NoError(t, err)
require.Equal(t, want, res)
res, err = mm.ExportGenesisForModules(ctx, cdc, []string{})
res, err = mm.ExportGenesisForModules(ctx, []string{})
require.NoError(t, err)
require.Equal(t, want, res)
res, err = mm.ExportGenesisForModules(ctx, cdc, []string{"module1"})
res, err = mm.ExportGenesisForModules(ctx, []string{"module1"})
require.NoError(t, err)
require.Equal(t, map[string]json.RawMessage{"module1": want["module1"]}, res)
res, err = mm.ExportGenesisForModules(ctx, cdc, []string{"module2"})
res, err = mm.ExportGenesisForModules(ctx, []string{"module2"})
require.NoError(t, err)
require.NotEqual(t, map[string]json.RawMessage{"module1": want["module1"]}, res)
_, err = mm.ExportGenesisForModules(ctx, cdc, []string{"module1", "modulefoo"})
_, err = mm.ExportGenesisForModules(ctx, []string{"module1", "modulefoo"})
require.Error(t, err)
}
@@ -594,7 +590,7 @@ func (MockCoreAppModule) ExportGenesis(ctx context.Context, target appmodule.Gen
}
var (
_ appmodule.AppModule = MockCoreAppModule{}
_ appmodule.HasGenesis = MockCoreAppModule{}
_ appmodule.HasServices = MockCoreAppModule{}
_ appmodule.AppModule = MockCoreAppModule{}
_ appmodule.HasGenesisAuto = MockCoreAppModule{}
_ appmodule.HasServices = MockCoreAppModule{}
)