Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce PreBlock #17421

Merged
merged 42 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
9944fe1
replace RunMigrationBeginBlock with PreBeginBlock
mmsqe Aug 17, 2023
97437d2
fix test
mmsqe Aug 17, 2023
5df47ca
update doc
mmsqe Aug 17, 2023
4cb3ead
Merge branch 'main' into pre-begin
mmsqe Aug 17, 2023
875aef9
fix doc
mmsqe Aug 17, 2023
fa4d36c
add test
mmsqe Aug 17, 2023
8f901a2
Apply suggestions from code review
mmsqe Aug 17, 2023
0bf24db
force register in upgrade
mmsqe Aug 18, 2023
6aef95e
Merge branch 'main' into pre-begin
mmsqe Aug 18, 2023
952c619
keep UpgradeModule
mmsqe Aug 18, 2023
9ab334d
Revert "keep UpgradeModule"
mmsqe Aug 19, 2023
81aea05
Merge branch 'main' into pre-begin
mmsqe Aug 19, 2023
bded698
add proto
mmsqe Aug 19, 2023
1294aba
allow sim test use latest config.PreBlockers
mmsqe Aug 19, 2023
41eac61
add SetOrderPreBlockers
mmsqe Aug 19, 2023
5a80397
fix doc
mmsqe Aug 19, 2023
b9d1447
fix test
mmsqe Aug 19, 2023
5306a6f
Apply suggestions from code review
mmsqe Aug 19, 2023
9fac2e9
rm dummy upgrade from begin blocker
mmsqe Aug 19, 2023
b5e9072
replace dep
mmsqe Aug 20, 2023
e9247db
decouple dep
mmsqe Aug 20, 2023
e40de51
use latest sdk ResponsePreBlock
mmsqe Aug 20, 2023
afbf503
add when dep is ready (to be reverted)
mmsqe Aug 20, 2023
069488d
replace dep
mmsqe Aug 21, 2023
91b8fb4
Revert "add when dep is ready (to be reverted)"
mmsqe Aug 21, 2023
f3d2aa6
Merge remote-tracking branch 'origin/main' into pre-begin
mmsqe Aug 21, 2023
67b41af
fix replace
mmsqe Aug 21, 2023
3ff3ca4
Merge remote-tracking branch 'origin/main' into pre-begin
mmsqe Aug 21, 2023
c2a4320
Apply suggestions from code review
mmsqe Aug 21, 2023
3ffb4e9
Apply suggestions from code review
mmsqe Aug 21, 2023
5b87a82
Merge remote-tracking branch 'origin/main' into pre-begin
mmsqe Aug 24, 2023
19b0153
Merge remote-tracking branch 'origin/main' into pre-begin
mmsqe Aug 26, 2023
c4cffdc
Merge remote-tracking branch 'origin/main' into pre-begin
mmsqe Aug 29, 2023
4fb0496
Merge remote-tracking branch 'origin/main' into pre-begin
mmsqe Aug 30, 2023
2a9966d
reset gas meter after update cp
mmsqe Aug 30, 2023
19901c9
Merge remote-tracking branch 'origin/main' into pre-begin
mmsqe Sep 6, 2023
f2ac765
Update docs/docs/build/building-modules/17-preblock.md
mmsqe Sep 6, 2023
7a7dbaa
Merge branch 'main' into pre-begin
mmsqe Sep 13, 2023
766c82d
Apply suggestions from code review
mmsqe Sep 13, 2023
95a19e0
Merge branch 'main' into pre-begin
mmsqe Sep 13, 2023
e55d9e5
Merge branch 'main' into pre-begin
mmsqe Sep 13, 2023
88b1801
Apply suggestions from code review
mmsqe Sep 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Bug Fixes

