feat: introduce PreBlock (#17421)
This commit is contained in:
@@ -30,6 +30,9 @@ type ExtendVoteHandler func(Context, *abci.RequestExtendVote) (*abci.ResponseExt
|
||||
// pre-commit vote extension.
|
||||
type VerifyVoteExtensionHandler func(Context, *abci.RequestVerifyVoteExtension) (*abci.ResponseVerifyVoteExtension, error)
|
||||
|
||||
// PreBlocker runs code before the `BeginBlocker`.
|
||||
type PreBlocker func(Context) (ResponsePreBlock, error)
|
||||
|
||||
// BeginBlocker defines a function type alias for executing application
|
||||
// business logic before transactions are executed.
|
||||
//
|
||||
@@ -66,3 +69,11 @@ type EndBlock struct {
|
||||
type BeginBlock struct {
|
||||
Events []abci.Event
|
||||
}
|
||||
|
||||
type ResponsePreBlock struct {
|
||||
ConsensusParamsChanged bool
|
||||
}
|
||||
|
||||
func (r ResponsePreBlock) IsConsensusParamsChanged() bool {
|
||||
return r.ConsensusParamsChanged
|
||||
}
|
||||
|
||||
@@ -39,8 +39,3 @@ type CoreAppModule interface {
|
||||
appmodule.HasPrecommit
|
||||
appmodule.HasPrepareCheckState
|
||||
}
|
||||
|
||||
type CoreUpgradeAppModule interface {
|
||||
CoreAppModule
|
||||
appmodule.UpgradeModule
|
||||
}
|
||||
|
||||
+42
-15
@@ -268,6 +268,7 @@ 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
|
||||
OrderPreBlockers []string
|
||||
OrderBeginBlockers []string
|
||||
OrderEndBlockers []string
|
||||
OrderPrepareCheckStaters []string
|
||||
@@ -279,15 +280,20 @@ type Manager struct {
|
||||
func NewManager(modules ...AppModule) *Manager {
|
||||
moduleMap := make(map[string]interface{})
|
||||
modulesStr := make([]string, 0, len(modules))
|
||||
preBlockModulesStr := make([]string, 0)
|
||||
for _, module := range modules {
|
||||
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,
|
||||
@@ -300,9 +306,13 @@ func NewManager(modules ...AppModule) *Manager {
|
||||
func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
|
||||
simpleModuleMap := make(map[string]interface{})
|
||||
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.
|
||||
@@ -312,6 +322,7 @@ func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager {
|
||||
Modules: simpleModuleMap,
|
||||
OrderInitGenesis: modulesStr,
|
||||
OrderExportGenesis: modulesStr,
|
||||
OrderPreBlockers: preBlockModulesStr,
|
||||
OrderBeginBlockers: modulesStr,
|
||||
OrderEndBlockers: modulesStr,
|
||||
OrderPrecommiters: modulesStr,
|
||||
@@ -355,6 +366,17 @@ func (m *Manager) SetOrderExportGenesis(moduleNames ...string) {
|
||||
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,
|
||||
@@ -713,32 +735,37 @@ func (m Manager) RunMigrations(ctx context.Context, cfg Configurator, fromVM Ver
|
||||
return updatedVM, nil
|
||||
}
|
||||
|
||||
// RunMigrationBeginBlock performs begin block functionality for upgrade module.
|
||||
// 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 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
|
||||
// indicating whether the migration was successfully executed or not.
|
||||
func (m *Manager) PreBlock(ctx sdk.Context) (sdk.ResponsePreBlock, error) {
|
||||
ctx = ctx.WithEventManager(sdk.NewEventManager())
|
||||
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 sdk.ResponsePreBlock{}, err
|
||||
}
|
||||
if rsp.IsConsensusParamsChanged() {
|
||||
paramsChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
return sdk.ResponsePreBlock{
|
||||
ConsensusParamsChanged: paramsChanged,
|
||||
}, 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
|
||||
// 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 _, ok := module.(appmodule.UpgradeModule); !ok {
|
||||
if err := module.BeginBlock(ctx); err != nil {
|
||||
return sdk.BeginBlock{}, err
|
||||
}
|
||||
if err := module.BeginBlock(ctx); err != nil {
|
||||
return sdk.BeginBlock{}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
-15
@@ -143,6 +143,10 @@ func TestManagerOrderSetters(t *testing.T) {
|
||||
mm.SetOrderExportGenesis("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderExportGenesis)
|
||||
|
||||
require.Equal(t, []string{}, mm.OrderPreBlockers)
|
||||
mm.SetOrderPreBlockers("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderPreBlockers)
|
||||
|
||||
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderBeginBlockers)
|
||||
mm.SetOrderBeginBlockers("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderBeginBlockers)
|
||||
@@ -444,6 +448,10 @@ func TestCoreAPIManagerOrderSetters(t *testing.T) {
|
||||
mm.SetOrderExportGenesis("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderExportGenesis)
|
||||
|
||||
require.Equal(t, []string{}, mm.OrderPreBlockers)
|
||||
mm.SetOrderPreBlockers("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderPreBlockers)
|
||||
|
||||
require.Equal(t, []string{"module1", "module2", "module3"}, mm.OrderBeginBlockers)
|
||||
mm.SetOrderBeginBlockers("module2", "module1", "module3")
|
||||
require.Equal(t, []string{"module2", "module1", "module3"}, mm.OrderBeginBlockers)
|
||||
@@ -461,35 +469,38 @@ func TestCoreAPIManagerOrderSetters(t *testing.T) {
|
||||
require.Equal(t, []string{"module3", "module2", "module1"}, mm.OrderPrecommiters)
|
||||
}
|
||||
|
||||
func TestCoreAPIManager_RunMigrationBeginBlock(t *testing.T) {
|
||||
func TestCoreAPIManager_PreBlock(t *testing.T) {
|
||||
mockCtrl := gomock.NewController(t)
|
||||
t.Cleanup(mockCtrl.Finish)
|
||||
|
||||
mockAppModule1 := mock.NewMockCoreAppModule(mockCtrl)
|
||||
mockAppModule2 := mock.NewMockCoreUpgradeAppModule(mockCtrl)
|
||||
mockAppModule1 := mock.NewMockCoreModuleWithPreBlock(mockCtrl)
|
||||
mm := module.NewManagerFromMap(map[string]appmodule.AppModule{
|
||||
"module1": mockAppModule1,
|
||||
"module2": mockAppModule2,
|
||||
"module2": mock.NewMockCoreAppModule(mockCtrl),
|
||||
})
|
||||
require.NotNil(t, mm)
|
||||
require.Equal(t, 2, len(mm.Modules))
|
||||
require.Equal(t, 1, len(mm.OrderPreBlockers))
|
||||
|
||||
mockAppModule1.EXPECT().BeginBlock(gomock.Any()).Times(0)
|
||||
mockAppModule2.EXPECT().BeginBlock(gomock.Any()).Times(1).Return(nil)
|
||||
success, err := mm.RunMigrationBeginBlock(sdk.Context{})
|
||||
require.Equal(t, true, success)
|
||||
mockAppModule1.EXPECT().PreBlock(gomock.Any()).Times(1).Return(sdk.ResponsePreBlock{
|
||||
ConsensusParamsChanged: true,
|
||||
}, nil)
|
||||
res, err := mm.PreBlock(sdk.Context{})
|
||||
require.NoError(t, err)
|
||||
require.True(t, res.ConsensusParamsChanged)
|
||||
|
||||
// test false
|
||||
success, err = module.NewManager().RunMigrationBeginBlock(sdk.Context{})
|
||||
require.Equal(t, false, success)
|
||||
mockAppModule1.EXPECT().PreBlock(gomock.Any()).Times(1).Return(sdk.ResponsePreBlock{
|
||||
ConsensusParamsChanged: false,
|
||||
}, nil)
|
||||
res, err = mm.PreBlock(sdk.Context{})
|
||||
require.NoError(t, err)
|
||||
require.False(t, res.ConsensusParamsChanged)
|
||||
|
||||
// test panic
|
||||
mockAppModule2.EXPECT().BeginBlock(gomock.Any()).Times(1).Return(errors.New("some error"))
|
||||
success, err = mm.RunMigrationBeginBlock(sdk.Context{})
|
||||
require.Equal(t, false, success)
|
||||
require.Error(t, err)
|
||||
// test error
|
||||
mockAppModule1.EXPECT().PreBlock(gomock.Any()).Times(1).Return(sdk.ResponsePreBlock{}, errors.New("some error"))
|
||||
_, err = mm.PreBlock(sdk.Context{})
|
||||
require.EqualError(t, err, "some error")
|
||||
}
|
||||
|
||||
func TestCoreAPIManager_BeginBlock(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user