refactor!: reimplement PreFinalizeBlockHook as PreBlocker (backport #17713) (#17754)

Co-authored-by: mmsqe <mavis@crypto.com>
Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
mergify[bot] 2023-09-15 08:14:23 +00:00 committed by GitHub
parent b1dd67aa77
commit 4955776845
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 104 additions and 105 deletions

View File

@ -99,7 +99,7 @@ app.ModuleManager.SetOrderBeginBlockers(
// ... //
+func (app *SimApp) PreBlocker(ctx sdk.Context, req abci.RequestBeginBlock) (sdk.ResponsePreBlock, error) {
+func (app *SimApp) PreBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
+ return app.ModuleManager.PreBlock(ctx, req)
+}
```

View File

@ -721,13 +721,7 @@ func (app *BaseApp) FinalizeBlock(req *abci.RequestFinalizeBlock) (*abci.Respons
WithHeaderHash(req.Hash)
}
if app.preFinalizeBlockHook != nil {
if err := app.preFinalizeBlockHook(app.finalizeBlockState.ctx, req); err != nil {
return nil, err
}
}
if err := app.preBlock(); err != nil {
if err := app.preBlock(req); err != nil {
return nil, err
}

View File

@ -2015,7 +2015,7 @@ func TestABCI_HaltChain(t *testing.T) {
}
}
func TestBaseApp_PreFinalizeBlockHook(t *testing.T) {
func TestBaseApp_PreBlocker(t *testing.T) {
db := dbm.NewMemDB()
name := t.Name()
logger := log.NewTestLogger(t)
@ -2025,9 +2025,11 @@ func TestBaseApp_PreFinalizeBlockHook(t *testing.T) {
require.NoError(t, err)
wasHookCalled := false
app.SetPreFinalizeBlockHook(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) error {
app.SetPreBlocker(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
wasHookCalled = true
return nil
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: true,
}, nil
})
app.Seal()
@ -2040,8 +2042,8 @@ func TestBaseApp_PreFinalizeBlockHook(t *testing.T) {
_, err = app.InitChain(&abci.RequestInitChain{})
require.NoError(t, err)
app.SetPreFinalizeBlockHook(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) error {
return errors.New("some error")
app.SetPreBlocker(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
return nil, errors.New("some error")
})
app.Seal()
@ -2102,7 +2104,7 @@ func TestBaseApp_VoteExtensions(t *testing.T) {
return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}, nil
})
app.SetPreFinalizeBlockHook(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) error {
app.SetPreBlocker(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
count := uint64(0)
pricesSum := uint64(0)
for _, v := range req.Txs {
@ -2121,7 +2123,9 @@ func TestBaseApp_VoteExtensions(t *testing.T) {
ctx.KVStore(capKey1).Set([]byte("avgPrice"), buf)
}
return nil
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: true,
}, nil
})
}

View File

@ -74,17 +74,16 @@ type BaseApp struct {
anteHandler sdk.AnteHandler // ante handler for fee and auth
postHandler sdk.PostHandler // post handler, optional, e.g. for tips
initChainer sdk.InitChainer // ABCI InitChain handler
preBlocker sdk.PreBlocker // logic to run before BeginBlocker
beginBlocker sdk.BeginBlocker // (legacy ABCI) BeginBlock handler
endBlocker sdk.EndBlocker // (legacy ABCI) EndBlock handler
processProposal sdk.ProcessProposalHandler // ABCI ProcessProposal handler
prepareProposal sdk.PrepareProposalHandler // ABCI PrepareProposal
extendVote sdk.ExtendVoteHandler // ABCI ExtendVote handler
verifyVoteExt sdk.VerifyVoteExtensionHandler // ABCI VerifyVoteExtension handler
prepareCheckStater sdk.PrepareCheckStater // logic to run during commit using the checkState
precommiter sdk.Precommiter // logic to run during commit using the deliverState
preFinalizeBlockHook sdk.PreFinalizeBlockHook // logic to run before FinalizeBlock
initChainer sdk.InitChainer // ABCI InitChain handler
preBlocker sdk.PreBlocker // logic to run before BeginBlocker
beginBlocker sdk.BeginBlocker // (legacy ABCI) BeginBlock handler
endBlocker sdk.EndBlocker // (legacy ABCI) EndBlock handler
processProposal sdk.ProcessProposalHandler // ABCI ProcessProposal handler
prepareProposal sdk.PrepareProposalHandler // ABCI PrepareProposal
extendVote sdk.ExtendVoteHandler // ABCI ExtendVote handler
verifyVoteExt sdk.VerifyVoteExtensionHandler // ABCI VerifyVoteExtension handler
prepareCheckStater sdk.PrepareCheckStater // logic to run during commit using the checkState
precommiter sdk.Precommiter // logic to run during commit using the deliverState
addrPeerFilter sdk.PeerFilter // filter peers by address and port
idPeerFilter sdk.PeerFilter // filter peers by node ID
@ -665,10 +664,10 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context
return ctx.WithMultiStore(msCache), msCache
}
func (app *BaseApp) preBlock() error {
func (app *BaseApp) preBlock(req *abci.RequestFinalizeBlock) error {
if app.preBlocker != nil {
ctx := app.finalizeBlockState.ctx
rsp, err := app.preBlocker(ctx)
rsp, err := app.preBlocker(ctx, req)
if err != nil {
return err
}

View File

@ -198,14 +198,6 @@ func (app *BaseApp) SetPrecommiter(precommiter sdk.Precommiter) {
app.precommiter = precommiter
}
func (app *BaseApp) SetPreFinalizeBlockHook(hook sdk.PreFinalizeBlockHook) {
if app.sealed {
panic("SetPreFinalizeBlockHook() on sealed BaseApp")
}
app.preFinalizeBlockHook = hook
}
func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) {
if app.sealed {
panic("SetAnteHandler() on sealed BaseApp")

View File

@ -292,32 +292,22 @@ decision based on the vote extensions.
#### Vote Extension Persistence
In certain contexts, it may be useful or necessary for applications to persist
data derived from vote extensions. In order to facilitate this use case, we
propose to allow application developers to manually retrieve the `finalizeState`
context (see [`FinalizeBlock`](#finalizeblock-1) below). Using this context,
state can be directly written to `finalizeState`, which will be used during
`FinalizeBlock` and eventually committed to the application state. Note, since
`ProcessProposal` can timeout and thus require another round of consensus, we
will reset `finalizeState` in the beginning of `ProcessProposal`.
data derived from vote extensions. In order to facilitate this use case, we propose
to allow app developers to define a pre-Blocker hook which will be called
at the very beginning of `FinalizeBlock`, i.e. before `BeginBlock` (see below).
A `ProcessProposal` handler could look like the following:
Note, we cannot allow applications to directly write to the application state
during `ProcessProposal` because during replay, CometBFT will NOT call `ProcessProposal`,
which would result in an incomplete state view.
```go
func (h MyHandler) ProcessProposalHandler() sdk.ProcessProposalHandler {
return func(ctx sdk.Context, req abci.RequestProcessProposal) abci.ResponseProcessProposal {
for _, txBytes := range req.Txs {
_, err := h.app.ProcessProposalVerifyTx(txBytes)
if err != nil {
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}
}
}
fCtx := h.app.GetFinalizeState()
// Any state changes that occur on the provided fCtx WILL be written to state!
h.myKeeper.SetVoteExtResult(fCtx, ...)
func (a MyApp) PreBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlock) error {
voteExts := GetVoteExtensions(ctx, req.Txs)
return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT}
// Process and perform some compute on vote extensions, storing any resulting
// state.
if err a.processVoteExtensions(ctx, voteExts); if err != nil {
return err
}
}
```
@ -360,11 +350,20 @@ legacy ABCI types, e.g. `LegacyBeginBlockRequest` and `LegacyEndBlockRequest`. O
we can come up with new types and names altogether.
```go
func (app *BaseApp) FinalizeBlock(req abci.RequestFinalizeBlock) abci.ResponseFinalizeBlock {
// merge any state changes from ProcessProposal into the FinalizeBlock state
app.MergeProcessProposalState()
func (app *BaseApp) FinalizeBlock(req abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) {
ctx := ...
beginBlockResp := app.beginBlock(ctx, req)
if app.preBlocker != nil {
ctx := app.finalizeBlockState.ctx
rsp, err := app.preBlocker(ctx, req)
if err != nil {
return nil, err
}
if rsp.ConsensusParamsChanged {
app.finalizeBlockState.ctx = ctx.WithConsensusParams(app.GetConsensusParams(ctx))
}
}
beginBlockResp, err := app.beginBlock(req)
appendBlockEventAttr(beginBlockResp.Events, "begin_block")
txExecResults := make([]abci.ExecTxResult, 0, len(req.Txs))
@ -373,7 +372,7 @@ func (app *BaseApp) FinalizeBlock(req abci.RequestFinalizeBlock) abci.ResponseFi
txExecResults = append(txExecResults, result)
}
endBlockResp := app.endBlock(ctx, req)
endBlockResp, err := app.endBlock(app.finalizeBlockState.ctx)
appendBlockEventAttr(beginBlockResp.Events, "end_block")
return abci.ResponseFinalizeBlock{

View File

@ -58,3 +58,4 @@ The new ctx must be passed to all the other lifecycle methods.
* [1] https://github.com/cosmos/cosmos-sdk/issues/16494
* [2] https://github.com/cosmos/cosmos-sdk/pull/16583
* [3] https://github.com/cosmos/cosmos-sdk/pull/17421
* [4] https://github.com/cosmos/cosmos-sdk/pull/17713

View File

@ -60,7 +60,7 @@ In addition to basic module wiring, setup the upgrade Keeper for the app and the
keeper's PreBlocker method:
```go
func (app *myApp) PreBlocker(ctx sdk.Context, req req.RequestFinalizeBlock) (sdk.ResponsePreBlock, error) {
func (app *myApp) PreBlocker(ctx sdk.Context, req req.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
// For demonstration sake, the app PreBlocker only returns the upgrade module pre-blocker.
// In a real app, the module manager should call all pre-blockers
// return return app.ModuleManager.PreBlock(ctx, req)

View File

@ -77,7 +77,7 @@ will be available to the application during the subsequent `FinalizeBlock` call.
An example of how a pre-FinalizeBlock hook could look like is shown below:
```go
app.SetPreFinalizeBlockHook(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) error {
app.SetPreBlocker(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) error {
allVEs := []VE{} // store all parsed vote extensions here
for _, tx := range req.Txs {
// define a custom function that tries to parse the tx as a vote extension

View File

@ -153,7 +153,7 @@ func (a *App) Load(loadLatest bool) error {
}
// PreBlocker application updates every pre block
func (a *App) PreBlocker(ctx sdk.Context) (sdk.ResponsePreBlock, error) {
func (a *App) PreBlocker(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
return a.ModuleManager.PreBlock(ctx)
}

View File

@ -583,7 +583,7 @@ func (app *SimApp) setPostHandler() {
func (app *SimApp) Name() string { return app.BaseApp.Name() }
// PreBlocker application updates every pre block
func (app *SimApp) PreBlocker(ctx sdk.Context) (sdk.ResponsePreBlock, error) {
func (app *SimApp) PreBlocker(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
return app.ModuleManager.PreBlock(ctx)
}

View File

@ -17,7 +17,7 @@ require (
cosmossdk.io/x/feegrant v0.0.0-20230913185058-9b5a203d35bc
cosmossdk.io/x/nft v0.0.0-20230913185058-9b5a203d35bc
cosmossdk.io/x/tx v0.10.0
cosmossdk.io/x/upgrade v0.0.0-20230913185058-9b5a203d35bc
cosmossdk.io/x/upgrade v0.0.0-20230915075604-076dc1ee9619
github.com/cometbft/cometbft v0.38.0
github.com/cosmos/cosmos-db v1.0.0
// this version is not used as it is always replaced by the latest Cosmos SDK version

View File

@ -217,8 +217,8 @@ cosmossdk.io/x/nft v0.0.0-20230913185058-9b5a203d35bc h1:Jm0ZJ1L6d8YZ6yQydUknNL6
cosmossdk.io/x/nft v0.0.0-20230913185058-9b5a203d35bc/go.mod h1:B+yw1SVhkUEANcuxisIgiT6cw6re1gGzSsMmY8+lvAI=
cosmossdk.io/x/tx v0.10.0 h1:LxWF/hksVDbeQmFj4voLM5ZCHyVZ1cCNIqKenfH9plc=
cosmossdk.io/x/tx v0.10.0/go.mod h1:MKo9/b5wsoL8dd9y9pvD2yOP1CMvzHIWYxi1l2oLPFo=
cosmossdk.io/x/upgrade v0.0.0-20230913185058-9b5a203d35bc h1:vLTAmHtVdNjil1QgYVUYKvn5UKk5Ntpz2dpMyXW3fMc=
cosmossdk.io/x/upgrade v0.0.0-20230913185058-9b5a203d35bc/go.mod h1:nLBiFTPw6e4LBT1ZWdGBIOjleiVNaqqmsTxU4GgEYaQ=
cosmossdk.io/x/upgrade v0.0.0-20230915075604-076dc1ee9619 h1:3wgUsnj/ElYA+B33h6Yn1KxWvB4hPFa+K90fw9gRO9M=
cosmossdk.io/x/upgrade v0.0.0-20230915075604-076dc1ee9619/go.mod h1:bqexnYfkwMCqbXXN4SprKS9N7cTwT1lFholB7UQhoDU=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=

View File

@ -15,7 +15,7 @@ require (
cosmossdk.io/x/feegrant v0.0.0-20230913185058-9b5a203d35bc
cosmossdk.io/x/nft v0.0.0-20230913185058-9b5a203d35bc // indirect
cosmossdk.io/x/tx v0.10.0
cosmossdk.io/x/upgrade v0.0.0-20230913185058-9b5a203d35bc
cosmossdk.io/x/upgrade v0.0.0-20230915075604-076dc1ee9619
github.com/cometbft/cometbft v0.38.0
github.com/cosmos/cosmos-db v1.0.0
github.com/cosmos/cosmos-proto v1.0.0-beta.3

View File

@ -215,8 +215,8 @@ cosmossdk.io/x/nft v0.0.0-20230913185058-9b5a203d35bc h1:Jm0ZJ1L6d8YZ6yQydUknNL6
cosmossdk.io/x/nft v0.0.0-20230913185058-9b5a203d35bc/go.mod h1:B+yw1SVhkUEANcuxisIgiT6cw6re1gGzSsMmY8+lvAI=
cosmossdk.io/x/tx v0.10.0 h1:LxWF/hksVDbeQmFj4voLM5ZCHyVZ1cCNIqKenfH9plc=
cosmossdk.io/x/tx v0.10.0/go.mod h1:MKo9/b5wsoL8dd9y9pvD2yOP1CMvzHIWYxi1l2oLPFo=
cosmossdk.io/x/upgrade v0.0.0-20230913185058-9b5a203d35bc h1:vLTAmHtVdNjil1QgYVUYKvn5UKk5Ntpz2dpMyXW3fMc=
cosmossdk.io/x/upgrade v0.0.0-20230913185058-9b5a203d35bc/go.mod h1:nLBiFTPw6e4LBT1ZWdGBIOjleiVNaqqmsTxU4GgEYaQ=
cosmossdk.io/x/upgrade v0.0.0-20230915075604-076dc1ee9619 h1:3wgUsnj/ElYA+B33h6Yn1KxWvB4hPFa+K90fw9gRO9M=
cosmossdk.io/x/upgrade v0.0.0-20230915075604-076dc1ee9619/go.mod h1:bqexnYfkwMCqbXXN4SprKS9N7cTwT1lFholB7UQhoDU=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=

View File

@ -30,8 +30,13 @@ 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)
// PreBlocker runs code before the `BeginBlocker` and defines a function type alias for executing logic right
// before FinalizeBlock is called (but after its context has been set up). It is
// intended to allow applications to perform computation on vote extensions and
// persist their results in state.
//
// Note: returning an error will make FinalizeBlock fail.
type PreBlocker func(Context, *abci.RequestFinalizeBlock) (*ResponsePreBlock, error)
// BeginBlocker defines a function type alias for executing application
// business logic before transactions are executed.
@ -51,14 +56,6 @@ type BeginBlocker func(Context) (BeginBlock, error)
// and allows for existing EndBlock functionality within applications.
type EndBlocker func(Context) (EndBlock, error)
// PreFinalizeBlockHook defines a function type alias for executing logic right
// before FinalizeBlock is called (but after its context has been set up). It is
// intended to allow applications to perform computation on vote extensions and
// persist their results in state.
//
// Note: returning an error will make FinalizeBlock fail.
type PreFinalizeBlockHook func(Context, *abci.RequestFinalizeBlock) error
// EndBlock defines a type which contains endblock events and validator set updates
type EndBlock struct {
ValidatorUpdates []abci.ValidatorUpdate

View File

@ -744,21 +744,21 @@ func (m Manager) RunMigrations(ctx context.Context, cfg Configurator, fromVM Ver
// 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 successfully executed or not.
func (m *Manager) PreBlock(ctx sdk.Context) (sdk.ResponsePreBlock, error) {
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
return nil, err
}
if rsp.IsConsensusParamsChanged() {
paramsChanged = true
}
}
}
return sdk.ResponsePreBlock{
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}

View File

@ -478,7 +478,7 @@ func TestCoreAPIManager_PreBlock(t *testing.T) {
require.Equal(t, 2, len(mm.Modules))
require.Equal(t, 1, len(mm.OrderPreBlockers))
mockAppModule1.EXPECT().PreBlock(gomock.Any()).Times(1).Return(sdk.ResponsePreBlock{
mockAppModule1.EXPECT().PreBlock(gomock.Any()).Times(1).Return(&sdk.ResponsePreBlock{
ConsensusParamsChanged: true,
}, nil)
res, err := mm.PreBlock(sdk.Context{})
@ -486,7 +486,7 @@ func TestCoreAPIManager_PreBlock(t *testing.T) {
require.True(t, res.ConsensusParamsChanged)
// test false
mockAppModule1.EXPECT().PreBlock(gomock.Any()).Times(1).Return(sdk.ResponsePreBlock{
mockAppModule1.EXPECT().PreBlock(gomock.Any()).Times(1).Return(&sdk.ResponsePreBlock{
ConsensusParamsChanged: false,
}, nil)
res, err = mm.PreBlock(sdk.Context{})
@ -494,7 +494,7 @@ func TestCoreAPIManager_PreBlock(t *testing.T) {
require.False(t, res.ConsensusParamsChanged)
// test error
mockAppModule1.EXPECT().PreBlock(gomock.Any()).Times(1).Return(sdk.ResponsePreBlock{}, errors.New("some error"))
mockAppModule1.EXPECT().PreBlock(gomock.Any()).Times(1).Return(nil, errors.New("some error"))
_, err = mm.PreBlock(sdk.Context{})
require.EqualError(t, err, "some error")
}

View File

@ -41,3 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [#16511](https://github.com/cosmos/cosmos-sdk/pull/16511) `plan.DownloadURLWithChecksum` has been renamed to `plan.DownloadURL` and does not validate the URL anymore. Call `plan.ValidateURL` before calling `plan.DownloadURL` to validate the URL.
* [#16511](https://github.com/cosmos/cosmos-sdk/pull/16511) `plan.DownloadUpgrade` does not validate URL anymore. Call `plan.ValidateURL` before calling `plan.DownloadUpgrade` to validate the URL.
* [#16227](https://github.com/cosmos/cosmos-sdk/issues/16227) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error`. `UpgradeHandler` now receives a `context.Context`. `GetUpgradedClient`, `GetUpgradedConsensusState`, `GetUpgradePlan` now return a specific error for "not found".
### Bug Fixes
* [#17421](https://github.com/cosmos/cosmos-sdk/pull/17421) Replace ` BeginBlock` by `PreBlock`. Read [ADR-68](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-068-preblock.md) for more information.

View File

@ -6,6 +6,7 @@ import (
"fmt"
"time"
"cosmossdk.io/core/appmodule"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/x/upgrade/keeper"
"cosmossdk.io/x/upgrade/types"
@ -22,17 +23,14 @@ import (
// The purpose is to ensure the binary is switched EXACTLY at the desired block, and to allow
// a migration to be executed if needed upon this switch (migration defined in the new binary)
// skipUpgradeHeightArray is a set of block heights for which the upgrade must be skipped
func PreBlocker(ctx context.Context, k *keeper.Keeper) (sdk.ResponsePreBlock, error) {
rsp := sdk.ResponsePreBlock{
ConsensusParamsChanged: false,
}
func PreBlocker(ctx context.Context, k *keeper.Keeper) (appmodule.ResponsePreBlock, error) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker)
sdkCtx := sdk.UnwrapSDKContext(ctx)
blockHeight := sdkCtx.HeaderInfo().Height
plan, err := k.GetUpgradePlan(ctx)
if err != nil && !errors.Is(err, types.ErrNoUpgradePlanFound) {
return rsp, err
return nil, err
}
found := err == nil
@ -46,7 +44,7 @@ func PreBlocker(ctx context.Context, k *keeper.Keeper) (sdk.ResponsePreBlock, er
if !found || !plan.ShouldExecute(blockHeight) || (plan.ShouldExecute(blockHeight) && k.IsSkipHeight(blockHeight)) {
lastAppliedPlan, _, err := k.GetLastCompletedUpgrade(ctx)
if err != nil {
return rsp, err
return nil, err
}
if lastAppliedPlan != "" && !k.HasHandler(lastAppliedPlan) {
@ -57,13 +55,15 @@ func PreBlocker(ctx context.Context, k *keeper.Keeper) (sdk.ResponsePreBlock, er
appVersion = cp.Version.App
}
return rsp, fmt.Errorf("wrong app version %d, upgrade handler is missing for %s upgrade plan", appVersion, lastAppliedPlan)
return nil, fmt.Errorf("wrong app version %d, upgrade handler is missing for %s upgrade plan", appVersion, lastAppliedPlan)
}
}
}
if !found {
return rsp, nil
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: false,
}, nil
}
logger := k.Logger(ctx)
@ -76,7 +76,12 @@ func PreBlocker(ctx context.Context, k *keeper.Keeper) (sdk.ResponsePreBlock, er
logger.Info(skipUpgradeMsg)
// Clear the upgrade plan at current height
return rsp, k.ClearUpgradePlan(ctx)
if err := k.ClearUpgradePlan(ctx); err != nil {
return nil, err
}
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: false,
}, nil
}
// Prepare shutdown if we don't have an upgrade handler for this upgrade name (meaning this software is out of date)
@ -85,25 +90,27 @@ func PreBlocker(ctx context.Context, k *keeper.Keeper) (sdk.ResponsePreBlock, er
// store migrations.
err := k.DumpUpgradeInfoToDisk(blockHeight, plan)
if err != nil {
return rsp, fmt.Errorf("unable to write upgrade info to filesystem: %w", err)
return nil, fmt.Errorf("unable to write upgrade info to filesystem: %w", err)
}
upgradeMsg := BuildUpgradeNeededMsg(plan)
logger.Error(upgradeMsg)
// Returning an error will end up in a panic
return rsp, errors.New(upgradeMsg)
return nil, errors.New(upgradeMsg)
}
// We have an upgrade handler for this upgrade name, so apply the upgrade
logger.Info(fmt.Sprintf("applying upgrade \"%s\" at %s", plan.Name, plan.DueAt()))
sdkCtx = sdkCtx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter())
err = k.ApplyUpgrade(sdkCtx, plan)
return sdk.ResponsePreBlock{
if err := k.ApplyUpgrade(sdkCtx, plan); err != nil {
return nil, err
}
return &sdk.ResponsePreBlock{
// the consensus parameters might be modified in the migration,
// refresh the consensus parameters in context.
ConsensusParamsChanged: true,
}, err
}, nil
}
// if we have a pending upgrade, but it is not yet time, make sure we did not
@ -113,9 +120,11 @@ func PreBlocker(ctx context.Context, k *keeper.Keeper) (sdk.ResponsePreBlock, er
logger.Error(downgradeMsg)
// Returning an error will end up in a panic
return rsp, errors.New(downgradeMsg)
return nil, errors.New(downgradeMsg)
}
return rsp, nil
return &sdk.ResponsePreBlock{
ConsensusParamsChanged: false,
}, nil
}
// BuildUpgradeNeededMsg prints the message that notifies that an upgrade is needed.