Docs: Anys Usage, Events & small cleanups (#8895)
Co-authored-by: Barrie Byron <barrie.byron@tendermint.com> Co-authored-by: Alessio Treglia <alessio@tendermint.com>
This commit is contained in:
parent
0836361c0e
commit
1a4418b32b
@ -75,7 +75,7 @@ func (m Migrator) Migrate1to2(ctx sdk.Context) error {
|
||||
}
|
||||
```
|
||||
|
||||
Each module's migration functions are specific to the module's store evolutions, and are not described in this ADR. An example of x/bank store key migrations following the introduction of ADR-028 length-prefixed addresses can be seen [here](https://github.com/cosmos/cosmos-sdk/blob/ef8dabcf0f2ecaf26db1c6c6d5922e9399458bb3/x/bank/legacy/v042/store.go#L15).
|
||||
Each module's migration functions are specific to the module's store evolutions, and are not described in this ADR. An example of x/bank store key migrations after the introduction of ADR-028 length-prefixed addresses can be seen in this [store.go code](https://github.com/cosmos/cosmos-sdk/blob/36f68eb9e041e20a5bb47e216ac5eb8b91f95471/x/bank/legacy/v043/store.go#L41-L62).
|
||||
|
||||
### Tracking Module Versions in `x/upgrade`
|
||||
|
||||
|
||||
@ -98,7 +98,7 @@ Also see the [`Addresses`](#addresses) section for more information.
|
||||
|
||||
`PubKey`s used in the Cosmos SDK are Protobuf messages and have the following methods:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/master/crypto/types/types.go#L8-L17
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/crypto/types/types.go#L8-L17
|
||||
|
||||
- For `secp256k1` keys, the actual implementation can be found [here](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/crypto/keys/secp256k1/secp256k1.go).
|
||||
- For `ed25519` keys, it can be found [here](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/crypto/keys/ed25519/ed25519.go).
|
||||
|
||||
@ -113,8 +113,8 @@ The `EncodingConfig` structure is the last important part of the `app.go` file.
|
||||
|
||||
Here are descriptions of what each of the four fields means:
|
||||
|
||||
- `InterfaceRegistry`: The `InterfaceRegistry` is used by the Protobuf codec to handle interfaces, which are encoded and decoded (we also say "unpacked") using [`google.protobuf.Any`](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). `Any` could be thought as a struct which contains a `type_url` (name of a concrete type implementing the interface) and a `value` (its encoded bytes). `InterfaceRegistry` provides a mechanism for registering interfaces and implementations that can be safely unpacked from `Any`. Each of the application's modules implements the `RegisterInterfaces` method, which can be used to register the module's own interfaces and implementations.
|
||||
- You can read more about Any in [ADR-19](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-019-protobuf-state-encoding.md#usage-of-any-to-encode-interfaces).
|
||||
- `InterfaceRegistry`: The `InterfaceRegistry` is used by the Protobuf codec to handle interfaces that are encoded and decoded (we also say "unpacked") using [`google.protobuf.Any`](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). `Any` could be thought as a struct that contains a `type_url` (name of a concrete type implementing the interface) and a `value` (its encoded bytes). `InterfaceRegistry` provides a mechanism for registering interfaces and implementations that can be safely unpacked from `Any`. Each of the application's modules implements the `RegisterInterfaces` method that can be used to register the module's own interfaces and implementations.
|
||||
- You can read more about Any in [ADR-19](../architecture/adr-019-protobuf-state-encoding.md#usage-of-any-to-encode-interfaces).
|
||||
- To go more into details, the SDK uses an implementation of the Protobuf specification called [`gogoprotobuf`](https://github.com/gogo/protobuf). By default, the [gogo protobuf implementation of `Any`](https://godoc.org/github.com/gogo/protobuf/types) uses [global type registration](https://github.com/gogo/protobuf/blob/master/proto/properties.go#L540) to decode values packed in `Any` into concrete Go types. This introduces a vulnerability where any malicious module in the dependency tree could registry a type with the global protobuf registry and cause it to be loaded and unmarshaled by a transaction that referenced it in the `type_url` field. For more information, please refer to [ADR-019](../architecture/adr-019-protobuf-state-encoding.md).
|
||||
- `Marshaler`: the default codec used throughout the SDK. It is composed of a `BinaryMarshaler` used to encode and decode state, and a `JSONMarshaler` used to output data to the users (for example in the [CLI](#cli)). By default, the SDK uses Protobuf as `Marshaler`.
|
||||
- `TxConfig`: `TxConfig` defines an interface a client can utilize to generate an application-defined concrete transaction type. Currently, the SDK handles two transaction types: `SIGN_MODE_DIRECT` (which uses Protobuf binary as over-the-wire encoding) and `SIGN_MODE_LEGACY_AMINO_JSON` (which depends on Amino). Read more about transactions [here](../core/transactions.md).
|
||||
|
||||
@ -74,7 +74,7 @@ At its core, the `InvariantRegistry` is defined in the SDK as an interface:
|
||||
|
||||
Typically, this interface is implemented in the `keeper` of a specific module. The most used implementation of an `InvariantRegistry` can be found in the `crisis` module:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/master/x/crisis/keeper/keeper.go#L50-L54
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/crisis/keeper/keeper.go#L50-L54
|
||||
|
||||
The `InvariantRegistry` is therefore typically instantiated by instantiating the `keeper` of the `crisis` module in the [application's constructor function](../basics/app-anatomy.md#constructor-function).
|
||||
|
||||
|
||||
@ -63,9 +63,9 @@ Operations on the simulation are simulated using the full [transaction cycle](..
|
||||
|
||||
Shown below is how weights are set:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/master/x/staking/simulation/operations.go#L18-L68
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/staking/simulation/operations.go#L18-L68
|
||||
|
||||
As you can see the weights are predefined in this case but there are options on how to override this behavior with different weights. One is allowing `*rand.Rand` to define a random weight for the operation, or you can inject your own predefined weights.
|
||||
As you can see, the weights are predefined in this case. Options exist to override this behavior with different weights. One option is to use `*rand.Rand` to define a random weight for the operation, or you can inject your own predefined weights.
|
||||
|
||||
Here is how one can override the above package `simappparams`.
|
||||
|
||||
|
||||
@ -126,7 +126,7 @@ is the canonical state of the application and the volatile states, `checkState`
|
||||
are used to handle state transitions in-between the main state made during [`Commit`](#commit).
|
||||
|
||||
Internally, there is only a single `CommitMultiStore` which we refer to as the main or root state.
|
||||
From this root state, we derive two volatile state through a mechanism called _store branching_ (performed by `CacheWrap` function).
|
||||
From this root state, we derive two volatile states by using a mechanism called _store branching_ (performed by `CacheWrap` function).
|
||||
The types can be illustrated as follows:
|
||||
|
||||

|
||||
@ -333,7 +333,7 @@ The `AnteHandler` is theoretically optional, but still a very important componen
|
||||
- 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 paraemter, which is initialized in the [application's constructor](../basics/app-anatomy.md#application-constructor). The most widely used `anteHandler` today is that of the [`auth` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/auth/ante/ante.go).
|
||||
`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).
|
||||
|
||||
Click [here](../basics/gas-fees.md#antehandler) for more on the `anteHandler`.
|
||||
|
||||
|
||||
@ -69,9 +69,141 @@ typically used for when the data needs to be streamed or grouped together
|
||||
|
||||
### Gogoproto
|
||||
|
||||
Modules are encouraged to utilize Protobuf encoding for their respective types.
|
||||
Modules are encouraged to utilize Protobuf encoding for their respective types. In the SDK, we use the [Gogoproto](https://github.com/gogo/protobuf) specific implementation of the Protobuf spec that offers speed and DX improvements compared to the official [Google protobuf implementation](https://github.com/protocolbuffers/protobuf).
|
||||
|
||||
#### FAQ
|
||||
### Guidelines for protobuf message definitions
|
||||
|
||||
In addition to [following official Protocol Buffer guidelines](https://developers.google.com/protocol-buffers/docs/proto3#simple), we recommend using these annotations in .proto files when dealing with interfaces:
|
||||
|
||||
- use `cosmos_proto.accepts_interface` to annote fields that accept interfaces
|
||||
- pass the same fully qualified name as `protoName` to `InterfaceRegistry.RegisterInterface`
|
||||
- annotate interface implementations with `cosmos_proto.implements_interface`
|
||||
- pass the same fully qualified name as `protoName` to `InterfaceRegistry.RegisterInterface`
|
||||
|
||||
### Transaction Encoding
|
||||
|
||||
Another important use of Protobuf is the encoding and decoding of
|
||||
[transactions](./transactions.md). Transactions are defined by the application or
|
||||
the SDK but are then passed to the underlying consensus engine to be relayed to
|
||||
other peers. Since the underlying consensus engine is agnostic to the application,
|
||||
the consensus engine accepts only transactions in the form of raw bytes.
|
||||
|
||||
- The `TxEncoder` object performs the encoding.
|
||||
- The `TxDecoder` object performs the decoding.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/types/tx_msg.go#L83-L87
|
||||
|
||||
A standard implementation of both these objects can be found in the [`auth` module](../../x/auth/spec/README.md):
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/x/auth/tx/decoder.go
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/x/auth/tx/encoder.go
|
||||
|
||||
See [ADR-020](../architecture/adr-020-protobuf-transaction-encoding.md) for details of how a transaction is encoded.
|
||||
|
||||
### Interface Encoding and Usage of `Any`
|
||||
|
||||
The Protobuf DSL is strongly typed, which can make inserting variable-typed fields difficult. Imagine we want to create a `Profile` protobuf message that serves as a wrapper over [an account](../basics/accounts.md):
|
||||
|
||||
```proto
|
||||
message Profile {
|
||||
// account is the account associated to a profile.
|
||||
cosmos.auth.v1beta1.BaseAccount account = 1;
|
||||
// bio is a short description of the account.
|
||||
string bio = 4;
|
||||
}
|
||||
```
|
||||
|
||||
In this `Profile` example, we hardcoded `account` as a `BaseAccount`. However, there are several other types of [user accounts related to vesting](../../x/auth/spec/05_vesting.md), such as `BaseVestingAccount` or `ContinuousVestingAccount`. All of these accounts are different, but they all implement the `AccountI` interface. How would you create a `Profile` that allows all these types of accounts with an `account` field that accepts an `AccountI` interface?
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/auth/types/account.go#L307-L330
|
||||
|
||||
In [ADR-019](../architecture/adr-019-protobuf-state-encoding.md), it has been decided to use [`Any`](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto)s to encode interfaces in protobuf. An `Any` contains an arbitrary serialized message as bytes, along with a URL that acts as a globally unique identifier for and resolves to that message's type. This strategy allows us to pack arbitrary Go types inside protobuf messages. Our new `Profile` then looks like:
|
||||
|
||||
```protobuf
|
||||
message Profile {
|
||||
// account is the account associated to a profile.
|
||||
google.protobuf.Any account = 1 [
|
||||
(cosmos_proto.accepts_interface) = "AccountI"; // Asserts that this field only accepts Go types implementing `AccountI`. It is purely informational for now.
|
||||
];
|
||||
// bio is a short description of the account.
|
||||
string bio = 4;
|
||||
}
|
||||
```
|
||||
|
||||
To add an account inside a profile, we need to "pack" it inside an `Any` first, using `codectypes.NewAnyWithValue`:
|
||||
|
||||
```go
|
||||
var myAccount AccountI
|
||||
myAccount = ... // Can be a BaseAccount, a ContinuousVestingAccount or any struct implementing `AccountI`
|
||||
|
||||
// Pack the account into an Any
|
||||
accAny, err := codectypes.NewAnyWithValue(myAccount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create a new Profile with the any.
|
||||
profile := Profile {
|
||||
Account: accAny,
|
||||
Bio: "some bio",
|
||||
}
|
||||
|
||||
// We can then marshal the profile as usual.
|
||||
bz, err := cdc.MarshalBinaryBare(profile)
|
||||
jsonBz, err := cdc.MarshalJSON(profile)
|
||||
```
|
||||
|
||||
To summarize, to encode an interface, you must 1/ pack the interface into an `Any` and 2/ marshal the `Any`. For convenience, the SDK provides a `MarshalInterface` method to bundle these two steps. Have a look at [a real-life example in the x/auth module](https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/auth/keeper/keeper.go#L218-L221).
|
||||
|
||||
The reverse operation of retrieving the concrete Go type from inside an `Any`, called "unpacking", is done with the `GetCachedValue()` on `Any`.
|
||||
|
||||
```go
|
||||
profileBz := ... // The proto-encoded bytes of a Profile, e.g. retrieved through gRPC.
|
||||
var myProfile Profile
|
||||
// Unmarshal the bytes into the myProfile struct.
|
||||
err := cdc.UnmarshalBinaryBare(profilebz, &myProfile)
|
||||
|
||||
// Let's see the types of the Account field.
|
||||
fmt.Printf("%T\n", myProfile.Account) // Prints "Any"
|
||||
fmt.Printf("%T\n", myProfile.Account.GetCachedValue()) // Prints "BaseAccount", "ContinuousVestingAccount" or whatever was initially packed in the Any.
|
||||
|
||||
// Get the address of the accountt.
|
||||
accAddr := myProfile.Account.GetCachedValue().(AccountI).GetAddress()
|
||||
```
|
||||
|
||||
It is important to note that for `GetCachedValue()` to work, `Profile` (and any other structs embedding `Profile`) must implement the `UnpackInterfaces` method:
|
||||
|
||||
```go
|
||||
func (p *Profile) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
|
||||
if p.Account != nil {
|
||||
var account AccountI
|
||||
return unpacker.UnpackAny(p.Account, &account)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
The `UnpackInterfaces` gets called recursively on all structs implementing this method, to allow all `Any`s to have their `GetCachedValue()` correctly populated.
|
||||
|
||||
For more information about interface encoding, and especially on `UnpackInterfaces` and how the `Any`'s `type_url` gets resolved using the `InterfaceRegistry`, please refer to [ADR-019](../architecture/adr-019-protobuf-state-encoding.md).
|
||||
|
||||
#### `Any` Encoding in the SDK
|
||||
|
||||
The above `Profile` example is a fictive example used for educational purposes. In the SDK, we use `Any` encoding in several places (non-exhaustive list):
|
||||
|
||||
- the `cryptotypes.PubKey` interface for encoding different types of public keys,
|
||||
- the `sdk.Msg` interface for encoding different `Msg`s in a transaction,
|
||||
- the `AccountI` interface for encodinig different types of accounts (similar to the above example) in the x/auth query responses,
|
||||
- the `Evidencei` interface for encoding different types of evidences in the x/evidence module,
|
||||
- the `AuthorizationI` interface for encoding different types of x/authz authorizations.
|
||||
|
||||
A real-life example of encoding the pubkey as `Any` inside the Validator struct in x/staking is shown in the following example:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/staking/types/validator.go#L40-L61
|
||||
|
||||
## FAQ
|
||||
|
||||
1. How to create modules using protobuf encoding?
|
||||
|
||||
@ -123,32 +255,6 @@ type UnpackInterfacesMessage interface {
|
||||
}
|
||||
```
|
||||
|
||||
#### Guidelines for protobuf message definitions
|
||||
|
||||
In addition to [following official guidelines](https://developers.google.com/protocol-buffers/docs/proto3#simple), we recommend to use these annotations in .proto files when dealing with interfaces:
|
||||
|
||||
- fields which accept interfaces should be annotated with `cosmos_proto.accepts_interface`
|
||||
using the same full-qualified name passed as `protoName` to `InterfaceRegistry.RegisterInterface`
|
||||
- interface implementations should be annotated with `cosmos_proto.implements_interface`
|
||||
using the same full-qualified name passed as `protoName` to `InterfaceRegistry.RegisterInterface`
|
||||
|
||||
#### Transaction Encoding
|
||||
|
||||
Another important use of Protobuf is the encoding and decoding of
|
||||
[transactions](./transactions.md). Transactions are defined by the application or
|
||||
the SDK, but passed to the underlying consensus engine in order to be relayed to
|
||||
other peers. Since the underlying consensus engine is agnostic to the application,
|
||||
it only accepts transactions in the form of raw bytes. The encoding is done by an
|
||||
object called `TxEncoder` and the decoding by an object called `TxDecoder`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/types/tx_msg.go#L83-L87
|
||||
|
||||
A standard implementation of both these objects can be found in the [`auth` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/auth):
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/x/auth/tx/decoder.go
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc4/x/auth/tx/encoder.go
|
||||
|
||||
## Next {hide}
|
||||
|
||||
Learn about [gRPC, REST and other endpoints](./grpc_rest.md) {hide}
|
||||
|
||||
@ -9,20 +9,28 @@ order: 9
|
||||
## Pre-requisite Readings
|
||||
|
||||
- [Anatomy of an SDK application](../basics/app-anatomy.md) {prereq}
|
||||
- [Tendermint Documentation on Events](https://docs.tendermint.com/master/spec/abci/abci.html#events) {prereq}
|
||||
|
||||
## Events
|
||||
|
||||
Events are implemented in the Cosmos SDK as an alias of the ABCI `Event` type and
|
||||
take the form of: `{eventType}.{eventAttribute}={value}`.
|
||||
take the form of: `{eventType}.{attributeKey}={attributeValue}`.
|
||||
|
||||
+++ https://github.com/tendermint/tendermint/blob/bc572217c07b90ad9cee851f193aaa8e9557cbc7/abci/types/types.pb.go#L2187-L2193
|
||||
+++ https://github.com/tendermint/tendermint/blob/v0.34.8/proto/tendermint/abci/types.proto#L304-L313
|
||||
|
||||
Events contain:
|
||||
An Event contains:
|
||||
|
||||
- A `type`, which is meant to categorize an event at a high-level (e.g. by module (e.g. `module=bank`) or action (e.g. `action=/cosmos.bank.v1beta1.Msg/Send`)).
|
||||
- A list of `attributes`, which are key-value pairs that give more information about
|
||||
the categorized `event`.
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L51-L56
|
||||
- A `type` to categorize the Event at a high-level; for example, the SDK uses the `"message"` type to filter Events by `Msg`s.
|
||||
- A list of `attributes` are key-value pairs that give more information about the categorized Event. For example, for the `"message"` type, we can filter Events by key-value pairs using `message.action={some_action}`, `message.module={some_module}` or `message.sender={some_sender}`.
|
||||
|
||||
::: tip
|
||||
To parse the attribute values as strings, make sure to add `'` (single quotes) around each attribute value.
|
||||
:::
|
||||
|
||||
Events, the `type` and `attributes` are defined on a **per-module basis** in the module's
|
||||
`/types/events.go` file, and triggered from the module's [`Msg` service](../building-modules/msg-services.md)
|
||||
by using the [`EventManager`](#eventmanager). In addition, each module documents its Events under
|
||||
`spec/xx_events.md`.
|
||||
|
||||
Events are returned to the underlying consensus engine in the response of the following ABCI messages:
|
||||
|
||||
@ -31,28 +39,35 @@ Events are returned to the underlying consensus engine in the response of the fo
|
||||
- [`CheckTx`](./baseapp.md#checktx)
|
||||
- [`DeliverTx`](./baseapp.md#delivertx)
|
||||
|
||||
Events, the `type` and `attributes`, are defined on a **per-module basis** in the module's
|
||||
`/types/events.go` file, and triggered from the module's [`Msg` service](../building-modules/msg-services.md)
|
||||
via the [`EventManager`](#eventmanager). In addition, each module documents its events under
|
||||
`spec/xx_events.md`.
|
||||
### Examples
|
||||
|
||||
The following examples show how to query Events using the SDK.
|
||||
|
||||
| Event | Description |
|
||||
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `tx.height=23` | Query all transactions at height 23 |
|
||||
| `message.action='/cosmos.bank.v1beta1.Msg/Send'` | Query all transactions containing a x/bank `Send` [Service `Msg`](../building-modules/msg-services.md). Note the `'`s around the value. |
|
||||
| `message.action='send'` | Query all transactions containing a x/bank `Send` [legacy `Msg`](../building-modules/msg-services.md#legacy-amino-msgs). Note the `'`s around the value. |
|
||||
| `message.module='bank'` | Query all transactions containing messages from the x/bank module. Note the `'`s around the value. |
|
||||
| `create_validator.validator='cosmosval1...'` | x/staking-specific Event, see [x/staking SPEC](../../../cosmos-sdk/x/staking/spec/07_events.md). |
|
||||
|
||||
## EventManager
|
||||
|
||||
In Cosmos SDK applications, events are managed by an abstraction called the `EventManager`.
|
||||
Internally, the `EventManager` tracks a list of `Events` for the entire execution flow of a
|
||||
In Cosmos SDK applications, Events are managed by an abstraction called the `EventManager`.
|
||||
Internally, the `EventManager` tracks a list of Events for the entire execution flow of a
|
||||
transaction or `BeginBlock`/`EndBlock`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L16-L20
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/types/events.go#L17-L25
|
||||
|
||||
The `EventManager` comes with a set of useful methods to manage events. Among them, the one that is
|
||||
used the most by module and application developers is the `EmitEvent` method, which tracks
|
||||
an `event` in the `EventManager`.
|
||||
The `EventManager` comes with a set of useful methods to manage Events. The method
|
||||
that is used most by module and application developers is `EmitEvent` that tracks
|
||||
an Event in the `EventManager`.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/events.go#L29-L31
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/types/events.go#L33-L37
|
||||
|
||||
Module developers should handle event emission via the `EventManager#EmitEvent` in each message
|
||||
Module developers should handle Event emission via the `EventManager#EmitEvent` in each message
|
||||
`Handler` and in each `BeginBlock`/`EndBlock` handler. The `EventManager` is accessed via
|
||||
the [`Context`](./context.md), where event emission generally follows this pattern:
|
||||
the [`Context`](./context.md), where Event emission generally follows this pattern:
|
||||
|
||||
```go
|
||||
ctx.EventManager().EmitEvent(
|
||||
@ -60,7 +75,8 @@ ctx.EventManager().EmitEvent(
|
||||
)
|
||||
```
|
||||
|
||||
Module's `handler` function should also set a new `EventManager` to the `context` to isolate emitted events per `message`:
|
||||
Module's `handler` function should also set a new `EventManager` to the `context` to isolate emitted Events per `message`:
|
||||
|
||||
```go
|
||||
func NewHandler(keeper Keeper) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
|
||||
@ -69,48 +85,53 @@ func NewHandler(keeper Keeper) sdk.Handler {
|
||||
```
|
||||
|
||||
See the [`Msg` services](../building-modules/msg-services.md) concept doc for a more detailed
|
||||
view on how to typically implement `Events` and use the `EventManager` in modules.
|
||||
view on how to typically implement Events and use the `EventManager` in modules.
|
||||
|
||||
## Subscribing to Events
|
||||
|
||||
It is possible to subscribe to `Events` via Tendermint's [Websocket](https://tendermint.com/docs/app-dev/subscribing-to-events-via-websocket.html#subscribing-to-events-via-websocket).
|
||||
This is done by calling the `subscribe` RPC method via Websocket:
|
||||
You can use Tendermint's [Websocket](https://docs.tendermint.com/master/tendermint-core/subscription.html#subscribing-to-events-via-websocket) to subscribe to Events by calling the `subscribe` RPC method:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "subscribe",
|
||||
"id": "0",
|
||||
"params": {
|
||||
"query": "tm.event='eventCategory' AND eventType.eventAttribute='attributeValue'"
|
||||
}
|
||||
"jsonrpc": "2.0",
|
||||
"method": "subscribe",
|
||||
"id": "0",
|
||||
"params": {
|
||||
"query": "tm.event='eventCategory' AND eventType.eventAttribute='attributeValue'"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The main `eventCategory` you can subscribe to are:
|
||||
|
||||
- `NewBlock`: Contains `events` triggered during `BeginBlock` and `EndBlock`.
|
||||
- `Tx`: Contains `events` triggered during `DeliverTx` (i.e. transaction processing).
|
||||
- `NewBlock`: Contains Events triggered during `BeginBlock` and `EndBlock`.
|
||||
- `Tx`: Contains Events triggered during `DeliverTx` (i.e. transaction processing).
|
||||
- `ValidatorSetUpdates`: Contains validator set updates for the block.
|
||||
|
||||
These events are triggered from the `state` package after a block is committed. You can get the
|
||||
full list of `event` categories [here](https://godoc.org/github.com/tendermint/tendermint/types#pkg-constants).
|
||||
These Events are triggered from the `state` package after a block is committed. You can get the
|
||||
full list of Event categories [on the Tendermint Godoc page](https://godoc.org/github.com/tendermint/tendermint/types#pkg-constants).
|
||||
|
||||
The `type` and `attribute` value of the `query` allow you to filter the specific `event` you are looking for. For example, a `transfer` transaction triggers an `event` of type `Transfer` and has `Recipient` and `Sender` as `attributes` (as defined in the [`events` file of the `bank` module](https://github.com/cosmos/cosmos-sdk/blob/master/x/bank/types/events.go)). Subscribing to this `event` would be done like so:
|
||||
The `type` and `attribute` value of the `query` allow you to filter the specific Event you are looking for. For example, a `transfer` transaction triggers an Event of type `Transfer` and has `Recipient` and `Sender` as `attributes` (as defined in the [`events.go` file of the `bank` module](https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/x/bank/types/events.go)). Subscribing to this Event would be done like so:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "subscribe",
|
||||
"id": "0",
|
||||
"params": {
|
||||
"query": "tm.event='Tx' AND transfer.sender='senderAddress'"
|
||||
}
|
||||
"jsonrpc": "2.0",
|
||||
"method": "subscribe",
|
||||
"id": "0",
|
||||
"params": {
|
||||
"query": "tm.event='Tx' AND transfer.sender='senderAddress'"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
where `senderAddress` is an address following the [`AccAddress`](../basics/accounts.md#addresses) format.
|
||||
|
||||
## Typed Events (coming soon)
|
||||
|
||||
As previously described, Events are defined on a per-module basis. It is the responsibility of the module developer to define Event types and Event attributes. Except in the `spec/XX_events.md` file, these Event types and attributes are unfortunately not easily discoverable, so the SDK proposes to use Protobuf-defined [Typed Events](../architecture/adr-032-typed-events.md) for emitting and querying Events.
|
||||
|
||||
The Typed Events proposal has not yet been fully implemented. Documentation is not yet available.
|
||||
|
||||
## Next {hide}
|
||||
|
||||
Learn about SDK [telemetry](./telemetry.md) {hide}
|
||||
|
||||
@ -56,11 +56,11 @@ The Cosmos SDK comes with a large set of stores to persist the state of applicat
|
||||
|
||||
### Store Interface
|
||||
|
||||
At its very core, a Cosmos SDK `store` is an object that holds a `CacheWrapper` and has a `GetStoreType()` method:
|
||||
At its very core, a Cosmos SDK `store` is an object that holds a `CacheWrapper` and has a `GetStoreType()` method:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/store/types/store.go#L15-L18
|
||||
|
||||
The `GetStoreType` is a simple method that returns the type of store, whereas a `CacheWrapper` is a simple interface that implements store read caching and write branching through `Write` method:
|
||||
The `GetStoreType` is a simple method that returns the type of store, whereas a `CacheWrapper` is a simple interface that implements store read caching and write branching through `Write` method:
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/store/types/store.go#L240-L264
|
||||
|
||||
@ -104,7 +104,7 @@ The `rootMulti.Store` is a base-layer multistore built around a `db` on top of w
|
||||
|
||||
### CacheMultiStore
|
||||
|
||||
Whenever the `rootMulti.Store` needs to be branched, a [`cachemulti.Store`](https://github.com/cosmos/cosmos-sdk/blob/master/store/cachemulti/store.go) is used.
|
||||
Whenever the `rootMulti.Store` needs to be branched, a [`cachemulti.Store`](https://github.com/cosmos/cosmos-sdk/blob/v0.42.1/store/cachemulti/store.go) is used.
|
||||
|
||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/store/cachemulti/store.go#L17-L28
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user