feat: Add PrepareCheckState and Precommit callbacks (#14860)

Co-authored-by: dydxwill <119354122+dydxwill@users.noreply.github.com>
This commit is contained in:
Bryce Neal
2023-04-23 16:04:36 +00:00
committed by GitHub
co-authored by dydxwill
parent be081b1051
commit 93d64cc6fe
18 changed files with 925 additions and 69 deletions
+7
View File
@@ -19,6 +19,13 @@ type BeginBlocker func(ctx Context, req abci.RequestBeginBlock) (abci.ResponseBe
// e.g. BFT timestamps rather than block height for any periodic EndBlock logic
type EndBlocker func(ctx Context, req abci.RequestEndBlock) (abci.ResponseEndBlock, error)
// PrepareCheckStater runs code during commit after the block has been committed, and the `checkState`
// has been branched for the new block.
type PrepareCheckStater func(ctx Context)
// Precommiter runs code during commit immediately before the `deliverState` is written to the `rootMultiStore`.
type Precommiter func(ctx Context)
// PeerFilter responds to p2p filtering queries from Tendermint
type PeerFilter func(info string) abci.ResponseQuery
+79 -16
View File
@@ -213,6 +213,19 @@ type EndBlockAppModule interface {
EndBlock(sdk.Context, abci.RequestEndBlock) []abci.ValidatorUpdate
}
// PrepareCheckStateAppModule is an extension interface that contains information about the AppModule
// and PrepareCheckState.
type PrepareCheckStateAppModule interface {
AppModule
PrepareCheckState(sdk.Context)
}
// PreommitAppModule is an extension interface that contains information about the AppModule and Precommit.
type PrecommitAppModule interface {
AppModule
Precommit(sdk.Context)
}
type HasABCIEndblock interface {
AppModule
EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
@@ -259,12 +272,14 @@ 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]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
OrderMigrations []string
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.
@@ -277,11 +292,13 @@ func NewManager(modules ...AppModule) *Manager {
}
return &Manager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderBeginBlockers: modulesStr,
OrderPrepareCheckStaters: modulesStr,
OrderPrecommiters: modulesStr,
OrderEndBlockers: modulesStr,
}
}
@@ -299,11 +316,13 @@ func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
sort.Strings(modulesStr)
return &Manager{
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
Modules: simpleModuleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
OrderPrecommiters: modulesStr,
OrderPrepareCheckStaters: modulesStr,
}
}
@@ -357,6 +376,28 @@ func (m *Manager) SetOrderEndBlockers(moduleNames ...string) {
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.(PrepareCheckStateAppModule)
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.(PrecommitAppModule)
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) {
@@ -728,6 +769,28 @@ func (m *Manager) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) (abci.Resp
}, nil
}
// Precommit performs precommit functionality for all modules.
func (m *Manager) Precommit(ctx sdk.Context) {
for _, moduleName := range m.OrderPrecommiters {
module, ok := m.Modules[moduleName].(PrecommitAppModule)
if !ok {
continue
}
module.Precommit(ctx)
}
}
// PrepareCheckState performs functionality for preparing the check state for all modules.
func (m *Manager) PrepareCheckState(ctx sdk.Context) {
for _, moduleName := range m.OrderPrepareCheckStaters {
module, ok := m.Modules[moduleName].(PrepareCheckStateAppModule)
if !ok {
continue
}
module.PrepareCheckState(ctx)
}
}
// GetVersionMap gets consensus version from all modules
func (m *Manager) GetVersionMap() VersionMap {
vermap := make(VersionMap)
+104
View File
@@ -100,6 +100,60 @@ func TestGenesisOnlyAppModule(t *testing.T) {
goam.RegisterInvariants(mockInvariantRegistry)
}
func TestAssertNoForgottenModules(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockAppModule1 := mock.NewMockEndBlockAppModule(mockCtrl)
mockAppModule2 := mock.NewMockBeginBlockAppModule(mockCtrl)
mockAppModule3 := mock.NewMockCoreAppModule(mockCtrl)
mockAppModule4 := mock.NewMockPrecommitAppModule(mockCtrl)
mockAppModule5 := mock.NewMockPrepareCheckStateAppModule(mockCtrl)
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
mockAppModule4.EXPECT().Name().Times(2).Return("module4")
mockAppModule5.EXPECT().Name().Times(2).Return("module5")
mm := module.NewManager(
mockAppModule1,
mockAppModule2,
module.CoreAppModuleBasicAdaptor("module3", mockAppModule3),
mockAppModule4,
mockAppModule5,
)
require.NotNil(t, mm)
require.Equal(t, 5, len(mm.Modules))
require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderInitGenesis)
require.PanicsWithValue(t, "all modules must be defined when setting SetOrderInitGenesis, missing: [module3]", func() {
mm.SetOrderInitGenesis("module2", "module1")
})
require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderExportGenesis)
require.PanicsWithValue(t, "all modules must be defined when setting SetOrderExportGenesis, missing: [module3]", func() {
mm.SetOrderExportGenesis("module2", "module1")
})
require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderBeginBlockers)
require.PanicsWithValue(t, "all modules must be defined when setting SetOrderBeginBlockers, missing: [module2]", func() {
mm.SetOrderBeginBlockers("module1", "module3")
})
require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderEndBlockers)
require.PanicsWithValue(t, "all modules must be defined when setting SetOrderEndBlockers, missing: [module1]", func() {
mm.SetOrderEndBlockers("module2", "module3")
})
require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderPrecommiters)
require.PanicsWithValue(t, "all modules must be defined when setting SetOrderPrecommiters, missing: [module4]", func() {
mm.SetOrderPrecommiters("module2", "module1")
})
require.Equal(t, []string{"module1", "module2", "module3", "module4", "module5"}, mm.OrderPrepareCheckStaters)
require.PanicsWithValue(t, "all modules must be defined when setting SetOrderPrepareCheckStaters, missing: [module5]", func() {
mm.SetOrderPrepareCheckStaters("module2", "module1")
})
}
func TestManagerOrderSetters(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
@@ -128,6 +182,14 @@ func TestManagerOrderSetters(t *testing.T) {
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderEndBlockers)
mm.SetOrderEndBlockers("module2", "module1", "module3")
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderEndBlockers)
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderPrepareCheckStaters)
mm.SetOrderPrepareCheckStaters("module3", "module2", "module1")
require.Equal(t, []string{"module3", "module2", "module1"}, mm.OrderPrepareCheckStaters)
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderPrecommiters)
mm.SetOrderPrecommiters("module3", "module2", "module1")
require.Equal(t, []string{"module3", "module2", "module1"}, mm.OrderPrecommiters)
}
func TestManager_RegisterInvariants(t *testing.T) {
@@ -319,6 +381,40 @@ func TestManager_EndBlock(t *testing.T) {
require.Error(t, err)
}
func TestManager_PrepareCheckState(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockAppModule1 := mock.NewMockPrepareCheckStateAppModule(mockCtrl)
mockAppModule2 := mock.NewMockPrepareCheckStateAppModule(mockCtrl)
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
mm := module.NewManager(mockAppModule1, mockAppModule2)
require.NotNil(t, mm)
require.Equal(t, 2, len(mm.Modules))
mockAppModule1.EXPECT().PrepareCheckState(gomock.Any()).Times(1)
mockAppModule2.EXPECT().PrepareCheckState(gomock.Any()).Times(1)
mm.PrepareCheckState(sdk.Context{})
}
func TestManager_Precommit(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockAppModule1 := mock.NewMockPrecommitAppModule(mockCtrl)
mockAppModule2 := mock.NewMockPrecommitAppModule(mockCtrl)
mockAppModule1.EXPECT().Name().Times(2).Return("module1")
mockAppModule2.EXPECT().Name().Times(2).Return("module2")
mm := module.NewManager(mockAppModule1, mockAppModule2)
require.NotNil(t, mm)
require.Equal(t, 2, len(mm.Modules))
mockAppModule1.EXPECT().Precommit(gomock.Any()).Times(1)
mockAppModule2.EXPECT().Precommit(gomock.Any()).Times(1)
mm.Precommit(sdk.Context{})
}
// Core API exclusive tests
func TestCoreAPIManager(t *testing.T) {
mockCtrl := gomock.NewController(t)
@@ -431,6 +527,14 @@ func TestCoreAPIManagerOrderSetters(t *testing.T) {
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderEndBlockers)
mm.SetOrderEndBlockers("module2", "module1", "module3")
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderEndBlockers)
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderPrepareCheckStaters)
mm.SetOrderPrepareCheckStaters("module3", "module2", "module1")
require.Equal(t, []string{"module3", "module2", "module1"}, mm.OrderPrepareCheckStaters)
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderPrecommiters)
mm.SetOrderPrecommiters("module3", "module2", "module1")
require.Equal(t, []string{"module3", "module2", "module1"}, mm.OrderPrecommiters)
}
func TestCoreAPIManager_BeginBlock(t *testing.T) {