docs: update docs for Check/DeliverTx middlewares (#11918)
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
This commit is contained in:
co-authored by
Aleksandr Bezobchuk
parent
b0edb6d3ef
commit
9d8beff497
+9
-9
@@ -11,15 +11,15 @@ This repository contains reference documentation on the core concepts of the Cos
|
||||
1. [`BaseApp`](./baseapp.md)
|
||||
2. [Transaction](./transactions.md)
|
||||
3. [Context](./context.md)
|
||||
4. [Node Client](./node.md)
|
||||
5. [Store](./store.md)
|
||||
6. [Encoding](./encoding.md)
|
||||
7. [gRPC, REST and Tendermint Endpoints](./grpc_rest.md)
|
||||
8. [Command-Line Interface](./cli.md)
|
||||
9. [Events](./events.md)
|
||||
10. [Telemetry](./telemetry.md)
|
||||
11. [Object-Capabilities](./ocap.md)
|
||||
12. [RunTx recovery middleware](./runtx_middleware.md)
|
||||
4. [CheckTx and DeliverTx middlewares](./middleware.md)
|
||||
5. [Node Client](./node.md)
|
||||
6. [Store](./store.md)
|
||||
7. [Encoding](./encoding.md)
|
||||
8. [gRPC, REST and Tendermint Endpoints](./grpc_rest.md)
|
||||
9. [Command-Line Interface](./cli.md)
|
||||
10. [Events](./events.md)
|
||||
11. [Telemetry](./telemetry.md)
|
||||
12. [Object-Capabilities](./ocap.md)
|
||||
13. [Simulation](./simulation.md)
|
||||
14. [Protobuf documentation](./proto-docs.md)
|
||||
15. [In-Place Store Migrations](./upgrade.md)
|
||||
|
||||
+38
-65
@@ -15,9 +15,9 @@ This document describes `BaseApp`, the abstraction that implements the core func
|
||||
|
||||
`BaseApp` is a base type that implements the core of a Cosmos SDK application, namely:
|
||||
|
||||
* The [Application Blockchain Interface](#abci), for the state-machine to communicate with the underlying consensus engine (e.g. Tendermint).
|
||||
* The [Application Blockchain Interface](#main-abci-messages), for the state-machine to communicate with the underlying consensus engine (e.g. Tendermint).
|
||||
* [Service Routers](#service-routers), to route messages and queries to the appropriate module.
|
||||
* Different [states](#states), as the state-machine can have different volatile states updated based on the ABCI message received.
|
||||
* Different [states](#state-updates), as the state-machine can have different volatile states updated based on the ABCI message received.
|
||||
|
||||
The goal of `BaseApp` is to provide the fundamental layer of a Cosmos SDK application
|
||||
that developers can easily extend to build their own custom application. Usually,
|
||||
@@ -45,7 +45,7 @@ management logic.
|
||||
|
||||
The `BaseApp` type holds many important parameters for any Cosmos SDK based application.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/baseapp/baseapp.go#L46-L131
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/baseapp/baseapp.go#L44-L131
|
||||
|
||||
Let us go through the most important components.
|
||||
|
||||
@@ -60,25 +60,21 @@ First, the important parameters that are initialized during the bootstrapping of
|
||||
The `CommitMultiStore` is a multi-store, meaning a store of stores. Each module of the application
|
||||
uses one or multiple `KVStores` in the multi-store to persist their subset of the state.
|
||||
* Database: The `db` is used by the `CommitMultiStore` to handle data persistence.
|
||||
* [`Msg` Service Router](#msg-service-router): The `msgServiceRouter` facilitates the routing of `sdk.Msg` requests to the appropriate
|
||||
module `Msg` service for processing. Here a `sdk.Msg` refers to the transaction component that needs to be
|
||||
processed by a service in order to update the application state, and not to ABCI message which implements
|
||||
the interface between the application and the underlying consensus engine.
|
||||
* [gRPC Query Router](#grpc-query-router): The `grpcQueryRouter` facilitates the routing of gRPC queries to the
|
||||
appropriate module for it to be processed. These queries are not ABCI messages themselves, but they
|
||||
are relayed to the relevant module's gRPC `Query` service.
|
||||
* [`TxDecoder`](https://godoc.org/github.com/cosmos/cosmos-sdk/types#TxDecoder): It is used to decode
|
||||
raw transaction bytes relayed by the underlying Tendermint engine.
|
||||
* [`ParamStore`](#paramstore): The parameter store used to get and set application consensus parameters.
|
||||
* [`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
|
||||
* [`TxHandler`](#middlewares): This handler is used to set middlewares. Middlewares can, for instace, handle signature verification,
|
||||
fee payment, and other pre-message execution checks when a transaction is received. It's executed during
|
||||
[`CheckTx/RecheckTx`](#checktx) and [`DeliverTx`](#delivertx).
|
||||
* [`InitChainer`](../basics/app-anatomy.md#initchainer),
|
||||
[`BeginBlocker` and `EndBlocker`](../basics/app-anatomy.md#beginblocker-and-endblocker): These are
|
||||
the functions executed when the application receives the `InitChain`, `BeginBlock` and `EndBlock`
|
||||
ABCI messages from the underlying Tendermint engine.
|
||||
|
||||
Then, parameters used to define [volatile states](#volatile-states) (i.e. cached states):
|
||||
Then, parameters used to define [volatile states](#state-updates) (i.e. cached states):
|
||||
|
||||
* `checkState`: This state is updated during [`CheckTx`](#checktx), and reset on [`Commit`](#commit).
|
||||
* `deliverState`: This state is updated during [`DeliverTx`](#delivertx), and set to `nil` on
|
||||
@@ -92,7 +88,7 @@ Finally, a few more important parameters:
|
||||
punishing absent validators.
|
||||
* `minGasPrices`: This parameter defines the minimum gas prices accepted by the node. This is a
|
||||
**local** parameter, meaning each full-node can set a different `minGasPrices`. It is used in the
|
||||
`AnteHandler` during [`CheckTx`](#checktx), mainly as a spam protection mechanism. The transaction
|
||||
`TxHandler` during [`CheckTx`](#checktx), mainly as a spam protection mechanism. The transaction
|
||||
enters the [mempool](https://docs.tendermint.com/master/tendermint-core/mempool/)
|
||||
only if the gas prices of the transaction are greater than one of the minimum gas price in
|
||||
`minGasPrices` (e.g. if `minGasPrices == 1uatom,1photon`, the `gas-price` of the transaction must be
|
||||
@@ -142,9 +138,8 @@ To avoid unnecessary roundtrip to the main state, all reads to the branched stor
|
||||
### CheckTx State Updates
|
||||
|
||||
During `CheckTx`, the `checkState`, which is based off of the last committed state from the root
|
||||
store, is used for any reads and writes. Here we only execute the `AnteHandler` and verify a service router
|
||||
exists for every message in the transaction. Note, when we execute the `AnteHandler`, we branch
|
||||
the already branched `checkState`. This has the side effect that if the `AnteHandler` fails,
|
||||
store, is used for any reads and writes. Here we only execute the wired middlewares `CheckTx` and verify a service router
|
||||
exists for every message in the transaction. Note, that if the a middleware's `CheckTx` fails,
|
||||
the state transitions won't be reflected in the `checkState` -- i.e. `checkState` is only updated on
|
||||
success.
|
||||
|
||||
@@ -164,7 +159,7 @@ The state flow for `DeliverTx` is nearly identical to `CheckTx` except state tra
|
||||
the `deliverState` and messages in a transaction are executed. Similarly to `CheckTx`, state transitions
|
||||
occur on a doubly branched state -- `deliverState`. Successful message execution results in
|
||||
writes being committed to `deliverState`. Note, if message execution fails, state transitions from
|
||||
the AnteHandler are persisted.
|
||||
the middlewares are persisted.
|
||||
|
||||

|
||||
|
||||
@@ -187,21 +182,13 @@ on-chain governance.
|
||||
|
||||
## Service Routers
|
||||
|
||||
When messages and queries are received by the application, they must be routed to the appropriate module in order to be processed. Routing is done via `BaseApp`, which holds a `msgServiceRouter` for messages, and a `grpcQueryRouter` for queries.
|
||||
|
||||
### `Msg` Service Router
|
||||
|
||||
[`sdk.Msg`s](#../building-modules/messages-and-queries.md#messages) need to be routed after they are extracted from transactions, which are sent from the underlying Tendermint engine via the [`CheckTx`](#checktx) and [`DeliverTx`](#delivertx) ABCI messages. To do so, `BaseApp` holds a `msgServiceRouter` which maps fully-qualified service methods (`string`, defined in each module's Protobuf `Msg` service) to the appropriate module's `MsgServer` implementation.
|
||||
|
||||
The [default `msgServiceRouter` included in `BaseApp`](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/baseapp/msg_service_router.go) is stateless. However, some applications may want to make use of more stateful routing mechanisms such as allowing governance to disable certain routes or point them to new modules for upgrade purposes. For this reason, the `sdk.Context` is also passed into each [route handler inside `msgServiceRouter`](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/baseapp/msg_service_router.go#L31-L32). For a stateless router that doesn't want to make use of this, you can just ignore the `ctx`.
|
||||
|
||||
The application's `msgServiceRouter` is initialized with all the routes using the application's [module manager](../building-modules/module-manager.md#manager) (via the `RegisterServices` method), which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor).
|
||||
When messages and queries are received by the application, they must be routed to the appropriate module in order to be processed. Routing is done via `BaseApp`, with `queryRouter` for queries and `grpcQueryRouter` for gRPC queries.
|
||||
|
||||
### gRPC Query Router
|
||||
|
||||
Similar to `sdk.Msg`s, [`queries`](../building-modules/messages-and-queries.md#queries) need to be routed to the appropriate module's [`Query` service](../building-modules/query-services.md). To do so, `BaseApp` holds a `grpcQueryRouter`, which maps modules' fully-qualified service methods (`string`, defined in their Protobuf `Query` gRPC) to their `QueryServer` implementation. The `grpcQueryRouter` is called during the initial stages of query processing, which can be either by directly sending a gRPC query to the gRPC endpoint, or via the [`Query` ABCI message](#query) on the Tendermint RPC endpoint.
|
||||
[`Queries`](../building-modules/messages-and-queries.md#queries) need to be routed to the appropriate module's [`Query` service](../building-modules/query-services.md). To do so, `BaseApp` holds a `grpcQueryRouter`, which maps modules' fully-qualified service methods (`string`, defined in their Protobuf `Query` gRPC) to their `QueryServer` implementation. The `grpcQueryRouter` is called during the initial stages of query processing, which can be either by directly sending a gRPC query to the gRPC endpoint, or via the [`Query` ABCI message](#query) on the Tendermint RPC endpoint.
|
||||
|
||||
Just like the `msgServiceRouter`, the `grpcQueryRouter` is initialized with all the query routes using the application's [module manager](../building-modules/module-manager.md) (via the `RegisterServices` method), which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor).
|
||||
The `grpcQueryRouter` is initialized with all the query routes using the application's [module manager](../building-modules/module-manager.md) (via the `RegisterServices` method), which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor).
|
||||
|
||||
## Main ABCI Messages
|
||||
|
||||
@@ -236,18 +223,17 @@ to do the following checks:
|
||||
3. Perform non-module related _stateful_ checks on the [account](../basics/accounts.md). This step is mainly about checking
|
||||
that the `sdk.Msg` signatures are valid, that enough fees are provided and that the sending account
|
||||
has enough funds to pay for said fees. Note that no precise [`gas`](../basics/gas-fees.md) counting occurs here,
|
||||
as `sdk.Msg`s are not processed. Usually, the [`AnteHandler`](../basics/gas-fees.md#antehandler) will check that the `gas` provided
|
||||
as `sdk.Msg`s are not processed. Usually, the [`middleware`](../basics/gas-fees.md#middleware) will check that the `gas` provided
|
||||
with the transaction is superior to a minimum reference gas amount based on the raw transaction size,
|
||||
in order to avoid spam with transactions that provide 0 gas.
|
||||
|
||||
`CheckTx` does **not** process `sdk.Msg`s - they only need to be processed when the canonical state need to be updated, which happens during `DeliverTx`.
|
||||
|
||||
Steps 2. and 3. are performed by the [`AnteHandler`](../basics/gas-fees.md#antehandler) in the [`RunTx()`](#runtx-antehandler-and-runmsgs)
|
||||
function, which `CheckTx()` calls with the `runTxModeCheck` mode. During each step of `CheckTx()`, a
|
||||
special [volatile state](#volatile-states) called `checkState` is updated. This state is used to keep
|
||||
track of the temporary changes triggered by the `CheckTx()` calls of each transaction without modifying
|
||||
the [main canonical state](#main-state) . For example, when a transaction goes through `CheckTx()`, the
|
||||
transaction's fees are deducted from the sender's account in `checkState`. If a second transaction is
|
||||
Steps 2. and 3. are performed by the [`middlewares`](../basics/gas-fees.md#middleware)' `CheckTx()`.
|
||||
During each step of `CheckTx()`, a special [volatile state](#state-updates) called `checkState` is updated.
|
||||
This state is used to keep track of the temporary changes triggered by the `CheckTx()` calls of each transaction
|
||||
without modifying the [main canonical state](#main-state) . For example, when a transaction goes through `CheckTx()`,
|
||||
the transaction's fees are deducted from the sender's account in `checkState`. If a second transaction is
|
||||
received from the same account before the first is processed, and the account has consumed all its
|
||||
funds in `checkState` during the first transaction, the second transaction will fail `CheckTx`() and
|
||||
be rejected. In any case, the sender's account will not actually pay the fees until the transaction
|
||||
@@ -280,16 +266,16 @@ This allows certain checks like signature verification can be skipped during `Ch
|
||||
|
||||
When the underlying consensus engine receives a block proposal, each transaction in the block needs to be processed by the application. To that end, the underlying consensus engine sends a `DeliverTx` message to the application for each transaction in a sequential order.
|
||||
|
||||
Before the first transaction of a given block is processed, a [volatile state](#volatile-states) called `deliverState` is intialized during [`BeginBlock`](#beginblock). This state is updated each time a transaction is processed via `DeliverTx`, and committed to the [main state](#main-state) when the block is [committed](#commit), after what is is set to `nil`.
|
||||
Before the first transaction of a given block is processed, a [volatile state](#state-updates) called `deliverState` is intialized during [`BeginBlock`](#beginblock). This state is updated each time a transaction is processed via `DeliverTx`, and committed to the [main state](#main-state) when the block is [committed](#commit), after what is is set to `nil`.
|
||||
|
||||
`DeliverTx` performs the **exact same steps as `CheckTx`**, with a little caveat at step 3 and the addition of a fifth step:
|
||||
|
||||
1. The `AnteHandler` does **not** check that the transaction's `gas-prices` is sufficient. That is because the `min-gas-prices` value `gas-prices` is checked against is local to the node, and therefore what is enough for one full-node might not be for another. This means that the proposer can potentially include transactions for free, although they are not incentivised to do so, as they earn a bonus on the total fee of the block they propose.
|
||||
1. The `GasTxMiddleware` does **not** check that the transaction's `gas-prices` is sufficient. That is because the `min-gas-prices` value `gas-prices` is checked against is local to the node, and therefore what is enough for one full-node might not be for another. This means that the proposer can potentially include transactions for free, although they are not incentivised to do so, as they earn a bonus on the total fee of the block they propose.
|
||||
2. For each `sdk.Msg` in the transaction, route to the appropriate module's Protobuf [`Msg` service](../building-modules/msg-services.md). Additional _stateful_ checks are performed, and the branched multistore held in `deliverState`'s `context` is updated by the module's `keeper`. If the `Msg` service returns successfully, the branched multistore held in `context` is written to `deliverState` `CacheMultiStore`.
|
||||
|
||||
During the additional fifth step outlined in (2), each read/write to the store increases the value of `GasConsumed`. You can find the default cost of each operation:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/store/types/gas.go#L164-L175
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/store/types/gas.go#L230-L241
|
||||
|
||||
At any point, if `GasConsumed > GasWanted`, the function returns with `Code != 0` and `DeliverTx` fails.
|
||||
|
||||
@@ -304,45 +290,32 @@ At any point, if `GasConsumed > GasWanted`, the function returns with `Code != 0
|
||||
* `Events ([]cmn.KVPair)`: Key-Value tags for filtering and indexing transactions (eg. by account). See [`event`s](./events.md) for more.
|
||||
* `Codespace (string)`: Namespace for the Code.
|
||||
|
||||
## RunTx, AnteHandler and RunMsgs
|
||||
## Middlewares
|
||||
|
||||
### RunTx
|
||||
Middlewares implement the `tx.Handler` interface. They are called within BaseApp `CheckTx` and `DeliverTx`, allowing to run custom logic before or after the transaction is processed. They are primaraly used to authenticate the transaction before the transaction's internal messages are processed, but also to perform additional checks on the transaction itself.
|
||||
|
||||
`RunTx` is called from `CheckTx`/`DeliverTx` to handle the transaction, with `runTxModeCheck` or `runTxModeDeliver` as parameter to differentiate between the two modes of execution. Note that when `RunTx` receives a transaction, it has already been decoded.
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/types/tx/middleware.go#L62:L68
|
||||
|
||||
The first thing `RunTx` does upon being called is to retrieve the `context`'s `CacheMultiStore` by calling the `getContextForTx()` function with the appropriate mode (either `runTxModeCheck` or `runTxModeDeliver`). This `CacheMultiStore` is a branch of the main store, with cache functionality (for query requests), instantiated during `BeginBlock` for `DeliverTx` and during the `Commit` of the previous block for `CheckTx`. After that, two `defer func()` are called for [`gas`](../basics/gas-fees.md) management. They are executed when `runTx` returns and make sure `gas` is actually consumed, and will throw errors, if any.
|
||||
|
||||
After that, `RunTx()` calls `ValidateBasic()` on each `sdk.Msg`in the `Tx`, which runs preliminary _stateless_ validity checks. If any `sdk.Msg` fails to pass `ValidateBasic()`, `RunTx()` returns with an error.
|
||||
|
||||
Then, the [`anteHandler`](#antehandler) of the application is run (if it exists). In preparation of this step, both the `checkState`/`deliverState`'s `context` and `context`'s `CacheMultiStore` are branched using the `cacheTxContext()` function.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/baseapp/baseapp.go#L623-L630
|
||||
|
||||
This allows `RunTx` not to commit the changes made to the state during the execution of `anteHandler` if it ends up failing. It also prevents the module implementing the `anteHandler` from writing to state, which is an important part of the [object-capabilities](./ocap.md) of the Cosmos SDK.
|
||||
|
||||
Finally, the [`RunMsgs()`](#runmsgs) function is called to process the `sdk.Msg`s in the `Tx`. In preparation of this step, just like with the `anteHandler`, both the `checkState`/`deliverState`'s `context` and `context`'s `CacheMultiStore` are branched using the `cacheTxContext()` function.
|
||||
|
||||
### AnteHandler
|
||||
|
||||
The `AnteHandler` is a special handler that implements the `AnteHandler` interface and is used to authenticate the transaction before the transaction's internal messages are processed.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/types/handler.go#L6-L8
|
||||
|
||||
The `AnteHandler` is theoretically optional, but still a very important component of public blockchain networks. It serves 3 primary purposes:
|
||||
Middlewares are theoretically optional, but still a very important component of public blockchain networks. They have 3 primary purposes:
|
||||
|
||||
* Be a primary line of defense against spam and second line of defense (the first one being the mempool) against transaction replay with fees deduction and [`sequence`](./transactions.md#transaction-generation) checking.
|
||||
* Perform preliminary _stateful_ validity checks like ensuring signatures are valid or that the sender has enough funds to pay for fees.
|
||||
* Play a role in the incentivisation of stakeholders via the collection of transaction fees.
|
||||
|
||||
`BaseApp` holds an `anteHandler` as parameter that is initialized in the [application's constructor](../basics/app-anatomy.md#application-constructor). The most widely used `anteHandler` is the [`auth` module](https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/auth/ante/ante.go).
|
||||
`BaseApp` holds a `txHandler` as parameter that is initialized in the [application's constructor](../basics/app-anatomy.md#application-constructor). The most widely used `middlewares` are the [`auth` module middlewares](https://github.com/cosmos/cosmos-sdk/blob/main/x/auth/middleware).
|
||||
|
||||
Click [here](../basics/gas-fees.md#antehandler) for more on the `anteHandler`.
|
||||
`NewDefaultTxHandler` groups a number a `middlewares` that are commonly used:
|
||||
|
||||
### RunMsgs
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/x/auth/middleware/middleware.go#L89:L130
|
||||
|
||||
`RunMsgs` is called from `RunTx` with `runTxModeCheck` as parameter to check the existence of a route for each message the transaction, and with `runTxModeDeliver` to actually process the `sdk.Msg`s.
|
||||
Click [here](../basics/gas-fees.md#middleware) for more on these `middlewares`.
|
||||
|
||||
First, it retrieves the `sdk.Msg`'s fully-qualified type name, by checking the `type_url` of the Protobuf `Any` representing the `sdk.Msg`. Then, using the application's [`msgServiceRouter`](#msg-service-router), it checks for the existence of `Msg` service method related to that `type_url`. At this point, if `mode == runTxModeCheck`, `RunMsgs` returns. Otherwise, if `mode == runTxModeDeliver`, the [`Msg` service](../building-modules/msg-services.md) RPC is executed, before `RunMsgs` returns.
|
||||
### RunMsgsTxHandler
|
||||
|
||||
`RunMsgsTxHandler` is a middleware that runs the `sdk.Msg`s in the transaction.
|
||||
When being called from `DeliverTx` or `SimulateTx`, it retrieves the `sdk.Msg`'s fully-qualified type name, by checking the `type_url` of the Protobuf `Any` representing the `sdk.Msg`. Then, using its [`msgServiceRouter`](#msg-service-router), it checks for the existence of `Msg` service method related to that `type_url`. At this point the [`Msg` service](../building-modules/msg-services.md) RPC is executed, before returning.
|
||||
|
||||
Note: When its `CheckTx` method is called, the `RunMsgsTxHandler` does not do anything as messages are not run during `CheckTx`.
|
||||
|
||||
## Other ABCI Messages
|
||||
|
||||
@@ -351,7 +324,7 @@ First, it retrieves the `sdk.Msg`'s fully-qualified type name, by checking the `
|
||||
The [`InitChain` ABCI message](https://docs.tendermint.com/master/spec/abci/abci.html#initchain) is sent from the underlying Tendermint engine when the chain is first started. It is mainly used to **initialize** parameters and state like:
|
||||
|
||||
* [Consensus Parameters](https://docs.tendermint.com/master/spec/abci/apps.html#consensus-parameters) via `setConsensusParams`.
|
||||
* [`checkState` and `deliverState`](#volatile-states) via `setCheckState` and `setDeliverState`.
|
||||
* [`checkState` and `deliverState`](#state-updates) via `setCheckState` and `setDeliverState`.
|
||||
* The [block gas meter](../basics/gas-fees.md#block-gas-meter), with infinite gas to process genesis transactions.
|
||||
|
||||
Finally, the `InitChain(req abci.RequestInitChain)` method of `BaseApp` calls the [`initChainer()`](../basics/app-anatomy.md#initchainer) of the application in order to initialize the main state of the application from the `genesis file` and, if defined, call the [`InitGenesis`](../building-modules/genesis.md#initgenesis) function of each of the application's modules.
|
||||
@@ -360,7 +333,7 @@ Finally, the `InitChain(req abci.RequestInitChain)` method of `BaseApp` calls th
|
||||
|
||||
The [`BeginBlock` ABCI message](https://docs.tendermint.com/master/spec/abci/abci.html#beginblock) is sent from the underlying Tendermint engine when a block proposal created by the correct proposer is received, before [`DeliverTx`](#delivertx) is run for each transaction in the block. It allows developers to have logic be executed at the beginning of each block. In the Cosmos SDK, the `BeginBlock(req abci.RequestBeginBlock)` method does the following:
|
||||
|
||||
* Initialize [`deliverState`](#volatile-states) with the latest header using the `req abci.RequestBeginBlock` passed as parameter via the `setDeliverState` function.
|
||||
* Initialize [`deliverState`](#state-updates) with the latest header using the `req abci.RequestBeginBlock` passed as parameter via the `setDeliverState` function.
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/baseapp/baseapp.go#L387-L397
|
||||
This function also resets the [main gas meter](../basics/gas-fees.md#main-gas-meter).
|
||||
* Initialize the [block gas meter](../basics/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.
|
||||
|
||||
+2
-25
@@ -72,32 +72,9 @@ goes wrong. The pattern of usage for a Context is as follows:
|
||||
needs to be done - the branch `ctx` is simply discarded. If successful, the changes made to
|
||||
the `CacheMultiStore` can be committed to the original `ctx.ms` via `Write()`.
|
||||
|
||||
For example, here is a snippet from the [`runTx`](./baseapp.md#runtx-and-runmsgs) function in
|
||||
[`baseapp`](./baseapp.md):
|
||||
For example, here is a snippet from the [`CustomTxHandlerMiddleware`](https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/baseapp/custom_txhandler_test.go#L23) used in tests:
|
||||
|
||||
```go
|
||||
runMsgCtx, msCache := app.cacheTxContext(ctx, txBytes)
|
||||
result = app.runMsgs(runMsgCtx, msgs, mode)
|
||||
result.GasWanted = gasWanted
|
||||
|
||||
if mode != runTxModeDeliver {
|
||||
return result
|
||||
}
|
||||
|
||||
if result.IsOK() {
|
||||
msCache.Write()
|
||||
}
|
||||
```
|
||||
|
||||
Here is the process:
|
||||
|
||||
1. Prior to calling `runMsgs` on the message(s) in the transaction, it uses `app.cacheTxContext()`
|
||||
to branch and cache the context and multistore.
|
||||
2. `runMsgCtx` - the context with branched store, is used in `runMsgs` to return a result.
|
||||
3. If the process is running in [`checkTxMode`](./baseapp.md#checktx), there is no need to write the
|
||||
changes - the result is returned immediately.
|
||||
4. If the process is running in [`deliverTxMode`](./baseapp.md#delivertx) and the result indicates
|
||||
a successful run over all the messages, the branched multistore is written back to the original.
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/baseapp/custom_txhandler_test.go#L62:L97
|
||||
|
||||
## Next {hide}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
order: 3
|
||||
order: 4
|
||||
-->
|
||||
|
||||
# Middlewares
|
||||
@@ -10,11 +10,11 @@ order: 3
|
||||
## Pre-requisite Readings
|
||||
|
||||
* [Anatomy of a Cosmos SDK Application](../basics/app-anatomy.md) {prereq}
|
||||
* [Transactons](transactions.md) {prereq}
|
||||
* [Transactions](transactions.md) {prereq}
|
||||
|
||||
## Middlewares
|
||||
|
||||
The SDK Baseapp's implementation of ABCI CheckTx, DeliverTx, and Baseapp's own Simulate methods use a middleware-based design. Middlewares can add logic to be executed before or after a transaction handler execution. Middlewares are like an `antehandler` with the added feature of being able to add post-transaction handler execution. Middlewares allow us to solve use cases like transaction Tips and refund unused gas (issue [#2150](https://github.com/cosmos/cosmos-sdk/issues/2150)).
|
||||
The SDK Baseapp's implementation of ABCI CheckTx, DeliverTx, and Baseapp's own Simulate methods use a middleware-based design. Middlewares can add logic to be executed before or after a transaction handler execution. Middlewares are like the previous notion of `antehandler` with the added feature of being able to add post-transaction handler execution. Middlewares allow us to solve use cases like transaction Tips and refund unused gas (issue [#2150](https://github.com/cosmos/cosmos-sdk/issues/2150)).
|
||||
|
||||
### Type Definition
|
||||
|
||||
@@ -107,7 +107,7 @@ While BaseApp holds a reference to a `tx.Handler`, this `tx.Handler` itself is d
|
||||
|
||||
Then, the app developer can compose multiple middlewares on top of the base `tx.Handler`. Each middleware can run pre-and-post-processing logic around its next middleware, as described in the section above. Conceptually, as an example, given the middlewares `A`, `B`, and `C` and the base `tx.Handler` `H` the stack looks like:
|
||||
|
||||

|
||||

|
||||
|
||||
```text
|
||||
A.pre
|
||||
@@ -143,11 +143,11 @@ While the app developer can define and compose the middlewares of their choice,
|
||||
| Middleware | Description |
|
||||
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| RunMsgsTxHandler | This is the base `tx.Handler`. It replaces the old baseapp's `runMsgs`, and executes a transaction's `Msg`s. |
|
||||
| TxDecoderMiddleware | This middleware takes in transaction raw bytes, and decodes them into a `sdk.Tx`. It replaces the `baseapp.txDecoder` field, so that BaseApp stays as thin as possible. Since most middlewares read the contents of the `sdk.Tx`, the TxDecoderMiddleware should be run first in the middelware stack. |
|
||||
| TxDecoderMiddleware | This middleware takes in transaction raw bytes, and decodes them into a `sdk.Tx`. It replaces the `baseapp.txDecoder` field, so that BaseApp stays as thin as possible. Since most middlewares read the contents of the `sdk.Tx`, the TxDecoderMiddleware should be run first in the middleware stack. |
|
||||
| {Antehandlers} | Each antehandler is converted to its own middleware. These middlewares perform signature verification, fee deductions and other validations on the incoming transaction. |
|
||||
| IndexEventsTxMiddleware | This is a simple middleware that chooses which events to index in Tendermint. Replaces `baseapp.indexEvents` (which unfortunately still exists in baseapp too, because it's used to index Begin/EndBlock events) |
|
||||
| RecoveryTxMiddleware | This index recovers from panics. It replaces baseapp.runTx's panic recovery described in [ADR-022](./adr-022-custom-panic-handling.md). |
|
||||
| GasTxMiddleware | This replaces the [`Setup`](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0/x/auth/ante/setup.go) Antehandler. It sets a GasMeter on sdk.Context. Note that before, GasMeter was set on sdk.Context inside the antehandlers, and there was some mess around the fact that antehandlers had their own panic recovery system so that the GasMeter could be read by baseapp's recovery system. Now, this mess is all removed: one middleware sets GasMeter, another one handles recovery. |
|
||||
| GasTxMiddleware | This replaces the [`Setup`](https://github.com/cosmos/cosmos-sdk/blob/v0.45.3/x/auth/ante/setup.go) Antehandler. It sets a GasMeter on sdk.Context. Note that before, GasMeter was set on sdk.Context inside the antehandlers, and there was some mess around the fact that antehandlers had their own panic recovery system so that the GasMeter could be read by baseapp's recovery system. Now, this mess is all removed: one middleware sets GasMeter, another one handles recovery. |
|
||||
| TipMiddleware | This pays for transaction fees using another denom than the native fee denom of the chain. [`docs`](tips.md) |
|
||||
| SigGasConsumeMiddleware | SigGasConsumeMiddleware consumes parameter-defined amount of gas for each signature. |
|
||||
| SigVerificationMiddleware | verifies all signatures for a tx and return an error if any are invalid |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!--
|
||||
order: 16
|
||||
order: 14
|
||||
-->
|
||||
|
||||
# Protobuf Documentation
|
||||
|
||||
This file has been replaced by [Cosmos-SDK Buf Proto-docs](https://buf.build/cosmos/cosmos-sdk/docs/main)
|
||||
See [Cosmos-SDK Buf Proto-docs](https://buf.build/cosmos/cosmos-sdk/docs/main)
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
<!--
|
||||
order: 13
|
||||
-->
|
||||
|
||||
# RunTx recovery middleware
|
||||
|
||||
`BaseApp.runTx()` function handles Golang panics that might occur during transactions execution, for example, keeper has faced an invalid state and paniced.
|
||||
Depending on the panic type different handler is used, for instance the default one prints an error log message.
|
||||
Recovery middleware is used to add custom panic recovery for Cosmos SDK application developers.
|
||||
|
||||
More context could be found in the corresponding [ADR-022](../architecture/adr-022-custom-panic-handling.md).
|
||||
|
||||
Implementation could be found in the [recovery.go](https://github.com/cosmos/cosmos-sdk/tree/v0.46.0-alpha2/x/auth/middleware/recovery.go) file.
|
||||
|
||||
## Interface
|
||||
|
||||
```go
|
||||
type RecoveryHandtree/v0.46.0-alpha2
|
||||
```
|
||||
|
||||
`recoveryObj` is a return value for `recover()` function from the `buildin` Golang package.
|
||||
|
||||
**Contract:**
|
||||
|
||||
* RecoveryHandler returns `nil` if `recoveryObj` wasn't handled and should be passed to the next recovery middleware;
|
||||
* RecoveryHandler returns a non-nil `error` if `recoveryObj` was handled;
|
||||
|
||||
## Custom RecoveryHandler register
|
||||
|
||||
`BaseApp.AddRunTxRecoveryHandler(handlers ...RecoveryHandler)`
|
||||
|
||||
BaseApp method adds recovery middleware to the default recovery chain.
|
||||
|
||||
## Example
|
||||
|
||||
Lets assume we want to emit the "Consensus failure" chain state if some particular error occurred.
|
||||
|
||||
We have a module keeper that panics:
|
||||
|
||||
```go
|
||||
func (k FooKeeper) Do(obj interface{}) {
|
||||
if obj == nil {
|
||||
// that shouldn't happen, we need to crash the app
|
||||
err := sdkErrors.Wrap(fooTypes.InternalError, "obj is nil")
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By default that panic would be recovered and an error message will be printed to log. To override that behaviour we should register a custom RecoveryHandler:
|
||||
|
||||
```go
|
||||
// Cosmos SDK application constructor
|
||||
customHandler := func(recoveryObj interface{}) error {
|
||||
err, ok := recoveryObj.(error)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if fooTypes.InternalError.Is(err) {
|
||||
panic(fmt.Errorf("FooKeeper did panic with error: %w", err))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
baseApp := baseapp.NewBaseApp(...)
|
||||
baseApp.AddRunTxRecoveryHandler(customHandler)
|
||||
```
|
||||
|
||||
## Next {hide}
|
||||
|
||||
Learn about the [IBC](./../ibc/README.md) protocol {hide}
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
order: 14
|
||||
order: 13
|
||||
-->
|
||||
|
||||
# Cosmos Blockchain Simulator
|
||||
|
||||
+12
-12
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
order: 15
|
||||
order: 14
|
||||
-->
|
||||
|
||||
# Transaction Tips
|
||||
@@ -14,9 +14,9 @@ Transaction tips is a new solution for cross-chain transaction fees payment, whe
|
||||
|
||||
Assuming we have two chains, A and B, we define the following terms:
|
||||
|
||||
- **the tipper**: this is the initiator of the transaction, who wants to execute a `Msg` on chain A, but doesn't have any native chain A tokens, only chain B tokens. In our example above, the tipper is the Osmosis (chain B) user wanting to vote on a Cosmos Hub (chain A) proposal.
|
||||
- **the fee payer**: this is the party that will relay and broadcast the final transaction on chain A, and has chain A tokens. The tipper doesn't need to trust the feepayer.
|
||||
- **the target chain**: the chain where the `Msg` is executed, chain A in this case.
|
||||
* **the tipper**: this is the initiator of the transaction, who wants to execute a `Msg` on chain A, but doesn't have any native chain A tokens, only chain B tokens. In our example above, the tipper is the Osmosis (chain B) user wanting to vote on a Cosmos Hub (chain A) proposal.
|
||||
* **the fee payer**: this is the party that will relay and broadcast the final transaction on chain A, and has chain A tokens. The tipper doesn't need to trust the feepayer.
|
||||
* **the target chain**: the chain where the `Msg` is executed, chain A in this case.
|
||||
|
||||
## Transaction Tips Flow
|
||||
|
||||
@@ -42,12 +42,12 @@ Notice that this document doesn't sign over the final chain A fees. Instead, it
|
||||
|
||||
4. From the signed `AuxSignerData` document, the fee payer constructs a transaction, using the following algorithm:
|
||||
|
||||
- use as `TxBody` the exact `AuxSignerData.SignDocDirectAux.body_bytes`, to not alter the original intent of the tipper,
|
||||
- create an `AuthInfo` with:
|
||||
- `AuthInfo.Tip` copied from `AuxSignerData.SignDocDirectAux.Tip`,
|
||||
- `AuthInfo.Fee` chosen by the fee payer, which should cover for the transaction gas, but also be small enough so that the tip/fee exchange rate is economically interesting for the fee payer,
|
||||
- `AuthInfo.SignerInfos` has two signers: the first signer is the tipper, using the public key, sequence and sign mode specified in `AuxSignerData`; and the second signer is the fee payer, using their favorite sign mode,
|
||||
- a `Signatures` array with two items: the tipper's signature from `AuxSignerData.Sig`, and the final fee payer's signature.
|
||||
* use as `TxBody` the exact `AuxSignerData.SignDocDirectAux.body_bytes`, to not alter the original intent of the tipper,
|
||||
* create an `AuthInfo` with:
|
||||
* `AuthInfo.Tip` copied from `AuxSignerData.SignDocDirectAux.Tip`,
|
||||
* `AuthInfo.Fee` chosen by the fee payer, which should cover for the transaction gas, but also be small enough so that the tip/fee exchange rate is economically interesting for the fee payer,
|
||||
* `AuthInfo.SignerInfos` has two signers: the first signer is the tipper, using the public key, sequence and sign mode specified in `AuxSignerData`; and the second signer is the fee payer, using their favorite sign mode,
|
||||
* a `Signatures` array with two items: the tipper's signature from `AuxSignerData.Sig`, and the final fee payer's signature.
|
||||
|
||||
5. Broadcast the final transaction signed by the two parties to the target chain. Once included, the Cosmos SDK will trigger a transfer of the `Tip` specified in the transaction from the tipper address to the fee payer address.
|
||||
|
||||
@@ -63,8 +63,8 @@ In the future, we imagine a market where fee payers will compete to include tran
|
||||
|
||||
As we mentioned in the flow above, the tipper signs over the `SignDocDirectAux`, and the fee payer signs over the whole final transaction. As such, both parties might use different sign modes.
|
||||
|
||||
- The tipper MUST use `SIGN_MODE_DIRECT_AUX` or `SIGN_MODE_LEGACY_AMINO_JSON`. That is because the tipper needs to sign over the body, the tip, but not the other signers' information and not over the fee (which is unknown to the tipper).
|
||||
- The fee payer MUST use `SIGN_MODE_DIRECT` or `SIGN_MODE_LEGACY_AMINO_JSON`. The fee payer signs over the whole transaction.
|
||||
* The tipper MUST use `SIGN_MODE_DIRECT_AUX` or `SIGN_MODE_LEGACY_AMINO_JSON`. That is because the tipper needs to sign over the body, the tip, but not the other signers' information and not over the fee (which is unknown to the tipper).
|
||||
* The fee payer MUST use `SIGN_MODE_DIRECT` or `SIGN_MODE_LEGACY_AMINO_JSON`. The fee payer signs over the whole transaction.
|
||||
|
||||
For example, if the fee payer signs the whole transaction with `SIGN_MODE_DIRECT_AUX`, it will be rejected by the node, as that would introduce malleability issues (`SIGN_MODE_DIRECT_AUX` doesn't sign over fees).
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@ When users want to interact with an application and make state changes (e.g. sen
|
||||
|
||||
Transaction objects are Cosmos SDK types that implement the `Tx` interface
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/types/tx_msg.go#L49-L57
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-beta2/types/tx_msg.go#L38-L46
|
||||
|
||||
It contains the following methods:
|
||||
|
||||
* **GetMsgs:** unwraps the transaction and returns a list of contained `sdk.Msg`s - one transaction may have one or multiple messages, which are defined by module developers.
|
||||
* **ValidateBasic:** lightweight, [_stateless_](../basics/tx-lifecycle.md#types-of-checks) checks used by ABCI messages [`CheckTx`](./baseapp.md#checktx) and [`DeliverTx`](./baseapp.md#delivertx) to make sure transactions are not invalid. For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/main/x/auth) module's `ValidateBasic` function checks that its transactions are signed by the correct number of signers and that the fees do not exceed what the user's maximum. Note that this function is to be distinct from `sdk.Msg` [`ValidateBasic`](../basics/tx-lifecycle.md#ValidateBasic) methods, which perform basic validity checks on messages only. When [`runTx`](./baseapp.md#runtx) is checking a transaction created from the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/main/x/auth/spec) module, it first runs `ValidateBasic` on each message, then runs the `auth` module AnteHandler which calls `ValidateBasic` for the transaction itself.
|
||||
* **ValidateBasic:** lightweight, [_stateless_](../basics/tx-lifecycle.md#types-of-checks) checks used by ABCI messages [`CheckTx`](./baseapp.md#checktx) and [`DeliverTx`](./baseapp.md#delivertx) to make sure transactions are not invalid. For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/main/x/auth) module's `ValidateBasic` function checks that its transactions are signed by the correct number of signers and that the fees do not exceed what the user's maximum. Note that this function is to be distinct from `sdk.Msg` [`ValidateBasic`](../basics/tx-lifecycle.md#ValidateBasic) methods, which perform basic validity checks on messages only. When using [`ValidateBasicMiddleware`](https://github.com/cosmos/cosmos-sdk/blob/main/x/auth/spec/03_middlewares.md), `ValidateBasic` is called on each message, and then the middleware calls `ValidateBasic` for the transaction itself.
|
||||
|
||||
As a developer, you should rarely manipulate `Tx` directly, as `Tx` is really an intermediate type used for transaction generation. Instead, developers should prefer the `TxBuilder` interface, which you can learn more about [below](#transaction-generation).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user