refactor: bring cometbft back to v0.38.x family (#25285)
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
* 10/14/2022:
|
||||
* Add `ListenCommit`, flatten the state writes in a block to a single batch.
|
||||
* Remove listeners from cache stores, should only listen to `rootmulti.Store`.
|
||||
* Remove `HaltAppOnDeliveryError()`, the errors are propagated by default, the implementations should return nil if they don't want to propagate errors.
|
||||
* Remove `HaltAppOnDeliveryError()`, the errors are propagated by default, the implementations should return nil if don't want to propogate errors.
|
||||
* 26/05/2023: Update with ABCI 2.0
|
||||
|
||||
## Status
|
||||
@@ -20,7 +20,7 @@ This ADR defines a set of changes to enable listening to state changes of indivi
|
||||
|
||||
## Context
|
||||
|
||||
Currently, KVStore data can be remotely accessed through [Queries](https://docs.cosmos.network/main/build/building-modules/messages-and-queries#queries)
|
||||
Currently, KVStore data can be remotely accessed through [Queries](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules/messages-and-queries.md#queries)
|
||||
which proceed either through Tendermint and the ABCI, or through the gRPC server.
|
||||
In addition to these request/response queries, it would be beneficial to have a means of listening to state changes as they occur in real time.
|
||||
|
||||
@@ -40,7 +40,7 @@ type MemoryListener struct {
|
||||
stateCache []StoreKVPair
|
||||
}
|
||||
|
||||
// NewMemoryListener creates a listener that accumulates the state writes in memory.
|
||||
// NewMemoryListener creates a listener that accumulate the state writes in memory.
|
||||
func NewMemoryListener() *MemoryListener {
|
||||
return &MemoryListener{}
|
||||
}
|
||||
@@ -114,7 +114,7 @@ func (s *Store) Delete(key []byte) {
|
||||
|
||||
### MultiStore interface updates
|
||||
|
||||
We will update the `CommitMultiStore` interface to allow us to wrap a `MemoryListener` to a specific `KVStore`.
|
||||
We will update the `CommitMultiStore` interface to allow us to wrap a `Memorylistener` to a specific `KVStore`.
|
||||
Note that the `MemoryListener` will be attached internally by the concrete `rootmulti` implementation.
|
||||
|
||||
```go
|
||||
@@ -224,9 +224,9 @@ so that the service can group the state changes with the ABCI requests.
|
||||
// ABCIListener is the interface that we're exposing as a streaming service.
|
||||
type ABCIListener interface {
|
||||
// ListenFinalizeBlock updates the streaming service with the latest FinalizeBlock messages
|
||||
ListenFinalizeBlock(ctx context.Context, req abci.FinalizeBlockRequest, res abci.FinalizeBlockResponse) error
|
||||
// ListenCommit updates the streaming service with the latest Commit messages and state changes
|
||||
ListenCommit(ctx context.Context, res abci.CommitResponse, changeSet []*StoreKVPair) error
|
||||
ListenFinalizeBlock(ctx context.Context, req abci.RequestFinalizeBlock, res abci.ResponseFinalizeBlock) error
|
||||
// ListenCommit updates the steaming service with the latest Commit messages and state changes
|
||||
ListenCommit(ctx context.Context, res abci.ResponseCommit, changeSet []*StoreKVPair) error
|
||||
}
|
||||
```
|
||||
|
||||
@@ -267,16 +267,16 @@ We will modify the `FinalizeBlock` and `Commit` methods to pass ABCI requests an
|
||||
to any streaming service hooks registered with the `BaseApp`.
|
||||
|
||||
```go
|
||||
func (app *BaseApp) FinalizeBlock(req abci.FinalizeBlockRequest) abci.FinalizeBlockResponse {
|
||||
func (app *BaseApp) FinalizeBlock(req abci.RequestFinalizeBlock) abci.ResponseFinalizeBlock {
|
||||
|
||||
var abciRes abci.FinalizeBlockResponse
|
||||
var abciRes abci.ResponseFinalizeBlock
|
||||
defer func() {
|
||||
// call the streaming service hook with the FinalizeBlock messages
|
||||
for _, abciListener := range app.abciListeners {
|
||||
ctx := app.finalizeState.ctx
|
||||
blockHeight := ctx.BlockHeight()
|
||||
if app.abciListenersAsync {
|
||||
go func(req abci.FinalizeBlockRequest, res abci.FinalizeBlockResponse) {
|
||||
go func(req abci.RequestFinalizeBlock, res abci.ResponseFinalizeBlock) {
|
||||
if err := app.abciListener.FinalizeBlock(blockHeight, req, res); err != nil {
|
||||
app.logger.Error("FinalizeBlock listening hook failed", "height", blockHeight, "err", err)
|
||||
}
|
||||
@@ -299,11 +299,11 @@ func (app *BaseApp) FinalizeBlock(req abci.FinalizeBlockRequest) abci.FinalizeBl
|
||||
```
|
||||
|
||||
```go
|
||||
func (app *BaseApp) Commit() abci.CommitResponse {
|
||||
func (app *BaseApp) Commit() abci.ResponseCommit {
|
||||
|
||||
...
|
||||
|
||||
res := abci.CommitResponse{
|
||||
res := abci.ResponseCommit{
|
||||
Data: commitID.Hash,
|
||||
RetainHeight: retainHeight,
|
||||
}
|
||||
@@ -314,7 +314,7 @@ func (app *BaseApp) Commit() abci.CommitResponse {
|
||||
blockHeight := ctx.BlockHeight()
|
||||
changeSet := app.cms.PopStateCache()
|
||||
if app.abciListenersAsync {
|
||||
go func(res abci.CommitResponse, changeSet []store.StoreKVPair) {
|
||||
go func(res abci.ResponseCommit, changeSet []store.StoreKVPair) {
|
||||
if err := app.abciListener.ListenCommit(ctx, res, changeSet); err != nil {
|
||||
app.logger.Error("ListenCommit listening hook failed", "height", blockHeight, "err", err)
|
||||
}
|
||||
@@ -354,7 +354,7 @@ var Handshake = plugin.HandshakeConfig{
|
||||
MagicCookieValue: "ef78114d-7bdf-411c-868f-347c99a78345",
|
||||
}
|
||||
|
||||
// ListenerPlugin is the base struct for all kinds of go-plugin implementations
|
||||
// ListenerPlugin is the base struc for all kinds of go-plugin implementations
|
||||
// It will be included in interfaces of different Plugins
|
||||
type ABCIListenerPlugin struct {
|
||||
// GRPCPlugin must still implement the Plugin interface
|
||||
@@ -433,13 +433,13 @@ type GRPCClient struct {
|
||||
client ABCIListenerServiceClient
|
||||
}
|
||||
|
||||
func (m *GRPCClient) ListenFinalizeBlock(goCtx context.Context, req abci.FinalizeBlockRequest, res abci.FinalizeBlockResponse) error {
|
||||
func (m *GRPCClient) ListenFinalizeBlock(goCtx context.Context, req abci.RequestFinalizeBlock, res abci.ResponseFinalizeBlock) error {
|
||||
ctx := sdk.UnwrapSDKContext(goCtx)
|
||||
_, err := m.client.ListenDeliverTx(ctx, &ListenDeliverTxRequest{BlockHeight: ctx.BlockHeight(), Req: req, Res: res})
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *GRPCClient) ListenCommit(goCtx context.Context, res abci.CommitResponse, changeSet []store.StoreKVPair) error {
|
||||
func (m *GRPCClient) ListenCommit(goCtx context.Context, res abci.ResponseCommit, changeSet []store.StoreKVPair) error {
|
||||
ctx := sdk.UnwrapSDKContext(goCtx)
|
||||
_, err := m.client.ListenCommit(ctx, &ListenCommitRequest{BlockHeight: ctx.BlockHeight(), Res: res, ChangeSet: changeSet})
|
||||
return err
|
||||
@@ -471,11 +471,11 @@ And the pre-compiled Go plugin `Impl`(*this is only used for plugins that are wr
|
||||
// ABCIListener is the implementation of the baseapp.ABCIListener interface
|
||||
type ABCIListener struct{}
|
||||
|
||||
func (m *ABCIListenerPlugin) ListenFinalizeBlock(ctx context.Context, req abci.FinalizeBlockRequest, res abci.FinalizeBlockResponse) error {
|
||||
func (m *ABCIListenerPlugin) ListenFinalizeBlock(ctx context.Context, req abci.RequestFinalizeBlock, res abci.ResponseFinalizeBlock) error {
|
||||
// send data to external system
|
||||
}
|
||||
|
||||
func (m *ABCIListenerPlugin) ListenCommit(ctx context.Context, res abci.CommitResponse, changeSet []store.StoreKVPair) error {
|
||||
func (m *ABCIListenerPlugin) ListenCommit(ctx context.Context, res abci.ResponseCommit, changeSet []store.StoreKVPair) error {
|
||||
// send data to external system
|
||||
}
|
||||
|
||||
@@ -529,7 +529,7 @@ func NewStreamingPlugin(name string, logLevel string) (interface{}, error) {
|
||||
|
||||
We propose a `RegisterStreamingPlugin` function for the App to register `NewStreamingPlugin`s with the App's BaseApp.
|
||||
Streaming plugins can be of `Any` type; therefore, the function takes in an interface vs a concrete type.
|
||||
For example, we could have plugins of `ABCIListener`, `WasmListener` or `IBCListener`. Note that `RegisterStreamingPlugin` function
|
||||
For example, we could have plugins of `ABCIListener`, `WasmListener` or `IBCListener`. Note that `RegisterStreamingPluing` function
|
||||
is helper function and not a requirement. Plugin registration can easily be moved from the App to the BaseApp directly.
|
||||
|
||||
```go
|
||||
@@ -720,5 +720,5 @@ These changes will provide a means of subscribing to KVStore state changes in re
|
||||
|
||||
### Neutral
|
||||
|
||||
* Introduces additional—but optional—complexity to configuring and running a cosmos application
|
||||
* Introduces additional- but optional- complexity to configuring and running a cosmos application
|
||||
* If an application developer opts to use these features to expose data, they need to be aware of the ramifications/risks of that data exposure as it pertains to the specifics of their application
|
||||
|
||||
@@ -92,7 +92,7 @@ A new database snapshot will be created in every `EndBlocker` and identified by
|
||||
NOTE: `Commit` must be called exactly once per block. Otherwise we risk going out of sync for the version number and block height.
|
||||
NOTE: For the Cosmos SDK storage, we may consider splitting that interface into `Committer` and `PruningCommitter` - only the multiroot should implement `PruningCommitter` (cache and prefix store don't need pruning).
|
||||
|
||||
Number of historical versions for `abci.QueryRequest` and state sync snapshots is part of a node configuration, not a chain configuration (configuration implied by the blockchain consensus). A configuration should allow to specify number of past blocks and number of past blocks modulo some number (eg: 100 past blocks and one snapshot every 100 blocks for past 2000 blocks). Archival nodes can keep all past versions.
|
||||
Number of historical versions for `abci.RequestQuery` and state sync snapshots is part of a node configuration, not a chain configuration (configuration implied by the blockchain consensus). A configuration should allow to specify number of past blocks and number of past blocks modulo some number (eg: 100 past blocks and one snapshot every 100 blocks for past 2000 blocks). Archival nodes can keep all past versions.
|
||||
|
||||
Pruning old snapshots is effectively done by a database. Whenever we update a record in `SC`, SMT won't update nodes - instead it creates new nodes on the update path, without removing the old one. Since we are snapshotting each block, we need to change that mechanism to immediately remove orphaned nodes from the database. This is a safe operation - snapshots will keep track of the records and make it available when accessing past versions.
|
||||
|
||||
@@ -100,8 +100,8 @@ To manage the active snapshots we will either use a DB _max number of snapshots_
|
||||
|
||||
#### Accessing old state versions
|
||||
|
||||
One of the functional requirements is to access old state. This is done through `abci.QueryRequest` structure. The version is specified by a block height (so we query for an object by a key `K` at block height `H`). The number of old versions supported for `abci.QueryRequest` is configurable. Accessing an old state is done by using available snapshots.
|
||||
`abci.QueryRequest` doesn't need old state of `SC` unless the `prove=true` parameter is set. The SMT merkle proof must be included in the `abci.QueryResponse` only if both `SC` and `SS` have a snapshot for requested version.
|
||||
One of the functional requirements is to access old state. This is done through `abci.RequestQuery` structure. The version is specified by a block height (so we query for an object by a key `K` at block height `H`). The number of old versions supported for `abci.RequestQuery` is configurable. Accessing an old state is done by using available snapshots.
|
||||
`abci.RequestQuery` doesn't need old state of `SC` unless the `prove=true` parameter is set. The SMT merkle proof must be included in the `abci.ResponseQuery` only if both `SC` and `SS` have a snapshot for requested version.
|
||||
|
||||
Moreover, Cosmos SDK could provide a way to directly access a historical state. However, a state machine shouldn't do that - since the number of snapshots is configurable, it would lead to nondeterministic execution.
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ Instead, we will define an additional ABCI interface method on the existing
|
||||
or `EndBlock`. This new interface method will be defined as follows:
|
||||
|
||||
```go
|
||||
ProcessProposal(sdk.Context, abci.ProcessProposalRequest) error {}
|
||||
ProcessProposal(sdk.Context, abci.RequestProcessProposal) error {}
|
||||
```
|
||||
|
||||
Note, we must call `ProcessProposal` with a new internal branched state on the
|
||||
|
||||
@@ -103,8 +103,8 @@ vote extensions.
|
||||
We propose the following new handlers for applications to implement:
|
||||
|
||||
```go
|
||||
type ExtendVoteHandler func(sdk.Context, abci.ExtendVoteRequest) abci.ExtendVoteResponse
|
||||
type VerifyVoteExtensionHandler func(sdk.Context, abci.VerifyVoteExtensionRequest) abci.VerifyVoteExtensionResponse
|
||||
type ExtendVoteHandler func(sdk.Context, abci.RequestExtendVote) abci.ResponseExtendVote
|
||||
type VerifyVoteExtensionHandler func(sdk.Context, abci.RequestVerifyVoteExtension) abci.ResponseVerifyVoteExtension
|
||||
```
|
||||
|
||||
An ephemeral context and state will be supplied to both handlers. The
|
||||
@@ -144,7 +144,7 @@ type VoteExtensionHandler struct {
|
||||
|
||||
// ExtendVoteHandler can do something with h.mk and possibly h.state to create
|
||||
// a vote extension, such as fetching a series of prices for supported assets.
|
||||
func (h VoteExtensionHandler) ExtendVoteHandler(ctx sdk.Context, req abci.ExtendVoteRequest) abci.ExtendVoteResponse {
|
||||
func (h VoteExtensionHandler) ExtendVoteHandler(ctx sdk.Context, req abci.RequestExtendVote) abci.ResponseExtendVote {
|
||||
prices := GetPrices(ctx, h.mk.Assets())
|
||||
bz, err := EncodePrices(h.cdc, prices)
|
||||
if err != nil {
|
||||
@@ -156,22 +156,22 @@ func (h VoteExtensionHandler) ExtendVoteHandler(ctx sdk.Context, req abci.Extend
|
||||
// NOTE: Vote extensions can be overridden since we can timeout in a round.
|
||||
SetPrices(h.state, req, bz)
|
||||
|
||||
return abci.ExtendVoteResponse{VoteExtension: bz}
|
||||
return abci.ResponseExtendVote{VoteExtension: bz}
|
||||
}
|
||||
|
||||
// VerifyVoteExtensionHandler can do something with h.state and req to verify
|
||||
// the req.VoteExtension field, such as ensuring the provided oracle prices are
|
||||
// within some valid range of our prices.
|
||||
func (h VoteExtensionHandler) VerifyVoteExtensionHandler(ctx sdk.Context, req abci.VerifyVoteExtensionRequest) abci.VerifyVoteExtensionResponse {
|
||||
func (h VoteExtensionHandler) VerifyVoteExtensionHandler(ctx sdk.Context, req abci.RequestVerifyVoteExtension) abci.ResponseVerifyVoteExtension {
|
||||
prices, err := DecodePrices(h.cdc, req.VoteExtension)
|
||||
if err != nil {
|
||||
log("failed to decode vote extension", "err", err)
|
||||
return abci.VerifyVoteExtensionResponse{Status: REJECT}
|
||||
return abci.ResponseVerifyVoteExtension{Status: REJECT}
|
||||
}
|
||||
|
||||
if err := ValidatePrices(h.state, req, prices); err != nil {
|
||||
log("failed to validate vote extension", "prices", prices, "err", err)
|
||||
return abci.VerifyVoteExtensionResponse{Status: REJECT}
|
||||
return abci.ResponseVerifyVoteExtension{Status: REJECT}
|
||||
}
|
||||
|
||||
// store updated vote extensions at the given height
|
||||
@@ -179,7 +179,7 @@ func (h VoteExtensionHandler) VerifyVoteExtensionHandler(ctx sdk.Context, req ab
|
||||
// NOTE: Vote extensions can be overridden since we can timeout in a round.
|
||||
SetPrices(h.state, req, req.VoteExtension)
|
||||
|
||||
return abci.VerifyVoteExtensionResponse{Status: ACCEPT}
|
||||
return abci.ResponseVerifyVoteExtension{Status: ACCEPT}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -301,7 +301,7 @@ during `ProcessProposal` because during replay, CometBFT will NOT call `ProcessP
|
||||
which would result in an incomplete state view.
|
||||
|
||||
```go
|
||||
func (a MyApp) PreBlocker(ctx sdk.Context, req *abci.FinalizeBlockRequest) error {
|
||||
func (a MyApp) PreBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlock) error {
|
||||
voteExts := GetVoteExtensions(ctx, req.Txs)
|
||||
|
||||
// Process and perform some compute on vote extensions, storing any resulting
|
||||
@@ -350,7 +350,7 @@ legacy ABCI types, e.g. `LegacyBeginBlockRequest` and `LegacyEndBlockRequest`. O
|
||||
we can come up with new types and names altogether.
|
||||
|
||||
```go
|
||||
func (app *BaseApp) FinalizeBlock(req abci.FinalizeBlockRequest) (*abci.FinalizeBlockResponse, error) {
|
||||
func (app *BaseApp) FinalizeBlock(req abci.RequestFinalizeBlock) (*abci.ResponseFinalizeBlock, error) {
|
||||
ctx := ...
|
||||
|
||||
if app.preBlocker != nil {
|
||||
@@ -375,7 +375,7 @@ func (app *BaseApp) FinalizeBlock(req abci.FinalizeBlockRequest) (*abci.Finalize
|
||||
endBlockResp, err := app.endBlock(app.finalizeBlockState.ctx)
|
||||
appendBlockEventAttr(beginBlockResp.Events, "end_block")
|
||||
|
||||
return abci.FinalizeBlockResponse{
|
||||
return abci.ResponseFinalizeBlock{
|
||||
TxResults: txExecResults,
|
||||
Events: joinEvents(beginBlockResp.Events, endBlockResp.Events),
|
||||
ValidatorUpdates: endBlockResp.ValidatorUpdates,
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ ABCI 2.0 (colloquially called ABCI++) allows an application to extend a pre-comm
|
||||
validator process. The Cosmos SDK defines [`baseapp.ExtendVoteHandler`](https://github.com/cosmos/cosmos-sdk/blob/v0.53.0/types/abci.go#L32):
|
||||
|
||||
```go
|
||||
type ExtendVoteHandler func(Context, *abci.ExtendVoteRequest) (*abci.ExtendVoteResponse, error)
|
||||
type ExtendVoteHandler func(Context, *abci.RequestExtendVote) (*abci.ResponseExtendVote, error)
|
||||
```
|
||||
|
||||
An application can set this handler in `app.go` via the `baseapp.SetExtendVoteHandler`
|
||||
@@ -38,7 +38,7 @@ other validators when validating their pre-commits. For a given vote extension,
|
||||
this process MUST be deterministic. The Cosmos SDK defines [`sdk.VerifyVoteExtensionHandler`](https://github.com/cosmos/cosmos-sdk/blob/v0.50.1/types/abci.go#L29-L31):
|
||||
|
||||
```go
|
||||
type VerifyVoteExtensionHandler func(Context, *abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error)
|
||||
type VerifyVoteExtensionHandler func(Context, *abci.RequestVerifyVoteExtension) (*abci.ResponseVerifyVoteExtension, error)
|
||||
```
|
||||
|
||||
An application can set this handler in `app.go` via the `baseapp.SetVerifyVoteExtensionHandler`
|
||||
@@ -78,7 +78,7 @@ will be available to the application during the subsequent `FinalizeBlock` call.
|
||||
An example of how a pre-FinalizeBlock hook could look like is shown below:
|
||||
|
||||
```go
|
||||
app.SetPreBlocker(func(ctx sdk.Context, req *abci.FinalizeBlockRequest) error {
|
||||
app.SetPreBlocker(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) error {
|
||||
allVEs := []VE{} // store all parsed vote extensions here
|
||||
for _, tx := range req.Txs {
|
||||
// define a custom function that tries to parse the tx as a vote extension
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ process does NOT have to be deterministic, and the data returned can be unique t
|
||||
validator process. The Cosmos SDK defines `baseapp.ExtendVoteHandler`:
|
||||
|
||||
```go
|
||||
type ExtendVoteHandler func(Context, *abci.ExtendVoteRequest) (*abci.ExtendVoteResponse, error)
|
||||
type ExtendVoteHandler func(Context, *abci.RequestExtendVote) (*abci.ResponseExtendVote, error)
|
||||
```
|
||||
|
||||
An application can set this handler in `app.go` via the `baseapp.SetExtendVoteHandler`
|
||||
@@ -77,7 +77,7 @@ will be available to the application during the subsequent `FinalizeBlock` call.
|
||||
An example of how a pre-FinalizeBlock hook could look is shown below:
|
||||
|
||||
```go
|
||||
app.SetPreBlocker(func(ctx sdk.Context, req *abci.FinalizeBlockRequest) error {
|
||||
app.SetPreBlocker(func(ctx sdk.Context, req *abci.RequestFinalizeBlock) error {
|
||||
allVEs := []VE{} // store all parsed vote extensions here
|
||||
for _, tx := range req.Txs {
|
||||
// define a custom function that tries to parse the tx as a vote extension
|
||||
|
||||
+1
-1
@@ -302,7 +302,7 @@ The module manager is used throughout the application whenever an action on a co
|
||||
* `SetOrderMigrations(moduleNames ...string)`: Sets the order of migrations to be run. If not set then migrations will be run with an order defined in `DefaultMigrationsOrder`.
|
||||
* `RegisterInvariants(ir sdk.InvariantRegistry)`: Registers the [invariants](./07-invariants.md) of module implementing the `HasInvariants` interface.
|
||||
* `RegisterServices(cfg Configurator)`: Registers the services of modules implementing the `HasServices` interface.
|
||||
* `InitGenesis(ctx context.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage)`: Calls the [`InitGenesis`](./08-genesis.md#initgenesis) function of each module when the application is first started, in the order defined in `OrderInitGenesis`. Returns an `abci.InitChainResponse` to the underlying consensus engine, which can contain validator updates.
|
||||
* `InitGenesis(ctx context.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage)`: Calls the [`InitGenesis`](./08-genesis.md#initgenesis) function of each module when the application is first started, in the order defined in `OrderInitGenesis`. Returns an `abci.ResponseInitChain` to the underlying consensus engine, which can contain validator updates.
|
||||
* `ExportGenesis(ctx context.Context, cdc codec.JSONCodec)`: Calls the [`ExportGenesis`](./08-genesis.md#exportgenesis) function of each module, in the order defined in `OrderExportGenesis`. The export constructs a genesis file from a previously existing state, and is mainly used when a hard-fork upgrade of the chain is required.
|
||||
* `ExportGenesisForModules(ctx context.Context, cdc codec.JSONCodec, modulesToExport []string)`: Behaves the same as `ExportGenesis`, except takes a list of modules to export.
|
||||
* `BeginBlock(ctx context.Context) error`: At the beginning of each block, this function is called from [`BaseApp`](../../learn/advanced/00-baseapp.md#beginblock) and, in turn, calls the [`BeginBlock`](./06-beginblock-endblock.md) function of each modules implementing the `appmodule.HasBeginBlocker` interface, in the order defined in `OrderBeginBlockers`. It creates a child [context](../../learn/advanced/02-context.md) with an event manager to aggregate [events](../../learn/advanced/08-events.md) emitted from each modules.
|
||||
|
||||
@@ -39,15 +39,15 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/proto/cosmos/bank/v1be
|
||||
|
||||
### `sdk.Msg` Interface
|
||||
|
||||
`sdk.Msg` is an alias of `proto.Message`.
|
||||
`sdk.Msg` is a alias of `proto.Message`.
|
||||
|
||||
To attach a `ValidateBasic()` method to a message then you must add methods to the type adhering to the `HasValidateBasic`.
|
||||
To attach a `ValidateBasic()` method to a message then you must add methods to the type adhereing to the `HasValidateBasic`.
|
||||
|
||||
```go reference
|
||||
https://github.com/cosmos/cosmos-sdk/blob/9c1e8b247cd47b5d3decda6e86fbc3bc996ee5d7/types/tx_msg.go#L84-L88
|
||||
```
|
||||
|
||||
In 0.50+ signers from the `GetSigners()` call are automated via a protobuf annotation.
|
||||
In 0.50+ signers from the `GetSigners()` call is automated via a protobuf annotation.
|
||||
|
||||
Read more about the signer field [here](./05-protobuf-annotations.md).
|
||||
|
||||
@@ -120,7 +120,7 @@ where:
|
||||
* `queryType` is used by the module's [`querier`](./04-query-services.md#legacy-queriers) to map the `query` to the appropriate `querier function` within the module.
|
||||
* `args` are the actual arguments needed to process the `query`. They are filled out by the end-user. Note that for bigger queries, you might prefer passing arguments in the `Data` field of the request `req` instead of the `path`.
|
||||
|
||||
The `path` for each `query` must be defined by the module developer in the module's [command-line interface file](./09-module-interfaces.md#query-commands). Overall, there are 3 mains components module developers need to implement in order to make the subset of the state defined by their module queryable:
|
||||
The `path` for each `query` must be defined by the module developer in the module's [command-line interface file](./09-module-interfaces.md#query-commands).Overall, there are 3 mains components module developers need to implement in order to make the subset of the state defined by their module queryable:
|
||||
|
||||
* A [`querier`](./04-query-services.md#legacy-queriers), to process the `query` once it has been [routed to the module](../../learn/advanced/00-baseapp.md#query-routing).
|
||||
* [Query commands](./09-module-interfaces.md#query-commands) in the module's CLI file, where the `path` for each `query` is specified.
|
||||
@@ -128,7 +128,7 @@ The `path` for each `query` must be defined by the module developer in the modul
|
||||
|
||||
### Store Queries
|
||||
|
||||
Store queries access store keys directly. They use `clientCtx.QueryABCI(req abci.QueryRequest)` to return the full `abci.QueryResponse` with inclusion Merkle proofs.
|
||||
Store queries query directly for store keys. They use `clientCtx.QueryABCI(req abci.RequestQuery)` to return the full `abci.ResponseQuery` with inclusion Merkle proofs.
|
||||
|
||||
See following examples:
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ Note that, unlike `CheckTx()`, `PrepareProposal` process `sdk.Msg`s, so it can d
|
||||
|
||||
It's important to note that `PrepareProposal` complements the `ProcessProposal` method which is executed after this method. The combination of these two methods means that it is possible to guarantee that no invalid transactions are ever committed. Furthermore, such a setup can give rise to other interesting use cases such as Oracles, threshold decryption and more.
|
||||
|
||||
`PrepareProposal` returns a response to the underlying consensus engine of type [`abci.CheckTxResponse`](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_methods.md#processproposal). The response contains:
|
||||
`PrepareProposal` returns a response to the underlying consensus engine of type [`abci.ResponseCheckTx`](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_methods.md#processproposal). The response contains:
|
||||
|
||||
* `Code (uint32)`: Response Code. `0` if successful.
|
||||
* `Data ([]byte)`: Result bytes, if any.
|
||||
@@ -291,7 +291,7 @@ CometBFT calls it when it receives a proposal and the CometBFT algorithm has not
|
||||
|
||||
However, developers must exercise greater caution when using these methods. Incorrectly coding these methods could affect liveness as CometBFT is unable to receive 2/3 valid precommits to finalize a block.
|
||||
|
||||
`ProcessProposal` returns a response to the underlying consensus engine of type [`abci.CheckTxResponse`](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_methods.md#processproposal). The response contains:
|
||||
`ProcessProposal` returns a response to the underlying consensus engine of type [`abci.ResponseCheckTx`](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_methods.md#processproposal). The response contains:
|
||||
|
||||
* `Code (uint32)`: Response Code. `0` if successful.
|
||||
* `Data ([]byte)`: Result bytes, if any.
|
||||
@@ -338,7 +338,7 @@ be rejected. In any case, the sender's account will not actually pay the fees un
|
||||
is actually included in a block, because `checkState` never gets committed to the main state. The
|
||||
`checkState` is reset to the latest state of the main state each time a blocks gets [committed](#commit).
|
||||
|
||||
`CheckTx` returns a response to the underlying consensus engine of type [`abci.CheckTxResponse`](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_methods.md#checktx).
|
||||
`CheckTx` returns a response to the underlying consensus engine of type [`abci.ResponseCheckTx`](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_methods.md#checktx).
|
||||
The response contains:
|
||||
|
||||
* `Code (uint32)`: Response Code. `0` if successful.
|
||||
@@ -432,7 +432,7 @@ The [`InitChain` ABCI message](https://github.com/cometbft/cometbft/blob/v0.37.x
|
||||
* [`checkState` and `finalizeBlockState`](#state-updates) via `setState`.
|
||||
* The [block gas meter](../beginner/04-gas-fees.md#block-gas-meter), with infinite gas to process genesis transactions.
|
||||
|
||||
Finally, the `InitChain(req abci.InitChainRequest)` method of `BaseApp` calls the [`initChainer()`](../beginner/00-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`](../../build/building-modules/08-genesis.md#initgenesis) function of each of the application's modules.
|
||||
Finally, the `InitChain(req abci.RequestInitChain)` method of `BaseApp` calls the [`initChainer()`](../beginner/00-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`](../../build/building-modules/08-genesis.md#initgenesis) function of each of the application's modules.
|
||||
|
||||
|
||||
### FinalizeBlock
|
||||
@@ -450,7 +450,7 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.53.0/baseapp/abci.go#L869
|
||||
|
||||
#### BeginBlock
|
||||
|
||||
* Initialize [`finalizeBlockState`](#state-updates) with the latest header using the `req abci.FinalizeBlockRequest` passed as parameter via the `setState` function.
|
||||
* Initialize [`finalizeBlockState`](#state-updates) with the latest header using the `req abci.RequestFinalizeBlock` passed as parameter via the `setState` function.
|
||||
|
||||
```go reference
|
||||
https://github.com/cosmos/cosmos-sdk/blob/v0.53.0/baseapp/baseapp.go#L746-L770
|
||||
@@ -508,7 +508,7 @@ At the end of `FinalizeBlock`, the application returns a `ResponseFinalizeBlock`
|
||||
|
||||
### Commit
|
||||
|
||||
The [`Commit` ABCI message](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_basic_concepts.md#method-overview) is sent from the underlying CometBFT engine after the full-node has received _precommits_ from 2/3+ of validators (weighted by voting power). On the `BaseApp` end, the `Commit(res abci.CommitResponse)` function is implemented to commit all the valid state transitions that occurred during `FinalizeBlock` and to reset state for the next block.
|
||||
The [`Commit` ABCI message](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_basic_concepts.md#method-overview) is sent from the underlying CometBFT engine after the full-node has received _precommits_ from 2/3+ of validators (weighted by voting power). On the `BaseApp` end, the `Commit(res abci.ResponseCommit)` function is implemented to commit all the valid state transitions that occurred during `FinalizeBlock` and to reset state for the next block.
|
||||
|
||||
To commit state-transitions, the `Commit` function calls the `Write()` function on `finalizeBlockState.ms`, where `finalizeBlockState.ms` is a branched multistore of the main store `app.cms`. Then, the `Commit` function sets `checkState` to the latest header (obtained from `finalizeBlockState.ctx.BlockHeader`) and `finalizeBlockState` to `nil`.
|
||||
|
||||
@@ -516,13 +516,13 @@ Finally, the `app_hash` that was returned in `ResponseFinalizeBlock` is now used
|
||||
|
||||
### Info
|
||||
|
||||
The [`Info` ABCI message](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_basic_concepts.md#info-methods) is a simple query from the underlying consensus engine, notably used to sync the latter with the application during a handshake that happens on startup. When called, the `Info(res abci.InfoResponse)` function from `BaseApp` will return the application's name, version and the hash of the last commit of `app.cms`.
|
||||
The [`Info` ABCI message](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_basic_concepts.md#info-methods) is a simple query from the underlying consensus engine, notably used to sync the latter with the application during a handshake that happens on startup. When called, the `Info(res abci.ResponseInfo)` function from `BaseApp` will return the application's name, version and the hash of the last commit of `app.cms`.
|
||||
|
||||
### Query
|
||||
|
||||
The [`Query` ABCI message](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_basic_concepts.md#info-methods) is used to serve queries received from the underlying consensus engine, including queries received via RPC like CometBFT RPC. It used to be the main entrypoint to build interfaces with the application, but with the introduction of [gRPC queries](../../build/building-modules/04-query-services.md) in Cosmos SDK v0.40, its usage is more limited. The application must respect a few rules when implementing the `Query` method, which are outlined [here](https://github.com/cometbft/cometbft/blob/v0.37.x/spec/abci/abci++_app_requirements.md#query).
|
||||
|
||||
Each CometBFT `query` comes with a `path`, which is a `string` which denotes what to query. If the `path` matches a gRPC fully-qualified service method, then `BaseApp` will defer the query to the `grpcQueryRouter` and let it handle it like explained [above](#grpc-query-router). Otherwise, the `path` represents a query that is not (yet) handled by the gRPC router. `BaseApp` splits the `path` string with the `/` delimiter. By convention, the first element of the split string (`split[0]`) contains the category of `query` (`app`, `p2p`, `store` or `custom` ). The `BaseApp` implementation of the `Query(req abci.QueryRequest)` method is a simple dispatcher serving these 4 main categories of queries:
|
||||
Each CometBFT `query` comes with a `path`, which is a `string` which denotes what to query. If the `path` matches a gRPC fully-qualified service method, then `BaseApp` will defer the query to the `grpcQueryRouter` and let it handle it like explained [above](#grpc-query-router). Otherwise, the `path` represents a query that is not (yet) handled by the gRPC router. `BaseApp` splits the `path` string with the `/` delimiter. By convention, the first element of the split string (`split[0]`) contains the category of `query` (`app`, `p2p`, `store` or `custom` ). The `BaseApp` implementation of the `Query(req abci.RequestQuery)` method is a simple dispatcher serving these 4 main categories of queries:
|
||||
|
||||
* Application-related queries like querying the application's version, which are served via the `handleQueryApp` method.
|
||||
* Direct queries to the multistore, which are served by the `handlerQueryStore` method. These direct queries are different from custom queries which go through `app.queryRouter`, and are mainly used by third-party service provider like block explorers.
|
||||
|
||||
@@ -103,7 +103,7 @@ if upgradeInfo.Name == "my-plan" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.
|
||||
When starting a new chain, the consensus version of each module MUST be saved to state during the application's genesis. To save the consensus version, add the following line to the `InitChainer` method in `app.go`:
|
||||
|
||||
```diff
|
||||
func (app *MyApp) InitChainer(ctx sdk.Context, req abci.InitChainRequest) abci.InitChainResponse {
|
||||
func (app *MyApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
...
|
||||
+ app.UpgradeKeeper.SetModuleVersionMap(ctx, app.mm.GetVersionMap())
|
||||
...
|
||||
|
||||
@@ -71,9 +71,9 @@ The command-line is an easy way to interact with an application, but `Tx` can al
|
||||
|
||||
## Addition to Mempool
|
||||
|
||||
Each full-node (running CometBFT) that receives a `Tx` sends an [ABCI message](https://docs.cometbft.com/v0.37/spec/p2p/legacy-docs/messages/),
|
||||
`CheckTx`, to the application layer to check for validity, and receives an `abci.CheckTxResponse`. If the `Tx` passes the checks, it is held in the node's
|
||||
[**Mempool**](https://docs.cometbft.com/v0.37/spec/p2p/legacy-docs/messages/mempool), an in-memory pool of transactions unique to each node, pending inclusion in a block - honest nodes discard a `Tx` if it is found to be invalid. Prior to consensus, nodes continuously check incoming transactions and gossip them to their peers.
|
||||
Each full-node (running CometBFT) that receives a `Tx` sends an [ABCI message](https://docs.cometbft.com/v0.37/spec/p2p/messages/),
|
||||
`CheckTx`, to the application layer to check for validity, and receives an `abci.ResponseCheckTx`. If the `Tx` passes the checks, it is held in the node's
|
||||
[**Mempool**](https://docs.cometbft.com/v0.37/spec/p2p/messages/mempool/), an in-memory pool of transactions unique to each node, pending inclusion in a block - honest nodes discard a `Tx` if it is found to be invalid. Prior to consensus, nodes continuously check incoming transactions and gossip them to their peers.
|
||||
|
||||
### Types of Checks
|
||||
|
||||
@@ -98,7 +98,7 @@ through several steps, beginning with decoding `Tx`.
|
||||
|
||||
### Decoding
|
||||
|
||||
When `Tx` is received by the application from the underlying consensus engine (e.g. CometBFT), it is still in its [encoded](../advanced/05-encoding.md) `[]byte` form and needs to be unmarshaled in order to be processed. Then, the [`runTx`](../advanced/00-baseapp.md#runtx-antehandler-runmsgs-posthandler) function is called to run in `runTxModeCheck` mode, meaning the function runs all checks but exits before executing messages and writing state changes.
|
||||
When `Tx` is received by the application from the underlying consensus engine (e.g. CometBFT ), it is still in its [encoded](../advanced/05-encoding.md) `[]byte` form and needs to be unmarshaled in order to be processed. Then, the [`runTx`](../advanced/00-baseapp.md#runtx-antehandler-runmsgs-posthandler) function is called to run in `runTxModeCheck` mode, meaning the function runs all checks but exits before executing messages and writing state changes.
|
||||
|
||||
### ValidateBasic (deprecated)
|
||||
|
||||
@@ -113,7 +113,7 @@ Read [RFC 001](https://docs.cosmos.network/main/rfc/rfc-001-tx-validation) for m
|
||||
:::
|
||||
|
||||
:::note
|
||||
`BaseApp` still calls `ValidateBasic` on messages that implement that method for backwards compatibility.
|
||||
`BaseApp` still calls `ValidateBasic` on messages that implements that method for backwards compatibility.
|
||||
:::
|
||||
|
||||
#### Guideline
|
||||
@@ -126,10 +126,10 @@ Read [RFC 001](https://docs.cosmos.network/main/rfc/rfc-001-tx-validation) for m
|
||||
|
||||
A copy of the cached context is provided to the `AnteHandler`, which performs limited checks specified for the transaction type. Using a copy allows the `AnteHandler` to do stateful checks for `Tx` without modifying the last committed state, and revert back to the original if the execution fails.
|
||||
|
||||
For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/blob/main/x/auth/README.md) module `AnteHandler` checks and increments sequence numbers, checks signatures and account numbers, and deducts fees from the first signer of the transaction - all state changes are made using the `checkState`.
|
||||
For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/main/x/auth/spec) module `AnteHandler` checks and increments sequence numbers, checks signatures and account numbers, and deducts fees from the first signer of the transaction - all state changes are made using the `checkState`.
|
||||
|
||||
:::warning
|
||||
Ante handlers only run on a transaction. If a transaction embeds multiple messages (like some x/authz, x/gov transactions for instance), the ante handlers only have awareness of the outer message. Inner messages are mostly directly routed to the [message router](https://docs.cosmos.network/main/learn/advanced/baseapp#msg-service-router) and will skip the chain of ante handlers. Keep that in mind when designing your own ante handler.
|
||||
Ante handlers only run on a transaction. If a transaction embed multiple messages (like some x/authz, x/gov transactions for instance), the ante handlers only have awareness of the outer message. Inner messages are mostly directly routed to the [message router](https://docs.cosmos.network/main/learn/advanced/baseapp#msg-service-router) and will skip the chain of ante handlers. Keep that in mind when designing your own ante handler.
|
||||
:::
|
||||
|
||||
### Gas
|
||||
@@ -230,7 +230,7 @@ to during consensus. Under the hood, transaction execution is almost identical t
|
||||
Instead of using their `checkState`, full-nodes use `finalizeblock`:
|
||||
|
||||
* **Decoding:** Since `FinalizeBlock` is an ABCI call, `Tx` is received in the encoded `[]byte` form.
|
||||
Nodes first unmarshal the transaction, using the [`TxConfig`](./00-app-anatomy.md#register-codec) defined in the app, then call `runTx` in `execModeFinalize`, which is very similar to `CheckTx` but also executes and writes state changes.
|
||||
Nodes first unmarshal the transaction, using the [`TxConfig`](./app-anatomy#register-codec) defined in the app, then call `runTx` in `execModeFinalize`, which is very similar to `CheckTx` but also executes and writes state changes.
|
||||
|
||||
* **Checks and `AnteHandler`:** Full-nodes call `validateBasicMsgs` and `AnteHandler` again. This second check
|
||||
happens because they may not have seen the same transactions during the addition to Mempool stage
|
||||
|
||||
@@ -17,7 +17,7 @@ This document describes the lifecycle of a query in a Cosmos SDK application, fr
|
||||
|
||||
A [**query**](../../build/building-modules/02-messages-and-queries.md#queries) is a request for information made by end-users of applications through an interface and processed by a full-node. Users can query information about the network, the application itself, and application state directly from the application's stores or modules. Note that queries are different from [transactions](../advanced/01-transactions.md) (view the lifecycle [here](./01-tx-lifecycle.md)), particularly in that they do not require consensus to be processed (as they do not trigger state-transitions); they can be fully handled by one full-node.
|
||||
|
||||
For the purpose of explaining the query lifecycle, let's say the query, `MyQuery`, is requesting a list of delegations made by a certain delegator address in the application called `simapp`. As is to be expected, the [`staking`](../../../../x/staking/README.md) module handles this query. But first, there are a few ways `MyQuery` can be created by users.
|
||||
For the purpose of explaining the query lifecycle, let's say the query, `MyQuery`, is requesting a list of delegations made by a certain delegator address in the application called `simapp`. As is to be expected, the [`staking`](../../build/modules/staking/README.md) module handles this query. But first, there are a few ways `MyQuery` can be created by users.
|
||||
|
||||
### CLI
|
||||
|
||||
@@ -27,7 +27,7 @@ The main interface for an application is the command-line interface. Users conne
|
||||
simd query staking delegations <delegatorAddress>
|
||||
```
|
||||
|
||||
This query command was defined by the [`staking`](../../../../x/staking/README.md) module developer and added to the list of subcommands by the application developer when creating the CLI.
|
||||
This query command was defined by the [`staking`](../../build/modules/staking/README.md) module developer and added to the list of subcommands by the application developer when creating the CLI.
|
||||
|
||||
Note that the general format is as follows:
|
||||
|
||||
@@ -47,7 +47,7 @@ One such tool is [grpcurl](https://github.com/fullstorydev/grpcurl), and a gRPC
|
||||
|
||||
```bash
|
||||
grpcurl \
|
||||
-plaintext # We want results in plain text
|
||||
-plaintext # We want results in plain test
|
||||
-import-path ./proto \ # Import these .proto files
|
||||
-proto ./proto/cosmos/staking/v1beta1/query.proto \ # Look into this .proto file for the Query protobuf service
|
||||
-d '{"address":"$MY_DELEGATOR"}' \ # Query arguments
|
||||
@@ -74,9 +74,9 @@ The preceding examples show how an external user can interact with a node by que
|
||||
The first thing that is created in the execution of a CLI command is a `client.Context`. A `client.Context` is an object that stores all the data needed to process a request on the user side. In particular, a `client.Context` stores the following:
|
||||
|
||||
* **Codec**: The [encoder/decoder](../advanced/05-encoding.md) used by the application, used to marshal the parameters and query before making the CometBFT RPC request and unmarshal the returned response into a JSON object. The default codec used by the CLI is Protobuf.
|
||||
* **Account Decoder**: The account decoder from the [`auth`](../../../../x/auth/README.md) module, which translates `[]byte`s into accounts.
|
||||
* **Account Decoder**: The account decoder from the [`auth`](../../build/modules/auth/README.md) module, which translates `[]byte`s into accounts.
|
||||
* **RPC Client**: The CometBFT RPC Client, or node, to which requests are relayed.
|
||||
* **Keyring**: A [Key Manager](../beginner/03-accounts.md#keyring) used to sign transactions and handle other operations with keys.
|
||||
* **Keyring**: A [Key Manager]../beginner/03-accounts.md#keyring) used to sign transactions and handle other operations with keys.
|
||||
* **Output Writer**: A [Writer](https://pkg.go.dev/io/#Writer) used to output the response.
|
||||
* **Configurations**: The flags configured by the user for this command, including `--height`, specifying the height of the blockchain to query, and `--indent`, which indicates to add an indent to the JSON response.
|
||||
|
||||
@@ -134,7 +134,7 @@ Once a result is received from the querier, `baseapp` begins the process of retu
|
||||
|
||||
## Response
|
||||
|
||||
Since `Query()` is an ABCI function, `baseapp` returns the response as an [`abci.QueryResponse`](https://docs.cometbft.com/main/spec/abci/abci++_methods#query) type. The `client.Context` `Query()` routine receives the response and processes it.
|
||||
Since `Query()` is an ABCI function, `baseapp` returns the response as an [`abci.ResponseQuery`](https://docs.cometbft.com/master/spec/abci/abci.html#query-2) type. The `client.Context` `Query()` routine receives the response and.
|
||||
|
||||
### CLI Response
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ state from each `KVStore` to disk and returning an application state Merkle root
|
||||
Queries can be performed to return state data along with associated state
|
||||
commitment proofs for both previous heights/versions and the current state root.
|
||||
Queries are routed based on store name, i.e. a module, along with other parameters
|
||||
which are defined in `abci.QueryRequest`.
|
||||
which are defined in `abci.RequestQuery`.
|
||||
|
||||
The `rootmulti.Store` also provides primitives for pruning data at a given
|
||||
height/version from state storage. When a height is committed, the `rootmulti.Store`
|
||||
|
||||
Reference in New Issue
Block a user