feat: introduce PreBlock (backport #17421) (#17712)

Co-authored-by: mmsqe <mavis@crypto.com>
Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
mergify[bot] 2023-09-13 19:40:08 +02:00 committed by GitHub
parent 92d1d9a106
commit 4c083c6f23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 476 additions and 94 deletions

View File

@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features
* (baseapp & types) [#17712](https://github.com/cosmos/cosmos-sdk/pull/17712) Introduce `PreBlock`, which runs before begin blocker other modules, and allows to modify consensus parameters, and the changes are visible to the following state machine logics. Additionally it can be used for vote extensions.
* (x/bank) [#14224](https://github.com/cosmos/cosmos-sdk/pull/14224) Allow injection of restrictions on transfers using `AppendSendRestriction` or `PrependSendRestriction`.
* (genutil) [#17571](https://github.com/cosmos/cosmos-sdk/pull/17571) Allow creation of `AppGenesis` without a file lookup.

View File

@ -67,6 +67,22 @@ allows an application to define handlers for these methods via `ExtendVoteHandle
and `VerifyVoteExtensionHandler` respectively. Please see [here](https://docs.cosmos.network/v0.50/building-apps/vote-extensions)
for more info.
#### Set PreBlocker
**Users using `depinject` / app v2 do not need any changes, this is abstracted for them.**
```diff
+ app.SetPreBlocker(app.PreBlocker)
```
```diff
+func (app *SimApp) PreBlocker(ctx sdk.Context, req abci.RequestBeginBlock) (sdk.ResponsePreBlock, error) {
+ return app.ModuleManager.PreBlock(ctx, req)
+}
```
BaseApp added `SetPreBlocker` for apps. This is essential for BaseApp to run `PreBlock` which runs before begin blocker other modules, and allows to modify consensus parameters, and the changes are visible to the following state machine logics.
#### Events
The log section of `abci.TxResult` is not populated in the case of successful

View File

@ -727,6 +727,10 @@ func (app *BaseApp) FinalizeBlock(req *abci.RequestFinalizeBlock) (*abci.Respons
}
}
if err := app.preBlock(); err != nil {
return nil, err
}
beginBlock, err := app.beginBlock(req)
if err != nil {
return nil, err

View File

@ -75,6 +75,7 @@ type BaseApp struct {
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
@ -664,6 +665,26 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context
return ctx.WithMultiStore(msCache), msCache
}
func (app *BaseApp) preBlock() error {
if app.preBlocker != nil {
ctx := app.finalizeBlockState.ctx
rsp, err := app.preBlocker(ctx)
if err != nil {
return err
}
// rsp.ConsensusParamsChanged is true from preBlocker means ConsensusParams in store get changed
// write the consensus parameters in store to context
if rsp.ConsensusParamsChanged {
ctx = ctx.WithConsensusParams(app.GetConsensusParams(ctx))
// GasMeter must be set after we get a context with updated consensus params.
gasMeter := app.getBlockGasMeter(ctx)
ctx = ctx.WithBlockGasMeter(gasMeter)
app.finalizeBlockState.ctx = ctx
}
}
return nil
}
func (app *BaseApp) beginBlock(req *abci.RequestFinalizeBlock) (sdk.BeginBlock, error) {
var (
resp sdk.BeginBlock

View File

@ -422,6 +422,9 @@ func TestBaseAppOptionSeal(t *testing.T) {
require.Panics(t, func() {
suite.baseApp.SetInitChainer(nil)
})
require.Panics(t, func() {
suite.baseApp.SetPreBlocker(nil)
})
require.Panics(t, func() {
suite.baseApp.SetBeginBlocker(nil)
})

View File

@ -158,6 +158,14 @@ func (app *BaseApp) SetInitChainer(initChainer sdk.InitChainer) {
app.initChainer = initChainer
}
func (app *BaseApp) SetPreBlocker(preBlocker sdk.PreBlocker) {
if app.sealed {
panic("SetPreBlocker() on sealed BaseApp")
}
app.preBlocker = preBlocker
}
func (app *BaseApp) SetBeginBlocker(beginBlocker sdk.BeginBlocker) {
if app.sealed {
panic("SetBeginBlocker() on sealed BaseApp")

View File

@ -92,3 +92,4 @@ When writing ADRs, follow the same best practices for writing RFCs. When writing
* [ADR 044: Guidelines for Updating Protobuf Definitions](./adr-044-protobuf-updates-guidelines.md)
* [ADR 047: Extend Upgrade Plan](./adr-047-extend-upgrade-plan.md)
* [ADR 053: Go Module Refactoring](./adr-053-go-module-refactoring.md)
* [ADR 068: Preblock](./adr-068-preblock.md)

View File

@ -280,6 +280,17 @@ type HasGenesis interface {
}
```
#### Pre Blockers
Modules that have functionality that runs before BeginBlock and should implement the has `HasPreBlocker` interfaces:
```go
type HasPreBlocker interface {
AppModule
PreBlock(context.Context) error
}
```
#### Begin and End Blockers
Modules that have functionality that runs before transactions (begin blockers) or after transactions

View File

@ -0,0 +1,60 @@
# ADR 068: Preblock
## Changelog
* Sept 13, 2023: Initial Draft
## Status
DRAFT
## Abstract
Introduce `PreBlock`, which runs before begin blocker other modules, and allows to modify consensus parameters, and the changes are visible to the following state machine logics.
## Context
When upgrading to sdk 0.47, the storage format for consensus parameters changed, but in the migration block, `ctx.ConsensusParams()` is always `nil`, because it fails to load the old format using new code, it's supposed to be migrated by the `x/upgrade` module first, but unfortunately, the migration happens in `BeginBlocker` handler, which runs after the `ctx` is initialized.
When we try to solve this, we find the `x/upgrade` module can't modify the context to make the consensus parameters visible for the other modules, the context is passed by value, and sdk team want to keep it that way, that's good for isolations between modules.
## Alternatives
The first alternative solution introduced a `MigrateModuleManager`, which only includes the `x/upgrade` module right now, and baseapp will run their `BeginBlocker`s before the other modules, and reload context's consensus parameters in between.
## Decision
Suggested this new lifecycle method.
### `PreBlocker`
There are two semantics around the new lifecycle method:
- It runs before the `BeginBlocker` of all modules
- It can modify consensus parameters in storage, and signal the caller through the return value.
When it returns `ConsensusParamsChanged=true`, the caller must refresh the consensus parameter in the finalize context:
```
app.finalizeBlockState.ctx = app.finalizeBlockState.ctx.WithConsensusParams(app.GetConsensusParams())
```
The new ctx must be passed to all the other lifecycle methods.
## Consequences
### Backwards Compatibility
### Positive
### Negative
### Neutral
## Further Discussions
## Test Cases
## References
* [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

View File

@ -37,7 +37,7 @@ The `app_config.go` file is the single place to configure all modules parameters
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/simapp/app_config.go#L103-L167
```
3. Configure the modules defined in the `BeginBlocker` and `EndBlocker` and the `tx` module:
3. Configure the modules defined in the `PreBlocker`, `BeginBlocker` and `EndBlocker` and the `tx` module:
```go reference
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/simapp/app_config.go#L112-L129

View File

@ -50,6 +50,24 @@ the rest of the block as normal. Once 2/3 of the voting power has upgraded, the
resume the consensus mechanism. If the majority of operators add a custom `do-upgrade` script, this should
be a matter of minutes and not even require them to be awake at that time.
## Set PreBlocker
:::tip
Users using `depinject` / app v2 do not need any changes, this is abstracted for them.
:::
Call `SetPreBlocker` to run `PreBlock`:
```go
app.SetPreBlocker(app.PreBlocker)
```
```go
func (app *SimApp) PreBlocker(ctx sdk.Context, req abci.RequestBeginBlock) (sdk.ResponsePreBlock, error) {
return app.ModuleManager.PreBlock(ctx, req)
}
```
## Integrating With An App
Setup an upgrade Keeper for the app and then define a `BeginBlocker` that calls the upgrade

View File

@ -5,7 +5,7 @@ sidebar_position: 1
# Module Manager
:::note Synopsis
Cosmos SDK modules need to implement the [`AppModule` interfaces](#application-module-interfaces), in order to be managed by the application's [module manager](#module-manager). The module manager plays an important role in [`message` and `query` routing](../../develop/advanced/00-baseapp.md#routing), and allows application developers to set the order of execution of a variety of functions like [`BeginBlocker` and `EndBlocker`](../../develop/beginner/00-app-anatomy.md#begingblocker-and-endblocker).
Cosmos SDK modules need to implement the [`AppModule` interfaces](#application-module-interfaces), in order to be managed by the application's [module manager](#module-manager). The module manager plays an important role in [`message` and `query` routing](../../develop/advanced/00-baseapp.md#routing), and allows application developers to set the order of execution of a variety of functions like [`PreBlocker`](../../develop/beginner/00-app-anatomy#preblocker) and [`BeginBlocker` and `EndBlocker`](../../develop/beginner/00-app-anatomy.md#begingblocker-and-endblocker).
:::
:::note Pre-requisite Readings
@ -36,6 +36,7 @@ The above interfaces are mostly embedding smaller interfaces (extension interfac
* [`module.HasGenesis`](#modulehasgenesis) for inter-dependent genesis-related module functionalities.
* [`module.HasABCIGenesis`](#modulehasabcigenesis) for inter-dependent genesis-related module functionalities.
* [`appmodule.HasGenesis` / `module.HasGenesis`](#appmodulehasgenesis): The extension interface for stateful genesis methods.
* [`appmodule.HasPreBlocker`](#haspreblocker): The extension interface that contains information about the `AppModule` and `PreBlock`.
* [`appmodule.HasBeginBlocker`](#hasbeginblocker): The extension interface that contains information about the `AppModule` and `BeginBlock`.
* [`appmodule.HasEndBlocker`](#hasendblocker): The extension interface that contains information about the `AppModule` and `EndBlock`.
* [`appmodule.HasPrecommit`](#hasprecommit): The extension interface that contains information about the `AppModule` and `Precommit`.
@ -181,6 +182,10 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go
* `ConsensusVersion() uint64`: Returns the consensus version of the module.
### `HasPreBlocker`
The `HasPreBlocker` is an extension interface from `appmodule.AppModule`. All modules that have an `PreBlock` method implement this interface.
### `HasBeginBlocker`
The `HasBeginBlocker` is an extension interface from `appmodule.AppModule`. All modules that have an `BeginBlock` method implement this interface.
@ -291,6 +296,7 @@ The module manager is used throughout the application whenever an action on a co
* `SetOrderInitGenesis(moduleNames ...string)`: Sets the order in which the [`InitGenesis`](./08-genesis.md#initgenesis) function of each module will be called when the application is first started. This function is generally called from the application's main [constructor function](../../develop/beginner/00-app-anatomy.md#constructor-function).
To initialize modules successfully, module dependencies should be considered. For example, the `genutil` module must occur after `staking` module so that the pools are properly initialized with tokens from genesis accounts, the `genutils` module must also occur after `auth` so that it can access the params from auth, IBC's `capability` module should be initialized before all other modules so that it can initialize any capabilities.
* `SetOrderExportGenesis(moduleNames ...string)`: Sets the order in which the [`ExportGenesis`](./08-genesis.md#exportgenesis) function of each module will be called in case of an export. This function is generally called from the application's main [constructor function](../../develop/beginner/00-app-anatomy.md#constructor-function).
* `SetOrderPreBlockers(moduleNames ...string)`: Sets the order in which the `PreBlock()` function of each module will be called before `BeginBlock()` of all modules. This function is generally called from the application's main [constructor function](../../develop/beginner/00-app-anatomy.md#constructor-function).
* `SetOrderBeginBlockers(moduleNames ...string)`: Sets the order in which the `BeginBlock()` function of each module will be called at the beginning of each block. This function is generally called from the application's main [constructor function](../../develop/beginner/00-app-anatomy.md#constructor-function).
* `SetOrderEndBlockers(moduleNames ...string)`: Sets the order in which the `EndBlock()` function of each module will be called at the end of each block. This function is generally called from the application's main [constructor function](../../develop/beginner/00-app-anatomy.md#constructor-function).
* `SetOrderPrecommiters(moduleNames ...string)`: Sets the order in which the `Precommit()` function of each module will be called during commit of each block. This function is generally called from the application's main [constructor function](../../develop/beginner/00-app-anatomy.md#constructor-function).
@ -301,12 +307,11 @@ The module manager is used throughout the application whenever an action on a co
* `InitGenesis(ctx context.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage)`: Calls the [`InitGenesis`](./08-genesis.md#initgenesis) function of each module when the application is first started, in the order defined in `OrderInitGenesis`. Returns an `abci.ResponseInitChain` to the underlying consensus engine, which can contain validator updates.
* `ExportGenesis(ctx context.Context, cdc codec.JSONCodec)`: Calls the [`ExportGenesis`](./08-genesis.md#exportgenesis) function of each module, in the order defined in `OrderExportGenesis`. The export constructs a genesis file from a previously existing state, and is mainly used when a hard-fork upgrade of the chain is required.
* `ExportGenesisForModules(ctx context.Context, cdc codec.JSONCodec, modulesToExport []string)`: Behaves the same as `ExportGenesis`, except takes a list of modules to export.
* `BeginBlock(ctx context.Context) error`: At the beginning of each block, this function is called from [`BaseApp`](.../../develop/advanced#beginblock) and, in turn, calls the [`BeginBlock`](./06-beginblock-endblock.md) function of all modules implementing the `appmodule.HasBeginBlocker` interface, in the order defined in `OrderBeginBlockers`. It creates a child [context](../../develop/advanced/02-context.md) with an event manager to aggregate [events](../../develop/advanced/08-events.md) emitted from modules.
* `EndBlock(ctx context.Context) error`: At the end of each block, this function is called from [`BaseApp`](.../../develop/advanced#endblock) and, in turn, calls the [`EndBlock`](./06-beginblock-endblock.md) function of each modules implementing the `appmodule.HasEndBlocker` interface, in the order defined in `OrderEndBlockers`. It creates a child [context](../../develop/advanced/02-context.md) with an event manager to aggregate [events](../../develop/advanced/08-events.md) emitted from all modules. The function returns an `abci` which contains the aforementioned events, as well as validator set updates (if any).
* `EndBlock(context.Context) ([]abci.ValidatorUpdate, error)`: At the end of each block, this function is called from [`BaseApp`](.../../develop/advanced#endblock) and, in turn, calls the [`EndBlock`](./06-beginblock-endblock.md) function of each modules implementing the `module.HasABCIEndblock` interface, in the order defined in `OrderEndBlockers`. It creates a child [context](../../develop/advanced/02-context.md) with an event manager to aggregate [events](../../develop/advanced/08-events.md) emitted from all modules. The function returns an `abci` which contains the aforementioned events, as well as validator set updates (if any).
* `Precommit(ctx context.Context)`: During [`Commit`](.../../develop/advanced#commit), this function is called from `BaseApp` immediately before the [`deliverState`](.../../develop/advanced#state-updates) is written to the underlying [`rootMultiStore`](../../develop/advanced/04-store.md#commitmultistore) and, in turn calls the `Precommit` function of each modules implementing the `HasPrecommit` interface, in the order defined in `OrderPrecommiters`. It creates a child [context](../../develop/advanced/02-context.md) where the underlying `CacheMultiStore` is that of the newly committed block's [`finalizeblockstate`](.../../develop/advanced#state-updates).
* `PrepareCheckState(ctx context.Context)`: During [`Commit`](.../../develop/advanced#commit), this function is called from `BaseApp` immediately after the [`deliverState`](.../../develop/advanced#state-updates) is written to the underlying [`rootMultiStore`](../../develop/advanced/04-store.md#commitmultistore) and, in turn calls the `PrepareCheckState` function of each module implementing the `HasPrepareCheckState` interface, in the order defined in `OrderPrepareCheckStaters`. It creates a child [context](../../develop/advanced/02-context.md) where the underlying `CacheMultiStore` is that of the next block's [`checkState`](.../../develop/advanced#state-updates). Writes to this state will be present in the [`checkState`](.../../develop/advanced#state-updates) of the next block, and therefore this method can be used to prepare the `checkState` for the next block.
* `RunMigrationBeginBlock(ctx sdk.Context) (bool, error)`: At the beginning of each block, this function is called from [`BaseApp`](../../develop/advanced/00-baseapp.md#beginblock) and, in turn, calls the [`BeginBlock`](./06-beginblock-endblock.md) function of the upgrade module implementing the `HasBeginBlocker` interface. The function returns a boolean value indicating whether the migration was executed or not and an error if fails.
* `BeginBlock(ctx context.Context) error`: At the beginning of each block, this function is called from [`BaseApp`](../../develop/advanced/00-baseapp.md#beginblock) and, in turn, calls the [`BeginBlock`](./05-beginblock-endblock.md) function of each modules implementing the `appmodule.HasBeginBlocker` interface, in the order defined in `OrderBeginBlockers`. It creates a child [context](../../develop/advanced/02-context.md) with an event manager to aggregate [events](../../develop/advanced/08-events.md) emitted from each modules.
* `EndBlock(ctx context.Context) error`: At the end of each block, this function is called from [`BaseApp`](../../develop/advanced/00-baseapp.md#endblock) and, in turn, calls the [`EndBlock`](./05-beginblock-endblock.md) function of each modules implementing the `appmodule.HasEndBlocker` interface, in the order defined in `OrderEndBlockers`. It creates a child [context](../../develop/advanced/02-context.md) with an event manager to aggregate [events](../../develop/advanced/08-events.md) emitted from all modules. The function returns an `abci` which contains the aforementioned events, as well as validator set updates (if any).
* `EndBlock(context.Context) ([]abci.ValidatorUpdate, error)`: At the end of each block, this function is called from [`BaseApp`](../../develop/advanced/00-baseapp.md#endblock) and, in turn, calls the [`EndBlock`](./05-beginblock-endblock.md) function of each modules implementing the `module.HasABCIEndblock` interface, in the order defined in `OrderEndBlockers`. It creates a child [context](../../develop/advanced/02-context.md) with an event manager to aggregate [events](../../develop/advanced/08-events.md) emitted from all modules. The function returns an `abci` which contains the aforementioned events, as well as validator set updates (if any).
* `Precommit(ctx context.Context)`: During [`Commit`](../../develop/advanced/00-baseapp.md#commit), this function is called from `BaseApp` immediately before the [`deliverState`](../../develop/advanced/00-baseapp.md#state-updates) is written to the underlying [`rootMultiStore`](../../develop/advanced/04-store.md#commitmultistore) and, in turn calls the `Precommit` function of each modules implementing the `HasPrecommit` interface, in the order defined in `OrderPrecommiters`. It creates a child [context](../../develop/advanced/02-context.md) where the underlying `CacheMultiStore` is that of the newly committed block's [`finalizeblockstate`](../../develop/advanced/00-baseapp.md#state-updates).
* `PrepareCheckState(ctx context.Context)`: During [`Commit`](../../develop/advanced/00-baseapp.md#commit), this function is called from `BaseApp` immediately after the [`deliverState`](../../develop/advanced/00-baseapp.md#state-updates) is written to the underlying [`rootMultiStore`](../../develop/advanced/04-store.md#commitmultistore) and, in turn calls the `PrepareCheckState` function of each module implementing the `HasPrepareCheckState` interface, in the order defined in `OrderPrepareCheckStaters`. It creates a child [context](../../develop/advanced/02-context.md) where the underlying `CacheMultiStore` is that of the next block's [`checkState`](../../develop/advanced/00-baseapp.md#state-updates). Writes to this state will be present in the [`checkState`](../../develop/advanced/00-baseapp.md#state-updates) of the next block, and therefore this method can be used to prepare the `checkState` for the next block.
Here's an example of a concrete integration within an `simapp`:

View File

@ -0,0 +1,31 @@
---
sidebar_position: 1
---
# PreBlocker
:::note Synopsis
`PreBlocker` is optional method module developers can implement in their module. They will be triggered before [`BeginBlock`](../../develop/advanced/00-baseapp.md#beginblock).
:::
:::note Pre-requisite Readings
* [Module Manager](./01-module-manager.md)
:::
## PreBlocker
There are two semantics around the new lifecycle method:
- It runs before the `BeginBlocker` of all modules
- It can modify consensus parameters in storage, and signal the caller through the return value.
When it returns `ConsensusParamsChanged=true`, the caller must refresh the consensus parameter in the deliver context:
```
app.finalizeBlockState.ctx = app.finalizeBlockState.ctx.WithConsensusParams(app.GetConsensusParams())
```
The new ctx must be passed to all the other lifecycle methods.
<!-- TODO: leaving this here to update docs with core api changes -->

View File

@ -78,8 +78,7 @@ First, the important parameters that are initialized during the bootstrapping of
* [`AnteHandler`](#antehandler): This handler is used to handle signature verification, fee payment,
and other pre-message execution checks when a transaction is received. It's executed during
[`CheckTx/RecheckTx`](#checktx) and [`FinalizeBlock`](#finalizeblock).
* [`InitChainer`](../beginner/00-app-anatomy.md#initchainer),
[`BeginBlocker` and `EndBlocker`](../beginner/00-app-anatomy.md#beginblocker-and-endblocker): These are
* [`InitChainer`](../beginner/00-app-anatomy.md#initchainer), [`PreBlocker`](../beginner/00-app-anatomy.md#preblocker), [`BeginBlocker` and `EndBlocker`](../beginner/00-app-anatomy.md#beginblocker-and-endblocker): These are
the functions executed when the application receives the `InitChain` and `FinalizeBlock`
ABCI messages from the underlying CometBFT engine.
@ -444,6 +443,10 @@ The [`FinalizeBlock` ABCI message](https://github.com/cometbft/cometbft/blob/v0.
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/baseapp/abci.go#L623
```
#### PreBlock
* Run the application's [`preBlocker()`](../beginner/00-app-anatomy.md#preblocker), which mainly runs the [`PreBlocker()`](../building-modules/17-preblock.md#preblock) method of each of the modules.
#### BeginBlock
* Initialize [`finalizeBlockState`](#state-updates) with the latest header using the `req abci.RequestFinalizeBlock` passed as parameter via the `setState` function.
@ -454,8 +457,8 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/baseapp/abci.go#L623
This function also resets the [main gas meter](../beginner/04-gas-fees.md#main-gas-meter).
* Initialize the [block gas meter](../basics/04-gas-fees.md#block-gas-meter) with the `maxGas` limit. The `gas` consumed within the block cannot go above `maxGas`. This parameter is defined in the application's consensus parameters.
* Run the application's [`beginBlocker()`](../basics/00-app-anatomy.md#beginblocker-and-endblock), which mainly runs the [`BeginBlocker()`](../building-modules/05-beginblock-endblock.md#beginblock) method of each of the application's modules.
* Initialize the [block gas meter](../beginner/04-gas-fees.md#block-gas-meter) with the `maxGas` limit. The `gas` consumed within the block cannot go above `maxGas`. This parameter is defined in the application's consensus parameters.
* Run the application's [`beginBlocker()`](../beginner/00-app-anatomy.md#beginblocker-and-endblocker), which mainly runs the [`BeginBlocker()`](../../build/building-modules/05-beginblock-endblock.md#beginblock) method of each of the modules.
* Set the [`VoteInfos`](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_methods.md#voteinfo) of the application, i.e. the list of validators whose _precommit_ for the previous block was included by the proposer of the current block. This information is carried into the [`Context`](./02-context.md) so that it can be used during transaction execution and EndBlock.
#### Transaction Execution

View File

@ -55,7 +55,7 @@ The first thing defined in `app.go` is the `type` of the application. It is gene
* **A list of module's `keeper`s.** Each module defines an abstraction called [`keeper`](../../build/building-modules/06-keeper.md), which handles reads and writes for this module's store(s). The `keeper`'s methods of one module can be called from other modules (if authorized), which is why they are declared in the application's type and exported as interfaces to other modules so that the latter can only access the authorized functions.
* **A reference to an [`appCodec`](../advanced/05-encoding.md).** The application's `appCodec` is used to serialize and deserialize data structures in order to store them, as stores can only persist `[]bytes`. The default codec is [Protocol Buffers](../advanced/05-encoding.md).
* **A reference to a [`legacyAmino`](../advanced/05-encoding.md) codec.** Some parts of the Cosmos SDK have not been migrated to use the `appCodec` above, and are still hardcoded to use Amino. Other parts explicitly use Amino for backwards compatibility. For these reasons, the application still holds a reference to the legacy Amino codec. Please note that the Amino codec will be removed from the SDK in the upcoming releases.
* **A reference to a [module manager](../../build/building-modules/01-module-manager.md#manager)** and a [basic module manager](../../build/building-modules/01-module-manager.md#basicmanager). The module manager is an object that contains a list of the application's modules. It facilitates operations related to these modules, like registering their [`Msg` service](../advanced/00-baseapp.md#msg-services) and [gRPC `Query` service](../advanced/00-baseapp.md#grpc-query-services), or setting the order of execution between modules for various functions like [`InitChainer`](#initchainer), [`BeginBlocker` and `EndBlocker`](#beginblocker-and-endblocker).
* **A reference to a [module manager](../../build/building-modules/01-module-manager.md#manager)** and a [basic module manager](../../build/building-modules/01-module-manager.md#basicmanager). The module manager is an object that contains a list of the application's modules. It facilitates operations related to these modules, like registering their [`Msg` service](../advanced/00-baseapp.md#msg-services) and [gRPC `Query` service](../advanced/00-baseapp.md#grpc-query-services), or setting the order of execution between modules for various functions like [`InitChainer`](#initchainer), [`PreBlocker`](#preblocker) and [`BeginBlocker` and `EndBlocker`](#beginblocker-and-endblocker).
See an example of application type definition from `simapp`, the Cosmos SDK's own app used for demo and testing purposes:
@ -79,10 +79,11 @@ Here are the main actions performed by this function:
* Instantiate the application's [module manager](../../build/building-modules/01-module-manager.md#manager) with the [`AppModule`](#application-module-interface) object of each of the application's modules.
* With the module manager, initialize the application's [`Msg` services](../advanced/00-baseapp.md#msg-services), [gRPC `Query` services](../advanced/00-baseapp.md#grpc-query-services), [legacy `Msg` routes](../advanced/00-baseapp.md#routing), and [legacy query routes](../advanced/00-baseapp.md#query-routing). When a transaction is relayed to the application by CometBFT via the ABCI, it is routed to the appropriate module's [`Msg` service](#msg-services) using the routes defined here. Likewise, when a gRPC query request is received by the application, it is routed to the appropriate module's [`gRPC query service`](#grpc-query-services) using the gRPC routes defined here. The Cosmos SDK still supports legacy `Msg`s and legacy CometBFT queries, which are routed using the legacy `Msg` routes and the legacy query routes, respectively.
* With the module manager, register the [application's modules' invariants](../../build/building-modules/07-invariants.md). Invariants are variables (e.g. total supply of a token) that are evaluated at the end of each block. The process of checking invariants is done via a special module called the [`InvariantsRegistry`](../../build/building-modules/07-invariants.md#invariant-registry). The value of the invariant should be equal to a predicted value defined in the module. Should the value be different than the predicted one, special logic defined in the invariant registry is triggered (usually the chain is halted). This is useful to make sure that no critical bug goes unnoticed, producing long-lasting effects that are hard to fix.
* With the module manager, set the order of execution between the `InitGenesis`, `BeginBlocker`, and `EndBlocker` functions of each of the [application's modules](#application-module-interface). Note that not all modules implement these functions.
* With the module manager, set the order of execution between the `InitGenesis`, `PreBlocker`, `BeginBlocker`, and `EndBlocker` functions of each of the [application's modules](#application-module-interface). Note that not all modules implement these functions.
* Set the remaining application parameters:
* [`InitChainer`](#initchainer): used to initialize the application when it is first started.
* [`BeginBlocker`, `EndBlocker`](#beginblocker-and-endlbocker): called at the beginning and at the end of every block.
* [`PreBlocker`](#preblocker): called before BeginBlock.
* [`BeginBlocker`, `EndBlocker`](#beginblocker-and-endblocker): called at the beginning and at the end of every block.
* [`anteHandler`](../advanced/00-baseapp.md#antehandler): used to handle fees and signature verification.
* Mount the stores.
* Return the application.
@ -107,6 +108,21 @@ See an example of an `InitChainer` from `simapp`:
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/simapp/app.go#L626-L634
```
### PreBlocker
There are two semantics around the new lifecycle method:
* It runs before the `BeginBlocker` of all modules
* It can modify consensus parameters in storage, and signal the caller through the return value.
When it returns `ConsensusParamsChanged=true`, the caller must refresh the consensus parameter in the finalize context:
```go
app.finalizeBlockState.ctx = app.finalizeBlockState.ctx.WithConsensusParams(app.GetConsensusParams())
```
The new ctx must be passed to all the other lifecycle methods.
### BeginBlocker and EndBlocker
The Cosmos SDK offers developers the possibility to implement automatic execution of code as part of their application. This is implemented through two functions called `BeginBlocker` and `EndBlocker`. They are called when the application receives the `FinalizeBlock` messages from the CometBFT consensus engine, which happens respectively at the beginning and at the end of each block. The application must set the `BeginBlocker` and `EndBlocker` in its [constructor](#constructor-function) via the [`SetBeginBlocker`](https://pkg.go.dev/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetBeginBlocker) and [`SetEndBlocker`](https://pkg.go.dev/github.com/cosmos/cosmos-sdk/baseapp#BaseApp.SetEndBlocker) methods.

2
go.mod
View File

@ -5,7 +5,7 @@ toolchain go1.21.0
module github.com/cosmos/cosmos-sdk
require (
cosmossdk.io/api v0.7.0
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0
cosmossdk.io/collections v0.4.0
cosmossdk.io/core v0.11.0
cosmossdk.io/depinject v1.0.0-alpha.4

4
go.sum
View File

@ -35,8 +35,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4=
cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0 h1:z1aCAqEXi5fzC5tjanWnkP/zhhuWTX17IiNKxLvXFcw=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0/go.mod h1:h4YT2OHIBT/YIwWrc5L+4dY05ZIqvo89zs6m7j4/RSk=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0=
cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo=

View File

@ -114,6 +114,11 @@ func (a *App) Load(loadLatest bool) error {
a.ModuleManager.SetOrderExportGenesis(a.config.InitGenesis...)
}
if len(a.config.PreBlockers) != 0 {
a.ModuleManager.SetOrderPreBlockers(a.config.PreBlockers...)
a.SetPreBlocker(a.PreBlocker)
}
if len(a.config.BeginBlockers) != 0 {
a.ModuleManager.SetOrderBeginBlockers(a.config.BeginBlockers...)
a.SetBeginBlocker(a.BeginBlocker)
@ -147,6 +152,11 @@ func (a *App) Load(loadLatest bool) error {
return nil
}
// PreBlocker application updates every pre block
func (a *App) PreBlocker(ctx sdk.Context) (sdk.ResponsePreBlock, error) {
return a.ModuleManager.PreBlock(ctx)
}
// BeginBlocker application updates every begin block
func (a *App) BeginBlocker(ctx sdk.Context) (sdk.BeginBlock, error) {
return a.ModuleManager.BeginBlock(ctx)

View File

@ -35,6 +35,7 @@ func (a *AppBuilder) Build(db dbm.DB, traceStore io.Writer, baseAppOptions ...fu
bApp.SetVersion(version.Version)
bApp.SetInterfaceRegistry(a.app.interfaceRegistry)
bApp.MountStores(a.app.storeKeys...)
bApp.SetPreBlocker(a.app.PreBlocker)
a.app.BaseApp = bApp
a.app.configurator = module.NewConfigurator(a.app.cdc, a.app.MsgServiceRouter(), a.app.GRPCQueryRouter())

View File

@ -419,12 +419,15 @@ func NewSimApp(
app.BasicModuleManager.RegisterLegacyAminoCodec(legacyAmino)
app.BasicModuleManager.RegisterInterfaces(interfaceRegistry)
// NOTE: upgrade module is required to be prioritized
app.ModuleManager.SetOrderPreBlockers(
upgradetypes.ModuleName,
)
// During begin block slashing happens after distr.BeginBlocker so that
// there is nothing left over in the validator fee pool, so as to keep the
// CanWithdrawInvariant invariant.
// NOTE: staking module is required if HistoricalEntries param > 0
app.ModuleManager.SetOrderBeginBlockers(
upgradetypes.ModuleName,
minttypes.ModuleName,
distrtypes.ModuleName,
slashingtypes.ModuleName,
@ -497,6 +500,7 @@ func NewSimApp(
// initialize BaseApp
app.SetInitChainer(app.InitChainer)
app.SetPreBlocker(app.PreBlocker)
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.setAnteHandler(txConfig)
@ -578,6 +582,11 @@ func (app *SimApp) setPostHandler() {
// Name returns the name of the App
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) {
return app.ModuleManager.PreBlock(ctx)
}
// BeginBlocker application updates every begin block
func (app *SimApp) BeginBlocker(ctx sdk.Context) (sdk.BeginBlock, error) {
return app.ModuleManager.BeginBlock(ctx)

View File

@ -105,12 +105,15 @@ var (
Name: runtime.ModuleName,
Config: appconfig.WrapAny(&runtimev1alpha1.Module{
AppName: "SimApp",
// NOTE: upgrade module is required to be prioritized
PreBlockers: []string{
upgradetypes.ModuleName,
},
// During begin block slashing happens after distr.BeginBlocker so that
// there is nothing left over in the validator fee pool, so as to keep the
// CanWithdrawInvariant invariant.
// NOTE: staking module is required if HistoricalEntries param > 0
BeginBlockers: []string{
upgradetypes.ModuleName,
minttypes.ModuleName,
distrtypes.ModuleName,
slashingtypes.ModuleName,

View File

@ -3,7 +3,7 @@ module cosmossdk.io/simapp
go 1.21
require (
cosmossdk.io/api v0.7.0
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0
cosmossdk.io/client/v2 v2.0.0-20230913132541-a4de97633356
cosmossdk.io/collections v0.4.0 // indirect
cosmossdk.io/core v0.11.0
@ -17,7 +17,7 @@ require (
cosmossdk.io/x/feegrant v0.0.0-20230830091712-93ab28fe0ea1
cosmossdk.io/x/nft v0.0.0-20230830091712-93ab28fe0ea1
cosmossdk.io/x/tx v0.9.2-0.20230913111958-e394604f8382
cosmossdk.io/x/upgrade v0.0.0-20230818115413-c402c51a1508
cosmossdk.io/x/upgrade v0.0.0-20230913161052-9f2c39bb9d01
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

@ -187,8 +187,8 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX
cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4=
cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0 h1:z1aCAqEXi5fzC5tjanWnkP/zhhuWTX17IiNKxLvXFcw=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0/go.mod h1:h4YT2OHIBT/YIwWrc5L+4dY05ZIqvo89zs6m7j4/RSk=
cosmossdk.io/client/v2 v2.0.0-20230913132541-a4de97633356 h1:uOD69eQuITHL+UXCbyXPit+MqNzo1tfhZwOEezphUbc=
cosmossdk.io/client/v2 v2.0.0-20230913132541-a4de97633356/go.mod h1:iqp9sDP2SihiZ1mC/E4tbo4YQFcrWn3t2Zo12bU3EvM=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
@ -217,8 +217,8 @@ cosmossdk.io/x/nft v0.0.0-20230830091712-93ab28fe0ea1 h1:YpE6N2yzG1NMvHzqkVbvObk
cosmossdk.io/x/nft v0.0.0-20230830091712-93ab28fe0ea1/go.mod h1:M4FXuqMk3cKuCm6K3HHCk337+3NEh+h7V5ocNnDo7PI=
cosmossdk.io/x/tx v0.9.2-0.20230913111958-e394604f8382 h1:p/wyc5pVTMtx2/RsKP0fUpOKGbDfy6q6WswJtmARdbg=
cosmossdk.io/x/tx v0.9.2-0.20230913111958-e394604f8382/go.mod h1:MKo9/b5wsoL8dd9y9pvD2yOP1CMvzHIWYxi1l2oLPFo=
cosmossdk.io/x/upgrade v0.0.0-20230818115413-c402c51a1508 h1:tZ5fSX+ev+QHQ15457Vhxug8BSZJcHeBhU8DpgwlkCc=
cosmossdk.io/x/upgrade v0.0.0-20230818115413-c402c51a1508/go.mod h1:M0JWINHzdN0eFHrWMs082akHHSO5muExS+/tNNIOyP8=
cosmossdk.io/x/upgrade v0.0.0-20230913161052-9f2c39bb9d01 h1:V1N66fJvKxreb5vJZdL3R/OlAO8a0KQTRUyYfZFDOC4=
cosmossdk.io/x/upgrade v0.0.0-20230913161052-9f2c39bb9d01/go.mod h1:nLBiFTPw6e4LBT1ZWdGBIOjleiVNaqqmsTxU4GgEYaQ=
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

@ -3,7 +3,7 @@ module github.com/cosmos/cosmos-sdk/tests
go 1.21
require (
cosmossdk.io/api v0.7.0
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0
cosmossdk.io/core v0.11.0
cosmossdk.io/depinject v1.0.0-alpha.4
cosmossdk.io/errors v1.0.0
@ -15,7 +15,7 @@ require (
cosmossdk.io/x/feegrant v0.0.0-20230830091712-93ab28fe0ea1
cosmossdk.io/x/nft v0.0.0-20230830091712-93ab28fe0ea1 // indirect
cosmossdk.io/x/tx v0.9.2-0.20230913111958-e394604f8382
cosmossdk.io/x/upgrade v0.0.0-20230818115413-c402c51a1508
cosmossdk.io/x/upgrade v0.0.0-20230913161052-9f2c39bb9d01
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

@ -187,8 +187,8 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX
cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4=
cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0 h1:z1aCAqEXi5fzC5tjanWnkP/zhhuWTX17IiNKxLvXFcw=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0/go.mod h1:h4YT2OHIBT/YIwWrc5L+4dY05ZIqvo89zs6m7j4/RSk=
cosmossdk.io/client/v2 v2.0.0-20230913132541-a4de97633356 h1:uOD69eQuITHL+UXCbyXPit+MqNzo1tfhZwOEezphUbc=
cosmossdk.io/client/v2 v2.0.0-20230913132541-a4de97633356/go.mod h1:iqp9sDP2SihiZ1mC/E4tbo4YQFcrWn3t2Zo12bU3EvM=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
@ -215,8 +215,8 @@ cosmossdk.io/x/nft v0.0.0-20230830091712-93ab28fe0ea1 h1:YpE6N2yzG1NMvHzqkVbvObk
cosmossdk.io/x/nft v0.0.0-20230830091712-93ab28fe0ea1/go.mod h1:M4FXuqMk3cKuCm6K3HHCk337+3NEh+h7V5ocNnDo7PI=
cosmossdk.io/x/tx v0.9.2-0.20230913111958-e394604f8382 h1:p/wyc5pVTMtx2/RsKP0fUpOKGbDfy6q6WswJtmARdbg=
cosmossdk.io/x/tx v0.9.2-0.20230913111958-e394604f8382/go.mod h1:MKo9/b5wsoL8dd9y9pvD2yOP1CMvzHIWYxi1l2oLPFo=
cosmossdk.io/x/upgrade v0.0.0-20230818115413-c402c51a1508 h1:tZ5fSX+ev+QHQ15457Vhxug8BSZJcHeBhU8DpgwlkCc=
cosmossdk.io/x/upgrade v0.0.0-20230818115413-c402c51a1508/go.mod h1:M0JWINHzdN0eFHrWMs082akHHSO5muExS+/tNNIOyP8=
cosmossdk.io/x/upgrade v0.0.0-20230913161052-9f2c39bb9d01 h1:V1N66fJvKxreb5vJZdL3R/OlAO8a0KQTRUyYfZFDOC4=
cosmossdk.io/x/upgrade v0.0.0-20230913161052-9f2c39bb9d01/go.mod h1:nLBiFTPw6e4LBT1ZWdGBIOjleiVNaqqmsTxU4GgEYaQ=
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

@ -28,6 +28,7 @@ import (
// Config should never need to be instantiated manually and is solely used for ModuleOption.
type Config struct {
ModuleConfigs map[string]*appv1alpha1.ModuleConfig
PreBlockersOrder []string
BeginBlockersOrder []string
EndBlockersOrder []string
InitGenesisOrder []string
@ -37,8 +38,10 @@ type Config struct {
func defaultConfig() *Config {
return &Config{
ModuleConfigs: make(map[string]*appv1alpha1.ModuleConfig),
BeginBlockersOrder: []string{
PreBlockersOrder: []string{
"upgrade",
},
BeginBlockersOrder: []string{
"mint",
"distribution",
"slashing",
@ -106,6 +109,12 @@ func defaultConfig() *Config {
type ModuleOption func(config *Config)
func WithCustomPreBlockersOrder(preBlockOrder ...string) ModuleOption {
return func(config *Config) {
config.PreBlockersOrder = preBlockOrder
}
}
func WithCustomBeginBlockersOrder(beginBlockOrder ...string) ModuleOption {
return func(config *Config) {
config.BeginBlockersOrder = beginBlockOrder
@ -315,11 +324,18 @@ func NewAppConfig(opts ...ModuleOption) depinject.Config {
opt(cfg)
}
preBlockers := make([]string, 0)
beginBlockers := make([]string, 0)
endBlockers := make([]string, 0)
initGenesis := make([]string, 0)
overrides := make([]*runtimev1alpha1.StoreKeyConfig, 0)
for _, s := range cfg.PreBlockersOrder {
if _, ok := cfg.ModuleConfigs[s]; ok {
preBlockers = append(preBlockers, s)
}
}
for _, s := range cfg.BeginBlockersOrder {
if _, ok := cfg.ModuleConfigs[s]; ok {
beginBlockers = append(beginBlockers, s)
@ -344,6 +360,7 @@ func NewAppConfig(opts ...ModuleOption) depinject.Config {
runtimeConfig := &runtimev1alpha1.Module{
AppName: "TestApp",
PreBlockers: preBlockers,
BeginBlockers: beginBlockers,
EndBlockers: endBlockers,
OverrideStoreKeys: overrides,

View File

@ -540,3 +540,45 @@ func (mr *MockCoreAppModuleMockRecorder) ValidateGenesis(arg0 interface{}) *gomo
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockCoreAppModule)(nil).ValidateGenesis), arg0)
}
// MockCoreModuleWithPreBlock is a mock of CoreModuleWithPreBlock interface.
type MockCoreModuleWithPreBlock struct {
MockCoreAppModule
recorder *MockCoreModuleWithPreBlockMockRecorder
}
// MockCoreModuleWithPreBlockMockRecorder is the mock recorder for MockCoreModuleWithPreBlock.
type MockCoreModuleWithPreBlockMockRecorder struct {
mock *MockCoreModuleWithPreBlock
}
// NewMockCoreModuleWithPreBlock creates a new mock instance.
func NewMockCoreModuleWithPreBlock(ctrl *gomock.Controller) *MockCoreModuleWithPreBlock {
mock := &MockCoreModuleWithPreBlock{
MockCoreAppModule: MockCoreAppModule{
ctrl: ctrl,
},
}
mock.recorder = &MockCoreModuleWithPreBlockMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockCoreModuleWithPreBlock) EXPECT() *MockCoreModuleWithPreBlockMockRecorder {
return m.recorder
}
// PreBlock mocks base method.
func (m *MockCoreModuleWithPreBlock) PreBlock(arg0 context.Context) (appmodule.ResponsePreBlock, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "PreBlock", arg0)
ret0, _ := ret[0].(appmodule.ResponsePreBlock)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// PreBlock indicates an expected call of PreBlock.
func (mr *MockCoreModuleWithPreBlockMockRecorder) PreBlock(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PreBlock", reflect.TypeOf((*MockCoreModuleWithPreBlock)(nil).PreBlock), arg0)
}

View File

@ -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
}

View File

@ -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,6 +735,28 @@ func (m Manager) RunMigrations(ctx context.Context, cfg Configurator, fromVM Ver
return updatedVM, nil
}
// 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) {
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 sdk.ResponsePreBlock{
ConsensusParamsChanged: paramsChanged,
}, nil
}
// BeginBlock performs begin block functionality for all modules. It creates a
// child context with an event manager to aggregate events emitted from all
// modules.

View File

@ -144,6 +144,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)
@ -440,6 +444,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)
@ -457,6 +465,40 @@ func TestCoreAPIManagerOrderSetters(t *testing.T) {
require.Equal(t, []string{"module3", "module2", "module1"}, mm.OrderPrecommiters)
}
func TestCoreAPIManager_PreBlock(t *testing.T) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)
mockAppModule1 := mock.NewMockCoreModuleWithPreBlock(mockCtrl)
mm := module.NewManagerFromMap(map[string]appmodule.AppModule{
"module1": mockAppModule1,
"module2": mock.NewMockCoreAppModule(mockCtrl),
})
require.NotNil(t, mm)
require.Equal(t, 2, len(mm.Modules))
require.Equal(t, 1, len(mm.OrderPreBlockers))
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
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 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) {
mockCtrl := gomock.NewController(t)
t.Cleanup(mockCtrl.Finish)

View File

@ -3,7 +3,7 @@ module cosmossdk.io/x/circuit
go 1.21
require (
cosmossdk.io/api v0.7.0
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0
cosmossdk.io/collections v0.4.0
cosmossdk.io/core v0.11.0
cosmossdk.io/depinject v1.0.0-alpha.4

View File

@ -35,8 +35,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4=
cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0 h1:z1aCAqEXi5fzC5tjanWnkP/zhhuWTX17IiNKxLvXFcw=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0/go.mod h1:h4YT2OHIBT/YIwWrc5L+4dY05ZIqvo89zs6m7j4/RSk=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0=
cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo=

View File

@ -3,7 +3,7 @@ module cosmossdk.io/x/evidence
go 1.21
require (
cosmossdk.io/api v0.7.0
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0
cosmossdk.io/collections v0.4.0
cosmossdk.io/core v0.11.0
cosmossdk.io/depinject v1.0.0-alpha.4

View File

@ -35,8 +35,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4=
cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0 h1:z1aCAqEXi5fzC5tjanWnkP/zhhuWTX17IiNKxLvXFcw=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0/go.mod h1:h4YT2OHIBT/YIwWrc5L+4dY05ZIqvo89zs6m7j4/RSk=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0=
cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo=

View File

@ -3,7 +3,7 @@ module cosmossdk.io/x/nft
go 1.21
require (
cosmossdk.io/api v0.7.0
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0
cosmossdk.io/core v0.11.0
cosmossdk.io/depinject v1.0.0-alpha.4
cosmossdk.io/errors v1.0.0

View File

@ -35,8 +35,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4=
cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0 h1:z1aCAqEXi5fzC5tjanWnkP/zhhuWTX17IiNKxLvXFcw=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0/go.mod h1:h4YT2OHIBT/YIwWrc5L+4dY05ZIqvo89zs6m7j4/RSk=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0=
cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo=

View File

@ -14,7 +14,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// BeginBlock will check if there is a scheduled plan and if it is ready to be executed.
// PreBlocker will check if there is a scheduled plan and if it is ready to be executed.
// If the current height is in the provided set of heights to skip, it will skip and clear the upgrade plan.
// If it is ready, it will execute it if the handler is installed, and panic/abort otherwise.
// If the plan is not ready, it will ensure the handler is not registered too early (and abort otherwise).
@ -22,14 +22,17 @@ 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 BeginBlocker(ctx context.Context, k *keeper.Keeper) error {
func PreBlocker(ctx context.Context, k *keeper.Keeper) (sdk.ResponsePreBlock, error) {
rsp := sdk.ResponsePreBlock{
ConsensusParamsChanged: false,
}
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 err
return rsp, err
}
found := err == nil
@ -43,7 +46,7 @@ func BeginBlocker(ctx context.Context, k *keeper.Keeper) error {
if !found || !plan.ShouldExecute(blockHeight) || (plan.ShouldExecute(blockHeight) && k.IsSkipHeight(blockHeight)) {
lastAppliedPlan, _, err := k.GetLastCompletedUpgrade(ctx)
if err != nil {
return err
return rsp, err
}
if lastAppliedPlan != "" && !k.HasHandler(lastAppliedPlan) {
@ -54,13 +57,13 @@ func BeginBlocker(ctx context.Context, k *keeper.Keeper) error {
appVersion = cp.Version.App
}
return fmt.Errorf("wrong app version %d, upgrade handler is missing for %s upgrade plan", appVersion, lastAppliedPlan)
return rsp, fmt.Errorf("wrong app version %d, upgrade handler is missing for %s upgrade plan", appVersion, lastAppliedPlan)
}
}
}
if !found {
return nil
return rsp, nil
}
logger := k.Logger(ctx)
@ -73,7 +76,7 @@ func BeginBlocker(ctx context.Context, k *keeper.Keeper) error {
logger.Info(skipUpgradeMsg)
// Clear the upgrade plan at current height
return k.ClearUpgradePlan(ctx)
return rsp, k.ClearUpgradePlan(ctx)
}
// Prepare shutdown if we don't have an upgrade handler for this upgrade name (meaning this software is out of date)
@ -82,20 +85,25 @@ func BeginBlocker(ctx context.Context, k *keeper.Keeper) error {
// store migrations.
err := k.DumpUpgradeInfoToDisk(blockHeight, plan)
if err != nil {
return fmt.Errorf("unable to write upgrade info to filesystem: %s", err.Error())
return rsp, 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 fmt.Errorf(upgradeMsg)
return rsp, 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())
return k.ApplyUpgrade(sdkCtx, plan)
err = k.ApplyUpgrade(sdkCtx, plan)
return sdk.ResponsePreBlock{
// the consensus parameters might be modified in the migration,
// refresh the consensus parameters in context.
ConsensusParamsChanged: true,
}, err
}
// if we have a pending upgrade, but it is not yet time, make sure we did not
@ -105,10 +113,9 @@ func BeginBlocker(ctx context.Context, k *keeper.Keeper) error {
logger.Error(downgradeMsg)
// Returning an error will end up in a panic
return fmt.Errorf(downgradeMsg)
return rsp, errors.New(downgradeMsg)
}
return nil
return rsp, nil
}
// BuildUpgradeNeededMsg prints the message that notifies that an upgrade is needed.

View File

@ -30,11 +30,11 @@ import (
)
type TestSuite struct {
module appmodule.HasBeginBlocker
keeper *keeper.Keeper
ctx sdk.Context
baseApp *baseapp.BaseApp
encCfg moduletestutil.TestEncodingConfig
preModule appmodule.HasPreBlocker
keeper *keeper.Keeper
ctx sdk.Context
baseApp *baseapp.BaseApp
encCfg moduletestutil.TestEncodingConfig
}
func (s *TestSuite) VerifyDoUpgrade(t *testing.T) {
@ -42,7 +42,7 @@ func (s *TestSuite) VerifyDoUpgrade(t *testing.T) {
t.Log("Verify that a panic happens at the upgrade height")
newCtx := s.ctx.WithHeaderInfo(header.Info{Height: s.ctx.HeaderInfo().Height + 1, Time: time.Now()})
err := s.module.BeginBlock(newCtx)
_, err := s.preModule.PreBlock(newCtx)
require.ErrorContains(t, err, "UPGRADE \"test\" NEEDED at height: 11: ")
t.Log("Verify that the upgrade can be successfully applied with a handler")
@ -50,7 +50,7 @@ func (s *TestSuite) VerifyDoUpgrade(t *testing.T) {
return vm, nil
})
err = s.module.BeginBlock(newCtx)
_, err = s.preModule.PreBlock(newCtx)
require.NoError(t, err)
s.VerifyCleared(t, newCtx)
@ -60,7 +60,7 @@ func (s *TestSuite) VerifyDoUpgradeWithCtx(t *testing.T, newCtx sdk.Context, pro
t.Helper()
t.Log("Verify that a panic happens at the upgrade height")
err := s.module.BeginBlock(newCtx)
_, err := s.preModule.PreBlock(newCtx)
require.ErrorContains(t, err, "UPGRADE \""+proposalName+"\" NEEDED at height: ")
t.Log("Verify that the upgrade can be successfully applied with a handler")
@ -68,7 +68,7 @@ func (s *TestSuite) VerifyDoUpgradeWithCtx(t *testing.T, newCtx sdk.Context, pro
return vm, nil
})
err = s.module.BeginBlock(newCtx)
_, err = s.preModule.PreBlock(newCtx)
require.NoError(t, err)
s.VerifyCleared(t, newCtx)
@ -126,7 +126,7 @@ func setupTest(t *testing.T, height int64, skip map[int64]bool) *TestSuite {
s.ctx = testCtx.Ctx.WithHeaderInfo(header.Info{Time: time.Now(), Height: height})
s.module = upgrade.NewAppModule(s.keeper, addresscodec.NewBech32Codec("cosmos"))
s.preModule = upgrade.NewAppModule(s.keeper, addresscodec.NewBech32Codec("cosmos"))
return &s
}
@ -167,23 +167,21 @@ func TestHaltIfTooNew(t *testing.T) {
})
newCtx := s.ctx.WithHeaderInfo(header.Info{Height: s.ctx.HeaderInfo().Height + 1, Time: time.Now()})
err := s.module.BeginBlock(newCtx)
_, err := s.preModule.PreBlock(newCtx)
require.NoError(t, err)
require.Equal(t, 0, called)
t.Log("Verify we error if we have a registered handler ahead of time")
err = s.keeper.ScheduleUpgrade(s.ctx, types.Plan{Name: "future", Height: s.ctx.HeaderInfo().Height + 3})
require.NoError(t, err)
err = s.module.BeginBlock(newCtx)
_, err = s.preModule.PreBlock(newCtx)
require.EqualError(t, err, "BINARY UPDATED BEFORE TRIGGER! UPGRADE \"future\" - in binary but not executed on chain. Downgrade your binary")
require.Equal(t, 0, called)
t.Log("Verify we no longer panic if the plan is on time")
futCtx := s.ctx.WithHeaderInfo(header.Info{Height: s.ctx.HeaderInfo().Height + 3, Time: time.Now()})
err = s.module.BeginBlock(futCtx)
_, err = s.preModule.PreBlock(futCtx)
require.NoError(t, err)
require.Equal(t, 1, called)
@ -217,7 +215,7 @@ func TestCantApplySameUpgradeTwice(t *testing.T) {
func TestNoSpuriousUpgrades(t *testing.T) {
s := setupTest(t, 10, map[int64]bool{})
t.Log("Verify that no upgrade panic is triggered in the BeginBlocker when we haven't scheduled an upgrade")
err := s.module.BeginBlock(s.ctx)
_, err := s.preModule.PreBlock(s.ctx)
require.NoError(t, err)
}
@ -254,7 +252,7 @@ func TestSkipUpgradeSkippingAll(t *testing.T) {
s.VerifySet(t, map[int64]bool{skipOne: true, skipTwo: true})
newCtx = newCtx.WithHeaderInfo(header.Info{Height: skipOne})
err = s.module.BeginBlock(newCtx)
_, err = s.preModule.PreBlock(newCtx)
require.NoError(t, err)
t.Log("Verify a second proposal also is being cleared")
@ -262,7 +260,7 @@ func TestSkipUpgradeSkippingAll(t *testing.T) {
require.NoError(t, err)
newCtx = newCtx.WithHeaderInfo(header.Info{Height: skipTwo})
err = s.module.BeginBlock(newCtx)
_, err = s.preModule.PreBlock(newCtx)
require.NoError(t, err)
// To ensure verification is being done only after both upgrades are cleared
@ -289,7 +287,7 @@ func TestUpgradeSkippingOne(t *testing.T) {
// Setting block height of proposal test
newCtx = newCtx.WithHeaderInfo(header.Info{Height: skipOne})
err = s.module.BeginBlock(newCtx)
_, err = s.preModule.PreBlock(newCtx)
require.NoError(t, err)
t.Log("Verify the second proposal is not skipped")
@ -322,7 +320,7 @@ func TestUpgradeSkippingOnlyTwo(t *testing.T) {
// Setting block height of proposal test
newCtx = newCtx.WithHeaderInfo(header.Info{Height: skipOne})
err = s.module.BeginBlock(newCtx)
_, err = s.preModule.PreBlock(newCtx)
require.NoError(t, err)
// A new proposal with height in skipUpgradeHeights
@ -330,7 +328,7 @@ func TestUpgradeSkippingOnlyTwo(t *testing.T) {
require.NoError(t, err)
// Setting block height of proposal test2
newCtx = newCtx.WithHeaderInfo(header.Info{Height: skipTwo})
err = s.module.BeginBlock(newCtx)
_, err = s.preModule.PreBlock(newCtx)
require.NoError(t, err)
t.Log("Verify a new proposal is not skipped")
@ -351,8 +349,7 @@ func TestUpgradeWithoutSkip(t *testing.T) {
err := s.keeper.ScheduleUpgrade(s.ctx, types.Plan{Name: "test", Height: s.ctx.HeaderInfo().Height + 1})
require.NoError(t, err)
t.Log("Verify if upgrade happens without skip upgrade")
err = s.module.BeginBlock(newCtx)
_, err = s.preModule.PreBlock(newCtx)
require.ErrorContains(t, err, "UPGRADE \"test\" NEEDED at height:")
s.VerifyDoUpgrade(t)
@ -442,7 +439,7 @@ func TestBinaryVersion(t *testing.T) {
for _, tc := range testCases {
ctx := tc.preRun()
err := s.module.BeginBlock(ctx)
_, err := s.preModule.PreBlock(ctx)
if tc.expectError {
require.Error(t, err)
} else {
@ -476,7 +473,8 @@ func TestDowngradeVerification(t *testing.T) {
})
// successful upgrade.
require.NoError(t, m.BeginBlock(ctx))
_, err = m.PreBlock(ctx)
require.NoError(t, err)
ctx = ctx.WithHeaderInfo(header.Info{Height: ctx.HeaderInfo().Height + 1})
testCases := map[string]struct {
@ -522,7 +520,7 @@ func TestDowngradeVerification(t *testing.T) {
tc.preRun(k, ctx, name)
}
err = m.BeginBlock(ctx)
_, err = m.PreBlock(ctx)
if tc.expectError {
require.Error(t, err, name)
} else {

View File

@ -3,7 +3,7 @@ module cosmossdk.io/x/upgrade
go 1.21
require (
cosmossdk.io/api v0.7.0
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0
cosmossdk.io/core v0.11.0
cosmossdk.io/depinject v1.0.0-alpha.4
cosmossdk.io/errors v1.0.0
@ -12,7 +12,7 @@ require (
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
github.com/cosmos/cosmos-sdk v0.50.0-rc.0.0.20230829152823-ca0f89e96ce9
github.com/cosmos/cosmos-sdk v0.50.0-rc.0.0.20230913151713-376c3ea7fd0c
github.com/cosmos/gogoproto v1.4.11
github.com/golang/protobuf v1.5.3
github.com/grpc-ecosystem/grpc-gateway v1.16.0

View File

@ -187,8 +187,8 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX
cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4=
cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0 h1:z1aCAqEXi5fzC5tjanWnkP/zhhuWTX17IiNKxLvXFcw=
cosmossdk.io/api v0.7.1-0.20230820170544-1bd37053e0c0/go.mod h1:h4YT2OHIBT/YIwWrc5L+4dY05ZIqvo89zs6m7j4/RSk=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0=
cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo=
@ -347,8 +347,8 @@ github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0
github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U=
github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o=
github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I=
github.com/cosmos/cosmos-sdk v0.50.0-rc.0.0.20230829152823-ca0f89e96ce9 h1:y235JKySvAU3UgksIY5nk4t90WPozlkV9ZefDZvPE3c=
github.com/cosmos/cosmos-sdk v0.50.0-rc.0.0.20230829152823-ca0f89e96ce9/go.mod h1:olbHxcVB4zWwnF+oNPbKIoEIO5HgHndzKUqdpuu4s34=
github.com/cosmos/cosmos-sdk v0.50.0-rc.0.0.20230913151713-376c3ea7fd0c h1:/B9YWdEuublZoLxpCLTpqIfwteIs16R6HiMOGj/g5SY=
github.com/cosmos/cosmos-sdk v0.50.0-rc.0.0.20230913151713-376c3ea7fd0c/go.mod h1:A4EWz1NvP6QHQf0y9+BpnB/0ruFrONnru+vEWwIX4DY=
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=

View File

@ -98,9 +98,9 @@ func NewAppModule(keeper *keeper.Keeper, ac address.Codec) AppModule {
}
var (
_ appmodule.AppModule = AppModule{}
_ appmodule.HasBeginBlocker = AppModule{}
_ module.HasGenesis = AppModule{}
_ appmodule.AppModule = AppModule{}
_ appmodule.HasPreBlocker = AppModule{}
_ module.HasGenesis = AppModule{}
)
// IsOnePerModuleType implements the depinject.OnePerModuleType interface.
@ -153,11 +153,11 @@ func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONCodec) json.RawMe
// ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return ConsensusVersion }
// BeginBlock calls the upgrade module hooks
// PreBlock calls the upgrade module hooks
//
// CONTRACT: this is registered in BeginBlocker *before* all other modules' BeginBlock functions
func (am AppModule) BeginBlock(ctx context.Context) error {
return BeginBlocker(ctx, am.keeper)
// CONTRACT: this is called *before* all other modules' BeginBlock functions
func (am AppModule) PreBlock(ctx context.Context) (appmodule.ResponsePreBlock, error) {
return PreBlocker(ctx, am.keeper)
}
//