From 9f3ad910e056d3def73fbbb32dde8df4c4b52c14 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Wed, 14 Oct 2020 14:38:14 +0200 Subject: [PATCH] Update Building Modules documentation (#7473) * Update module-manager.md * Update modules #messages doc * Fix typo * Update message implementation example link * Update messages-and-queries.md#queries doc * Update querier.md * Update handler.md * Update links in beginblock-endblock.md * Update keeper.md * Update invariants.md * Update genesis.md * Update module-interfaces.md#transaction-commands * Update module-interfaces.md#query-commands * Update module-interfaces.md#flags * Update module-interfaces.md#rest * Update structure.md * Update module-interfaces.md#grpc * Update errors.md * Update module-interfaces.md#grpc-gateway-rest * Add more info on swagger * Address comments * Fix go.sum * Fix app-anatomy.md * Update docs/building-modules/module-interfaces.md Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update docs/building-modules/querier.md Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update docs/building-modules/querier.md Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update docs/building-modules/module-interfaces.md Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Update docs/building-modules/module-interfaces.md Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> * Address part of review comments * Update old ref of RegisterQueryService * Add example code for Manager * Update queriers.md to query-services.md and refs * Add new query-services.md * Revert "Update old ref of RegisterQueryService" This reverts commit 1ea1ea8559604d5c0aa13951b3016967438da2a5. * Update keeper.md * Update handler.md * Update handler.md * Update messages-and-queries.md * Update docs/basics/app-anatomy.md Co-authored-by: Amaury Martiny * Update docs/building-modules/intro.md Co-authored-by: Amaury Martiny * Fix typo Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Amaury Martiny --- docs/basics/app-anatomy.md | 4 +- docs/building-modules/README.md | 2 +- docs/building-modules/beginblock-endblock.md | 4 +- docs/building-modules/errors.md | 2 +- docs/building-modules/genesis.md | 24 ++-- docs/building-modules/handler.md | 32 +++-- docs/building-modules/intro.md | 3 +- docs/building-modules/invariants.md | 4 +- docs/building-modules/keeper.md | 24 ++-- docs/building-modules/messages-and-queries.md | 56 +++++---- docs/building-modules/module-interfaces.md | 110 ++++++++++++------ docs/building-modules/module-manager.md | 48 +++++--- docs/building-modules/querier.md | 56 --------- docs/building-modules/query-services.md | 77 ++++++++++++ docs/building-modules/structure.md | 5 +- docs/core/baseapp.md | 2 +- docs/core/encoding.md | 2 +- docs/core/transactions.md | 2 +- docs/interfaces/query-lifecycle.md | 6 +- docs/interfaces/rest.md | 4 +- 20 files changed, 287 insertions(+), 180 deletions(-) delete mode 100644 docs/building-modules/querier.md create mode 100644 docs/building-modules/query-services.md diff --git a/docs/basics/app-anatomy.md b/docs/basics/app-anatomy.md index 5556b0c6a777..529ec9b27567 100644 --- a/docs/basics/app-anatomy.md +++ b/docs/basics/app-anatomy.md @@ -182,7 +182,7 @@ Finally, each module should also implement the `RegisterQueryService` method as Legacy queriers were queriers used before the introduction of Protobuf and gRPC in the SDK. They are present for existing modules, but will be deprecated in a future release of the SDK. If you are developing new modules, gRPC query services should be preferred, and you only need to implement the `LegacyQuerierHandler` interface if you wish to use legacy queriers. -[`Queriers`](../building-modules/querier.md) are very similar to `handlers`, except they serve user queries to the state as opposed to processing transactions. A [query](../building-modules/messages-and-queries.md#queries) is initiated from an [interface](#application-interface) by an end-user who provides a `queryRoute` and some `data`. The query is then routed to the correct application's `querier` by `baseapp`'s `handleQueryCustom` method using `queryRoute`: +[`Legacy queriers`](../building-modules/query-services.md#legacy-queriers) are very similar to `handlers`, except they serve user queries to the state as opposed to processing transactions. A [query](../building-modules/messages-and-queries.md#queries) is initiated from an [interface](#application-interface) by an end-user who provides a `queryRoute` and some `data`. The query is then routed to the correct application's `querier` by `baseapp`'s `handleQueryCustom` method using `queryRoute`: +++ https://github.com/cosmos/cosmos-sdk/blob/d9175200920e96bfa4182b5c8bc46d91b17a28a1/baseapp/abci.go#L388-L418 @@ -236,7 +236,7 @@ The SDK also provides a development endpoint to generate [Swagger](https://swagg #### Legacy API REST Endpoints -The [module's Legacy REST interface](../building-modules/module-interfaces.md#rest) lets users generate transactions and query the state through REST calls to the application's Legacy API Service. REST routes are defined in a file `client/rest/rest.go`, which is composed of: +The [module's Legacy REST interface](../building-modules/module-interfaces.md#legacy-rest) lets users generate transactions and query the state through REST calls to the application's Legacy API Service. REST routes are defined in a file `client/rest/rest.go`, which is composed of: - A `RegisterRoutes` function, which registers each route defined in the file. This function is called from the [main application's interface](#application-interfaces) for each module used within the application. The router used in the SDK is [Gorilla's mux](https://github.com/gorilla/mux). - Custom request type definitions for each query or transaction creation function that needs to be exposed. These custom request types build on the base `request` type of the Cosmos SDK: diff --git a/docs/building-modules/README.md b/docs/building-modules/README.md index 12dd140f89ad..43b8638ca96b 100644 --- a/docs/building-modules/README.md +++ b/docs/building-modules/README.md @@ -12,7 +12,7 @@ This repository contains documentation on concepts developers need to know in or 2. [`AppModule` Interface and Module Manager](./module-manager.md) 3. [Messages and Queries](./messages-and-queries.md) 4. [`Handler`s - Processing Messages](./handler.md) -5. [`Querier`s - Processing Queries](./querier.md) +5. [Query Services - Processing Queries](./query-services.md) 6. [BeginBlocker and EndBlocker](./beginblock-endblock.md) 7. [`Keeper`s](./keeper.md) 8. [Invariants](./invariants.md) diff --git a/docs/building-modules/beginblock-endblock.md b/docs/building-modules/beginblock-endblock.md index fc9c93302660..b4f3abaff971 100644 --- a/docs/building-modules/beginblock-endblock.md +++ b/docs/building-modules/beginblock-endblock.md @@ -28,11 +28,11 @@ It is possible for developers to defined the order of execution between the `Beg See an example implementation of `BeginBlocker` from the `distr` module: -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/distribution/abci.go#L10-L32 ++++ https://github.com/cosmos/cosmos-sdk/blob/f33749263f4ecc796115ad6e789cb0f7cddf9148/x/distribution/abci.go#L14-L38 and an example implementation of `EndBlocker` from the `staking` module: -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/staking/handler.go#L44-L96 ++++ https://github.com/cosmos/cosmos-sdk/blob/f33749263f4ecc796115ad6e789cb0f7cddf9148/x/staking/abci.go#L22-L27 ## Next {hide} diff --git a/docs/building-modules/errors.md b/docs/building-modules/errors.md index 5e3c31bca0d8..3b6d90535e45 100644 --- a/docs/building-modules/errors.md +++ b/docs/building-modules/errors.md @@ -38,7 +38,7 @@ execution. Example: -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.38.1/x/distribution/keeper/querier.go#L62-L80 ++++ https://github.com/cosmos/cosmos-sdk/blob/b2d48a9e815fe534a7faeec6ca2adb0874252b81/x/bank/keeper/keeper.go#L85-L122 Regardless if an error is wrapped or not, the SDK's `errors` package provides an API to determine if an error is of a particular kind via `Is`. diff --git a/docs/building-modules/genesis.md b/docs/building-modules/genesis.md index a95064dc0369..7314442969a2 100644 --- a/docs/building-modules/genesis.md +++ b/docs/building-modules/genesis.md @@ -13,25 +13,25 @@ Modules generally handle a subset of the state and, as such, they need to define ## Type Definition -The subset of the genesis state defined from a given module is generally defined in a `./internal/types/genesis.go` file, along with the `DefaultGenesis` and `ValidateGenesis` methods. The struct defining the module's subset of the genesis state is usually called `GenesisState` and contains all the module-related values that need to be initialized during the genesis process. +The subset of the genesis state defined from a given module is generally defined in a `genesis.proto` file ([more info](../core/encoding.md#gogoproto) on how to define protobuf messages). The struct defining the module's subset of the genesis state is usually called `GenesisState` and contains all the module-related values that need to be initialized during the genesis process. -See an example of `GenesisState` type definition from the nameservice tutorial +See an example of `GenesisState` protobuf message definition from the `auth` module: -+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/genesis.go#L10-L12 ++++ https://github.com/cosmos/cosmos-sdk/blob/a9547b54ffac9729fe1393651126ddfc0d236cff/proto/cosmos/auth/v1beta1/genesis.proto Next we present the main genesis-related methods that need to be implemented by module developers in order for their module to be used in Cosmos SDK applications. ### `DefaultGenesis` -The `DefaultGenesis()` method is a simple method that calls the constructor function for `GenesisState` with the default value for each parameter. See an example from the `nameservice` module: +The `DefaultGenesis()` method is a simple method that calls the constructor function for `GenesisState` with the default value for each parameter. See an example from the `auth` module: -+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/genesis.go#L33-L37 ++++ https://github.com/cosmos/cosmos-sdk/blob/64b6bb5270e1a3b688c2d98a8f481ae04bb713ca/x/auth/module.go#L48-L52 ### `ValidateGenesis` -The `ValidateGenesis(genesisState GenesisState)` method is called to verify that the provided `genesisState` is correct. It should perform validity checks on each of the parameter listed in `GenesisState`. See an example from the `nameservice` module: +The `ValidateGenesis(genesisState GenesisState)` method is called to verify that the provided `genesisState` is correct. It should perform validity checks on each of the parameter listed in `GenesisState`. See an example from the `auth` module: -+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/genesis.go#L18-L31 ++++ https://github.com/cosmos/cosmos-sdk/blob/64b6bb5270e1a3b688c2d98a8f481ae04bb713ca/x/auth/types/genesis.go#L57-L70 ## Other Genesis Methods @@ -43,18 +43,18 @@ The `InitGenesis` method is executed during [`InitChain`](../core/baseapp.md#ini The [module manager](./module-manager.md#manager) of the application is responsible for calling the `InitGenesis` method of each of the application's modules, in order. This order is set by the application developer via the manager's `SetOrderGenesisMethod`, which is called in the [application's constructor function](../basics/app-anatomy.md#constructor-function) -See an example of `InitGenesis` from the nameservice tutorial +See an example of `InitGenesis` from the `auth` module -+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/genesis.go#L39-L44 ++++ https://github.com/cosmos/cosmos-sdk/blob/64b6bb5270e1a3b688c2d98a8f481ae04bb713ca/x/auth/genesis.go#L13-L28 ### `ExportGenesis` The `ExportGenesis` method is executed whenever an export of the state is made. It takes the latest known version of the subset of the state managed by the module and creates a new `GenesisState` out of it. This is mainly used when the chain needs to be upgraded via a hard fork. -See an example of `ExportGenesis` from the nameservice tutorial. +See an example of `ExportGenesis` from the `auth` module. -+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/genesis.go#L46-L57 ++++ https://github.com/cosmos/cosmos-sdk/blob/64b6bb5270e1a3b688c2d98a8f481ae04bb713ca/x/auth/genesis.go#L31-L42 ## Next {hide} -Learn about [modules interfaces](#module-interfaces.md) {hide} \ No newline at end of file +Learn about [modules interfaces](module-interfaces.md) {hide} \ No newline at end of file diff --git a/docs/building-modules/handler.md b/docs/building-modules/handler.md index 88f114f390bd..45e9a4c11944 100644 --- a/docs/building-modules/handler.md +++ b/docs/building-modules/handler.md @@ -21,8 +21,8 @@ Let us break it down: - The [`Msg`](./messages-and-queries.md#messages) is the actual object being processed. - The [`Context`](../core/context.md) contains all the necessary information needed to process the `msg`, as well as a cache-wrapped copy of the latest state. If the `msg` is succesfully processed, the modified version of the temporary state contained in the `ctx` will be written to the main state. -- The [`Result`] returned to `baseapp`, which contains (among other things) information on the execution of the `handler`, [`gas`](../basics/gas-fees.md) consumption and [`events`](../core/events.md). - +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/result.go#L15-L40 +- The [`*Result`] returned to `baseapp`, which contains (among other things) information on the execution of the `handler` and [`events`](../core/events.md). + +++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/proto/cosmos/base/abci/v1beta1/abci.proto#L81-L95 ## Implementation of a module `handler`s @@ -37,10 +37,10 @@ func NewHandler(keeper Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { - case MsgType1: + case *MsgType1: return handleMsgType1(ctx, keeper, msg) - case MsgType2: + case *MsgType2: return handleMsgType2(ctx, keeper, msg) default: @@ -69,16 +69,28 @@ ctx.EventManager().EmitEvent( These `events` are relayed back to the underlying consensus engine and can be used by service providers to implement services around the application. Click [here](../core/events.md) to learn more about `events`. -Finally, the `handler` function returns a `sdk.Result` which contains the aforementioned `events` and an optional `Data` field. +Finally, the `handler` function returns a `*sdk.Result` which contains the aforementioned `events` and an optional `Data` field. -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/result.go#L15-L40 ++++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/proto/cosmos/base/abci/v1beta1/abci.proto#L81-L95 -Next is an example of how to return a `Result` from the `gov` module: +Next is an example of how to return a `*Result` from the `gov` module: -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/gov/handler.go#L59-L62 ++++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/x/gov/handler.go#L67-L70 -For a deeper look at `handler`s, see this [example implementation of a `handler` function](https://github.com/cosmos/sdk-application-tutorial/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/x/nameservice/handler.go) from the nameservice tutorial. +For a deeper look at `handler`s, see this [example implementation of a `handler` function](https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/x/gov/handler.go) from the `gov` module. + +The `handler` can then be registered from [`AppModule.Route()`](./module-manager.md#appmodule) as shown in the example below: + ++++ https://github.com/cosmos/cosmos-sdk/blob/228728cce2af8d494c8b4e996d011492139b04ab/x/gov/module.go#L143-L146 + +## Telemetry + +New [telemetry metrics](../core/telemetry.md) can be created from the `handler` when handling messages for instance. + +This is an example from the `auth` module: + ++++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/x/auth/vesting/handler.go#L68-L80 ## Next {hide} -Learn about [queriers](./querier.md) {hide} +Learn about [query services](./query-services.md) {hide} diff --git a/docs/building-modules/intro.md b/docs/building-modules/intro.md index 99a9a57caafd..7b3a4c3faa5e 100644 --- a/docs/building-modules/intro.md +++ b/docs/building-modules/intro.md @@ -81,7 +81,7 @@ Modules are by convention defined in the `.x/` subfolder (e.g. the `bank` module - Custom [`message` types](./messages-and-queries.md#messages) to trigger state-transitions. - A [`handler`](./handler.md) used to process messages when they are routed to the module by [`baseapp`](../core/baseapp.md#message-routing). - A [`keeper`](./keeper.md), used to access the module's store(s) and update the state. -- A [`querier`](./querier.md), used to process user queries when they are routed to the module by [`baseapp`](../core/baseapp.md#query-routing). +- A [query service](./query-services.md), used to process user queries when they are routed to the module by [`baseapp`](../core/baseapp.md#query-routing). - Interfaces, for end users to query the subset of the state defined by the module and create `message`s of the custom types defined in the module. In addition to these components, modules implement the `AppModule` interface in order to be managed by the [`module manager`](./module-manager.md). @@ -91,4 +91,3 @@ Please refer to the [structure document](./structure.md) to learn about the reco ## Next {hide} Read more on the [`AppModule` interface and the `module manager`](./module-manager.md) {hide} - diff --git a/docs/building-modules/invariants.md b/docs/building-modules/invariants.md index 576baa796b96..d21100cb24b5 100644 --- a/docs/building-modules/invariants.md +++ b/docs/building-modules/invariants.md @@ -18,7 +18,7 @@ An `Invariant` is a function that checks for a particular invariant within a mod where the `string` return value is the invariant message, which can be used when printing logs, and the `bool` return value is the actual result of the invariant check. -In practice, each module implements `Invariant`s in a `./internal/keeper/invariants.go` file within the module's folder. The standard is to implement one `Invariant` function per logical grouping of invariants with the following model: +In practice, each module implements `Invariant`s in a `./keeper/invariants.go` file within the module's folder. The standard is to implement one `Invariant` function per logical grouping of invariants with the following model: ```go // Example for an Invariant that checks balance-related invariants @@ -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/7d7821b9af132b0f6131640195326aa02b6751db/x/crisis/internal/keeper/keeper.go#L45-L49 ++++ https://github.com/cosmos/cosmos-sdk/blob/master/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). diff --git a/docs/building-modules/keeper.md b/docs/building-modules/keeper.md index ee373d8b567f..5c57faef1fe5 100644 --- a/docs/building-modules/keeper.md +++ b/docs/building-modules/keeper.md @@ -20,7 +20,7 @@ The core idea behind the object-capabilities approach is to only reveal what is ## Type Definition -`keeper`s are generally implemented in a `internal/keeper/keeper.go` file located in the module's folder. By convention, the type `keeper` of a module is simply named `Keeper` and usually follows the following structure: +`keeper`s are generally implemented in a `/keeper/keeper.go` file located in the module's folder. By convention, the type `keeper` of a module is simply named `Keeper` and usually follows the following structure: ```go type Keeper struct { @@ -32,15 +32,15 @@ type Keeper struct { } ``` -For example, here is the [type definition of the `keeper` from the nameservice tutorial: +For example, here is the type definition of the `keeper` from the `staking` module: -+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/internal/keeper/keeper.go#L10-L17 ++++ https://github.com/cosmos/cosmos-sdk/blob/3bafd8255a502e5a9cee07391cf8261538245dfd/x/staking/keeper/keeper.go#L23-L33 Let us go through the different parameters: -- An expected `keeper` is a `keeper` external to a module that is required by the internal `keeper` of said module. External `keeper`s are listed in the internal `keeper`'s type definition as interfaces. These interfaces are themselves defined in a `internal/types/expected_keepers.go` file within the module's folder. In this context, interfaces are used to reduce the number of dependencies, as well as to facilitate the maintenance of the module itself. +- An expected `keeper` is a `keeper` external to a module that is required by the internal `keeper` of said module. External `keeper`s are listed in the internal `keeper`'s type definition as interfaces. These interfaces are themselves defined in a `types/expected_keepers.go` file within the module's folder. In this context, interfaces are used to reduce the number of dependencies, as well as to facilitate the maintenance of the module itself. - `storeKey`s grant access to the store(s) of the [multistore](../core/store.md) managed by the module. They should always remain unexposed to external modules. -- A [codec `cdc`](../core/encoding.md), used to marshall and unmarshall struct to/from `[]byte`. +- A [codec `cdc`](../core/encoding.md), used to marshall and unmarshall struct to/from `[]byte`, that can be any of `codec.BinaryMarshaler`,`codec.JSONMarshaler` or `codec.Marshaler` based on your requirements. It can be either a proto or amino codec as long as they implement these interfaces. Of course, it is possible to define different types of internal `keeper`s for the same module (e.g. a read-only `keeper`). Each type of `keeper` comes with its own constructor function, which is called from the [application's constructor function](../basics/app-anatomy.md). This is where `keeper`s are instantiated, and where developers make sure to pass correct instances of modules' `keeper`s to other modules that require it. @@ -56,7 +56,7 @@ func (k Keeper) Get(ctx sdk.Context, key string) returnType and go through the following steps: -1. Retrieve the appropriate store from the `ctx` using the `storeKey`. This is done through the `KVStore(storeKey sdk.StoreKey` method of the `ctx`. +1. Retrieve the appropriate store from the `ctx` using the `storeKey`. This is done through the `KVStore(storeKey sdk.StoreKey)` method of the `ctx`. Then it's prefered to use the `prefix.Store` to access only the desired limited subset of the store for convenience and safety. 2. If it exists, get the `[]byte` value stored at location `[]byte(key)` using the `Get(key []byte)` method of the store. 3. Unmarshall the retrieved value from `[]byte` to `returnType` using the codec `cdc`. Return the value. @@ -68,11 +68,17 @@ func (k Keeper) Set(ctx sdk.Context, key string, value valueType) and go through the following steps: -1. Retrieve the appropriate store from the `ctx` using the `storeKey`. This is done through the `KVStore(storeKey sdk.StoreKey` method of the `ctx`. -2. Marhsall `value` to `[]byte` using the codec `cdc`. +1. Retrieve the appropriate store from the `ctx` using the `storeKey`. This is done through the `KVStore(storeKey sdk.StoreKey)` method of the `ctx`. Then it's prefered to use the `prefix.Store` to access only the desired limited subset of the store for convenience and safety. +2. Marshal `value` to `[]byte` using the codec `cdc`. 3. Set the encoded value in the store at location `key` using the `Set(key []byte, value []byte)` method of the store. -For more, see an example of `keeper`'s [methods implementation from the nameservice tutorial](https://github.com/cosmos/sdk-application-tutorial/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/x/nameservice/internal/keeper/keeper.go). +For more, see an example of `keeper`'s [methods implementation from the `staking` module](https://github.com/cosmos/cosmos-sdk/blob/3bafd8255a502e5a9cee07391cf8261538245dfd/x/staking/keeper/keeper.go). + +The [module `KVStore`](../core/store.md#kvstore-and-commitkvstore-interfaces) also provides an `Iterator()` method which returns an `Iterator` object to iterate over a domain of keys. + +This is an example from the `auth` module to iterate accounts: + ++++ https://github.com/cosmos/cosmos-sdk/blob/bf8809ef9840b4f5369887a38d8345e2380a567f/x/auth/keeper/account.go#L70-L83 ## Next {hide} diff --git a/docs/building-modules/messages-and-queries.md b/docs/building-modules/messages-and-queries.md index 30ea4f344d9f..71390449812e 100644 --- a/docs/building-modules/messages-and-queries.md +++ b/docs/building-modules/messages-and-queries.md @@ -16,39 +16,47 @@ order: 3 When a transaction is relayed from the underlying consensus engine to the SDK application, it is first decoded by [`baseapp`](../core/baseapp.md). Then, each `message` contained in the transaction is extracted and routed to the appropriate module via `baseapp`'s `router` so that it can be processed by the module's [`handler`](./handler.md). For a more detailed explanation of the lifecycle of a transaction, click [here](../basics/tx-lifecycle.md). -Defining `message`s is the responsibility of module developers. Typically, they are defined in a `./internal/types/msgs.go` file inside the module's folder. The `message`'s type definition usually includes a list of parameters needed to process the message that will be provided by end-users when they want to create a new transaction containing said `message`. +Defining `message`s is the responsibility of module developers. Typically, they are defined as protobuf messages in a `proto/` directory (see more info about [conventions and naming](../core/encoding.md#faq)). The `message`'s definition usually includes a list of parameters needed to process the message that will be provided by end-users when they want to create a new transaction containing said `message`. -```go -// Example of a message type definition +Here's an example of a protobuf message definition: -type MsgSubmitProposal struct { - Content Content `json:"content" yaml:"content"` - InitialDeposit sdk.Coins `json:"initial_deposit" yaml:"initial_deposit"` - Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"` -} -``` ++++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/proto/cosmos/gov/v1beta1/tx.proto#L15-L27 The `Msg` is typically accompanied by a standard constructor function, that is called from one of the [module's interface](./module-interfaces.md). `message`s also need to implement the [`Msg`] interface: -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L7-L29 ++++ https://github.com/cosmos/cosmos-sdk/blob/4a1b2fba43b1052ca162b3a1e0b6db6db9c26656/types/tx_msg.go#L10-L33 -It contains the following methods: +It extends `proto.Message` and contains the following methods: - `Route() string`: Name of the route for this message. Typically all `message`s in a module have the same route, which is most often the module's name. - `Type() string`: Type of the message, used primarly in [events](../core/events.md). This should return a message-specific `string`, typically the denomination of the message itself. -- `ValidateBasic() Error`: This method is called by `baseapp` very early in the processing of the `message` (in both [`CheckTx`](../core/baseapp.md#checktx) and [`DeliverTx`](../core/baseapp.md#delivertx)), in order to discard obviously invalid messages. `ValidateBasic` should only include *stateless* checks, i.e. checks that do not require access to the state. This usually consists in checking that the message's parameters are correctly formatted and valid (i.e. that the `amount` is strictly positive for a transfer). +- `ValidateBasic() error`: This method is called by `baseapp` very early in the processing of the `message` (in both [`CheckTx`](../core/baseapp.md#checktx) and [`DeliverTx`](../core/baseapp.md#delivertx)), in order to discard obviously invalid messages. `ValidateBasic` should only include *stateless* checks, i.e. checks that do not require access to the state. This usually consists in checking that the message's parameters are correctly formatted and valid (i.e. that the `amount` is strictly positive for a transfer). - `GetSignBytes() []byte`: Return the canonical byte representation of the message. Used to generate a signature. - `GetSigners() []AccAddress`: Return the list of signers. The SDK will make sure that each `message` contained in a transaction is signed by all the signers listed in the list returned by this method. -See an example implementation of a `message` from the `nameservice` module: +See an example implementation of a `message` from the `gov` module: -+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/internal/types/msgs.go#L10-L51 ++++ https://github.com/cosmos/cosmos-sdk/blob/master/x/gov/types/msgs.go#L94-L136 ## Queries -A `query` is a request for information made by end-users of applications through an interface and processed by a full-node. A `query` is received by a full-node through its consensus engine and relayed to the application via the ABCI. It is then routed to the appropriate module via `baseapp`'s `queryrouter` so that it can be processed by the module's [`querier`](./querier.md). For a deeper look at the lifecycle of a `query`, click [here](../interfaces/query-lifecycle.md). +A `query` is a request for information made by end-users of applications through an interface and processed by a full-node. A `query` is received by a full-node through its consensus engine and relayed to the application via the ABCI. It is then routed to the appropriate module via `baseapp`'s `queryrouter` so that it can be processed by the module's query service (./query-services.md). For a deeper look at the lifecycle of a `query`, click [here](../interfaces/query-lifecycle.md). + +### gRPC Queries + +Starting from v0.40, the prefered way to define queries is by using [Protobuf services](https://developers.google.com/protocol-buffers/docs/proto#services). A `Query` service should be created per module in `query.proto`. This service lists endpoints starting with `rpc`. + +Here's an example of such a `Query` service definition: + ++++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/proto/cosmos/auth/v1beta1/query.proto#L12-L23 + +As `proto.Message`s, generated `Response` types implement by default `String()` method of [`fmt.Stringer`](https://golang.org/pkg/fmt/#Stringer). -Contrary to `message`s, there is usually no specific `query` object defined by module developers. Instead, the SDK takes the simpler approach of using a simple `path` to define each `query`. The `path` contains the `query` type and all the arguments needed in order to process it. For most module queries, the `path` should look like the following: +A `RegisterQueryServer` method is also generated and should be used to register the module's query server in `RegisterQueryService` method from the [`AppModule` interface](./module-manager.md#appmodule). + +### Legacy Queries + +Before the introduction of Protobuf and gRPC in the SDK, there was usually no specific `query` object defined by module developers, contrary to `message`s. Instead, the SDK took the simpler approach of using a simple `path` to define each `query`. The `path` contains the `query` type and all the arguments needed in order to process it. For most module queries, the `path` should look like the following: ``` queryCategory/queryRoute/queryType/arg1/arg2/... @@ -58,18 +66,24 @@ where: - `queryCategory` is the category of the `query`, typically `custom` for module queries. It is used to differentiate between different kinds of queries within `baseapp`'s [`Query` method](../core/baseapp.md#query). - `queryRoute` is used by `baseapp`'s [`queryRouter`](../core/baseapp.md#query-routing) to map the `query` to its module. Usually, `queryRoute` should be the name of the module. -- `queryType` is used by the module's [`querier`](./querier.md) to map the `query` to the appropriate `querier function` within the module. +- `queryType` is used by the module's [`querier`](./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](./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`](./querier.md), to process the `query` once it has been [routed to the module](../core/baseapp.md#query-routing). +- A [`querier`](./query-services.md#legacy-queriers), to process the `query` once it has been [routed to the module](../core/baseapp.md#query-routing). - [Query commands](./module-interfaces.md#query-commands) in the module's CLI file, where the `path` for each `query` is specified. -- `query` return types. Typically defined in a file `internal/types/querier.go`, they specify the result type of each of the module's `queries`. These custom types must implement the `String()` method of [`fmt.Stringer`](https://golang.org/pkg/fmt/#Stringer). +- `query` return types. Typically defined in a file `types/querier.go`, they specify the result type of each of the module's `queries`. These custom types must implement the `String()` method of [`fmt.Stringer`](https://golang.org/pkg/fmt/#Stringer). + +### Store Queries + +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: -See an example of `query` return types from the `nameservice` module: ++++ https://github.com/cosmos/cosmos-sdk/blob/080fcf1df25ccdf97f3029b6b6f83caaf5a235e4/x/ibc/core/client/query.go#L36-L46 -+++ https://github.com/cosmos/sdk-tutorials/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/x/nameservice/internal/types/querier.go#L5-L21 ++++ https://github.com/cosmos/cosmos-sdk/blob/080fcf1df25ccdf97f3029b6b6f83caaf5a235e4/baseapp/abci.go#L722-L749 ## Next {hide} diff --git a/docs/building-modules/module-interfaces.md b/docs/building-modules/module-interfaces.md index d2761248d94b..1c8dcdbce26e 100644 --- a/docs/building-modules/module-interfaces.md +++ b/docs/building-modules/module-interfaces.md @@ -16,49 +16,47 @@ One of the main interfaces for an application is the [command-line interface](.. ### Transaction Commands -[Transactions](../core/transactions.md) are created by users to wrap messages that trigger state changes when they get included in a valid block. Transaction commands typically have their own `tx.go` file in the module `./x/moduleName/client/cli` folder. The commands are specified in getter functions prefixed with `GetCmd` and include the name of the command. +[Transactions](../core/transactions.md) are created by users to wrap messages that trigger state changes when they get included in a valid block. Transaction commands typically have their own `tx.go` file in the module `./x/moduleName/client/cli` folder. The commands are specified in getter functions and include the name of the command. -Here is an example from the `nameservice` module: +Here is an example from the `auth` module: -+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/client/cli/tx.go#L33-L58 ++++ https://github.com/cosmos/cosmos-sdk/blob/64b6bb5270e1a3b688c2d98a8f481ae04bb713ca/x/auth/client/cli/tx_sign.go#L160-L194 -This getter function creates the command for the Buy Name transaction. It does the following: +This getter function creates the command for the `Sign` transaction. It does the following: -- **Construct the command:** Read the [Cobra Documentation](https://github.com/spf13/cobra) for details on how to create commands. +- **Construct the command:** Read the [Cobra Documentation](https://godoc.org/github.com/spf13/cobra) for details on how to create commands. - **Use:** Specifies the format of a command-line entry users should type in order to invoke this command. In this case, the user uses `buy-name` as the name of the transaction command and provides the `name` the user wishes to buy and the `amount` the user is willing to pay. - **Args:** The number of arguments the user provides, in this case exactly two: `name` and `amount`. - **Short and Long:** A description for the function is provided here. A `Short` description is expected, and `Long` can be used to provide a more detailed description when a user uses the `--help` flag to ask for more information. - **RunE:** Defines a function that can return an error, called when the command is executed. Using `Run` would do the same thing, but would not allow for errors to be returned. - **`RunE` Function Body:** The function should be specified as a `RunE` to allow for errors to be returned. This function encapsulates all of the logic to create a new transaction that is ready to be relayed to nodes. - - The function should first initialize a [`TxBuilder`](../core/transactions.md#txbuilder) with the application `codec`'s `TxEncoder`, as well as a new [`Context`](../interfaces/query-lifecycle.md#context) with the `codec` and `AccountDecoder`. These contexts contain all the information provided by the user and will be used to transfer this user-specific information between processes. To learn more about how contexts are used in a transaction, click [here](../core/transactions.md#transaction-generation). - - If applicable, the command's arguments are parsed. Here, the `amount` given by the user is parsed into a denomination of `coins`. - - If applicable, the `Context` is used to retrieve any parameters such as the transaction originator's address to be used in the transaction. Here, the `from` address is retrieved by calling `cliCtx.getFromAddress()`. + - The function should first get the `clientCtx` with `client.GetClientContextFromCmd(cmd)` and `client.ReadTxCommandFlags(clientCtx, cmd.Flags())`. This context contains all the information provided by the user and will be used to transfer this user-specific information between processes. To learn more about how contexts are used in a transaction, click [here](../core/transactions.md#transaction-generation). + - If applicable, the command's arguments are parsed. + - If applicable, the `Context` is used to retrieve any parameters such as the transaction originator's address to be used in the transaction. Here, the `from` address is retrieved by calling `clientCtx.GetFromAddress()`. - A [message](./messages-and-queries.md) is created using all parameters parsed from the command arguments and `Context`. The constructor function of the specific message type is called directly. It is good practice to call `ValidateBasic()` on the newly created message to run a sanity check and check for invalid arguments. - Depending on what the user wants, the transaction is either generated offline or signed and broadcasted to the preconfigured node using `GenerateOrBroadcastMsgs()`. -- **Flags.** Add any [flags](#flags) to the command. No flags were specified here, but all transaction commands have flags to provide additional information from the user (e.g. amount of fees they are willing to pay). These _persistent_ [transaction flags](../interfaces/cli.md#flags) can be added to a higher-level command so that they apply to all transaction commands. +- **Flags.** Add any [flags](#flags) to the command. All transaction commands have flags to provide additional information from the user (e.g. amount of fees they are willing to pay). These _persistent_ [transaction flags](../interfaces/cli.md#flags) can be added to a higher-level command so that they apply to all transaction commands. -Finally, the module needs to have a `GetTxCmd()`, which aggregates all of the transaction commands of the module. Often, each command getter function has its own file in the module's `cli` folder, and a separate `tx.go` file contains `GetTxCmd()`. Application developers wishing to include the module's transactions will call this function to add them as subcommands in their CLI. Here is the `auth` `GetTxCmd()` function, which adds the `Sign` and `MultiSign` commands. +Finally, the module needs to have a `GetTxCmd()`, which aggregates all of the transaction commands of the module. Often, each command getter function has its own file in the module's `cli` folder, and a separate `tx.go` file contains `GetTxCmd()`. Application developers wishing to include the module's transactions will call this function to add them as subcommands in their CLI. Here is the `auth` `GetTxCmd()` function, which adds the `Sign`, `MultiSign`, `ValidateSignatures` and `SignBatch` commands. -+++ https://github.com/cosmos/cosmos-sdk/blob/67f6b021180c7ef0bcf25b6597a629aca27766b8/x/auth/client/cli/tx.go#L11-L25 ++++ https://github.com/cosmos/cosmos-sdk/blob/351192aa0b52a42b66ff06e81cfa7a9e26667a7f/x/auth/client/cli/tx.go#L10-L26 An application using this module likely adds `auth` module commands to its root `TxCmd` command by calling `txCmd.AddCommand(authModuleClient.GetTxCmd())`. ### Query Commands -[Queries](./messages-and-queries.md#queries) allow users to gather information about the application or network state; they are routed by the application and processed by the module in which they are defined. Query commands typically have their own `query.go` file in the module `x/moduleName/client/cli` folder. Like transaction commands, they are specified in getter functions and have the prefix `GetCmdQuery`. Here is an example of a query command from the `nameservice` module: +[Queries](./messages-and-queries.md#queries) allow users to gather information about the application or network state; they are routed by the application and processed by the module in which they are defined. Query commands typically have their own `query.go` file in the module `x/moduleName/client/cli` folder. Like transaction commands, they are specified in getter functions. Here is an example of a query command from the `auth` module: -+++ https://github.com/cosmos/sdk-tutorials/blob/86a27321cf89cc637581762e953d0c07f8c78ece/nameservice/x/nameservice/client/cli/query.go#L52-L73 ++++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/x/auth/client/cli/query.go#L76-L108 -This query returns the address that owns a particular name. The getter function does the following: +This query returns the account at a given address. The getter function does the following: -- **`codec` and `queryRoute`.** In addition to taking in the application `codec`, query command getters also take a `queryRoute` used to construct a path [Baseapp](../core/baseapp.md#query-routing) uses to route the query in the application. -- **Construct the command.** Read the [Cobra Documentation](https://github.com/spf13/cobra) and the [transaction command](#transaction-commands) example above for more information. The user must type `whois` and provide the `name` they are querying for as the only argument. +- **Construct the command.** Read the [Cobra Documentation](https://godoc.org/github.com/spf13/cobra) and the [transaction command](#transaction-commands) example above for more information. The user must type `account` and provide the `address` they are querying for as the only argument. - **`RunE`.** The function should be specified as a `RunE` to allow for errors to be returned. This function encapsulates all of the logic to create a new query that is ready to be relayed to nodes. - - The function should first initialize a new [`Context`](../interfaces/query-lifecycle.md#context) with the application `codec`. + - The function should first initialize a new client [`Context`](../interfaces/query-lifecycle.md#context) as described in the [previous section](#transaction-commands) - If applicable, the `Context` is used to retrieve any parameters (e.g. the query originator's address to be used in the query) and marshal them with the query parameter type, in preparation to be relayed to a node. There are no `Context` parameters in this case because the query does not involve any information about the user. - - The `queryRoute` is used to construct a `path` [`baseapp`](../core/baseapp.md) will use to route the query to the appropriate [querier](./querier.md). The expected format for a query `path` is "queryCategory/queryRoute/queryType/arg1/arg2/...", where `queryCategory` can be `p2p`, `store`, `app`, or `custom`, `queryRoute` is the name of the module, and `queryType` is the name of the query type defined within the module. [`baseapp`](../core/baseapp.md) can handle each type of `queryCategory` by routing it to a module querier or retrieving results directly from stores and functions for querying peer nodes. Module queries are `custom` type queries (some SDK modules have exceptions, such as `auth` and `gov` module queries). - - The `Context` `QueryWithData()` function is used to relay the query to a node and retrieve the response. It requires the `path`. It returns the result and height of the query upon success or an error if the query fails. - - The `codec` is used to nmarshal the response and the `Context` is used to print the output back to the user. + - A new `queryClient` should be initialized using `NewQueryClient(clientCtx)`, this method being generated from `query.proto`. Then it can be used to call the appropriate [query](./messages-and-queries.md#grpc-queries). + - The `clientCtx.PrintOutput` method is used to print the output back to the user. - **Flags.** Add any [flags](#flags) to the command. Finally, the module also needs a `GetQueryCmd`, which aggregates all of the query commands of the module. Application developers wishing to include the module's queries will call this function to add them as subcommands in their CLI. Its structure is identical to the `GetTxCmd` command shown above. @@ -71,9 +69,9 @@ The flags for a module are typically found in a `flags.go` file in the `./x/modu For full details on flags, visit the [Cobra Documentation](https://github.com/spf13/cobra). -For example, the SDK `./client/flags` package includes a `PostCommands()` function that adds necessary flags to transaction commands, such as the `from` flag to indicate which address the transaction originates from. +For example, the SDK `./client/flags` package includes a `AddTxFlagsToCmd(cmd *cobra.Command)` function that adds necessary flags to a transaction command, such as the `from` flag to indicate which address the transaction originates from. -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/client/flags/flags.go#L85-L116 ++++ https://github.com/cosmos/cosmos-sdk/blob/cfb5fc03e5092395403d10156c0ee96e6ff1ddbe/client/flags/flags.go#L85-L112 Here is an example of how to add a flag using the `from` flag from this function. @@ -89,11 +87,54 @@ A flag can be marked as _required_ so that an error is automatically thrown if t cmd.MarkFlagRequired(FlagFrom) ``` -Since `PostCommands()` includes all of the basic flags required for a transaction command, module developers may choose not to add any of their own (specifying arguments instead may often be more appropriate). For a full list of what flags are included in the `PostCommands()` function, including which are required inputs from users, see the CLI documentation [here](../interfaces/cli.md#transaction-flags). +Since `AddTxFlagsToCmd(cmd *cobra.Command)` includes all of the basic flags required for a transaction command, module developers may choose not to add any of their own (specifying arguments instead may often be more appropriate). -## REST +Similarly, there is a `AddQueryFlagsToCmd(cmd *cobra.Command)` to add common flags to a module query command. -Applications typically support web services that use HTTP requests (e.g. a web wallet like [Lunie.io](https://lunie.io). Thus, application developers will also use REST Routes to route HTTP requests to the application's modules; these routes will be used by service providers. The module developer's responsibility is to define the REST client by defining [routes](#register-routes) for all possible [requests](#request-types) and [handlers](#request-handlers) for each of them. It's up to the module developer how to organize the REST interface files; there is typically a `rest.go` file found in the module's `./x/moduleName/client/rest` folder. +## gRPC + +[gRPC](https://grpc.io/) is the prefered way for external clients like wallets and exchanges to interact with a node. + +In addition to providing an ABCI query pathway, modules [custom queries](./messages-and-queries.md#grpc-queries) can provide a GRPC proxy server that routes requests in the GRPC protocol to ABCI query requests under the hood. + +In order to do that, module should implement `RegisterGRPCRoutes(clientCtx client.Context, mux *runtime.ServeMux)` on `AppModuleBasic` to wire the client gRPC requests to the correct handler inside the module. + +Here's an example from the `auth` module: + ++++ https://github.com/cosmos/cosmos-sdk/blob/64b6bb5270e1a3b688c2d98a8f481ae04bb713ca/x/auth/module.go#L69-L72 + +## gRPC-gateway REST + +Applications typically support web services that use HTTP requests (e.g. a web wallet like [Lunie.io](https://lunie.io). Thus, application developers can also use REST Routes to route HTTP requests to the application's modules; these routes will be used by service providers. + +[grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) translates REST calls into gRPC calls, which might be useful for clients that do not use gRPC. + +Modules that want to expose REST queries should add `google.api.http` annotations to their `rpc` methods, such as in the example below from the `auth` module: + +```proto +// Query defines the gRPC querier service. +service Query{ + // Account returns account details based on address. + rpc Account (QueryAccountRequest) returns (QueryAccountResponse) { + option (google.api.http).get = "/cosmos/auth/v1beta1/accounts/{address}"; + } + + // Params queries all parameters. + rpc Params (QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/cosmos/auth/v1beta1/params"; + } +} +``` + +gRPC gateway is started in-process along with the application and Tendermint. It can be enabled or disabled by setting gRPC Configuration `enable` in `app.toml`. + +The SDK provides a command for generating [Swagger](https://swagger.io/) documentation (`protoc-gen-swagger`). Setting `swagger` in `app.toml` defines if swagger documentation should be automatically registered. + +## Legacy REST + +Legacy REST endpoints will be deprecated. But developers may choose to keep using legacy REST endpoints for backward compatibility, although the recommended way is to use [gRPC](#grpc) and [gRPC-gateway](#grpc-gateway-rest). + +With this implementation, module developers need to define the REST client by defining [routes](#register-routes) for all possible [requests](#request-types) and [handlers](#request-handlers) for each of them. It's up to the module developer how to organize the REST interface files; there is typically a `rest.go` file found in the module's `./x/moduleName/client/rest` folder. To support HTTP requests, the module developer needs to define possible request types, how to handle them, and provide a way to register them with a provided router. @@ -101,11 +142,11 @@ To support HTTP requests, the module developer needs to define possible request Request types, which define structured interactions from users, must be defined for all _transaction_ requests. Users using this method to interact with an application will send HTTP Requests with the required fields in order to trigger state changes in the application. Conventionally, each request is named with the suffix `Req`, e.g. `SendReq` for a Send transaction. Each struct should include a base request [`baseReq`](../interfaces/rest.md#basereq), the name of the transaction, and all the arguments the user must provide for the transaction. -Here is an example of a request to buy a name from the `nameservice` module: +Here is an example of a request to send coins from the `bank` module: -+++ https://github.com/cosmos/sdk-tutorials/blob/master/nameservice/x/nameservice/client/rest/tx.go#L14-L19 ++++ https://github.com/cosmos/cosmos-sdk/blob/7f59723d889b69ca19966167f0b3a7fec7a39e53/x/bank/client/rest/tx.go#L15-L19 -The `BaseReq` includes basic information that every request needs to have, similar to required flags in a CLI. All of these values, including `GasPrices` and `AccountNumber`, will be provided in the request body. The user will also need to specify the arguments `Name` and `Amount` fields in the body and `Buyer` will be provided by the user's address. +The `BaseReq` includes basic information that every request needs to have, similar to required flags in a CLI. All of these values, including `GasPrices` and `AccountNumber`, will be provided in the request body. The user will also need to specify the argument `Amount` fields in the body. #### BaseReq @@ -116,6 +157,7 @@ The `BaseReq` includes basic information that every request needs to have, simil - `ChainID` specifies the unique identifier of the blockchain the transaction pertains to. - `AccountNumber` is an identifier for the account. - `Sequence`is the value of a counter measuring how many transactions have been sent from the account. It is used to prevent replay attacks. +- `TimeoutHeight` allows a transaction to be rejected if it's committed at a height greater than the timeout. - `Gas` refers to how much [gas](../basics/gas-fees.md), which represents computational resources, Tx consumes. Gas is dependent on the transaction and is not precisely calculated until execution, but can be estimated by providing auto as the value for `Gas`. - `GasAdjustment` can be used to scale gas up in order to avoid underestimating. For example, users can specify their gas adjustment as 1.5 to use 1.5 times the estimated gas. - `GasPrices` specifies how much the user is willing pay per unit of gas, which can be one or multiple denominations of tokens. For example, --gas-prices=0.025uatom, 0.025upho means the user is willing to pay 0.025uatom AND 0.025upho per unit of gas. @@ -124,17 +166,17 @@ The `BaseReq` includes basic information that every request needs to have, simil ### Request Handlers -Request handlers must be defined for both transaction and query requests. Handlers' arguments include a reference to the application's `codec` and the [`Context`](../interfaces/query-lifecycle.md#context) created in the user interaction. +Request handlers must be defined for both transaction and query requests. Handlers' arguments include a reference to the [client `Context`](../interfaces/query-lifecycle.md#context). -Here is an example of a request handler for the nameservice module `buyNameReq` request (the same one shown above): +Here is an example of a request handler for the `bank` module `SendReq` request (the same one shown above): -+++ https://github.com/cosmos/sdk-tutorials/blob/master/nameservice/x/nameservice/client/rest/tx.go#L21-L57 ++++ https://github.com/cosmos/cosmos-sdk/blob/7f59723d889b69ca19966167f0b3a7fec7a39e53/x/bank/client/rest/tx.go#L21-L51 The request handler can be broken down as follows: -- **Parse Request:** The request handler first attempts to parse the request, and then run `Sanitize` and `ValidateBasic` on the underlying `BaseReq` to check the validity of the request. Next, it attempts to parse the arguments `Buyer` and `Amount` to the types `AccountAddress` and `Coins` respectively. -- **Message:** Then, a [message](./messages-and-queries.md) of the type `MsgBuyName` (defined by the module developer to trigger the state changes for this transaction) is created from the values and another sanity check, `ValidateBasic` is run on it. -- **Generate Transaction:** Finally, the HTTP `ResponseWriter`, application [`codec`](../core/encoding.md), [`Context`](../interfaces/query-lifecycle.md#context), request [`BaseReq`](../interfaces/rest.md#basereq), and message is passed to `WriteGenerateStdTxResponse` to further process the request. +- **Parse Request:** First, it tries to parse the argument `address` into a `AccountAddress`. Then, the request handler attempts to parse the request, and then run `Sanitize` and `ValidateBasic` on the underlying `BaseReq` to check the validity of the request. Finally, it attempts to parse `BaseReq.From` to the type `AccountAddress`. +- **Message:** Then, a [message](./messages-and-queries.md#messages) of the type `MsgSend` (defined by the module developer to trigger the state changes for this transaction) is created from the values. +- **Generate Transaction:** Finally, the HTTP `ResponseWriter`, client `Context`, request [`BaseReq`](../interfaces/rest.md#basereq), and message is passed to `WriteGeneratedTxResponse` to further process the request. To read more about how a transaction is generated, visit the transactions documentation [here](../core/transactions.md#transaction-generation). diff --git a/docs/building-modules/module-manager.md b/docs/building-modules/module-manager.md index dad35a9da3aa..1c034bde7157 100644 --- a/docs/building-modules/module-manager.md +++ b/docs/building-modules/module-manager.md @@ -29,15 +29,17 @@ are only used for genesis can take advantage of the `Module` patterns without ha The `AppModuleBasic` interface defines the independent methods modules need to implement. -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/module/module.go#L46-L59 ++++ https://github.com/cosmos/cosmos-sdk/blob/325be6ff215db457c6fc7668109640cd7fdac461/types/module/module.go#L49-L63 Let us go through the methods: - `Name()`: Returns the name of the module as a `string`. -- `RegisterLegacyAminoCodec(*codec.LegacyAmino)`: Registers the `amino` codec for the module, which is used to marhsal and unmarshal structs to/from `[]byte` in order to persist them in the moduel's `KVStore`. -- `DefaultGenesis()`: Returns a default [`GenesisState`](./genesis.md#genesisstate) for the module, marshalled to `json.RawMessage`. The default `GenesisState` need to be defined by the module developer and is primarily used for testing. -- `ValidateGenesis(json.RawMessage)`: Used to validate the `GenesisState` defined by a module, given in its `json.RawMessage` form. It will usually unmarshall the `json` before running a custom [`ValidateGenesis`](./genesis.md#validategenesis) function defined by the module developer. +- `RegisterLegacyAminoCodec(*codec.LegacyAmino)`: Registers the `amino` codec for the module, which is used to marshal and unmarshal structs to/from `[]byte` in order to persist them in the module's `KVStore`. +- `RegisterInterfaces(codectypes.InterfaceRegistry)`: Registers a module's interface types and their concrete implementations as `proto.Message`. +- `DefaultGenesis(codec.JSONMarshaler)`: Returns a default [`GenesisState`](./genesis.md#genesisstate) for the module, marshalled to `json.RawMessage`. The default `GenesisState` need to be defined by the module developer and is primarily used for testing. +- `ValidateGenesis(codec.JSONMarshaler, client.TxEncodingConfig, json.RawMessage)`: Used to validate the `GenesisState` defined by a module, given in its `json.RawMessage` form. It will usually unmarshall the `json` before running a custom [`ValidateGenesis`](./genesis.md#validategenesis) function defined by the module developer. - `RegisterRESTRoutes(client.Context, *mux.Router)`: Registers the REST routes for the module. These routes will be used to map REST request to the module in order to process them. See [../interfaces/rest.md] for more. +- `RegisterGRPCRoutes(client.Context, *runtime.ServeMux)`: Registers gRPC routes for the module. - `GetTxCmd()`: Returns the root [`Tx` command](./module-interfaces.md#tx) for the module. The subcommands of this root command are used by end-users to generate new transactions containing [`message`s](./messages-and-queries.md#queries) defined in the module. - `GetQueryCmd()`: Return the root [`query` command](./module-interfaces.md#query) for the module. The subcommands of this root command are used by end-users to generate new queries to the subset of the state defined by the module. @@ -47,20 +49,20 @@ All the `AppModuleBasic` of an application are managed by the [`BasicManager`](# The `AppModuleGenesis` interface is a simple embedding of the `AppModuleBasic` interface with two added methods. -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/module/module.go#L126-L131 ++++ https://github.com/cosmos/cosmos-sdk/blob/325be6ff215db457c6fc7668109640cd7fdac461/types/module/module.go#L152-L158 Let us go through the two added methods: -- `InitGenesis(sdk.Context, json.RawMessage)`: Initializes the subset of the state managed by the module. It is called at genesis (i.e. when the chain is first started). -- `ExportGenesis(sdk.Context)`: Exports the latest subset of the state managed by the module to be used in a new genesis file. `ExportGenesis` is called for each module when a new chain is started from the state of an existing chain. +- `InitGenesis(sdk.Context, codec.JSONMarshaler, json.RawMessage)`: Initializes the subset of the state managed by the module. It is called at genesis (i.e. when the chain is first started). +- `ExportGenesis(sdk.Context, codec.JSONMarshaler)`: Exports the latest subset of the state managed by the module to be used in a new genesis file. `ExportGenesis` is called for each module when a new chain is started from the state of an existing chain. -It does not have its own manager, and exists separately from [`AppModule`](#appmodule) only for modules that exist only to implement genesis functionalities, so that they can be managed without having to implement all of `AppModule`'s methods. If the module is not only used during genesis, `InitGenesis(sdk.Context, json.RawMessage)` and `ExportGenesis(sdk.Context)` will generally be defined as methods of the concrete type implementing hte `AppModule` interface. +It does not have its own manager, and exists separately from [`AppModule`](#appmodule) only for modules that exist only to implement genesis functionalities, so that they can be managed without having to implement all of `AppModule`'s methods. If the module is not only used during genesis, `InitGenesis(sdk.Context, codec.JSONMarshaler, json.RawMessage)` and `ExportGenesis(sdk.Context, codec.JSONMarshaler)` will generally be defined as methods of the concrete type implementing hte `AppModule` interface. ### `AppModule` The `AppModule` interface defines the inter-dependent methods modules need to implement. -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/module/module.go#L133-L149 ++++ https://github.com/cosmos/cosmos-sdk/blob/228728cce2af8d494c8b4e996d011492139b04ab/types/module/module.go#L160-L182 `AppModule`s are managed by the [module manager](#manager). This interface embeds the `AppModuleGenesis` interface so that the manager can access all the independent and genesis inter-dependent methods of the module. This means that a concrete type implementing the `AppModule` interface must either implement all the methods of `AppModuleGenesis` (and by extension `AppModuleBasic`), or include a concrete type that does as parameter. @@ -68,8 +70,9 @@ Let us go through the methods of `AppModule`: - `RegisterInvariants(sdk.InvariantRegistry)`: Registers the [`invariants`](./invariants.md) of the module. If the invariants deviates from its predicted value, the [`InvariantRegistry`](./invariants.md#registry) triggers appropriate logic (most often the chain will be halted). - `Route()`: Returns the route for [`message`s](./messages-and-queries.md#messages) to be routed to the module by [`baseapp`](../core/baseapp.md#message-routing). -- `QuerierRoute()`: Returns the name of the module's query route, for [`queries`](./messages-and-queries.md#queries) to be routes to the module by [`baseapp`](../core/baseapp.md#query-routing). -- `NewQuerierHandler()`: Returns a [`querier`](./querier.md) given the query `path`, in order to process the `query`. +- `QuerierRoute()` (deprecated): Returns the name of the module's query route, for [`queries`](./messages-and-queries.md#queries) to be routes to the module by [`baseapp`](../core/baseapp.md#query-routing). +- `LegacyQuerierHandler(*codec.LegacyAmino)` (deprecated): Returns a [`querier`](./query-services.md#legacy-queriers) given the query `path`, in order to process the `query`. +- `RegisterQueryService(grpc.Server)`: Allows a module to register a gRPC query service. - `BeginBlock(sdk.Context, abci.RequestBeginBlock)`: This method gives module developers the option to implement logic that is automatically triggered at the beginning of each block. Implement empty if no logic needs to be triggered at the beginning of each block for this module. - `EndBlock(sdk.Context, abci.RequestEndBlock)`: This method gives module developers the option to implement logic that is automatically triggered at the beginning of each block. This is also where the module can inform the underlying consensus engine of validator set changes (e.g. the `staking` module). Implement empty if no logic needs to be triggered at the beginning of each block for this module. @@ -103,15 +106,17 @@ Module managers are used to manage collections of `AppModuleBasic` and `AppModul The `BasicManager` is a structure that lists all the `AppModuleBasic` of an application: -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/module/module.go#L61-L63 ++++ https://github.com/cosmos/cosmos-sdk/blob/325be6ff215db457c6fc7668109640cd7fdac461/types/module/module.go#L65-L66 It implements the following methods: - `NewBasicManager(modules ...AppModuleBasic)`: Constructor function. It takes a list of the application's `AppModuleBasic` and builds a new `BasicManager`. This function is generally called in the `init()` function of [`app.go`](../basics/app-anatomy.md#core-application-file) to quickly initialize the independent elements of the application's modules (click [here](https://github.com/cosmos/gaia/blob/master/app/app.go#L59-L74) to see an example). -- `RegisterLegacyAminoCodec(cdc *codec.LegacyAmino)`: Registers the [`codec`s](../core/encoding.md) of each of the application's `AppModuleBasic`. This function is usually called early on in the [application's construction](../basics/app-anatomy.md#constructor). -- `DefaultGenesis()`: Provides default genesis information for modules in the application by calling the [`DefaultGenesis()`](./genesis.md#defaultgenesis) function of each module. It is used to construct a default genesis file for the application. -- `ValidateGenesis(genesis map[string]json.RawMessage)`: Validates the genesis information modules by calling the [`ValidateGenesis()`](./genesis.md#validategenesis) function of each module. +- `RegisterLegacyAminoCodec(cdc *codec.LegacyAmino)`: Registers the [`codec.LegacyAmino`s](../core/encoding.md#amino) of each of the application's `AppModuleBasic`. This function is usually called early on in the [application's construction](../basics/app-anatomy.md#constructor). +- `RegisterInterfaces(registry codectypes.InterfaceRegistry)`: Registers interface types and implementations of each of the application's `AppModuleBasic`. +- `DefaultGenesis(cdc codec.JSONMarshaler)`: Provides default genesis information for modules in the application by calling the [`DefaultGenesis(cdc codec.JSONMarshaler)`](./genesis.md#defaultgenesis) function of each module. It is used to construct a default genesis file for the application. +- `ValidateGenesis(cdc codec.JSONMarshaler, txEncCfg client.TxEncodingConfig, genesis map[string]json.RawMessage)`: Validates the genesis information modules by calling the [`ValidateGenesis(codec.JSONMarshaler, client.TxEncodingConfig, json.RawMessage)`](./genesis.md#validategenesis) function of each module. - `RegisterRESTRoutes(ctx client.Context, rtr *mux.Router)`: Registers REST routes for modules by calling the [`RegisterRESTRoutes`](./module-interfaces.md#register-routes) function of each module. This function is usually called function from the `main.go` function of the [application's command-line interface](../interfaces/cli.md). +- `RegisterGRPCRoutes(clientCtx client.Context, rtr *runtime.ServeMux)`: Registers gRPC routes for modules. - `AddTxCommands(rootTxCmd *cobra.Command)`: Adds modules' transaction commands to the application's [`rootTxCommand`](../interfaces/cli.md#transaction-commands). This function is usually called function from the `main.go` function of the [application's command-line interface](../interfaces/cli.md). - `AddQueryCommands(rootQueryCmd *cobra.Command)`: Adds modules' query commands to the application's [`rootQueryCommand`](../interfaces/cli.md#query-commands). This function is usually called function from the `main.go` function of the [application's command-line interface](../interfaces/cli.md). @@ -119,7 +124,7 @@ It implements the following methods: The `Manager` is a structure that holds all the `AppModule` of an application, and defines the order of execution between several key components of these modules: -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/module/module.go#L190-L198 ++++ https://github.com/cosmos/cosmos-sdk/blob/325be6ff215db457c6fc7668109640cd7fdac461/types/module/module.go#L223-L231 The module manager is used throughout the application whenever an action on a collection of modules is required. It implements the following methods: @@ -129,12 +134,17 @@ The module manager is used throughout the application whenever an action on a co - `SetOrderBeginBlockers(moduleNames ...string)`: Sets the order in which the `BeginBlock()` function of each module will be called at the beginning of each block. This function is generally called from the application's main [constructor function](../basics/app-anatomy.md#constructor-function). - `SetOrderEndBlockers(moduleNames ...string)`: Sets the order in which the `EndBlock()` function of each module will be called at the beginning of each block. This function is generally called from the application's main [constructor function](../basics/app-anatomy.md#constructor-function). - `RegisterInvariants(ir sdk.InvariantRegistry)`: Registers the [invariants](./invariants.md) of each module. -- `RegisterRoutes(router sdk.Router, queryRouter sdk.QueryRouter)`: Registers module routes to the application's `router`, in order to route [`message`s](./messages-and-queries.md#messages) to the appropriate [`handler`](./handler.md), and module query routes to the application's `queryRouter`, in order to route [`queries`](./messages-and-queries.md#queries) to the appropriate [`querier`](./querier.md). -- `InitGenesis(ctx sdk.Context, genesisData map[string]json.RawMessage)`: Calls the [`InitGenesis`](./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 sdk.Context)`: Calls the [`ExportGenesis`](./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. +- `RegisterRoutes(router sdk.Router, queryRouter sdk.QueryRouter, legacyQuerierCdc *codec.LegacyAmino)`: Registers module routes to the application's `router`, in order to route [`message`s](./messages-and-queries.md#messages) to the appropriate [`handler`](./handler.md), and module query routes to the application's `queryRouter`, in order to route [`queries`](./messages-and-queries.md#queries) to the appropriate [`querier`](./query-services.md#legacy-queriers). +- `RegisterQueryServices(grpcRouter grpc.Server)`: Registers all module gRPC query services. +- `InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, genesisData map[string]json.RawMessage)`: Calls the [`InitGenesis`](./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 sdk.Context, cdc codec.JSONMarshaler)`: Calls the [`ExportGenesis`](./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. - `BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock)`: At the beginning of each block, this function is called from [`baseapp`](../core/baseapp.md#beginblock) and, in turn, calls the [`BeginBlock`](./beginblock-endblock.md) function of each module, in the order defined in `OrderBeginBlockers`. It creates a child [context](../core/context.md) with an event manager to aggregate [events](../core/events.md) emitted from all modules. The function returns an `abci.ResponseBeginBlock` which contains the aforementioned events. - `EndBlock(ctx sdk.Context, req abci.RequestEndBlock)`: At the end of each block, this function is called from [`baseapp`](../core/baseapp.md#endblock) and, in turn, calls the [`EndBlock`](./beginblock-endblock.md) function of each module, in the order defined in `OrderEndBlockers`. It creates a child [context](../core/context.md) with an event manager to aggregate [events](../core/events.md) emitted from all modules. The function returns an `abci.ResponseEndBlock` which contains the aforementioned events, as well as validator set updates (if any). +Here's an example of a concrete integration within an application: + ++++ https://github.com/cosmos/cosmos-sdk/blob/2323f1ac0e9a69a0da6b43693061036134193464/simapp/app.go#L315-L362 + ## Next {hide} Learn more about [`message`s and `queries`](./messages-and-queries.md) {hide} diff --git a/docs/building-modules/querier.md b/docs/building-modules/querier.md deleted file mode 100644 index 61eb1c5e10df..000000000000 --- a/docs/building-modules/querier.md +++ /dev/null @@ -1,56 +0,0 @@ - - -# Queriers - -A `Querier` designates a function that processes [`queries`](./messages-and-queries.md#queries). `querier`s are specific to the module in which they are defined, and only process `queries` defined within said module. They are called from `baseapp`'s [`Query` method](../core/baseapp.md#query). {synopsis} - -## Pre-requisite Readings - -- [Module Manager](./module-manager.md) {prereq} -- [Messages and Queries](./messages-and-queries.md) {prereq} - -## `Querier` type - -The `querier` type defined in the Cosmos SDK specifies the typical structure of a `querier` function: - -+++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/queryable.go#L6 - -Let us break it down: - -- The `path` is an array of `string`s that contains the type of the query, and that can also contain `query` arguments. See [`queries`](./messages-and-queries.md#queries) for more information. -- The `req` itself is primarily used to retrieve arguments if they are too large to fit in the `path`. This is done using the `Data` field of `req`. -- The [`Context`](../core/context.md) contains all the necessary information needed to process the `query`, as well as a cache-wrapped copy of the latest state. It is primarily used by the [`keeper`](./keeper.md) to access the state. -- The result `res` returned to `baseapp`, marhsalled using the application's [`codec`](../core/encoding.md). - -## Implementation of a module `querier`s - -Module `querier`s are typically implemented in a `./internal/keeper/querier.go` file inside the module's folder. The [module manager](./module-manager.md) is used to add the module's `querier`s to the [application's `queryRouter`](../core/baseapp.md#query-routing) via the `NewQuerier()` method. Typically, the manager's `NewQuerier()` method simply calls a `NewQuerier()` method defined in `keeper/querier.go`, which looks like the following: - -```go -func NewQuerier(keeper Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { - switch path[0] { - case QueryType1: - return queryType1(ctx, path[1:], req, keeper) - - case QueryType2: - return queryType2(ctx, path[1:], req, keeper) - - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) - } - } -} -``` - -This simple switch returns a `querier` function specific to the type of the received `query`. At this point of the [query lifecycle](../interfaces/query-lifecycle.md), the first element of the `path` (`path[0]`) contains the type of the query. The following elements are either empty or contain arguments needed to process the query. - -The `querier` functions themselves are pretty straighforward. They generally fetch a value or values from the state using the [`keeper`](./keeper.md). Then, they marshall the value(s) using the [`codec`](../core/encoding.md) and return the `[]byte` obtained as result. - -For a deeper look at `querier`s, see this [example implementation of a `querier` function](https://github.com/cosmos/sdk-application-tutorial/blob/c6754a1e313eb1ed973c5c91dcc606f2fd288811/x/nameservice/internal/keeper/querier.go) from the nameservice tutorial. - -## Next {hide} - -Learn about [`BeginBlocker` and `EndBlocker`](./beginblock-endblock.md) {hide} diff --git a/docs/building-modules/query-services.md b/docs/building-modules/query-services.md new file mode 100644 index 000000000000..fa7a6e0bae4f --- /dev/null +++ b/docs/building-modules/query-services.md @@ -0,0 +1,77 @@ + + +# Query Services + +A query service processes [`queries`](./messages-and-queries.md#queries). Query services are specific to the module in which they are defined, and only process `queries` defined within said module. They are called from `baseapp`'s [`Query` method](../core/baseapp.md#query). {synopsis} + +## Pre-requisite Readings + +- [Module Manager](./module-manager.md) {prereq} +- [Messages and Queries](./messages-and-queries.md) {prereq} + +## `Querier` type + +The `querier` type defined in the Cosmos SDK will be deprecated in favor of [gRPC Services](#grpc-service). It specifies the typical structure of a `querier` function: + ++++ https://github.com/cosmos/cosmos-sdk/blob/9a183ffbcc0163c8deb71c7fd5f8089a83e58f05/types/queryable.go#L9 + +Let us break it down: + +- The `path` is an array of `string`s that contains the type of the query, and that can also contain `query` arguments. See [`queries`](./messages-and-queries.md#queries) for more information. +- The `req` itself is primarily used to retrieve arguments if they are too large to fit in the `path`. This is done using the `Data` field of `req`. +- The [`Context`](../core/context.md) contains all the necessary information needed to process the `query`, as well as a cache-wrapped copy of the latest state. It is primarily used by the [`keeper`](./keeper.md) to access the state. +- The result `res` returned to `baseapp`, marshalled using the application's [`codec`](../core/encoding.md). + +## Implementation of a module query service + +### gRPC Service + +When defining a Protobuf `Query` service, a `QueryServer` interface is generated for each module with all the service methods: + +```go +type QueryServer interface { + QueryBalance(context.Context, *QueryBalanceParams) (*types.Coin, error) + QueryAllBalances(context.Context, *QueryAllBalancesParams) (*QueryAllBalancesResponse, error) +} +``` + +These custom queries methods should be implemented by a module's keeper, typically in `./keeper/grpc_query.go`. The first parameter of these methods is a generic `context.Context`, whereas querier methods generally need an instance of `sdk.Context` to read +from the store. Therefore, the SDK provides a function `sdk.UnwrapSDKContext` to retrieve the `sdk.Context` from the provided +`context.Context`. + +Here's an example implementation for the bank module: + ++++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/x/bank/keeper/grpc_query.go + +### Legacy Queriers + +Module legacy `querier`s are typically implemented in a `./keeper/querier.go` file inside the module's folder. The [module manager](./module-manager.md) is used to add the module's `querier`s to the [application's `queryRouter`](../core/baseapp.md#query-routing) via the `NewQuerier()` method. Typically, the manager's `NewQuerier()` method simply calls a `NewQuerier()` method defined in `keeper/querier.go`, which looks like the following: + +```go +func NewQuerier(keeper Keeper) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { + switch path[0] { + case QueryType1: + return queryType1(ctx, path[1:], req, keeper) + + case QueryType2: + return queryType2(ctx, path[1:], req, keeper) + + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) + } + } +} +``` + +This simple switch returns a `querier` function specific to the type of the received `query`. At this point of the [query lifecycle](../interfaces/query-lifecycle.md), the first element of the `path` (`path[0]`) contains the type of the query. The following elements are either empty or contain arguments needed to process the query. + +The `querier` functions themselves are pretty straighforward. They generally fetch a value or values from the state using the [`keeper`](./keeper.md). Then, they marshall the value(s) using the [`codec`](../core/encoding.md) and return the `[]byte` obtained as result. + +For a deeper look at `querier`s, see this [example implementation of a `querier` function](https://github.com/cosmos/cosmos-sdk/blob/7f59723d889b69ca19966167f0b3a7fec7a39e53/x/gov/keeper/querier.go) from the bank module. + +## Next {hide} + +Learn about [`BeginBlocker` and `EndBlocker`](./beginblock-endblock.md) {hide} diff --git a/docs/building-modules/structure.md b/docs/building-modules/structure.md index 15e9c4bcede2..cdc2c6983c8c 100644 --- a/docs/building-modules/structure.md +++ b/docs/building-modules/structure.md @@ -27,6 +27,7 @@ x/{module} │   ├── keeper.go │   ├── ... │   └── querier.go +│   └── grpc_query.go ├── types │ ├── codec.go │ ├── errors.go @@ -36,10 +37,12 @@ x/{module} │ ├── keys.go │ ├── msgs.go │ ├── params.go -│ ├── types.pb.go │ ├── types.proto │ ├── ... │ └── querier.go +│ └── {module_name}.pb.go +│ └── query.pb.go +│ └── genesis.pb.go ├── simulation │   ├── decoder.go │   ├── genesis.go diff --git a/docs/core/baseapp.md b/docs/core/baseapp.md index beaba8b5e8b3..c4ea2c9faf08 100644 --- a/docs/core/baseapp.md +++ b/docs/core/baseapp.md @@ -200,7 +200,7 @@ The application's `router` is initilalized with all the routes using the applica ### Query Routing -Similar to `message`s, [`queries`](../building-modules/messages-and-queries.md#queries) need to be routed to the appropriate module's [querier](../building-modules/querier.md). To do so, `baseapp` holds a `query router`, which maps module names to module `querier`s. The `queryRouter` is called during the initial stages of `query` processing, which is done via the [`Query` ABCI message](#query). +Similar to `message`s, [`queries`](../building-modules/messages-and-queries.md#queries) need to be routed to the appropriate module's [querier](../building-modules/query-services.md). To do so, `baseapp` holds a `query router`, which maps module names to module `querier`s. The `queryRouter` is called during the initial stages of `query` processing, which is done via the [`Query` ABCI message](#query). Just like the `router`, the `query router` is initilalized with all the query routes using the application's [module manager](../building-modules/module-manager.md), which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor). diff --git a/docs/core/encoding.md b/docs/core/encoding.md index 2e0012407fab..69059b39c6a0 100644 --- a/docs/core/encoding.md +++ b/docs/core/encoding.md @@ -80,7 +80,7 @@ Modules are encouraged to utilize Protobuf encoding for their respective types. Protobuf types can be defined to encode: - state - [`Msg`s](../building-modules/messages-and-queries.md#messages) - - [queries](../building-modules/querier.md) + - [Query services](../building-modules/query-services.md) - [genesis](../building-modules/genesis.md) **Naming and conventions** diff --git a/docs/core/transactions.md b/docs/core/transactions.md index b5ae3bc57fb1..507f47e6b1f0 100644 --- a/docs/core/transactions.md +++ b/docs/core/transactions.md @@ -39,7 +39,7 @@ A transaction is created by an end-user through one of the possible [interfaces] Application developers create entrypoints to the application by creating a [command-line interface](../interfaces/cli.md) and/or [REST interface](../interfaces/rest.md), typically found in the application's `./cmd` folder. These interfaces allow users to interact with the application through command-line or through HTTP requests. -For the [command-line interface](../building-modules/module-interfaces.md#cli), module developers create subcommands to add as children to the application top-level transaction command `TxCmd`. For [HTTP requests](../building-modules/module-interfaces.md#rest), module developers specify acceptable request types, register REST routes, and create HTTP Request Handlers. +For the [command-line interface](../building-modules/module-interfaces.md#cli), module developers create subcommands to add as children to the application top-level transaction command `TxCmd`. For [HTTP requests](../building-modules/module-interfaces.md#legacy-rest), module developers specify acceptable request types, register REST routes, and create HTTP Request Handlers. When users interact with the application's interfaces, they invoke the underlying modules' handlers or command functions, directly creating messages. diff --git a/docs/interfaces/query-lifecycle.md b/docs/interfaces/query-lifecycle.md index 26fe4df978fe..ae4a2e800b50 100644 --- a/docs/interfaces/query-lifecycle.md +++ b/docs/interfaces/query-lifecycle.md @@ -107,7 +107,7 @@ params := types.NewQueryDelegatorParams(delegatorAddr) #### Query Route Creation -Important to note is that there will never be a "query" object created for `Query`; the SDK actually takes a simpler approach. Instead of an object, all the full-node needs to process a query is its `route` which specifies exactly which module to route the query to and the name of this query type. The `route` will be passed to the application `baseapp`, then module, then [querier](../building-modules/querier.md), and each will understand the `route` and pass it to the appropriate next step. [`baseapp`](../core/baseapp.md#query-routing) will understand this query to be a `custom` query in the module `staking`, and the `staking` module querier supports the type `QueryDelegatorDelegations`. Thus, the route will be `"custom/staking/delegatorDelegations"`. +Important to note is that there will never be a "query" object created for `Query`; the SDK actually takes a simpler approach. Instead of an object, all the full-node needs to process a query is its `route` which specifies exactly which module to route the query to and the name of this query type. The `route` will be passed to the application `baseapp`, then module, then [querier](../building-modules/query-services.md#legacy-queriers), and each will understand the `route` and pass it to the appropriate next step. [`baseapp`](../core/baseapp.md#query-routing) will understand this query to be a `custom` query in the module `staking`, and the `staking` module querier supports the type `QueryDelegatorDelegations`. Thus, the route will be `"custom/staking/delegatorDelegations"`. Here is what the code looks like: @@ -133,9 +133,9 @@ Read more about ABCI Clients and Tendermint RPC in the Tendermint documentation ## Application Query Handling -When a query is received by the full-node after it has been relayed from the underlying consensus engine, it is now being handled within an environment that understands application-specific types and has a copy of the state. [`baseapp`](../core/baseapp.md) implements the ABCI [`Query()`](../core/baseapp.md#query) function and handles four different types of queries: `app`, `store`, `p2p`, and `custom`. The `queryRoute` is parsed such that the first string must be one of the four options, then the rest of the path is parsed within the subroutines handling each type of query. The first three types (`app`, `store`, `p2p`) are purely application-level and thus directly handled by `baseapp` or the stores, but the `custom` query type requires `baseapp` to route the query to a module's [querier](../building-modules/querier.md). +When a query is received by the full-node after it has been relayed from the underlying consensus engine, it is now being handled within an environment that understands application-specific types and has a copy of the state. [`baseapp`](../core/baseapp.md) implements the ABCI [`Query()`](../core/baseapp.md#query) function and handles four different types of queries: `app`, `store`, `p2p`, and `custom`. The `queryRoute` is parsed such that the first string must be one of the four options, then the rest of the path is parsed within the subroutines handling each type of query. The first three types (`app`, `store`, `p2p`) are purely application-level and thus directly handled by `baseapp` or the stores, but the `custom` query type requires `baseapp` to route the query to a module's [query service](../building-modules/query-services.md). -Since `Query` is a custom query type from the `staking` module, `baseapp` first parses the path, then uses the `QueryRouter` to retrieve the corresponding querier, and routes the query to the module. The querier is responsible for recognizing this query, retrieving the appropriate values from the application's stores, and returning a response. Read more about queriers [here](../building-modules/querier.md). +Since `Query` is a custom query type from the `staking` module, `baseapp` first parses the path, then uses the `QueryRouter` to retrieve the corresponding querier, and routes the query to the module. The querier is responsible for recognizing this query, retrieving the appropriate values from the application's stores, and returning a response. Read more about query services [here](../building-modules/query-services.md). Once a result is received from the querier, `baseapp` begins the process of returning a response to the user. diff --git a/docs/interfaces/rest.md b/docs/interfaces/rest.md index 6db69bc8bf81..00e94b1d9a9d 100644 --- a/docs/interfaces/rest.md +++ b/docs/interfaces/rest.md @@ -4,7 +4,7 @@ order: 4 # REST Interface -This document describes how to create a REST interface for an SDK **application**. A separate document for creating a [**module**](../building-modules/intro.md) REST interface can be found [here](#../module-interfaces.md#rest). {synopsis} +This document describes how to create a REST interface for an SDK **application**. A separate document for creating a [**module**](../building-modules/intro.md) REST interface can be found [here](#../module-interfaces.md#legacy-rest). {synopsis} ## Pre-requisite Readings @@ -41,7 +41,7 @@ In order to enable the REST Server in an SDK application, the `rest.ServeCommand ## Registering Routes -To include routes for each module in an application, the CLI must have some kind of function to register routes in its REST Server. This function is called `RegisterRoutes()`, and is utilized by the `ServeCommand` and must include routes for each of the application's modules. Since each module used by an SDK application implements a [`RegisterRESTRoutes`](../building-modules/module-interfaces.md#rest) function, application developers simply use the [Module Manager](../building-modules/module-manager.md) to call this function for each module (this is done in the [application's constructor](../basics/app-anatomy.md#constructor-function)). +To include routes for each module in an application, the CLI must have some kind of function to register routes in its REST Server. This function is called `RegisterRoutes()`, and is utilized by the `ServeCommand` and must include routes for each of the application's modules. Since each module used by an SDK application implements a [`RegisterRESTRoutes`](../building-modules/module-interfaces.md#legacy-rest) function, application developers simply use the [Module Manager](../building-modules/module-manager.md) to call this function for each module (this is done in the [application's constructor](../basics/app-anatomy.md#constructor-function)). At the bare minimum, a `RegisterRoutes()` function should use the SDK client package `RegisterRoutes()` function to be able to route RPC calls, and instruct the application Module Manager to call `RegisterRESTRoutes()` for all of its modules. This is done in the `main.go` file of the CLI (typically located in `./cmd/appcli/main.go`).