docs: rewrite building module section (2/n) -- env + core services (#22790)

Co-authored-by: Akhil Kumar P <36399231+akhilkumarpilli@users.noreply.github.com>
This commit is contained in:
Julien Robert
2024-12-09 09:30:13 +00:00
committed by GitHub
co-authored by Akhil Kumar P
parent 6cf9d57be9
commit 8ef35c39ba
12 changed files with 105 additions and 80 deletions
+2 -2
View File
@@ -92,7 +92,7 @@ Finally, a few more important parameters:
* `voteInfos`: This parameter carries the list of validators whose precommit is missing, either
because they did not vote or because the proposer did not include their vote. This information is
carried by the [Context](./02-context.md) and can be used by the application for various things like
carried by the [Context](./17-context.md) and can be used by the application for various things like
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
@@ -474,7 +474,7 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/baseapp/abci.go#L894
* 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/06-preblock-beginblock-endblock.md#beginblocker-and-endblocker) method of each of the modules.
* Set the [`VoteInfos`](https://docs.cometbft.com/v1.0/spec/abci/abci++_methods#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.
* Set the [`VoteInfos`](https://docs.cometbft.com/v1.0/spec/abci/abci++_methods#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`](./17-context.md) so that it can be used during transaction execution and EndBlock.
#### Transaction Execution
+1 -1
View File
@@ -16,7 +16,7 @@ sidebar_position: 1
## Transactions
Transactions are comprised of metadata held in [contexts](./02-context.md) and [`sdk.Msg`s](../../build/building-modules/02-messages-and-queries.md) that trigger state changes within a module through the module's Protobuf [`Msg` service](../../build/building-modules/03-msg-services.md).
Transactions are comprised of metadata held in [contexts](./17-context.md) and [`sdk.Msg`s](../../build/building-modules/02-messages-and-queries.md) that trigger state changes within a module through the module's Protobuf [`Msg` service](../../build/building-modules/03-msg-services.md).
When users want to interact with an application and make state changes (e.g. sending coins), they create transactions. Each of a transaction's `sdk.Msg` must be signed using the private key associated with the appropriate account(s), before the transaction is broadcasted to the network. A transaction must then be included in a block, validated, and approved by the network through the consensus process. To read more about the lifecycle of a transaction, click [here](../beginner/01-tx-lifecycle.md).
@@ -4,8 +4,7 @@ sidebar_position: 1
# Core
Core is package which specifies the interfaces for core components of the Cosmos SDK. Other
packages in the SDK implement these interfaces to provide the core functionality. This design
Core (`cosmossdk.io/core`) is package which specifies the interfaces for core components of the Cosmos SDK. Other packages in the SDK implement these interfaces to provide the core functionality. This design
provides modularity and flexibility to the SDK, allowing developers to swap out implementations
of core components as needed. As such it is often referred to as the Core API.
@@ -16,19 +15,28 @@ services of the SDK, such as the KVStore, EventManager, and Logger. The `Enviro
passed to modules and other components of the SDK to provide access to these services.
```go reference
https://github.com/cosmos/cosmos-sdk/blob/core/v1.0.0-alpha.4/core/appmodule/v2/environment.go#L16-L29
https://github.com/cosmos/cosmos-sdk/blob/core/v1.0.0-alpha.6/core/appmodule/v2/environment.go#L16-L29
```
Historically the SDK has used an [sdk.Context](02-context.md) to pass around services and data.
Historically the SDK has used an [sdk.Context](https://docs.cosmos.network/v0.50/learn/advanced/context) to pass around services and data.
`Environment` is a newer construct that is intended to replace an `sdk.Context` in many cases.
`sdk.Context` will be deprecated in the future on the same timeline as [Baseapp](00-baseapp.md).
## Logger
The [Logger](https://pkg.go.dev/cosmossdk.io/log) provides a structured logging interface to the SDK. It is used throughout the SDK to log messages at various levels of severity. The Logger service is a thin wrapper around the [zerolog](https://github.com/rs/zerolog) logging library.
When used via environment, the logger is scoped to the module that is using it.
```go reference
https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/runtime/module.go#L274
```
## Branch Service
The [BranchService](https://pkg.go.dev/cosmossdk.io/core/branch#Service.Execute) provides an
interface to execute arbitrary code in a branched store. This is useful for executing code
that needs to make changes to the store, but may need to be rolled back if an error occurs.
Below is a contrived example based on the `x/epoch` module's BeginBlocker logic.
Below is a contrived example based on the `x/epochs` module's BeginBlocker logic.
```go
func (k Keeper) BeginBlocker(ctx context.Context) error {
+5 -30
View File
@@ -45,7 +45,9 @@ The `GetStoreType` is a simple method that returns the type of store, whereas a
https://github.com/cosmos/cosmos-sdk/blob/store/v1.1.1/store/types/store.go#L287-L303
```
Branching and cache is used ubiquitously in the Cosmos SDK and required to be implemented on every store type. A storage branch creates an isolated, ephemeral branch of a store that can be passed around and updated without affecting the main underlying store. This is used to trigger temporary state-transitions that may be reverted later should an error occur. Read more about it in [context](./02-context.md#store-branching)
Branching and cache is used ubiquitously in the Cosmos SDK and required to be implemented on every store type. A storage branch creates an isolated, ephemeral branch of a store that can be passed around and updated without affecting the main underlying store. This is used to trigger temporary state-transitions that may be reverted later should an error occur.
Branching is available as a service for modules. Read more about it in the [core](./02-core.md#branch-service) documentation.
### Commit Store
@@ -147,29 +149,7 @@ The documentation on the IAVL Tree is located [here](https://github.com/cosmos/i
https://github.com/cosmos/cosmos-sdk/blob/store/v1.1.1/store/dbadapter/store.go#L13-L16
```
`dbadapter.Store` embeds `corestore.KVStoreWithBatch`, meaning most of the `KVStore` interface functions are implemented. The other functions (mostly miscellaneous) are manually implemented. This store is primarily used within [Transient Stores](#transient-store)
### `Transient` Store
`Transient.Store` is a base-layer `KVStore` which is automatically discarded at the end of the block.
```go reference
https://github.com/cosmos/cosmos-sdk/blob/store/v1.1.1/store/transient/store.go#L16-L19
```
`Transient.Store` is a `dbadapter.Store` with a `coretesting.NewMemDB()`. All `KVStore` methods are reused. When `Store.Commit()` is called, a new `dbadapter.Store` is assigned, discarding previous reference and making it garbage collected.
This type of store is useful to persist information that is only relevant per-block. One example would be to store parameter changes (i.e. a bool set to `true` if a parameter changed in a block).
```go reference
https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/x/params/types/subspace.go#L23-L33
```
Transient stores are typically accessed via the [`context`](./02-context.md) via the `TransientStore()` method:
```go reference
https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/types/context.go#L344-L347
```
`dbadapter.Store` embeds `corestore.KVStoreWithBatch`, meaning most of the `KVStore` interface functions are implemented. The other functions (mostly miscellaneous) are manually implemented.
## KVStore Wrappers
@@ -215,12 +195,7 @@ By default, all `KVStores` are wrapped in `GasKv.Stores` when retrieved. This is
https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/types/context.go#L339-L342
```
In this case, the gas configuration set in the `context` is used. The gas configuration can be set using the `WithKVGasConfig` method of the `context`.
Otherwise it uses the following default:
```go reference
https://github.com/cosmos/cosmos-sdk/blob/store/v1.1.1/store/types/gas.go#L231-L242
```
`KVStores` can be accessed in their corresponding modules by using the [`kvStoreService` and `memStoreService`](./02-core.md#kvstore-service).
### `TraceKv` Store
+21 -24
View File
@@ -77,10 +77,11 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/types/events.go#L62-L86
```
Module developers should handle Event emission via the `EventManager#EmitTypedEvent` or `EventManager#EmitEvent` in each
message `Handler` and in each `BeginBlock`/`EndBlock` handler. The `EventManager` is accessed via
the [`Context`](./02-context.md), where Event should be already registered, and emitted like this:
message `Handler` and in each `BeginBlock`/`EndBlock` handler.
The `EventManager` is accessible via the event service, present in the `Environment` struct.
This event service is a [core service](./02-core.md) available to all modules.
Note: it is preferred to use `EmitTypedEvent` over `EmitEvent` as the latter has been deprecated.
Events can be emitted like this using the `EventService`:
**Typed events:**
@@ -90,18 +91,28 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/x/group/keeper/msg_serv
**Legacy events:**
```go
ctx.EventManager().EmitEvent(
sdk.NewEvent(eventType, sdk.NewAttribute(attributeKey, attributeValue)),
)
```go reference
https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/x/gov/keeper/vote.go#L91-L95
```
Where the `EventManager` is accessed via the [`Context`](./02-context.md).
See the [`Msg` services](../../build/building-modules/03-msg-services.md) concept doc for a more detailed
view on how to typically implement Events and use the `EventManager` in modules.
## Subscribing to Events
## Default Events
There are a few events that are automatically emitted for all messages, directly from `baseapp`.
* `message.action`: The name of the message type.
* `message.sender`: The address of the message signer.
* `message.module`: The name of the module that emitted the message.
:::tip
The module name is assumed by `baseapp` to be the second element of the message route: `"cosmos.bank.v1beta1.MsgSend" -> "bank"`.
In case a module does not follow the standard message path, (e.g. IBC), it is advised to keep emitting the module name event.
`Baseapp` only emits that event if the module have not already done so.
:::
## Subscribing to CometBFT Events
You can use CometBFT's [Websocket](https://docs.cometbft.com/v1.0/explanation/core/subscription) to subscribe to Events by calling the `subscribe` RPC method:
@@ -143,17 +154,3 @@ Subscribing to this Event would be done like so:
where `ownerAddress` is an address following the [`AccAddress`](../beginner/03-accounts.md#addresses) format.
The same way can be used to subscribe to [legacy events](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/bank/types/events.go).
## Default Events
There are a few events that are automatically emitted for all messages, directly from `baseapp`.
* `message.action`: The name of the message type.
* `message.sender`: The address of the message signer.
* `message.module`: The name of the module that emitted the message.
:::tip
The module name is assumed by `baseapp` to be the second element of the message route: `"cosmos.bank.v1beta1.MsgSend" -> "bank"`.
In case a module does not follow the standard message path, (e.g. IBC), it is advised to keep emitting the module name event.
`Baseapp` only emits that event if the module have not already done so.
:::
@@ -5,7 +5,7 @@ sidebar_position: 1
# Context
:::note Synopsis
The `context` is a data structure intended to be passed from function to function that carries information about the current state of the application. It provides access to a branched storage (a safe branch of the entire state) as well as useful objects and information like `gasMeter`, `block height`, `consensus parameters` and more.
The `context` is a data structure that carries information about the current state of the application. It provides access to a branched storage (a safe branch of the entire state) as well as useful objects and information like `gasMeter`, `block height`, `consensus parameters` and more.
:::
:::note Pre-requisite Readings
@@ -15,6 +15,10 @@ The `context` is a data structure intended to be passed from function to functio
:::
:::warning
The `sdk.Context` should not be used directly. `Runtime` is implementing the [core services](./02-core.md), which are using directly the `sdk.Context`.
:::
## Context Definition
The Cosmos SDK `Context` is a custom data structure that contains Go's stdlib [`context`](https://pkg.go.dev/context) as its base, and has many additional types within its definition that are specific to the Cosmos SDK. The `Context` is integral to transaction processing in that it allows modules to easily access their respective [store](./04-store.md#base-layer-kvstores) in the [`multistore`](./04-store.md#multistore) and retrieve transactional context such as the block header and gas meter.
+8 -4
View File
@@ -26,7 +26,7 @@ In the Cosmos SDK, `gas` is a special unit that is used to track the consumption
In the Cosmos SDK, `gas` is a simple alias for `uint64`, and is managed by an object called a _gas meter_. Gas meters implement the `GasMeter` interface
```go reference
https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/store/types/gas.go#L40-L51
https://github.com/cosmos/cosmos-sdk/blob/b795646/store/types/gas.go#L40-L51
```
where:
@@ -40,17 +40,21 @@ where:
* `IsPastLimit()` returns `true` if the amount of gas consumed by the gas meter instance is strictly above the limit, `false` otherwise.
* `IsOutOfGas()` returns `true` if the amount of gas consumed by the gas meter instance is above or equal to the limit, `false` otherwise.
The gas meter is generally held in [`ctx`](../advanced/02-context.md), and consuming gas is done with the following pattern:
The gas meter is held under the `GasMeterService` in [`Environment`](../advanced/02-core.md), and consuming gas is done with the following pattern:
:::note
The gas.Service does not give access to all the methods of the gas meter.
:::
```go
ctx.GasMeter().ConsumeGas(amount, "description")
environment.GasMeter(ctx).Consume(amount, "description")
```
By default, the Cosmos SDK makes use of two different gas meters, the [main gas meter](#main-gas-meter) and the [block gas meter](#block-gas-meter).
### Main Gas Meter
`ctx.GasMeter()` is the main gas meter of the application. The main gas meter is initialized in `FinalizeBlock` via `setFinalizeBlockState`, and then tracks gas consumption during execution sequences that lead to state-transitions, i.e. those originally triggered by [`FinalizeBlock`](../advanced/00-baseapp.md#finalizeblock). At the beginning of each transaction execution, the main gas meter **must be set to 0** in the [`AnteHandler`](#antehandler), so that it can track gas consumption per-transaction.
The main gas meter is initialized in `FinalizeBlock` via `setFinalizeBlockState`, and then tracks gas consumption during execution sequences that lead to state-transitions, i.e. those originally triggered by [`FinalizeBlock`](../advanced/00-baseapp.md#finalizeblock). At the beginning of each transaction execution, the main gas meter **must be set to 0** in the [`AnteHandler`](#antehandler), so that it can track gas consumption per-transaction.
Gas consumption can be done manually, generally by the module developer in the [`BeginBlocker`, `EndBlocker`](../../build/building-modules/06-preblock-beginblock-endblock.md) or [`Msg` service](../../build/building-modules/03-msg-services.md), but most of the time it is done automatically whenever there is a read or write to the store. This automatic gas consumption logic is implemented in a special store called [`GasKv`](../advanced/04-store.md#gaskv-store).