* (types) [#16583](https://github.com/cosmos/cosmos-sdk/pull/16583), [#17372](https://github.com/cosmos/cosmos-sdk/pull/17372) Add `MigrationModuleManager` to handle migration of upgrade module before other modules, ensuring access to the updated context with consensus parameters within the same block that executes the migration.
* (types) [#16583](https://github.com/cosmos/cosmos-sdk/pull/16583), [#17372](https://github.com/cosmos/cosmos-sdk/pull/17372), [#17421](https://github.com/cosmos/cosmos-sdk/pull/17421) 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.

### API Breaking Changes

Expand Down
13 changes: 10 additions & 3 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,20 @@ and `VerifyVoteExtensionHandler` respectively. Please see [here](https://docs.co
for more info.


#### Upgrade
#### Set PreBlocker

**Users using `depinject` / app v2 do not need any changes, this is abstracted for them.**

```diff
+ app.SetPreBlocker(app.PreBlocker)
```
```diff
+ app.BaseApp.SetMigrationModuleManager(app.ModuleManager)
+func (app *SimApp) PreBlocker(ctx sdk.Context, req abci.RequestBeginBlock) (sdk.ResponsePreBlock, error) {
+ return app.ModuleManager.PreBlock(ctx, req)
+}
```
BaseApp added `SetMigrationModuleManager` for apps to set their ModuleManager which implements `RunMigrationBeginBlock`. This is essential for BaseApp to run `BeginBlock` of upgrade module and inject `ConsensusParams` to context for `beginBlocker` during `beginBlock`.

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

Expand Down
43 changes: 14 additions & 29 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@ type (
StoreLoader func(ms storetypes.CommitMultiStore) error
)

// MigrationModuleManager is the interface that a migration module manager should implement to handle
// the execution of migration logic during the beginning of a block.
type MigrationModuleManager interface {
RunMigrationBeginBlock(ctx sdk.Context) (bool, error)
}

const (
execModeCheck execMode = iota // Check a transaction
execModeReCheck // Recheck a (pending) transaction after a commit
Expand Down Expand Up @@ -81,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
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
beginBlocker sdk.BeginBlocker // (legacy ABCI) BeginBlock handler
endBlocker sdk.EndBlocker // (legacy ABCI) EndBlock handler
processProposal sdk.ProcessProposalHandler // ABCI ProcessProposal handler
Expand All @@ -98,9 +93,6 @@ type BaseApp struct {
// manages snapshots, i.e. dumps of app state at certain intervals
snapshotManager *snapshots.Manager

// manages migrate module
migrationModuleManager MigrationModuleManager

// volatile states:
//
// - checkState is set on InitChain and reset on Commit
Expand Down Expand Up @@ -276,11 +268,6 @@ func (app *BaseApp) SetMsgServiceRouter(msgServiceRouter *MsgServiceRouter) {
app.msgServiceRouter = msgServiceRouter
}

// SetMigrationModuleManager sets the MigrationModuleManager of a BaseApp.
func (app *BaseApp) SetMigrationModuleManager(migrationModuleManager MigrationModuleManager) {
app.migrationModuleManager = migrationModuleManager
}

// MountStores mounts all IAVL or DB stores to the provided keys in the BaseApp
// multistore.
func (app *BaseApp) MountStores(keys ...storetypes.StoreKey) {
Expand Down Expand Up @@ -684,22 +671,20 @@ func (app *BaseApp) beginBlock(req *abci.RequestFinalizeBlock) (sdk.BeginBlock,
err error
)

if app.beginBlocker != nil {
ctx := app.finalizeBlockState.ctx
if app.migrationModuleManager != nil {
if success, err := app.migrationModuleManager.RunMigrationBeginBlock(ctx); success {
cp := ctx.ConsensusParams()
// Manager skips this step if Block is non-nil since upgrade module is expected to set this params
// and consensus parameters should not be overwritten.
if cp.Block == nil {
if cp = app.GetConsensusParams(ctx); cp.Block != nil {
ctx = ctx.WithConsensusParams(cp)
}
}
} else if err != nil {
return sdk.BeginBlock{}, err
}
ctx := app.finalizeBlockState.ctx
if app.preBlocker != nil {
rsp, err := app.preBlocker(ctx)
if err != nil {
return sdk.BeginBlock{}, 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))
app.finalizeBlockState.ctx = ctx
}
}
if app.beginBlocker != nil {
resp, err = app.beginBlocker(ctx)
if err != nil {
return resp, err
Expand Down
3 changes: 3 additions & 0 deletions baseapp/baseapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,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)
})
Expand Down
8 changes: 8 additions & 0 deletions baseapp/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
7 changes: 0 additions & 7 deletions core/appmodule/module.go
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,3 @@ type HasEndBlocker interface {
// a block.
EndBlock(context.Context) error
}

// UpgradeModule is the extension interface that upgrade module should implement to differentiate
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
// it from other modules, migration handler need ensure the upgrade module's migration is executed
// before the rest of the modules.
type UpgradeModule interface {
IsUpgradeModule()
}
11 changes: 11 additions & 0 deletions docs/architecture/adr-063-core-module-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 17 additions & 3 deletions docs/docs/basics/00-app-anatomy.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`](../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`](../core/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](../core/05-encoding.md).
* **A reference to a [`legacyAmino`](../core/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](../building-modules/01-module-manager.md#manager)** and a [basic module manager](../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](../core/00-baseapp.md#msg-services) and [gRPC `Query` service](../core/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](../building-modules/01-module-manager.md#manager)** and a [basic module manager](../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](../core/00-baseapp.md#msg-services) and [gRPC `Query` service](../core/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:

Expand All @@ -79,10 +79,11 @@ Here are the main actions performed by this function:
* Instantiate the application's [module manager](../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](../core/00-baseapp.md#msg-services), [gRPC `Query` services](../core/00-baseapp.md#grpc-query-services), [legacy `Msg` routes](../core/00-baseapp.md#routing), and [legacy query routes](../core/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](../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`](../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`](../core/00-baseapp.md#antehandler): used to handle fees and signature verification.
* Mount the stores.
* Return the application.
Expand All @@ -107,6 +108,19 @@ 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:
```
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.
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/building-apps/01-app-go-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 9 additions & 3 deletions docs/docs/building-apps/03-app-upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,22 @@ 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 Migration Module Manager
## Set PreBlocker

:::tip
Users using `depinject` / app v2 do not need any changes, this is abstracted for them.
:::

After app initiation, call `SetMigrationModuleManager` with ModuleManager to give BaseApp access to `RunMigrationBeginBlock`:
Call `SetPreBlocker` to run `PreBlock`:

```go
app.BaseApp.SetMigrationModuleManager(app.ModuleManager)
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
Expand Down
Loading
Loading