diff --git a/docs/build/building-apps/01-app-go-v2.md b/docs/build/building-apps/01-app-go-v2.md index a0f1b815c..d77899d26 100644 --- a/docs/build/building-apps/01-app-go-v2.md +++ b/docs/build/building-apps/01-app-go-v2.md @@ -7,13 +7,13 @@ sidebar_position: 1 :::note Synopsis The Cosmos SDK allows much easier wiring of an `app.go` thanks to App Wiring and [`depinject`](../packages/01-depinject.md). -Learn more about the rationale of App Wiring in [ADR-057](../../architecture/adr-057-app-wiring.md). +Learn more about the rationale of App Wiring in [ADR-057](../architecture/adr-057-app-wiring.md). ::: :::note Pre-requisite Readings -* [ADR 057: App Wiring](../../architecture/adr-057-app-wiring.md) +* [ADR 057: App Wiring](../architecture/adr-057-app-wiring.md) * [Depinject Documentation](../packages/01-depinject.md) * [Modules depinject-ready](../building-modules/15-depinject.md) diff --git a/docs/build/building-modules/01-module-manager.md b/docs/build/building-modules/01-module-manager.md index e0ab0e54f..ce9c229ce 100644 --- a/docs/build/building-modules/01-module-manager.md +++ b/docs/build/building-modules/01-module-manager.md @@ -5,7 +5,7 @@ sidebar_position: 1 # Module Manager :::note Synopsis -Cosmos SDK modules need to implement the [`AppModule` interfaces](#application-module-interfaces), in order to be managed by the application's [module manager](#module-manager). The module manager plays an important role in [`message` and `query` routing](../../learn/advanced/00-baseapp.md#routing), and allows application developers to set the order of execution of a variety of functions like [`PreBlocker`](../../learn/beginner/00-app-anatomy#preblocker) and [`BeginBlocker` and `EndBlocker`](../../learn/beginner/00-app-anatomy.md#begingblocker-and-endblocker). +Cosmos SDK modules need to implement the [`AppModule` interfaces](#application-module-interfaces), in order to be managed by the application's [module manager](#module-manager). The module manager plays an important role in [`message` and `query` routing](../../learn/advanced/00-baseapp.md#routing), and allows application developers to set the order of execution of a variety of functions like [`PreBlocker`](https://docs.cosmos.network/main/learn/beginner/app-anatomy) and [`BeginBlocker` and `EndBlocker`](https://docs.cosmos.network/main/learn/beginner/app-anatomy). ::: :::note Pre-requisite Readings @@ -27,50 +27,51 @@ For legacy reason modules can still implement interfaces from the SDK `module` p There are 2 main application module interfaces: * [`appmodule.AppModule` / `module.AppModule`](#appmodule) for inter-dependent module functionalities (except genesis-related functionalities). -* (legacy) [`module.AppModuleBasic`](#appmodulebasic) for independent module functionalities. New modules can use `module.CoreAppModuleBasicAdaptor` instead. The above interfaces are mostly embedding smaller interfaces (extension interfaces), that defines specific functionalities: + + * (legacy) `module.HasName`: Allows the module to provide its own name for legacy purposes. * (legacy) [`module.HasGenesisBasics`](#modulehasgenesisbasics): The legacy interface for stateless genesis methods. -* [`module.HasGenesis`](#modulehasgenesis) for inter-dependent genesis-related module functionalities. -* [`module.HasABCIGenesis`](#modulehasabcigenesis) for inter-dependent genesis-related module functionalities. -* [`appmodule.HasGenesis` / `module.HasGenesis`](#appmodulehasgenesis): The extension interface for stateful genesis methods. +* (legacy) [`module.HasGenesis`](#modulehasgenesis) for inter-dependent genesis-related module functionalities. +* (legacy) [`module.HasABCIGenesis`](#modulehasabcigenesis) for inter-dependent genesis-related module functionalities. * [`appmodule.HasPreBlocker`](#haspreblocker): The extension interface that contains information about the `AppModule` and `PreBlock`. * [`appmodule.HasBeginBlocker`](#hasbeginblocker): The extension interface that contains information about the `AppModule` and `BeginBlock`. * [`appmodule.HasEndBlocker`](#hasendblocker): The extension interface that contains information about the `AppModule` and `EndBlock`. -* [`appmodule.HasPrecommit`](#hasprecommit): The extension interface that contains information about the `AppModule` and `Precommit`. -* [`appmodule.HasPrepareCheckState`](#haspreparecheckstate): The extension interface that contains information about the `AppModule` and `PrepareCheckState`. * [`appmodule.HasService` / `module.HasServices`](#hasservices): The extension interface for modules to register services. * [`module.HasABCIEndBlock`](#hasabciendblock): The extension interface that contains information about the `AppModule`, `EndBlock` and returns an updated validator set. * (legacy) [`module.HasInvariants`](#hasinvariants): The extension interface for registering invariants. * (legacy) [`module.HasConsensusVersion`](#hasconsensusversion): The extension interface for declaring a module consensus version. -The `AppModuleBasic` interface exists to define independent methods of the module, i.e. those that do not depend on other modules in the application. This allows for the construction of the basic application structure early in the application definition, generally in the `init()` function of the [main application file](../../learn/beginner/00-app-anatomy.md#core-application-file). - The `AppModule` interface exists to define inter-dependent module methods. Many modules need to interact with other modules, typically through [`keeper`s](./06-keeper.md), which means there is a need for an interface where modules list their `keeper`s and other methods that require a reference to another module's object. `AppModule` interface extension, such as `HasBeginBlocker` and `HasEndBlocker`, also enables the module manager to set the order of execution between module's methods like `BeginBlock` and `EndBlock`, which is important in cases where the order of execution between modules matters in the context of the application. The usage of extension interfaces allows modules to define only the functionalities they need. For example, a module that does not need an `EndBlock` does not need to define the `HasEndBlocker` interface and thus the `EndBlock` method. `AppModule` and `AppModuleGenesis` are voluntarily small interfaces, that can take advantage of the `Module` patterns without having to define many placeholder functions. -### `AppModuleBasic` +### `HasAminoCodec` -:::note -Use `module.CoreAppModuleBasicAdaptor` instead for creating an `AppModuleBasic` from an `appmodule.AppModule`. -::: +```go reference +https://github.com/cosmos/cosmos-sdk/blob/eee5e21e1c8d0995b6d4f83b7f55ec0b58d27ba7/core/appmodule/module.go#L74-L78 +``` -The `AppModuleBasic` interface defines the independent methods modules need to implement. +* `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`. + +### `HasRegisterInterfaces` ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L56-L66 +https://github.com/cosmos/cosmos-sdk/blob/eee5e21e1c8d0995b6d4f83b7f55ec0b58d27ba7/core/appmodule/v2/module.go#L103-L106 ``` -Let us go through the methods: - -* `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`. + +### `HasGRPCGateway` + +```go reference +https://github.com/cosmos/cosmos-sdk/blob/eee5e21e1c8d0995b6d4f83b7f55ec0b58d27ba7/types/module/module.go#L84-L87 +``` + * `RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux)`: Registers gRPC routes for the module. -All the `AppModuleBasic` of an application are managed by the [`BasicManager`](#basicmanager). ### `HasName` @@ -83,7 +84,7 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go ### Genesis :::tip -For easily creating an `AppModule` that only has genesis functionalities, use `module.GenesisOnlyAppModule`. +For easily creating an `AppModule` that only has genesis functionalities, implement `module.HasGenesis/HasABCIGenesis` and `module.HasName`. ::: #### `module.HasGenesisBasics` @@ -102,7 +103,7 @@ Let us go through the methods: `HasGenesis` is an extension interface for allowing modules to implement genesis functionalities. ```go reference -https://github.com/cosmos/cosmos-sdk/blob/6ce2505/types/module/module.go#L184-L189 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8/types/module/module.go#L184-L189 ``` #### `module.HasABCIGenesis` @@ -110,17 +111,7 @@ https://github.com/cosmos/cosmos-sdk/blob/6ce2505/types/module/module.go#L184-L1 `HasABCIGenesis` is an extension interface for allowing modules to implement genesis functionalities and returns validator set updates. ```go reference -https://github.com/cosmos/cosmos-sdk/blob/6ce2505/types/module/module.go#L191-L196 -``` - -#### `appmodule.HasGenesis` - -:::warning -`appmodule.HasGenesis` is experimental and should be considered unstable, it is recommended to not use this interface at this time. -::: - -```go reference -https://github.com/cosmos/cosmos-sdk/blob/6ce2505/core/appmodule/genesis.go#L8-L25 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8/types/module/module.go#L94-L98 ``` ### `AppModule` @@ -131,7 +122,7 @@ The `AppModule` interface defines a module. Modules can declare their functional #### `appmodule.AppModule` ```go reference -https://github.com/cosmos/cosmos-sdk/blob/6afece6/core/appmodule/module.go#L11-L20 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8/core/appmodule/module.go#L11-L20 ``` #### `module.AppModule` @@ -141,7 +132,7 @@ Previously the `module.AppModule` interface was containing all the methods that ::: ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L195-L199 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8/core/appmodule/v2/module.go#L14-L20 ``` ### `HasInvariants` @@ -161,7 +152,7 @@ This interface defines one method. It allows to checks if a module can register #### `appmodule.HasService` ```go reference -https://github.com/cosmos/cosmos-sdk/blob/6afece6/core/appmodule/module.go#L22-L40 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8/core/appmodule/module.go#L22-L40 ``` #### `module.HasServices` @@ -177,7 +168,7 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go This interface defines one method for checking a module consensus version. ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L214-L220 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8/core/appmodule/v2/migrations.go#L6-L12 ``` * `ConsensusVersion() uint64`: Returns the consensus version of the module. @@ -191,96 +182,51 @@ The `HasPreBlocker` is an extension interface from `appmodule.AppModule`. All mo The `HasBeginBlocker` is an extension interface from `appmodule.AppModule`. All modules that have an `BeginBlock` method implement this interface. ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/core/appmodule/module.go#L56-L63 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8dfcb3208d3b1cfbae08eda519e4cc1560/core/appmodule/v2/module.go#L30-L38 ``` * `BeginBlock(context.Context) error`: This method gives module developers the option to implement logic that is automatically triggered at the beginning of each block. ### `HasEndBlocker` -The `HasEndBlocker` is an extension interface from `appmodule.AppModule`. All modules that have an `EndBlock` method implement this interface. If a module need to return validator set updates (staking), they can use `HasABCIEndBlock` +The `HasEndBlocker` is an extension interface from `appmodule.AppModule`. All modules that have an `EndBlock` method implement this interface. If a module needs to return validator set updates (staking), they can use `HasABCIEndBlock` ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/core/appmodule/module.go#L66-L72 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8dfcb3208d3b1cfbae08eda519e4cc1560/core/appmodule/v2/module.go#L40-L48 ``` * `EndBlock(context.Context) error`: This method gives module developers the option to implement logic that is automatically triggered at the end of each block. ### `HasABCIEndBlock` -The `HasABCIEndBlock` is an extension interface from `module.AppModule`. All modules that have an `EndBlock` which return validator set updates implement this interface. +The `HasUpdateValidators` is an extension interface from `module.AppModule`. All modules that have an `EndBlock` which return validator set updates implement this interface. ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L222-L225 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8dfcb3208d3b1cfbae08eda519e4cc1560/core/appmodule/v2/module.go#L87-L94 ``` -* `EndBlock(context.Context) ([]abci.ValidatorUpdate, error)`: This method gives module developers the option to inform the underlying consensus engine of validator set changes (e.g. the `staking` module). +* `UpdateValidators(context.Context) ([]abci.ValidatorUpdate, error)`: This method gives module developers the option to inform the underlying consensus engine of validator set changes (e.g. the `staking` module). -### `HasPrecommit` - -`HasPrecommit` is an extension interface from `appmodule.AppModule`. All modules that have a `Precommit` method implement this interface. - -```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/core/appmodule/module.go#L49-L52 -``` - -* `Precommit(context.Context)`: This method gives module developers the option to implement logic that is automatically triggered during [`Commit'](../../learn/advanced/00-baseapp.md#commit) of each block using the [`finalizeblockstate`](../../learn/advanced/00-baseapp.md#state-updates) of the block to be committed. Implement empty if no logic needs to be triggered during `Commit` of each block for this module. - -### `HasPrepareCheckState` - -`HasPrepareCheckState` is an extension interface from `appmodule.AppModule`. All modules that have a `PrepareCheckState` method implement this interface. - -```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/core/appmodule/module.go#L49-L52 -``` - -* `PrepareCheckState(context.Context)`: This method gives module developers the option to implement logic that is automatically triggered during [`Commit'](../../learn/advanced/00-baseapp.md#commit) of each block using the [`checkState`](../../learn/advanced/00-baseapp.md#state-updates) of the next block. Implement empty if no logic needs to be triggered during `Commit` of each block for this module. ### Implementing the Application Module Interfaces + Typically, the various application module interfaces are implemented in a file called `module.go`, located in the module's folder (e.g. `./x/module/module.go`). -Almost every module needs to implement the `AppModuleBasic` and `AppModule` interfaces. If the module is only used for genesis, it will implement `AppModuleGenesis` instead of `AppModule`. The concrete type that implements the interface can add parameters that are required for the implementation of the various methods of the interface. For example, the `Route()` function often calls a `NewMsgServerImpl(k keeper)` function defined in `keeper/msg_server.go` and therefore needs to pass the module's [`keeper`](./06-keeper.md) as a parameter. +Almost every module needs to implement the `AppModule` interfaces. If the module is only used for genesis, it will implement `AppModuleGenesis` instead of `AppModule`. The concrete type that implements the interface can add parameters that are required for the implementation of the various methods of the interface. ```go // example type AppModule struct { - AppModuleBasic keeper Keeper } ``` In the example above, you can see that the `AppModule` concrete type references an `AppModuleBasic`, and not an `AppModuleGenesis`. That is because `AppModuleGenesis` only needs to be implemented in modules that focus on genesis-related functionalities. In most modules, the concrete `AppModule` type will have a reference to an `AppModuleBasic` and implement the two added methods of `AppModuleGenesis` directly in the `AppModule` type. -If no parameter is required (which is often the case for `AppModuleBasic`), just declare an empty concrete type like so: - -```go -type AppModuleBasic struct{} -``` - -## Module Managers - -Module managers are used to manage collections of `AppModuleBasic` and `AppModule`. - -### `BasicManager` - -The `BasicManager` is a structure that lists all the `AppModuleBasic` of an application: - -```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/module/module.go#L82 -``` - -It implements the following methods: +## Module Manager -* `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`](../../learn/beginner/00-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/main/app/app.go#L59-L74) to see an example). -* `NewBasicManagerFromManager(manager *Manager, customModuleBasics map[string]AppModuleBasic)`: Constructor function. It creates a new `BasicManager` from a `Manager`. The `BasicManager` will contain all `AppModuleBasic` from the `AppModule` manager using `CoreAppModuleBasicAdaptor` whenever possible. Module's `AppModuleBasic` can be overridden by passing a custom AppModuleBasic map -* `RegisterLegacyAminoCodec(cdc *codec.LegacyAmino)`: Registers the [`codec.LegacyAmino`s](../../learn/advanced/05-encoding.md#amino) of each of the application's `AppModuleBasic`. This function is usually called early on in the [application's construction](../../learn/beginner/00-app-anatomy.md#constructor). -* `RegisterInterfaces(registry codectypes.InterfaceRegistry)`: Registers interface types and implementations of each of the application's `AppModuleBasic`. -* `DefaultGenesis(cdc codec.JSONCodec)`: Provides default genesis information for modules in the application by calling the [`DefaultGenesis(cdc codec.JSONCodec)`](./08-genesis.md#defaultgenesis) function of each module. It only calls the modules that implements the `HasGenesisBasics` interfaces. -* `ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesis map[string]json.RawMessage)`: Validates the genesis information modules by calling the [`ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)`](./08-genesis.md#validategenesis) function of modules implementing the `HasGenesisBasics` interface. -* `RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux)`: Registers gRPC routes for modules. -* `AddTxCommands(rootTxCmd *cobra.Command)`: Adds modules' transaction commands (defined as `GetTxCmd() *cobra.Command`) to the application's [`rootTxCommand`](../../learn/advanced/07-cli.md#transaction-commands). This function is usually called function from the `main.go` function of the [application's command-line interface](../../learn/advanced/07-cli.md). -* `AddQueryCommands(rootQueryCmd *cobra.Command)`: Adds modules' query commands (defined as `GetQueryCmd() *cobra.Command`) to the application's [`rootQueryCommand`](../../learn/advanced/07-cli.md#query-commands). This function is usually called function from the `main.go` function of the [application's command-line interface](../../learn/advanced/07-cli.md). +The module manager is used to manage collections of `appmodule.AppModule` and `AppModule` and all the extensions interfaces. ### `Manager` @@ -304,14 +250,19 @@ The module manager is used throughout the application whenever an action on a co * `SetOrderMigrations(moduleNames ...string)`: Sets the order of migrations to be run. If not set then migrations will be run with an order defined in `DefaultMigrationsOrder`. * `RegisterInvariants(ir sdk.InvariantRegistry)`: Registers the [invariants](./07-invariants.md) of module implementing the `HasInvariants` interface. * `RegisterServices(cfg Configurator)`: Registers the services of modules implementing the `HasServices` interface. -* `InitGenesis(ctx context.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage)`: Calls the [`InitGenesis`](./08-genesis.md#initgenesis) function of each module when the application is first started, in the order defined in `OrderInitGenesis`. Returns an `abci.ResponseInitChain` to the underlying consensus engine, which can contain validator updates. -* `ExportGenesis(ctx context.Context, cdc codec.JSONCodec)`: Calls the [`ExportGenesis`](./08-genesis.md#exportgenesis) function of each module, in the order defined in `OrderExportGenesis`. The export constructs a genesis file from a previously existing state, and is mainly used when a hard-fork upgrade of the chain is required. -* `ExportGenesisForModules(ctx context.Context, cdc codec.JSONCodec, modulesToExport []string)`: Behaves the same as `ExportGenesis`, except takes a list of modules to export. +* `InitGenesis(ctx context.Context, genesisData map[string]json.RawMessage)`: Calls the [`InitGenesis`](./08-genesis.md#initgenesis) function of each module when the application is first started, in the order defined in `OrderInitGenesis`. Returns an `abci.InitChainResponse` to the underlying consensus engine, which can contain validator updates. +* `ExportGenesis(ctx context.Context)`: Calls the [`ExportGenesis`](./08-genesis.md#exportgenesis) function of each module, in the order defined in `OrderExportGenesis`. The export constructs a genesis file from a previously existing state, and is mainly used when a hard-fork upgrade of the chain is required. +* `ExportGenesisForModules(ctx context.Context, modulesToExport []string)`: Behaves the same as `ExportGenesis`, except takes a list of modules to export. * `BeginBlock(ctx context.Context) error`: At the beginning of each block, this function is called from [`BaseApp`](../../learn/advanced/00-baseapp.md#beginblock) and, in turn, calls the [`BeginBlock`](./06-beginblock-endblock.md) function of each modules implementing the `appmodule.HasBeginBlocker` interface, in the order defined in `OrderBeginBlockers`. It creates a child [context](../../learn/advanced/02-context.md) with an event manager to aggregate [events](../../learn/advanced/08-events.md) emitted from each modules. * `EndBlock(ctx context.Context) error`: At the end of each block, this function is called from [`BaseApp`](../../learn/advanced/00-baseapp.md#endblock) and, in turn, calls the [`EndBlock`](./06-beginblock-endblock.md) function of each modules implementing the `appmodule.HasEndBlocker` interface, in the order defined in `OrderEndBlockers`. It creates a child [context](../../learn/advanced/02-context.md) with an event manager to aggregate [events](../../learn/advanced/08-events.md) emitted from all modules. The function returns an `abci` which contains the aforementioned events, as well as validator set updates (if any). * `EndBlock(context.Context) ([]abci.ValidatorUpdate, error)`: At the end of each block, this function is called from [`BaseApp`](../../learn/advanced/00-baseapp.md#endblock) and, in turn, calls the [`EndBlock`](./06-beginblock-endblock.md) function of each modules implementing the `module.HasABCIEndBlock` interface, in the order defined in `OrderEndBlockers`. It creates a child [context](../../learn/advanced/02-context.md) with an event manager to aggregate [events](../../learn/advanced/08-events.md) emitted from all modules. The function returns an `abci` which contains the aforementioned events, as well as validator set updates (if any). * `Precommit(ctx context.Context)`: During [`Commit`](../../learn/advanced/00-baseapp.md#commit), this function is called from `BaseApp` immediately before the [`deliverState`](../../learn/advanced/00-baseapp.md#state-updates) is written to the underlying [`rootMultiStore`](../../learn/advanced/04-store.md#commitmultistore) and, in turn calls the `Precommit` function of each modules implementing the `HasPrecommit` interface, in the order defined in `OrderPrecommiters`. It creates a child [context](../../learn/advanced/02-context.md) where the underlying `CacheMultiStore` is that of the newly committed block's [`finalizeblockstate`](../../learn/advanced/00-baseapp.md#state-updates). * `PrepareCheckState(ctx context.Context)`: During [`Commit`](../../learn/advanced/00-baseapp.md#commit), this function is called from `BaseApp` immediately after the [`deliverState`](../../learn/advanced/00-baseapp.md#state-updates) is written to the underlying [`rootMultiStore`](../../learn/advanced/04-store.md#commitmultistore) and, in turn calls the `PrepareCheckState` function of each module implementing the `HasPrepareCheckState` interface, in the order defined in `OrderPrepareCheckStaters`. It creates a child [context](../../learn/advanced/02-context.md) where the underlying `CacheMultiStore` is that of the next block's [`checkState`](../../learn/advanced/00-baseapp.md#state-updates). Writes to this state will be present in the [`checkState`](../../learn/advanced/00-baseapp.md#state-updates) of the next block, and therefore this method can be used to prepare the `checkState` for the next block. +* (Optional) `RegisterLegacyAminoCodec(cdc *codec.LegacyAmino)`: Registers the [`codec.LegacyAmino`s](../../learn/advanced/05-encoding.md#amino) of each of the application module. This function is usually called early on in the [application's construction](../../learn/beginner/00-app-anatomy.md#constructor). +* `RegisterInterfaces(registry codectypes.InterfaceRegistry)`: Registers interface types and implementations of each of the application's `AppModule`. +* (Optional) `RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux)`: Registers gRPC routes for modules. +* `DefaultGenesis(cdc codec.JSONCodec)`: Provides default genesis information for modules in the application by calling the [`DefaultGenesis(cdc codec.JSONCodec)`](./08-genesis.md#defaultgenesis) function of each module. It only calls the modules that implements the `HasGenesisBasics` interfaces. +* `ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesis map[string]json.RawMessage)`: Validates the genesis information modules by calling the [`ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage)`](./08-genesis.md#validategenesis) function of modules implementing the `HasGenesisBasics` interface. Here's an example of a concrete integration within an `simapp`: diff --git a/docs/build/building-modules/02-messages-and-queries.md b/docs/build/building-modules/02-messages-and-queries.md index 5c97401b9..4dfeae41e 100644 --- a/docs/build/building-modules/02-messages-and-queries.md +++ b/docs/build/building-modules/02-messages-and-queries.md @@ -25,7 +25,7 @@ When a transaction is relayed from the underlying consensus engine to the Cosmos Defining Protobuf `Msg` services is the recommended way to handle messages. A Protobuf `Msg` service should be created for each module, typically in `tx.proto` (see more info about [conventions and naming](../../learn/advanced/05-encoding.md#faq)). It must have an RPC service method defined for each message in the module. -Each `Msg` service method must have exactly one argument, which must implement the `sdk.Msg` interface, and a Protobuf response. The naming convention is to call the RPC argument `Msg` and the RPC response `MsgResponse`. For example: +Each `Msg` service method must have exactly one argument, which must implement the `transaction.Msg` interface, and a Protobuf response. The naming convention is to call the RPC argument `Msg` and the RPC response `MsgResponse`. For example: ```protobuf rpc Send(MsgSend) returns (MsgSendResponse); @@ -34,14 +34,18 @@ Each `Msg` service method must have exactly one argument, which must implement t See an example of a `Msg` service definition from `x/bank` module: ```protobuf reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/proto/cosmos/bank/v1beta1/tx.proto#L13-L36 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8/x/bank/proto/cosmos/bank/v1beta1/tx.proto#L13-L41 ``` -### `sdk.Msg` Interface +### `transaction.Msg` Interface -`sdk.Msg` is a alias of `proto.Message`. +`transaction.Msg` is an alias of `proto.Message`. -To attach a `ValidateBasic()` method to a message then you must add methods to the type adhereing to the `HasValidateBasic`. +```go reference +https://github.com/cosmos/cosmos-sdk/blob/main/core/transaction/transaction.go#L8 +``` + +To attach a `ValidateBasic()` method to a message, then you must add methods to the type adhereing to the `HasValidateBasic`. ```go reference https://github.com/cosmos/cosmos-sdk/blob/9c1e8b247cd47b5d3decda6e86fbc3bc996ee5d7/types/tx_msg.go#L84-L88 @@ -105,26 +109,6 @@ As `proto.Message`s, generated `Response` types implement by default `String()` A `RegisterQueryServer` method is also generated and should be used to register the module's query server in the `RegisterServices` method from the [`AppModule` interface](./01-module-manager.md#appmodule). -### Legacy Queries - -Before the introduction of Protobuf and gRPC in the Cosmos SDK, there was usually no specific `query` object defined by module developers, contrary to `message`s. Instead, the Cosmos 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 to process it. For most module queries, the `path` should look like the following: - -```text -queryCategory/queryRoute/queryType/arg1/arg2/... -``` - -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](../../learn/advanced/00-baseapp.md#query). -* `queryRoute` is used by `BaseApp`'s [`queryRouter`](../../learn/advanced/00-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`](./04-query-services.md#legacy-queriers) to map the `query` to the appropriate `querier function` within the module. -* `args` are the actual arguments needed to process the `query`. They are filled out by the end-user. Note that for bigger queries, you might prefer passing arguments in the `Data` field of the request `req` instead of the `path`. - -The `path` for each `query` must be defined by the module developer in the module's [command-line interface file](./09-module-interfaces.md#query-commands).Overall, there are 3 mains components module developers need to implement in order to make the subset of the state defined by their module queryable: - -* A [`querier`](./04-query-services.md#legacy-queriers), to process the `query` once it has been [routed to the module](../../learn/advanced/00-baseapp.md#query-routing). -* [Query commands](./09-module-interfaces.md#query-commands) in the module's CLI file, where the `path` for each `query` is specified. -* `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://pkg.go.dev/fmt#Stringer). ### Store Queries diff --git a/docs/build/building-modules/03-msg-services.md b/docs/build/building-modules/03-msg-services.md index 83f8f6e70..99725182a 100644 --- a/docs/build/building-modules/03-msg-services.md +++ b/docs/build/building-modules/03-msg-services.md @@ -19,27 +19,35 @@ A Protobuf `Msg` service processes [messages](./02-messages-and-queries.md#messa Each module should define a Protobuf `Msg` service, which will be responsible for processing requests (implementing `sdk.Msg`) and returning responses. -As further described in [ADR 031](../../architecture/adr-031-msg-service.md), this approach has the advantage of clearly specifying return types and generating server and client code. +As further described in [ADR 031](../architecture/adr-031-msg-service.md), this approach has the advantage of clearly specifying return types and generating server and client code. -Protobuf generates a `MsgServer` interface based on a definition of `Msg` service. It is the role of the module developer to implement this interface, by implementing the state transition logic that should happen upon receival of each `sdk.Msg`. As an example, here is the generated `MsgServer` interface for `x/bank`, which exposes two `sdk.Msg`s: +Protobuf generates a `MsgServer` interface based on the definition of `Msg` service. It is the role of the module developer to implement this interface, by implementing the state transition logic that should happen upon receival of each `transaction.Msg`. As an example, here is the generated `MsgServer` interface for `x/bank`, which exposes two `transaction.Msg`s: ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/bank/types/tx.pb.go#L550-L568 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8/x/bank/types/tx.pb.go#L564-L579 ``` When possible, the existing module's [`Keeper`](./06-keeper.md) should implement `MsgServer`, otherwise a `msgServer` struct that embeds the `Keeper` can be created, typically in `./keeper/msg_server.go`: ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/bank/keeper/msg_server.go#L17-L19 +https://github.com/cosmos/cosmos-sdk/blob/28fa3b8/x/bank/keeper/msg_server.go#L16-L19 ``` -`msgServer` methods can retrieve the `context.Context` from the `context.Context` parameter method using the `sdk.UnwrapSDKContext`: +`msgServer` methods can retrieve the auxiliary information or services using the environment variable, it is always located in the keeper: + +Environment: + +```go reference +https://github.com/cosmos/cosmos-sdk/blob/07151304e2ec6a185243d083f59a2d543253cb15/core/appmodule/v2/environment.go#L14-L29 +``` + +Keeper Example: ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/bank/keeper/msg_server.go#L56 +https://github.com/cosmos/cosmos-sdk/blob/07151304e2ec6a185243d083f59a2d543253cb15/x/bank/keeper/keeper.go#L56-L58 ``` -`sdk.Msg` processing usually follows these 3 steps: +`transaction.Msg` processing usually follows these 3 steps: ### Validation @@ -71,14 +79,18 @@ After the validation is successful, the `msgServer` method uses the [`keeper`](. ### Events -Before returning, `msgServer` methods generally emit one or more [events](../../learn/advanced/08-events.md) by using the `EventManager` held in the `ctx`. Use the new `EmitTypedEvent` function that uses protobuf-based event types: +Before returning, `msgServer` methods generally emit one or more [events](../../learn/advanced/08-events.md) by using the `EventManager` held in `environment`. + +There are two ways to emit events, typed events using protobuf or arbitrary key & values. + +Typed Events: ```go ctx.EventManager().EmitTypedEvent( &group.EventABC{Key1: Value1, Key2, Value2}) ``` -or the older `EmitEvent` function: +Arbitrary Events: ```go ctx.EventManager().EmitEvent( @@ -98,7 +110,7 @@ The invoked `msgServer` method returns a `proto.Message` response and an `error` https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/baseapp/msg_service_router.go#L160 ``` -This method takes care of marshaling the `res` parameter to protobuf and attaching any events on the `ctx.EventManager()` to the `sdk.Result`. +This method takes care of marshaling the `res` parameter to protobuf and attaching any events on the `EventManager()` to the `sdk.Result`. ```protobuf reference https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/proto/cosmos/base/abci/v1beta1/abci.proto#L93-L113 @@ -106,7 +118,37 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/proto/cosmos/base/abci This diagram shows a typical structure of a Protobuf `Msg` service, and how the message propagates through the module. -![Transaction flow](https://raw.githubusercontent.com/cosmos/cosmos-sdk/release/v0.46.x/docs/uml/svg/transaction_flow.svg) +```mermaid +sequenceDiagram + participant User + participant baseApp + participant router + participant handler + participant msgServer + participant keeper + participant EventManager + + User->>baseApp: Transaction Type + baseApp->>router: Route(ctx, msgRoute) + router->>handler: handler + handler->>msgServer: Msg(Context, Msg(..)) + + alt addresses invalid, denominations wrong, etc. + msgServer->>handler: error + handler->>router: error + router->>baseApp: result, error code + else + msgServer->>keeper: perform action, update context + keeper->>msgServer: results, error code + msgServer->>EventManager: Emit relevant events + msgServer->>msgServer: maybe wrap results in more structure + msgServer->>handler: result, error code + handler->>router: result, error code + router->>baseApp: result, error code + end + + baseApp->>User: result, error code +``` ## Telemetry @@ -117,3 +159,7 @@ This is an example from the `x/auth/vesting` module: ```go reference https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/auth/vesting/msg_server.go#L76-L88 ``` + +:::Warning +Telemetry adds a performance overhead to the chain. It is recommended to only use this in critical paths +::: diff --git a/docs/build/building-modules/06-beginblock-endblock.md b/docs/build/building-modules/06-beginblock-endblock.md index a8eafdf67..51b72b7f0 100644 --- a/docs/build/building-modules/06-beginblock-endblock.md +++ b/docs/build/building-modules/06-beginblock-endblock.md @@ -26,9 +26,9 @@ The actual implementation of `BeginBlocker` and `EndBlocker` in `abci.go` are ve * They generally use the [`keeper`](./06-keeper.md) and [`ctx`](../../learn/advanced/02-context.md) to retrieve information about the latest state. * If needed, they use the `keeper` and `ctx` to trigger state-transitions. -* If needed, they can emit [`events`](../../learn/advanced/08-events.md) via the `ctx`'s `EventManager`. +* If needed, they can emit [`events`](../../learn/advanced/08-events.md) via the `environments`'s `EventManager`. -A specific type of `EndBlocker` is available to return validator updates to the underlying consensus engine in the form of an [`[]abci.ValidatorUpdates`](https://docs.cometbft.com/v0.37/spec/abci/abci++_methods#endblock). This is the preferred way to implement custom validator changes. +A specific method (`UpdateValidators`) is available to return validator updates to the underlying consensus engine in the form of an [`[]appmodule.ValidatorUpdates`](https://github.com/cosmos/cosmos-sdk/blob/07151304e2ec6a185243d083f59a2d543253cb15/core/appmodule/v2/module.go#L87-L101). This is the preferred way to implement custom validator changes. It is possible for developers to define the order of execution between the `BeginBlocker`/`EndBlocker` functions of each of their application's modules via the module's manager `SetOrderBeginBlocker`/`SetOrderEndBlocker` methods. For more on the module manager, click [here](./01-module-manager.md#manager). diff --git a/docs/build/building-modules/06-keeper.md b/docs/build/building-modules/06-keeper.md index 491c732d8..1302a46d6 100644 --- a/docs/build/building-modules/06-keeper.md +++ b/docs/build/building-modules/06-keeper.md @@ -47,7 +47,7 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/staking/keeper/keepe 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 an `expected_keepers.go` file in the root of 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](../../learn/advanced/04-store.md) managed by the module. They should always remain unexposed to external modules. +* `KVStoreService`s grant access to the store(s) of the [multistore](../../learn/advanced/04-store.md) managed by the module. They should always remain unexposed to external modules. * `cdc` is the [codec](../../learn/advanced/05-encoding.md) used to marshall and unmarshall structs to/from `[]byte`. The `cdc` can be any of `codec.BinaryCodec`, `codec.JSONCodec` or `codec.Codec` based on your requirements. It can be either a proto or amino codec as long as they implement these interfaces. * The authority listed is a module account or user account that has the right to change module level parameters. Previously this was handled by the param module, which has been deprecated. @@ -55,38 +55,8 @@ Of course, it is possible to define different types of internal `keeper`s for th ## Implementing Methods -`Keeper`s primarily expose getter and setter methods for the store(s) managed by their module. These methods should remain as simple as possible and strictly be limited to getting or setting the requested value, as validity checks should have already been performed by the [`Msg` server](./03-msg-services.md) when `keeper`s' methods are called. +`Keeper`s primarily expose methods for business logic, as validity checks should have already been performed by the [`Msg` server](./03-msg-services.md) when `keeper`s' methods are called. -Typically, a *getter* method will have the following signature - -```go -func (k Keeper) Get(ctx context.Context, key string) returnType -``` - -and the method will 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`. Then it's preferred 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. - -Similarly, a *setter* method will have the following signature - -```go -func (k Keeper) Set(ctx context.Context, key string, value valueType) -``` - -and the method will 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`. It's preferred 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 `staking` module](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/staking/keeper/keeper.go). - -The [module `KVStore`](../../learn/advanced/04-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: - -```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/auth/keeper/account.go -``` + +State management is recommended to be done via [Collections](../packages/collections) + diff --git a/docs/build/building-modules/07-invariants.md b/docs/build/building-modules/07-invariants.md index 018796f71..2e8edfcad 100644 --- a/docs/build/building-modules/07-invariants.md +++ b/docs/build/building-modules/07-invariants.md @@ -4,6 +4,8 @@ sidebar_position: 1 # Invariants + + :::note Synopsis An invariant is a property of the application that should always be true. In the context of the Cosmos SDK, an `Invariant` is a function that checks for a particular invariant. These functions are useful to detect bugs early on and act upon them to limit their potential consequences (e.g. by halting the chain). They are also useful in the development process of the application to detect bugs via simulations. ::: diff --git a/docs/build/building-modules/08-genesis.md b/docs/build/building-modules/08-genesis.md index 7abb21fb6..b7b35478b 100644 --- a/docs/build/building-modules/08-genesis.md +++ b/docs/build/building-modules/08-genesis.md @@ -56,7 +56,7 @@ The [module manager](./01-module-manager.md#manager) of the application is respo See an example of `InitGenesis` from the `auth` module: ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/auth/keeper/genesis.go#L8-L35 +https://github.com/cosmos/cosmos-sdk/blob/452129d6aa45134f598f05be13f3fd961ff9734e/x/auth/keeper/genesis.go#L12-L43 ``` ### `ExportGenesis` @@ -66,7 +66,7 @@ The `ExportGenesis` method is executed whenever an export of the state is made. See an example of `ExportGenesis` from the `auth` module. ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/auth/keeper/genesis.go#L37-L49 +https://github.com/cosmos/cosmos-sdk/blob/452129d6aa45134f598f05be13f3fd961ff9734e/x/auth/keeper/genesis.go#L45-L60 ``` ### GenesisTxHandler diff --git a/docs/build/building-modules/11-structure.md b/docs/build/building-modules/11-structure.md index 678c740db..6b66f5380 100644 --- a/docs/build/building-modules/11-structure.md +++ b/docs/build/building-modules/11-structure.md @@ -2,10 +2,12 @@ sidebar_position: 1 --- -# Recommended Folder Structure +# Folder Structure :::note Synopsis -This document outlines the recommended structure of Cosmos SDK modules. These ideas are meant to be applied as suggestions. Application developers are encouraged to improve upon and contribute to module structure and development design. +This document outlines the structure of Cosmos SDK modules. These ideas are meant to be applied as suggestions. Application developers are encouraged to improve upon and contribute to module structure and development design. + +The required interface for a module is located in the module.go. Everything beyond this is suggestive. ::: ## Structure @@ -18,14 +20,12 @@ proto    └── {module_name}    └── {proto_version}       ├── {module_name}.proto -       ├── event.proto       ├── genesis.proto       ├── query.proto       └── tx.proto ``` * `{module_name}.proto`: The module's common message type definitions. -* `event.proto`: The module's message type definitions related to events. * `genesis.proto`: The module's message type definitions related to genesis state. * `query.proto`: The module's Query service and related message type definitions. * `tx.proto`: The module's Msg service and related message type definitions. @@ -79,11 +79,11 @@ x/{module_name} * `client/`: The module's CLI client functionality implementation and the module's CLI testing suite. * `exported/`: The module's exported types - typically interface types. If a module relies on keepers from another module, it is expected to receive the keepers as interface contracts through the `expected_keepers.go` file (see below) in order to avoid a direct dependency on the module implementing the keepers. However, these interface contracts can define methods that operate on and/or return types that are specific to the module that is implementing the keepers and this is where `exported/` comes into play. The interface types that are defined in `exported/` use canonical types, allowing for the module to receive the keepers as interface contracts through the `expected_keepers.go` file. This pattern allows for code to remain DRY and also alleviates import cycle chaos. * `keeper/`: The module's `Keeper` and `MsgServer` implementation. -* `module/`: The module's `AppModule` implementation. * `abci.go`: The module's `BeginBlocker` and `EndBlocker` implementations (this file is only required if `BeginBlocker` and/or `EndBlocker` need to be defined). +* `module/`: The module's `AppModule` implementation. * `autocli.go`: The module [autocli](https://docs.cosmos.network/main/core/autocli) options. * `simulation/`: The module's [simulation](./14-simulator.md) package defines functions used by the blockchain simulator application (`simapp`). -* `README.md`: The module's specification documents outlining important concepts, state storage structure, and message and event type definitions. Learn more how to write module specs in the [spec guidelines](../../spec/SPEC_MODULE.md). +* `README.md`: The module's specification documents outlining important concepts, state storage structure, and message and event type definitions. Learn more how to write module specs in the [spec guidelines](../spec/SPEC_MODULE.md). * The root directory includes type definitions for messages, events, and genesis state, including the type definitions generated by Protocol Buffers. * `codec.go`: The module's registry methods for interface types. * `errors.go`: The module's sentinel errors. diff --git a/docs/build/building-modules/12-errors.md b/docs/build/building-modules/12-errors.md index 214ab70e8..b6935e626 100644 --- a/docs/build/building-modules/12-errors.md +++ b/docs/build/building-modules/12-errors.md @@ -10,8 +10,13 @@ This document outlines the recommended usage and APIs for error handling in Cosm Modules are encouraged to define and register their own errors to provide better context on failed message or handler execution. Typically, these errors should be -common or general errors which can be further wrapped to provide additional specific -execution context. +common or general errors which can be further wrapped to provide additional specific execution context. + +There are two ways to return errors. You can register custom errors with a codespace that is meant to provide more information to clients and normal go errors. The Cosmos SDK uses a mixture of both. + +:::Warning +If errors are registered they are part of consensus and cannot be changed in a minor release +::: ## Registration @@ -32,13 +37,10 @@ necessarily have to be. The only restrictions on error codes are the following: * Must be greater than one, as a code value of one is reserved for internal errors. * Must be unique within the module. -Note, the Cosmos SDK provides a core set of *common* errors. These errors are defined in [`types/errors/errors.go`](https://github.com/cosmos/cosmos-sdk/blob/main/types/errors/errors.go). - ## Wrapping The custom module errors can be returned as their concrete type as they already fulfill the `error` -interface. However, module errors can be wrapped to provide further context and meaning to failed -execution. +interface. However, module errors can be wrapped to provide further context and meaning to failed execution. Example: @@ -46,9 +48,6 @@ Example: https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/bank/keeper/keeper.go#L141-L182 ``` -Regardless if an error is wrapped or not, the Cosmos SDK's `errors` package provides a function to determine if -an error is of a particular kind via `Is`. - ## ABCI If a module error is registered, the Cosmos SDK `errors` package allows ABCI information to be extracted diff --git a/docs/build/building-modules/13-upgrade.md b/docs/build/building-modules/13-upgrade.md index 5cdce2b44..fc3dc384b 100644 --- a/docs/build/building-modules/13-upgrade.md +++ b/docs/build/building-modules/13-upgrade.md @@ -62,4 +62,4 @@ func (m Migrator) Migrate1to2(ctx sdk.Context) error { } ``` -To see example code of changes that were implemented in a migration of balance keys, check out [migrateBalanceKeys](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/bank/migrations/v2/store.go#L55-L76). For context, this code introduced migrations of the bank store that updated addresses to be prefixed by their length in bytes as outlined in [ADR-028](../../architecture/adr-028-public-key-addresses.md). +To see example code of changes that were implemented in a migration of balance keys, check out [migrateBalanceKeys](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/bank/migrations/v2/store.go#L55-L76). For context, this code introduced migrations of the bank store that updated addresses to be prefixed by their length in bytes as outlined in [ADR-028](../architecture/adr-028-public-key-addresses.md). diff --git a/docs/build/building-modules/14-simulator.md b/docs/build/building-modules/14-simulator.md index fe337edb8..0d8b4c5a8 100644 --- a/docs/build/building-modules/14-simulator.md +++ b/docs/build/building-modules/14-simulator.md @@ -71,6 +71,7 @@ Here is how one can override the above package `simappparams`. ```go reference https://github.com/cosmos/cosmos-sdk/blob/release/v0.51.x/Makefile#L292-L334 ``` + The SDK simulations can be executed like normal tests in Go from the shell or within an IDE. Make sure that you pass the `-tags='sims` parameter to enable them and other params that make sense for your scenario. @@ -133,4 +134,4 @@ can be done at a high level with the deterministic pseudo random number generato ```go reference https://github.com/cosmos/cosmos-sdk/blob/release/v0.51.x/Makefile#L352-L355 -``` \ No newline at end of file +``` diff --git a/docs/build/building-modules/17-preblock.md b/docs/build/building-modules/17-preblock.md index a79646bd4..81c81bd94 100644 --- a/docs/build/building-modules/17-preblock.md +++ b/docs/build/building-modules/17-preblock.md @@ -18,14 +18,7 @@ sidebar_position: 1 There are two semantics around the new lifecycle method: -- It runs before the `BeginBlocker` of all modules -- It can modify consensus parameters in storage, and signal the caller through the return value. +* It runs before the `BeginBlocker` of all modules +* It can modify consensus parameters in storage, and signal the caller through the return value. -When it returns `ConsensusParamsChanged=true`, the caller must refresh the consensus parameter in the deliver context: -``` -app.finalizeBlockState.ctx = app.finalizeBlockState.ctx.WithConsensusParams(app.GetConsensusParams()) -``` - -The new ctx must be passed to all the other lifecycle methods. - - +Modules are required to get the consensus params from the consensus module. Consensus params located in `sdk.Context` were deprecated and should be treated as unsafe. `sdk.Context` is deprecated due to it being a global state within the entire state machine, it has been replaced with `appmodule.Environment`. diff --git a/docs/build/migrations/02-upgrading.md b/docs/build/migrations/02-upgrading.md index e99c120b0..64f8b5678 100644 --- a/docs/build/migrations/02-upgrading.md +++ b/docs/build/migrations/02-upgrading.md @@ -476,7 +476,7 @@ Use `confix` to clean-up your `app.toml`. A nginx (or alike) reverse-proxy can b #### Database Support -ClevelDB, BoltDB and BadgerDB are not supported anymore. To migrate from a unsupported database to a supported database please use a database migration tool. +ClevelDB, BoltDB and BadgerDB are not supported anymore. To migrate from an unsupported database to a supported database please use a database migration tool. ### Protobuf @@ -1219,7 +1219,7 @@ mistakes. #### `x/params` -* The `x/params` module has been deprecated in favour of each module housing and providing way to modify their parameters. Each module that has parameters that are changeable during runtime have an authority, the authority can be a module or user account. The Cosmos SDK team recommends migrating modules away from using the param module. An example of how this could look like can be found [here](https://github.com/cosmos/cosmos-sdk/pull/12363). +* The `x/params` module has been deprecated in favour of each module housing and providing way to modify their parameters. Each module that has parameters that are changeable during runtime has an authority, the authority can be a module or user account. The Cosmos SDK team recommends migrating modules away from using the param module. An example of how this could look like can be found [here](https://github.com/cosmos/cosmos-sdk/pull/12363). * The Param module will be maintained until April 18, 2023. At this point the module will reach end of life and be removed from the Cosmos SDK. #### `x/gov` @@ -1232,11 +1232,11 @@ More information can be found in the gov module [client documentation](https://d #### `x/staking` -The `staking module` added a new message type to cancel unbonding delegations. Users that have unbonded by accident or wish to cancel a undelegation can now specify the amount and valdiator they would like to cancel the unbond from +The `staking module` added a new message type to cancel unbonding delegations. Users that have unbonded by accident or wish to cancel an undelegation can now specify the amount and validator they would like to cancel the unbond from ### Protobuf -The `third_party/proto` folder that existed in [previous version](https://github.com/cosmos/cosmos-sdk/tree/v0.45.3/third_party/proto) now does not contains directly the [proto files](https://github.com/cosmos/cosmos-sdk/tree/release/v0.46.x/third_party/proto). +The `third_party/proto` folder that existed in [previous version](https://github.com/cosmos/cosmos-sdk/tree/v0.45.3/third_party/proto) now does not contain directly the [proto files](https://github.com/cosmos/cosmos-sdk/tree/release/v0.46.x/third_party/proto). Instead, the SDK uses [`buf`](https://buf.build). Clients should have their own [`buf.yaml`](https://docs.buf.build/configuration/v1/buf-yaml) with `buf.build/cosmos/cosmos-sdk` as dependency, in order to avoid having to copy paste these files. diff --git a/docs/learn/advanced/00-baseapp.md b/docs/learn/advanced/00-baseapp.md index f19c13299..418ec64d3 100644 --- a/docs/learn/advanced/00-baseapp.md +++ b/docs/learn/advanced/00-baseapp.md @@ -311,6 +311,8 @@ Unconfirmed transactions are relayed to peers only if they pass `CheckTx`. `CheckTx()` can perform both _stateful_ and _stateless_ checks, but developers should strive to make the checks **lightweight** because gas fees are not charged for the resources (CPU, data load...) used during the `CheckTx`. +The [`Context`](../advanced/02-context.md), which includes a `GasMeter` that tracks how much gas is used during the execution of `Tx`, is initialized at the beginning of `CheckTx`. The user-provided amount of gas for `Tx` is referred to as `GasWanted`. If `GasConsumed`, the amount of gas used during execution, exceeds `GasWanted`, the execution is halted and the changes made to the cached copy of the state are not committed. Otherwise, `CheckTx` sets `GasUsed` equal to `GasConsumed` and returns it in the result. After calculating the gas and fee values, validator-nodes ensure that the user-specified `gas-prices` exceed their locally defined `min-gas-prices`. + In the Cosmos SDK, after [decoding transactions](https://docs.cosmos.network/main/learn/advanced/encoding), `CheckTx()` is implemented to do the following checks: @@ -388,17 +390,25 @@ Finally, the [`RunMsgs()`](#runmsgs) function is called to process the `sdk.Msg` ### AnteHandler -The `AnteHandler` is a special handler that implements the `AnteHandler` interface and is used to authenticate the transaction before the transaction's internal messages are processed. +The `AnteHandler` is a special handler that implements the `AnteHandler` interface and is used to authenticate the transaction before the transaction's internal messages are processed. It is theoretically optional but serves as a crucial component in most public blockchain networks. -```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/types/handler.go#L6-L8 -``` +The `AnteHandler` operates on a copy of the cached context, allowing it to perform stateful checks such as signature verification, sequence number incrementation, and fee deduction without altering the last committed state. If the execution fails, it can revert to the original state, ensuring that only successful transactions modify the blockchain state. + +Key operations performed by the `AnteHandler` include: + +- **Signature Verification**: Ensures that the transaction's signatures are valid. +- **Sequence Checking**: Verifies and increments the sequence numbers to prevent replay attacks. +- **Fee Deduction**: Deducts the transaction fees from the accounts involved, typically starting with the first signer. -The `AnteHandler` is theoretically optional, but still a very important component of public blockchain networks. It serves 3 primary purposes: +These operations are crucial for maintaining the security and integrity of transactions on the blockchain. -* Be a primary line of defense against spam and second line of defense (the first one being the mempool) against transaction replay with fees deduction and [`sequence`](./01-transactions.md#transaction-generation) checking. -* Perform preliminary _stateful_ validity checks like ensuring signatures are valid or that the sender has enough funds to pay for fees. -* Play a role in the incentivisation of stakeholders via the collection of transaction fees. +For more detailed examples, see the [`auth` module's `AnteHandler`](https://github.com/cosmos/cosmos-sdk/tree/main/x/auth) which is widely used for these purposes. + +:::warning +Ante handlers typically operate at the transaction level. By default, they process only the outermost message of a transaction. However, transactions that embed multiple messages, such as those found in modules like x/authz or x/gov, may have inner messages that are not automatically processed by these default ante handlers. These inner messages are generally routed directly to the [message router](https://docs.cosmos.network/main/learn/advanced/baseapp#msg-service-router) bypassing the ante handlers. To ensure comprehensive processing, custom ante handlers can be designed to recursively inspect and apply necessary checks to all embedded messages within a transaction. This capability must be explicitly implemented to extend the awareness of ante handlers to inner messages. +::: + +The `AnteHandler` is a primary line of defense against spam and a second line of defense (the first one being the mempool) against transaction replay with fees deduction and [`sequence`](./01-transactions.md#transaction-generation) checking. It also performs preliminary _stateful_ validity checks like ensuring signatures are valid or that the sender has enough funds to pay for fees, and plays a role in the incentivisation of stakeholders via the collection of transaction fees. `BaseApp` holds an `anteHandler` as parameter that is initialized in the [application's constructor](../beginner/00-app-anatomy.md#application-constructor). The most widely used `anteHandler` is the [`auth` module](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/x/auth/ante/ante.go). @@ -408,6 +418,10 @@ Click [here](../beginner/04-gas-fees.md#antehandler) for more on the `anteHandle `RunMsgs` is called from `RunTx` with `runTxModeCheck` as parameter to check the existence of a route for each message the transaction, and with `execModeFinalize` to actually process the `sdk.Msg`s. +`FinalizeBlock`, calls [`runMsgs`](../advanced/00-baseapp.md#runtx-antehandler-runmsgs-posthandler) to fully execute each `Msg` within the transaction. Since the transaction may have messages from different modules, `BaseApp` needs to know which module to find the appropriate handler. This is achieved using `BaseApp`'s `MsgServiceRouter` so that it can be processed by the module's Protobuf [`Msg` service](../../build/building-modules/03-msg-services.md). + +For `LegacyMsg` routing, the `Route` function is called via the [module manager](../../build/building-modules/01-module-manager.md) to retrieve the route name and find the legacy [`Handler`](../../build/building-modules/03-msg-services.md#handler-type) within the module. + First, it retrieves the `sdk.Msg`'s fully-qualified type name, by checking the `type_url` of the Protobuf `Any` representing the `sdk.Msg`. Then, using the application's [`msgServiceRouter`](#msg-service-router), it checks for the existence of `Msg` service method related to that `type_url`. At this point, if `mode == runTxModeCheck`, `RunMsgs` returns. Otherwise, if `mode == execModeFinalize`, the [`Msg` service](../../build/building-modules/03-msg-services.md) RPC is executed, before `RunMsgs` returns. ### PostHandler @@ -468,8 +482,16 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/baseapp/abci.go#L623 When the underlying consensus engine receives a block proposal, each transaction in the block needs to be processed by the application. To that end, the underlying consensus engine sends the transactions in FinalizeBlock message to the application for each transaction in a sequential order. +Since `FinalizeBlock` is an ABCI call, `Tx` is received in the encoded `[]byte` form. Nodes first unmarshal the transaction, using the [`TxConfig`](./00-app-anatomy.md#register-codec) defined in the app, then call `runTx` in `execModeFinalize`, which is very similar to `CheckTx` but also executes and writes state changes. + +![blockprocessing](./blockprocessing-1.png) + Before the first transaction of a given block is processed, a [volatile state](#state-updates) called `finalizeBlockState` is initialized during FinalizeBlock. This state is updated each time a transaction is processed via `FinalizeBlock`, and committed to the [main state](#state-updates) when the block is [committed](#commit), after what it is set to `nil`. +The `FinalizeBlock` ABCI function defined in `BaseApp` does the bulk of the state transitions: it is run for each transaction in the block in sequential order as committed to during consensus. Under the hood, transaction execution is almost identical to `CheckTx` but calls the [`runTx`](#runtx) function in deliver mode instead of check mode. + +Instead of using their `checkState`, full-nodes use `finalizeblock`: + ```go reference https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/baseapp/baseapp.go#LL708-L743 ``` @@ -477,7 +499,7 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/baseapp/baseapp.go#LL7 Transaction execution within `FinalizeBlock` performs the **exact same steps as `CheckTx`**, with a little caveat at step 3 and the addition of a fifth step: 1. The `AnteHandler` does **not** check that the transaction's `gas-prices` is sufficient. That is because the `min-gas-prices` value `gas-prices` is checked against is local to the node, and therefore what is enough for one full-node might not be for another. This means that the proposer can potentially include transactions for free, although they are not incentivised to do so, as they earn a bonus on the total fee of the block they propose. -2. For each `sdk.Msg` in the transaction, route to the appropriate module's Protobuf [`Msg` service](../../build/building-modules/03-msg-services.md). Additional _stateful_ checks are performed, and the branched multistore held in `finalizeBlockState`'s `context` is updated by the module's `keeper`. If the `Msg` service returns successfully, the branched multistore held in `context` is written to `finalizeBlockState` `CacheMultiStore`. +2. For each `sdk.Msg` in the transaction, route to the appropriate module's Protobuf [`Msg` service](../../build/building-modules/03-msg-services.md). Additional _stateful_ checks are performed, and the branched multistore held in `finalizeBlockState`'s `context` is updated by the module's `keeper`. If the `Msg` service returns successfully, the branched multistore held in `context` is written to `finalizeBlockState` `CacheMultiStore`. Meaning, Protobuf `Msg` service is responsible for executing each message in the `Tx` and causes state transitions to persist in `finalizeBlockState` During the additional fifth step outlined in (2), each read/write to the store increases the value of `GasConsumed`. You can find the default cost of each operation: @@ -487,6 +509,8 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/store/types/gas.go#L23 At any point, if `GasConsumed > GasWanted`, the function returns with `Code != 0` and the execution fails. +If there are any failed state changes resulting from a `Tx` being invalid or `GasMeter` running out, the transaction processing terminates and any state changes are reverted. Invalid transactions in a block proposal cause validator nodes to reject the block and vote for a `nil` block instead. + Each transaction returns a response to the underlying consensus engine of type [`abci.ExecTxResult`](https://docs.cometbft.com/v1.0/spec/abci/abci++_methods#exectxresult). The response contains: * `Code (uint32)`: Response Code. `0` if successful. @@ -508,11 +532,15 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/baseapp/baseapp.go#L74 ### Commit -The [`Commit` ABCI message](https://docs.cometbft.com/v1.0/spec/abci/abci++_methods#commit) is sent from the underlying CometBFT engine after the full-node has received _precommits_ from 2/3+ of validators (weighted by voting power). On the `BaseApp` end, the `Commit(res abci.CommitResponse)` function is implemented to commit all the valid state transitions that occurred during `FinalizeBlock` and to reset state for the next block. +The [`Commit` ABCI message](https://docs.cometbft.com/v1.0/spec/abci/abci++_methods#commit) is sent from the underlying CometBFT engine after the full-node has received _precommits_ from 2/3+ of validators (weighted by voting power). This is the final step where nodes commit the block and state changes. Validator nodes perform the previous step of executing state transitions to validate the transactions, then sign the block to confirm it. Full nodes that are not validators do not participate in consensus but listen for votes to understand whether or not they should commit the state changes. + +On the `BaseApp` end, the `Commit(res abci.CommitResponse)` function is implemented to commit all the valid state transitions that occurred during `FinalizeBlock` and to reset state for the next block. It syncs all the state transitions by writing the `finalizeBlockState.ms` into the application's internal state. `finalizeBlockState.ms` is a branched multistore of the main store `app.cms`. The `Commit` function calls the `Write()` function on `finalizeBlockState.ms`, effectively committing the state transitions. Then, the `Commit` function sets `checkState` to the latest header (obtained from `finalizeBlockState.ctx.BlockHeader`) and `finalizeBlockState` to `nil`. + +Finally, `Commit` returns the hash of the commitment of `app.cms` back to the underlying consensus engine. This hash is used as a reference in the header of the next block. As soon as the state changes are committed, `checkState` starts afresh from the most recently committed state and `finalizeBlockState` resets to `nil` in order to be consistent and reflect the changes. -To commit state-transitions, the `Commit` function calls the `Write()` function on `finalizeBlockState.ms`, where `finalizeBlockState.ms` is a branched multistore of the main store `app.cms`. Then, the `Commit` function sets `checkState` to the latest header (obtained from `finalizeBlockState.ctx.BlockHeader`) and `finalizeBlockState` to `nil`. +Note that not all blocks have the same number of transactions and it is possible for consensus to result in a `nil` block or one with none at all. In a public blockchain network, it is also possible for validators to be byzantine, or malicious, which may prevent a `Tx` from being committed in the blockchain. Possible malicious behaviors include the proposer deciding to censor a `Tx` by excluding it from the block or a validator voting against the block. -Finally, `Commit` returns the hash of the commitment of `app.cms` back to the underlying consensus engine. This hash is used as a reference in the header of the next block. +At this point, the transaction lifecycle of a `Tx` is over: nodes have verified its validity, delivered it by executing its state changes, and committed those changes. The `Tx` itself, in `[]byte` form, is stored in a block and appended to the blockchain. ### Info diff --git a/docs/learn/advanced/07-cli.md b/docs/learn/advanced/07-cli.md index 77c2fe861..b4932ad4c 100644 --- a/docs/learn/advanced/07-cli.md +++ b/docs/learn/advanced/07-cli.md @@ -172,7 +172,7 @@ Flags are added to commands directly (generally in the [module's CLI file](../.. ## Environment variables -Each flag is bound to its respective named environment variable. Then name of the environment variable consist of two parts - capital case `basename` followed by flag name of the flag. `-` must be substituted with `_`. For example flag `--home` for application with basename `GAIA` is bound to `GAIA_HOME`. It allows reducing the amount of flags typed for routine operations. For example instead of: +Each flag is bound to its respective named environment variable. Then name of the environment variable consist of two parts - capital case `basename` followed by flag name of the flag. `-` must be substituted with `_`. For example flag `--node` for application with basename `GAIA` is bound to `GAIA_NODE`. It allows reducing the amount of flags typed for routine operations. For example instead of: ```shell gaia --home=./ --node= --chain-id="testchain-1" --keyring-backend=test tx ... --from= @@ -182,7 +182,7 @@ this will be more convenient: ```shell # define env variables in .env, .envrc etc -GAIA_HOME= +NODE_HOME= GAIA_NODE= GAIA_CHAIN_ID="testchain-1" GAIA_KEYRING_BACKEND="test" diff --git a/docs/learn/advanced/17-autocli.md b/docs/learn/advanced/17-autocli.md index 50d1684c2..80e6e65e9 100644 --- a/docs/learn/advanced/17-autocli.md +++ b/docs/learn/advanced/17-autocli.md @@ -75,10 +75,10 @@ if err := rootCmd.Execute(); err != nil { ### Keyring -`autocli` uses a keyring for key name resolving and signing transactions. Providing a keyring is optional, but if you want to use the `autocli` generated commands to sign transactions, you must provide a keyring. +`autocli` uses a keyring for key name resolving names and signing transactions. :::tip -This provides a better UX as it allows to resolve key names directly from the keyring in all transactions and commands. +AutoCLI provides a better UX than normal CLI as it allows to resolve key names directly from the keyring in all transactions and commands. ```sh q bank balances alice @@ -87,8 +87,9 @@ This provides a better UX as it allows to resolve key names directly from the ke ::: -The keyring to be provided to `client/v2` must match the `client/v2` keyring interface. -The keyring should be provided in the `appOptions` struct as follows, and can be gotten from the client context: +The keyring used for resolving names and signing transactions is provided via the `client.Context`. +The keyring is then converted to the `client/v2/autocli/keyring` interface. +If no keyring is provided, the `autocli` generated command will not be able to sign transactions, but will still be able to query the chain. :::tip The Cosmos SDK keyring and Hubl keyring both implement the `client/v2/autocli/keyring` interface, thanks to the following wrapper: @@ -99,18 +100,6 @@ keyring.NewAutoCLIKeyring(kb) ::: -:::warning -When using AutoCLI the keyring will only be created once and before any command flag parsing. -::: - -```go -// Set the keyring in the appOptions -appOptions.Keyring = keyring - -err := autoCliOpts.EnhanceRootCommand(rootCmd) -... -``` - ## Signing `autocli` supports signing transactions with the keyring. @@ -255,7 +244,7 @@ The `encoding` flag lets you choose how the contents of the file should be encod * `simd off-chain sign-file alice myFile.json` - * ```json + * ```json { "@type": "/offchain.MsgSignArbitraryData", "appDomain": "simd", @@ -266,7 +255,7 @@ The `encoding` flag lets you choose how the contents of the file should be encod * `simd off-chain sign-file alice myFile.json --encoding base64` - * ```json + * ```json { "@type": "/offchain.MsgSignArbitraryData", "appDomain": "simd", @@ -277,7 +266,7 @@ The `encoding` flag lets you choose how the contents of the file should be encod * `simd off-chain sign-file alice myFile.json --encoding hex` - * ```json + * ```json { "@type": "/offchain.MsgSignArbitraryData", "appDomain": "simd", diff --git a/docs/learn/advanced/blockprocessing-1.png b/docs/learn/advanced/blockprocessing-1.png new file mode 100644 index 000000000..d4167f339 Binary files /dev/null and b/docs/learn/advanced/blockprocessing-1.png differ diff --git a/docs/learn/advanced/blockprocessing.excalidraw b/docs/learn/advanced/blockprocessing.excalidraw new file mode 100644 index 000000000..84e2d5db2 Binary files /dev/null and b/docs/learn/advanced/blockprocessing.excalidraw differ diff --git a/docs/learn/beginner/01-tx-lifecycle.md b/docs/learn/beginner/01-tx-lifecycle.md index 03f5e9767..100ae7d00 100644 --- a/docs/learn/beginner/01-tx-lifecycle.md +++ b/docs/learn/beginner/01-tx-lifecycle.md @@ -13,9 +13,7 @@ This document describes the lifecycle of a transaction from creation to committe * [Anatomy of a Cosmos SDK Application](./00-app-anatomy.md) ::: -## Creation - -### Transaction Creation +## Transaction Creation One of the main application interfaces is the command-line interface. The transaction `Tx` can be created by the user inputting a command in the following format from the [command-line](../advanced/07-cli.md), providing the type of transaction in `[command]`, arguments in `[args]`, and configurations such as gas prices in `[flags]`: @@ -27,7 +25,7 @@ This command automatically **creates** the transaction, **signs** it using the a There are several required and optional flags for transaction creation. The `--from` flag specifies which [account](./03-accounts.md) the transaction is originating from. For example, if the transaction is sending coins, the funds are drawn from the specified `from` address. -#### Gas and Fees +### Gas and Fees Additionally, there are several [flags](../advanced/07-cli.md) users can use to indicate how much they are willing to pay in [fees](./04-gas-fees.md): @@ -41,7 +39,7 @@ The ultimate value of the fees paid is equal to the gas multiplied by the gas pr Later, validators decide whether or not to include the transaction in their block by comparing the given or calculated `gas-prices` to their local `min-gas-prices`. `Tx` is rejected if its `gas-prices` is not high enough, so users are incentivized to pay more. -#### CLI Example +### CLI Example Users of the application `app` can enter the following command into their CLI to generate a transaction to send 1000uatom from a `senderAddress` to a `recipientAddress`. The command specifies how much gas they are willing to pay: an automatic estimate scaled up by 1.5 times, with a gas price of 0.025uatom per unit gas. @@ -49,45 +47,93 @@ Users of the application `app` can enter the following command into their CLI to appd tx send 1000uatom --from --gas auto --gas-adjustment 1.5 --gas-prices 0.025uatom ``` -#### Other Transaction Creation Methods +### Other Transaction Creation Methods The command-line is an easy way to interact with an application, but `Tx` can also be created using a [gRPC or REST interface](../advanced/06-grpc_rest.md) or some other entry point defined by the application developer. From the user's perspective, the interaction depends on the web interface or wallet they are using (e.g. creating `Tx` using [Keplr](https://www.keplr.app/) and signing it with a Ledger Nano S). -## Addition to Mempool +## Transaction Broadcasting + +This is the next phase, where a transactison is sent from a client (such as a wallet or a command-line interface) to the network of nodes. This process is consensus-agnostic, meaning it can work with various consensus engines. + +Below are the steps involved in transaction broadcasting: + +1. **Transaction Creation and Signing:** +Transactions are created and signed using the client's private key to ensure authenticity and integrity. -Each full-node (running CometBFT) that receives a `Tx` sends an [ABCI message](https://docs.cometbft.com/v1.0/spec/abci/abci++_methods#checktx) -`abci.CheckTxRequest` to the application layer to check for validity, and receives an `abci.CheckTxResponse`. If the `Tx` passes the checks, it is held in the node's -[**Mempool**](https://docs.cometbft.com/v1.0/explanation/core/mempool/), an in-memory pool of transactions unique to each node, pending inclusion in a block - honest nodes discard a `Tx` if it is found to be invalid. Prior to consensus, nodes continuously check incoming transactions and gossip them to their peers. +2. **Broadcasting to the Network:** +The signed transaction is sent to the network. This is handled by the `BroadcastTx` function in the client context. -### Types of Checks +3. **Network Propagation:** +Once received by a node, the transaction is propagated to other nodes in the network. This ensures that all nodes have a copy of the transaction. -The full-nodes perform stateless, then stateful checks on `Tx` during `CheckTx`, with the goal to -identify and reject an invalid transaction as early on as possible to avoid wasted computation. +4. **Consensus Engine Interaction:** +The specific method of broadcasting may vary depending on the consensus engine used. The SDK's design allows for easy integration with any consensus engine by configuring the `clientCtx` appropriately. + +The function `BroadcastTx` in `client/tx/tx.go` demonstrates how a transaction is prepared, signed, and broadcasted. Here's the relevant part of the function that handles the broadcasting: + +```go +res, err := clientCtx.BroadcastTx(txBytes) +if err != nil { + return err +} +``` -**_Stateless_** checks do not require nodes to access state - light clients or offline nodes can do -them - and are thus less computationally expensive. Stateless checks include making sure addresses -are not empty, enforcing nonnegative numbers, and other logic specified in the definitions. +**Configuration:** -**_Stateful_** checks validate transactions and messages based on a committed state. Examples -include checking that the relevant values exist and can be transacted with, the address -has sufficient funds, and the sender is authorized or has the correct ownership to transact. -At any given moment, full-nodes typically have [multiple versions](../advanced/00-baseapp.md#state-updates) -of the application's internal state for different purposes. For example, nodes execute state -changes while in the process of verifying transactions, but still need a copy of the last committed -state in order to answer queries - they should not respond using state with uncommitted changes. +To adapt this function for different consensus engines, ensure that the `clientCtx` is configured with the correct network settings and transaction handling mechanisms for your chosen engine. This might involve setting up specific encoders, decoders, and network endpoints that are compatible with the engine. -In order to verify a `Tx`, full-nodes call `CheckTx`, which includes both _stateless_ and _stateful_ -checks. Further validation happens later in the [`DeliverTx`](../advanced/00-baseapp.md#delivertx) stage. `CheckTx` goes -through several steps, beginning with decoding `Tx`. +## Transaction Processing + +After a transaction is broadcasted to the network, it undergoes several processing steps to ensure its validity. These steps are managed by the application's core transaction processing layer, which is responsible for handling transactions. Within the SDK, this core layer is wrapped with a runtime layer defined in `runtime/app.go`. This layer extends the core functionality with additional features to handle transactions, allowing for more flexibility and customization, such as the ability to swap out different consensus engines. The key steps in transaction processing are: ### Decoding -When `Tx` is received by the application from the underlying consensus engine (e.g. CometBFT ), it is still in its [encoded](../advanced/05-encoding.md) `[]byte` form and needs to be unmarshaled in order to be processed. Then, the [`runTx`](../advanced/00-baseapp.md#runtx-antehandler-runmsgs-posthandler) function is called to run in `runTxModeCheck` mode, meaning the function runs all checks but exits before executing messages and writing state changes. +The transaction is decoded from its binary format into a structured format that the application can understand. + +* **During Transaction Processing:** Transactions are received in the encoded `[]byte` form. Nodes first unmarshal the transaction using the configuration defined in the app, then proceed to execute the transaction, which includes state changes. + +### Routing + +How Routing Works: +The transaction is routed to the appropriate module based on the message type. Each message type is associated with a specific module, which is responsible for processing the message. The core transaction processing layer uses a `MsgServiceRouter` to direct the transaction to the correct module. + +1. **Transaction Type Identification:** +Each transaction contains one or more messages (`sdk.Msg`), and each message has a `Type()` method that identifies its type. This type is used to determine the appropriate module to handle the message. +2. **Module Routing:** +The core transaction processing layer holds a `MsgServiceRouter` which maps each message type to a specific module's handler. When a transaction is processed, this router is used to direct the message to the correct module. + +### Example of Routing -### ValidateBasic (deprecated) +Let's say there is a transaction that involves transferring tokens. The message type might be `MsgSend`, and the `MsgServiceRouter` in `BaseApp` would route this message to the bank module's handler. The bank module would then validate the transaction details (like sender balance) and update the state to reflect the transfer if valid... -Messages ([`sdk.Msg`](../advanced/01-transactions.md#messages)) are extracted from transactions (`Tx`). The `ValidateBasic` method of the `sdk.Msg` interface implemented by the module developer is run for each transaction. -To discard obviously invalid messages, the `BaseApp` type calls the `ValidateBasic` method very early in the processing of the message in the [`CheckTx`](../advanced/00-baseapp.md#checktx) and [`DeliverTx`](../advanced/00-baseapp.md#delivertx) transactions. +### Validation + +Preliminary checks are performed. These include signature verification to ensure the transaction hasn't been tampered with and checking if the transaction meets the minimum fee requirements, which is handled by the `AnteHandler`. The `Antehandler` is invoked during the `runTx` method in `BaseApp`. + +#### Types of Transaction Checks + +During the transaction lifecycle, full-nodes perform a series of checks to validate transactions before they are finalized in a block. These checks are categorized into stateless and stateful checks. + +**Stateless Checks**: +Stateless checks are validations that do not require access to the state of the blockchain. They are computationally inexpensive and can be performed by light clients or offline nodes. Examples include: + +* Ensuring addresses are not empty. +* Enforcing nonnegative values for transaction fields. +* Validating the format of the data in the transaction. + +**Stateful Checks**: +Stateful checks involve validating transactions against the current committed state of the blockchain. These checks are more computationally intensive as they require access to the state. Examples include: + +* Verifying that the account has sufficient funds. +* Checking that the sender has the necessary permissions for the transaction. +* Ensuring that the transaction does not result in any state conflicts. + +Full-nodes use these checks during the validation process to quickly reject invalid transactions, minimizing wasted computational resources. Further validation occurs during the transaction execution phase, where transactions are fully executed. + +#### ValidateBasic (deprecated) + +* Messages ([`sdk.Msg`](../advanced/01-transactions.md#messages)) are extracted from transactions (`Tx`). The `ValidateBasic` method of the `sdk.Msg` interface implemented by the module developer is run for each transaction. +* To discard obviously invalid messages, the `BaseApp` type calls the `ValidateBasic` method very early in the processing of the message in the [`CheckTx`](../advanced/00-baseapp.md#checktx) and [`DeliverTx`](../advanced/00-baseapp.md#delivertx) transactions. `ValidateBasic` can include only **stateless** checks (the checks that do not require access to the state). :::warning @@ -96,140 +142,86 @@ The `ValidateBasic` method on messages has been deprecated in favor of validatin Read [RFC 001](https://docs.cosmos.network/main/rfc/rfc-001-tx-validation) for more details. ::: -:::note -`BaseApp` still calls `ValidateBasic` on messages that implements that method for backwards compatibility. -::: +### Discard or Addition to Mempool -#### Guideline +If at any point during the initial transaction validation the transaction (`Tx`) fails, it is discarded, and the transaction lifecycle ends there. Otherwise, if it passes this preliminary check successfully, the general protocol is to relay it to peer nodes and add it to the node's transaction pool (often referred to as the mempool). This makes the `Tx` a candidate for inclusion in the next block, pending further consensus processes. -`ValidateBasic` should not be used anymore. Message validation should be performed in the `Msg` service when [handling a message](../../build/building-modules/03-msg-services.md#validation) in a module Msg Server. +The **app-side mempool**, serves the purpose of keeping track of transactions seen by all full-nodes. Full-nodes maintain a **mempool cache** of the last `mempool.cache_size` transactions they have seen, serving as a first line of defense to prevent replay attacks. Ideally, `mempool.cache_size` should be large enough to encompass all transactions in the full mempool. If the mempool cache is too small to track all transactions, the initial transaction validation process is responsible for identifying and rejecting replayed transactions. -### AnteHandler +Currently existing preventative measures include fees and a `sequence` (nonce) counter to distinguish replayed transactions from identical but valid ones. If an attacker tries to spam nodes with many copies of a `Tx`, full-nodes maintaining a transaction cache reject all identical copies. Even if the copies have incremented sequence numbers, attackers are disincentivized by the need to pay fees. -`AnteHandler`s even though optional, are in practice very often used to perform signature verification, gas calculation, fee deduction, and other core operations related to blockchain transactions. +Validator nodes maintain a transaction pool to prevent replay attacks, similar to full-nodes, but also use it to hold unconfirmed transactions in preparation for block inclusion. It's important to note that even if a `Tx` passes all preliminary checks, it can still be found invalid later on, as these initial checks do not fully execute the transaction's logic. -A copy of the cached context is provided to the `AnteHandler`, which performs limited checks specified for the transaction type. Using a copy allows the `AnteHandler` to do stateful checks for `Tx` without modifying the last committed state, and revert back to the original if the execution fails. +### Module Execution -For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/main/x/auth) module `AnteHandler` checks and increments sequence numbers, checks signatures and account numbers, and deducts fees from the first signer of the transaction - all state changes are made using the `checkState`. +After the transaction has been appropriately routed to the correct module by the `MsgServiceRouter` and passed all necessary validations, the execution phase begins: -:::warning -Ante handlers only run on a transaction. If a transaction embed multiple messages (like some x/authz, x/gov transactions for instance), the ante handlers only have awareness of the outer message. Inner messages are mostly directly routed to the [message router](https://docs.cosmos.network/main/learn/advanced/baseapp#msg-service-router) and will skip the chain of ante handlers. Keep that in mind when designing your own ante handler. -::: +* **Handler Activation**: Each module's handler processes the routed message, applying the necessary business logic such as updating account balances or transferring tokens. +* **State Changes**: Handlers may modify the state as required by the business logic, which could involve writing to the module's portion of the state store. This can be seen in the next subsection. +* **Event Emission and Logging**: During execution, modules can emit events and log information, which are crucial for monitoring and querying transaction outcomes. -### Gas +For messages that adhere to older standards or specific formats, a routing function retrieves the route name from the message, identifying the corresponding module. The message is then processed by the designated handler within that module, ensuring accurate and consistent application of the transaction's logic. -The [`Context`](../advanced/02-context.md), which keeps a `GasMeter` that tracks how much gas is used during the execution of `Tx`, is initialized. The user-provided amount of gas for `Tx` is known as `GasWanted`. If `GasConsumed`, the amount of gas consumed during execution, ever exceeds `GasWanted`, the execution stops and the changes made to the cached copy of the state are not committed. Otherwise, `CheckTx` sets `GasUsed` equal to `GasConsumed` and returns it in the result. After calculating the gas and fee values, validator-nodes check that the user-specified `gas-prices` is greater than their locally defined `min-gas-prices`. +4. During the execution, the module's handler will modify the state as required by the business logic. This could involve writing to the module's portion of the state store. -### Discard or Addition to Mempool +5. Modules can emit events and log information during execution, which are used for monitoring and querying transaction outcomes. + +During the module execution phase, each message that has been routed to the appropriate module is processed according to the module-specific business logic. For example, the `handleMsgSend` function in the bank module processes `MsgSend` messages by checking balances, transferring tokens, and emitting events: + +```go +func handleMsgSend(ctx sdk.Context, keeper BankKeeper, msg MsgSend) error { + if keeper.GetBalance(ctx, msg.Sender).Amount < msg.Amount { + return sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "sender does not have enough tokens") + } + keeper.SendCoins(ctx, msg.Sender, msg.Receiver, msg.Amount) + ctx.EventManager().EmitEvent( + sdk.NewEvent("transfer", sdk.NewAttribute("from", msg.Sender.String()), sdk.NewAttribute("to", msg.Receiver.String()), sdk.NewAttribute("amount", msg.Amount.String())), + ) + return nil +} +``` -If at any point during `CheckTx` the `Tx` fails, it is discarded and the transaction lifecycle ends -there. Otherwise, if it passes `CheckTx` successfully, the default protocol is to relay it to peer -nodes and add it to the Mempool so that the `Tx` becomes a candidate to be included in the next block. +This function exemplifies how a module's handler executes the transaction logic, modifies the state, and logs the transaction events, which are essential aspects of module execution. -The **mempool** serves the purpose of keeping track of transactions seen by all full-nodes. -Full-nodes keep a **mempool cache** of the last `mempool.cache_size` transactions they have seen, as a first line of -defense to prevent replay attacks. Ideally, `mempool.cache_size` is large enough to encompass all -of the transactions in the full mempool. If the mempool cache is too small to keep track of all -the transactions, `CheckTx` is responsible for identifying and rejecting replayed transactions. +### State Changes During Consensus -Currently existing preventative measures include fees and a `sequence` (nonce) counter to distinguish -replayed transactions from identical but valid ones. If an attacker tries to spam nodes with many -copies of a `Tx`, full-nodes keeping a mempool cache reject all identical copies instead of running -`CheckTx` on them. Even if the copies have incremented `sequence` numbers, attackers are -disincentivized by the need to pay fees. +Before finalizing the transactions within a block, full-nodes perform a second round of checks using `validateBasicMsgs` and `AnteHandler`. This is crucial to ensure that all transactions are valid, especially since a malicious proposer might include invalid transactions. Unlike the checks during the transaction addition to the Mempool, the `AnteHandler` in this phase does not compare the transaction's `gas-prices` to the node's `min-gas-prices`. This is because `min-gas-prices` can vary between nodes, and using them here would lead to nondeterministic results across the network. -Validator nodes keep a mempool to prevent replay attacks, just as full-nodes do, but also use it as -a pool of unconfirmed transactions in preparation of block inclusion. Note that even if a `Tx` -passes all checks at this stage, it is still possible to be found invalid later on, because -`CheckTx` does not fully validate the transaction (that is, it does not actually execute the messages). +* After module execution, the transactions are included in a block proposal by the proposer. + +* All full-nodes that receive this block proposal execute the transactions to ensure that the state changes are applied consistently across all nodes, maintaining the deterministic nature of the blockchain. This includes the execution of initial, transaction-specific, and finalizing operations. ## Inclusion in a Block -Consensus, the process through which validator nodes come to agreement on which transactions to -accept, happens in **rounds**. Each round begins with a proposer creating a block of the most -recent transactions and ends with **validators**, special full-nodes with voting power responsible -for consensus, agreeing to accept the block or go with a `nil` block instead. Validator nodes -execute the consensus algorithm adopted in [CometBFT](https://docs.cometbft.com/v1.0/spec/consensus/), -confirming the transactions using ABCI requests to the application, in order to come to this agreement. - -The first step of consensus is the **block proposal**. One proposer amongst the validators is chosen -by the consensus algorithm to create and propose a block - in order for a `Tx` to be included, it -must be in this proposer's mempool. - -## State Changes - -The next step of consensus is to execute the transactions to fully validate them. All full-nodes -that receive a block proposal from the correct proposer execute the transactions by calling the ABCI function `FinalizeBlock`. -As mentioned throughout the documentation `BeginBlock`, `ExecuteTx` and `EndBlock` are called within FinalizeBlock. -Although every full-node operates individually and locally, the outcome is always consistent and unequivocal. This is because the state changes brought about by the messages are predictable, and the transactions are specifically sequenced in the proposed block. - -```mermaid - flowchart TD - A[Receive Block Proposal] --> B[FinalizeBlock] - B --> C[BeginBlock] - C --> D["ExecuteTx(tx0, tx1, 1x2)"] - D --> E[EndBlock] - E --> F[Commit] -``` +Consensus is the process through which nodes in a blockchain network agree on which transactions to include in the blockchain. This process typically occurs in rounds, starting with a designated node (often called a proposer) compiling a block from transactions in its transaction pool (mempool). The block is then proposed to other nodes (validators) in the network. + +Each validator independently verifies the proposed block against the blockchain's rules. If the block is accepted by a sufficient number of validators according to the network's consensus rules, it is added to the blockchain. If not, the process may repeat, potentially with a different proposer or even resulting in a block that contains no transactions (a nil block). + +The specific mechanisms of choosing a proposer, the criteria for a valid block, and the method of achieving agreement among validators can vary depending on the consensus algorithm used by the blockchain. + + +## Post-Transaction Handling + +After execution, any additional actions that need to be taken are processed. This could include updating logs, sending events, or handling errors. + +These steps are managed by `BaseApp` in the Cosmos SDK, which routes transactions to the appropriate handlers and manages state transitions. + +After a transaction is executed in the Cosmos SDK, several steps are taken to finalise the process: + +1. Event Emission: Modules emit events that can be used for logging, monitoring, or triggering other workflows. These events are collected during the transaction execution. + +2. Logging: Information about the transaction execution, such as success or failure, and any significant state changes, are logged for audit and diagnostic purposes. + +3. Error Handling: If any errors occur during transaction execution, they are handled appropriately, which may include rolling back certain operations to maintain state consistency. + +4. State Commitment: Changes made to the state during the transaction are finalised and written to the blockchain. This step is crucial as it ensures that all state transitions are permanently recorded. + +5. PostHandlers: After the execution of the message, `PostHandlers` are run. If they fail, the state changes made during `runMsgs` and by the `PostHandlers` themselves are both reverted. This ensures that only successful transactions affect the state. + + +After post-transaction handling, the exact sequence of the transaction lifecycle is dependent on the consensus mechanism used. This includes how transactions are grouped into blocks, how blocks are validated, and how consensus is achieved among validators to commit the block to the blockchain. Each consensus protocol may implement these steps differently to ensure network agreement and maintain the integrity of the blockchain state. + +## Learn More + +For a deeper dive into the underlying mechanisms of transaction processing and block commitment in the Cosmos SDK, consider exploring the [BaseApp documentation](../advanced/00-baseapp.md). This advanced documentation provides detailed insights into the internal workings and state management of the Cosmos SDK. -### Transaction Execution - -The `FinalizeBlock` ABCI function defined in [`BaseApp`](../advanced/00-baseapp.md) does the bulk of the -state transitions: it is run for each transaction in the block in sequential order as committed -to during consensus. Under the hood, transaction execution is almost identical to `CheckTx` but calls the -[`runTx`](../advanced/00-baseapp.md#runtx) function in deliver mode instead of check mode. -Instead of using their `checkState`, full-nodes use `finalizeblock`: - -* **Decoding:** Since `FinalizeBlock` is an ABCI call, `Tx` is received in the encoded `[]byte` form. - Nodes first unmarshal the transaction, using the [`TxConfig`](./00-app-anatomy.md#register-codec) defined in the app, then call `runTx` in `execModeFinalize`, which is very similar to `CheckTx` but also executes and writes state changes. - -* **Checks and `AnteHandler`:** Full-nodes call `validateBasicMsgs` and `AnteHandler` again. This second check - happens because they may not have seen the same transactions during the addition to Mempool stage - and a malicious proposer may have included invalid ones. One difference here is that the - `AnteHandler` does not compare `gas-prices` to the node's `min-gas-prices` since that value is local - to each node - differing values across nodes yield nondeterministic results. - -* **`MsgServiceRouter`:** After `CheckTx` exits, `FinalizeBlock` continues to run - [`runMsgs`](../advanced/00-baseapp.md#runtx-antehandler-runmsgs-posthandler) to fully execute each `Msg` within the transaction. - Since the transaction may have messages from different modules, `BaseApp` needs to know which module - to find the appropriate handler. This is achieved using `BaseApp`'s `MsgServiceRouter` so that it can be processed by the module's Protobuf [`Msg` service](../../build/building-modules/03-msg-services.md). - For `LegacyMsg` routing, the `Route` function is called via the [module manager](../../build/building-modules/01-module-manager.md) to retrieve the route name and find the legacy [`Handler`](../../build/building-modules/03-msg-services.md#handler-type) within the module. - -* **`Msg` service:** Protobuf `Msg` service is responsible for executing each message in the `Tx` and causes state transitions to persist in `finalizeBlockState`. - -* **PostHandlers:** [`PostHandler`](../advanced/00-baseapp.md#posthandler)s run after the execution of the message. If they fail, the state change of `runMsgs`, as well of `PostHandlers`, are both reverted. - -* **Gas:** While a `Tx` is being delivered, a `GasMeter` is used to keep track of how much - gas is being used; if execution completes, `GasUsed` is set and returned in the - `abci.ExecTxResult`. If execution halts because `BlockGasMeter` or `GasMeter` has run out or something else goes - wrong, a deferred function at the end appropriately errors or panics. - -If there are any failed state changes resulting from a `Tx` being invalid or `GasMeter` running out, -the transaction processing terminates and any state changes are reverted. Invalid transactions in a -block proposal cause validator nodes to reject the block and vote for a `nil` block instead. - -### Commit - -The final step is for nodes to commit the block and state changes. Validator nodes -perform the previous step of executing state transitions in order to validate the transactions, -then sign the block to confirm it. Full nodes that are not validators do not -participate in consensus - i.e. they cannot vote - but listen for votes to understand whether or -not they should commit the state changes. - -When they receive enough validator votes (2/3+ _precommits_ weighted by voting power), full nodes commit to a new block to be added to the blockchain and -finalize the state transitions in the application layer. A new state root is generated to serve as -a merkle proof for the state transitions. Applications use the [`Commit`](../advanced/00-baseapp.md#commit) -ABCI method inherited from [Baseapp](../advanced/00-baseapp.md); it syncs all the state transitions by -writing the `deliverState` into the application's internal state. As soon as the state changes are -committed, `checkState` starts afresh from the most recently committed state and `deliverState` -resets to `nil` in order to be consistent and reflect the changes. - -Note that not all blocks have the same number of transactions and it is possible for consensus to -result in a `nil` block or one with none at all. In a public blockchain network, it is also possible -for validators to be **byzantine**, or malicious, which may prevent a `Tx` from being committed in -the blockchain. Possible malicious behaviors include the proposer deciding to censor a `Tx` by -excluding it from the block or a validator voting against the block. - -At this point, the transaction lifecycle of a `Tx` is over: nodes have verified its validity, -delivered it by executing its state changes, and committed those changes. The `Tx` itself, -in `[]byte` form, is stored in a block and appended to the blockchain. diff --git a/docs/learn/intro/02-sdk-app-architecture.md b/docs/learn/intro/02-sdk-app-architecture.md index cb217da6e..6ace65e57 100644 --- a/docs/learn/intro/02-sdk-app-architecture.md +++ b/docs/learn/intro/02-sdk-app-architecture.md @@ -4,7 +4,33 @@ sidebar_position: 1 # Blockchain Architecture -## State machine +## Introduction + +Blockchain architecture is a complex topic that involves many different components. In this section, we will cover the main layers of a blockchain application built with the Cosmos SDK. + +At its core, a blockchain is a replicated deterministic state machine. This document explores the various layers of blockchain architecture, focusing on the execution, settlement, consensus, data availability, and interoperability layers. + + +```mermaid +graph TD + A[Modular SDK Blockchain Architecture] + A --> B[Execution Layer] + A --> C[Settlement Layer] + A --> D[Consensus Layer] + D --> E[Data Availability Layer] + A --> F[Interoperability Layer] +``` + + +## Layered Architecture + +Understanding blockchain architecture through the lens of different layers helps in comprehending its complex functionalities. We will give a high-level overview of the execution layer, settlement layer, consensus layer, data availability layer, and interoperability layer. + +## Execution Layer + +The Execution Layer is where the blockchain processes and executes transactions. The state machine within the blockchain handles the execution of transaction logic. This is done by the blockchain itself, ensuring that every transaction follows the predefined rules and state transitions. When a transaction is submitted, the execution layer processes it, updates the state, and ensures that the output is deterministic and consistent across all nodes. In the context of the Cosmos SDK, this typically involves predefined modules and transaction types rather than general-purpose smart contracts, which are used in chains with CosmWasm. + +### State machine At its core, a blockchain is a [replicated deterministic state machine](https://en.wikipedia.org/wiki/State_machine_replication). @@ -30,9 +56,23 @@ flowchart LR In a blockchain context, the state machine is deterministic. This means that if a node is started at a given state and replays the same sequence of transactions, it will always end up with the same final state. -The Cosmos SDK gives developers maximum flexibility to define the state of their application, transaction types and state transition functions. The process of building state-machines with the Cosmos SDK will be described more in depth in the following sections. But first, let us see how the state-machine is replicated using **CometBFT**. +The Cosmos SDK gives developers maximum flexibility to define the state of their application, transaction types and state transition functions. The process of building state machines with the Cosmos SDK will be described more in-depth in the following sections. But first, let us see how the state machine is replicated using various consensus engines, such as CometBFT. + +## Settlement Layer + +The Settlement Layer is responsible for finalising and recording transactions on the blockchain. This layer ensures that all transactions are accurately settled and immutable, providing a verifiable record of all activities on the blockchain. It is critical for maintaining the integrity and trustworthiness of the blockchain. -## CometBFT +The settlement layer can be performed on the chain itself or it can be externalised, allowing for the possibility of plugging in a different settlement layer as needed. For example if we were to use Rollkit and celestia for our Data Availability and Consensus, we could separate our settlement layer by introducing fraud or validity proofs. From there the settlement layer can create trust-minimised light clients, further enhancing security and efficiency. This process ensures that all transactions are accurately finalized and immutable, providing a verifiable record of all activities. + +## Consensus Layer + +The Consensus Layer ensures that all nodes in the network agree on the order and validity of transactions. This layer uses consensus algorithms like Byzantine Fault Tolerance (BFT) or Proof of Stake (PoS) to achieve agreement, even in the presence of malicious nodes. Consensus is crucial for maintaining the security and reliability of the blockchain. + +What has been a default consensus engine in the Cosmos SDK has been CometBFT. In the most recent releases we have been moving away from this and allowing users to plug and play their own consensus engines. This is a big step forward for the Cosmos SDK as it allows for more flexibility and customisation. Other consensus engine options for example can be Rollkit with Celestias Data Availability Layer. + +Here is an example of how the consensus layer works with CometBFT in the context of the Cosmos SDK: + +### CometBFT Thanks to the Cosmos SDK, developers just have to define the state machine, and [*CometBFT*](https://docs.cometbft.com/v1.0/explanation/introduction/) will handle replication over the network for them. @@ -65,22 +105,12 @@ The [consensus algorithm adopted by CometBFT](https://docs.cometbft.com/v1.0/exp CometBFT passes transactions to the application through an interface called the [ABCI](https://docs.cometbft.com/v1.0/spec/abci/), which the application must implement. -```text - +---------------------+ - | | - | Application | - | | - +--------+---+--------+ - ^ | - | | ABCI - | v - +--------+---+--------+ - | | - | | - | CometBFT | - | | - | | - +---------------------+ +```mermaid +graph TD + A[Application] + B[CometBFT] + A <-->|ABCI| B + ``` Note that **CometBFT only handles transaction bytes**. It has no knowledge of what these bytes mean. All CometBFT does is order these transaction bytes deterministically. CometBFT passes the bytes to the application via the ABCI, and expects a return code to inform it if the messages contained in the transactions were successfully processed or not. @@ -94,3 +124,16 @@ Here are the most important messages of the ABCI: Find a more detailed view of the ABCI methods from the [CometBFT docs](https://docs.cometbft.com/v1.0/spec/abci/). Any application built on CometBFT needs to implement the ABCI interface in order to communicate with the underlying local CometBFT engine. Fortunately, you do not have to implement the ABCI interface. The Cosmos SDK provides a boilerplate implementation of it in the form of [baseapp](./03-sdk-design.md#baseapp). + +## Data Availability Layer + +The Data Availability (DA) Layer is a critical component of within the umbrella of the consensus layer that ensures all necessary data for transactions is available to all network participants. This layer is essential for preventing data withholding attacks, where some nodes might attempt to disrupt the network by not sharing critical transaction data. + +If we use the example of Rollkit, a user initiates a transaction, which is then propagated through the rollup network by a light node. The transaction is validated by full nodes and aggregated into a block by the sequencer. This block is posted to a data availability layer like Celestia, ensuring the data is accessible and correctly ordered. The rollup light node verifies data availability from the DA layer. Full nodes then validate the block and generate necessary proofs, such as fraud proofs for optimistic rollups or zk-SNARKs/zk-STARKs for zk-rollups. These proofs are shared across the network and verified by other nodes, ensuring the rollup's integrity. Once all validations are complete, the rollup's state is updated, finalising the transaction + + +## Interoperability Layer + +The Interoperability Layer enables communication and interaction between different blockchains. This layer facilitates cross-chain transactions and data sharing, allowing various blockchain networks to interoperate seamlessly. Interoperability is key for building a connected ecosystem of blockchains, enhancing their functionality and reach. + +In this case we have separated the layers even further to really illustrate the components that make-up the blockchain architecture and it is important to note that the Cosmos SDK is designed to be interoperable with other blockchains. This is achieved through the use of the Inter-Blockchain Communication (IBC) protocol, which allows different blockchains to communicate and transfer assets between each other. diff --git a/docs/learn/intro/03-sdk-design.md b/docs/learn/intro/03-sdk-design.md index 563dc11eb..e2edcd4ef 100644 --- a/docs/learn/intro/03-sdk-design.md +++ b/docs/learn/intro/03-sdk-design.md @@ -13,6 +13,8 @@ Here is a simplified view of how transactions are handled by an application buil 3. Route each message to the appropriate module so that it can be processed. 4. Commit state changes. +![main-components](main-components.png) + ## `baseapp` `baseapp` is the boilerplate implementation of a Cosmos SDK application. It comes with an implementation of the ABCI to handle the connection with the underlying consensus engine. Typically, a Cosmos SDK application extends `baseapp` by embedding it in [`app.go`](../beginner/00-app-anatomy.md#core-application-file). diff --git a/docs/learn/intro/Maincomps.excalidraw b/docs/learn/intro/Maincomps.excalidraw new file mode 100644 index 000000000..289d1010a --- /dev/null +++ b/docs/learn/intro/Maincomps.excalidraw @@ -0,0 +1,603 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "TT806C8wYC1giNDrB3j0H", + "type": "rectangle", + "x": 392.3992464191551, + "y": 377.59281643418194, + "width": 368.5810298094963, + "height": 300.3445584269905, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b20", + "roundness": { + "type": 3 + }, + "seed": 1095376796, + "version": 379, + "versionNonce": 395388196, + "isDeleted": false, + "boundElements": null, + "updated": 1717946215725, + "link": null, + "locked": false + }, + { + "id": "sTDd-IcaEk93yvorkOjjx", + "type": "rectangle", + "x": 425.6105707309967, + "y": 407.3907865247813, + "width": 291.7422935286128, + "height": 57.093323969660304, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ebfbee", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b21", + "roundness": { + "type": 3 + }, + "seed": 534261156, + "version": 200, + "versionNonce": 320694564, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "DfQ_v0mZK9I65EtQ6glTr" + } + ], + "updated": 1717946141898, + "link": null, + "locked": false + }, + { + "id": "DfQ_v0mZK9I65EtQ6glTr", + "type": "text", + "x": 540.1377462428617, + "y": 425.93744850961144, + "width": 62.68794250488281, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b22", + "roundness": null, + "seed": 1825368092, + "version": 129, + "versionNonce": 1358928420, + "isDeleted": false, + "boundElements": null, + "updated": 1717945861493, + "link": null, + "locked": false, + "text": "baseapp", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "sTDd-IcaEk93yvorkOjjx", + "originalText": "baseapp", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "0eOjlptq2QPkgMZD4ilw_", + "type": "rectangle", + "x": 423.5441903728455, + "y": 483.4335837047473, + "width": 305.81281311550566, + "height": 100.72456256899451, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#e7f5ff", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b23", + "roundness": { + "type": 3 + }, + "seed": 774424100, + "version": 711, + "versionNonce": 1241388444, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "To8Ifauc4u3pXYXE-BuBm" + }, + { + "id": "5U3m__cEk0384Je1xS8Lt", + "type": "arrow" + } + ], + "updated": 1717946136493, + "link": null, + "locked": false + }, + { + "id": "To8Ifauc4u3pXYXE-BuBm", + "type": "text", + "x": 537.3546267767897, + "y": 488.4335837047473, + "width": 78.19194030761719, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b24", + "roundness": null, + "seed": 268281380, + "version": 653, + "versionNonce": 240902940, + "isDeleted": false, + "boundElements": null, + "updated": 1717946115508, + "link": null, + "locked": false, + "text": "multistore", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "top", + "containerId": "0eOjlptq2QPkgMZD4ilw_", + "originalText": "multistore", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "6ZMBBGC0e67HCiZuw1ZGQ", + "type": "rectangle", + "x": 433.0074470871197, + "y": 611.2583420078661, + "width": 296.0816922807304, + "height": 40.43217567449267, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ebfbee", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b25", + "roundness": { + "type": 3 + }, + "seed": 73209500, + "version": 210, + "versionNonce": 506281508, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "lDvSHg5T_n2nFJyxXar85" + }, + { + "id": "5U3m__cEk0384Je1xS8Lt", + "type": "arrow" + } + ], + "updated": 1717946145151, + "link": null, + "locked": false + }, + { + "id": "lDvSHg5T_n2nFJyxXar85", + "type": "text", + "x": 550.5683127587349, + "y": 621.4744298451124, + "width": 60.9599609375, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b26", + "roundness": null, + "seed": 169830436, + "version": 101, + "versionNonce": 99685404, + "isDeleted": false, + "boundElements": null, + "updated": 1717946143284, + "link": null, + "locked": false, + "text": "Modules", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "6ZMBBGC0e67HCiZuw1ZGQ", + "originalText": "Modules", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "5U3m__cEk0384Je1xS8Lt", + "type": "arrow", + "x": 730.0891393678501, + "y": 627.8029150748303, + "width": 33.89886827099872, + "height": 77.8473208768944, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b27", + "roundness": { + "type": 2 + }, + "seed": 2017356060, + "version": 847, + "versionNonce": 601341212, + "isDeleted": false, + "boundElements": null, + "updated": 1717946143287, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 33.89886827099872, + -59.624776904124815 + ], + [ + 0.2678641205010308, + -77.8473208768944 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "6ZMBBGC0e67HCiZuw1ZGQ", + "focus": 0.9211394284163724, + "gap": 1 + }, + "endBinding": { + "elementId": "0eOjlptq2QPkgMZD4ilw_", + "focus": -0.504700685555249, + "gap": 1 + }, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "ECiME4kCyLcElqpESHieN", + "type": "text", + "x": 779.3728577032684, + "y": 549.0028937731206, + "width": 230.17587280273438, + "height": 40, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b28", + "roundness": null, + "seed": 1031090332, + "version": 173, + "versionNonce": 153810724, + "isDeleted": false, + "boundElements": null, + "updated": 1717946206425, + "link": null, + "locked": false, + "text": "Each KVstore \nmanaged by keeper of Module", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Each KVstore \nmanaged by keeper of Module", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "9gSP2Ihxnhrj8VPzU3iMs", + "type": "rectangle", + "x": 440.01400715336973, + "y": 528.7255798511883, + "width": 82.2687246664696, + "height": 43.508786429962356, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fff5f5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b29", + "roundness": { + "type": 3 + }, + "seed": 862728356, + "version": 81, + "versionNonce": 2003221028, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "bo-ZnZOJ2RMYEwiQDJwhQ" + } + ], + "updated": 1717946171042, + "link": null, + "locked": false + }, + { + "id": "bo-ZnZOJ2RMYEwiQDJwhQ", + "type": "text", + "x": 451.95639103201466, + "y": 540.4799730661695, + "width": 58.38395690917969, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fff5f5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b29V", + "roundness": null, + "seed": 1054504484, + "version": 32, + "versionNonce": 374592932, + "isDeleted": false, + "boundElements": null, + "updated": 1717946171043, + "link": null, + "locked": false, + "text": "kvstore", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "9gSP2Ihxnhrj8VPzU3iMs", + "originalText": "kvstore", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "sS09HXQCLT5o584RLcoh0", + "type": "rectangle", + "x": 535.7029587057802, + "y": 526.7472119897728, + "width": 85.49840063365426, + "height": 45.291996146440965, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fff5f5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2A", + "roundness": { + "type": 3 + }, + "seed": 1969890340, + "version": 163, + "versionNonce": 795200668, + "isDeleted": false, + "boundElements": null, + "updated": 1717946178372, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 243, + "versionNonce": 1959742876, + "index": "b2B", + "isDeleted": false, + "id": "dOSADw14E7lwG6QVycTWj", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 634.8832415027643, + "y": 525.0060952065161, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fff5f5", + "width": 81.61054425609542, + "height": 44.80601409924611, + "seed": 964534684, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1717946186317, + "link": null, + "locked": false + }, + { + "id": "Jn2VZB4Laog2zIHreQ13v", + "type": "text", + "x": 550.053971904952, + "y": 541.2988719488441, + "width": 58.38395690917969, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fff5f5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2C", + "roundness": null, + "seed": 268605596, + "version": 81, + "versionNonce": 271008028, + "isDeleted": false, + "boundElements": null, + "updated": 1717946183225, + "link": null, + "locked": false, + "text": "kvstore", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "kvstore", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "bmEWq6ldGd19BN7P3CPgk", + "type": "text", + "x": 649.2096160538688, + "y": 540.0169508007317, + "width": 58.38395690917969, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fff5f5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2D", + "roundness": null, + "seed": 1351980700, + "version": 78, + "versionNonce": 1793931548, + "isDeleted": false, + "boundElements": null, + "updated": 1717946190092, + "link": null, + "locked": false, + "text": "kvstore", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "kvstore", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "W3LH6VESuV13qvhxI7mcM", + "type": "text", + "x": 458.21179209642423, + "y": 348.25404197872706, + "width": 219.0238800048828, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#fff5f5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b2E", + "roundness": null, + "seed": 100014108, + "version": 34, + "versionNonce": 554727332, + "isDeleted": false, + "boundElements": null, + "updated": 1717946232701, + "link": null, + "locked": false, + "text": "Main components of the sdk", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Main components of the sdk", + "autoResize": true, + "lineHeight": 1.25 + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/docs/learn/intro/main-components.png b/docs/learn/intro/main-components.png new file mode 100644 index 000000000..fa82eb9bb Binary files /dev/null and b/docs/learn/intro/main-components.png differ diff --git a/versioned_docs/version-0.50/build/modules/auth/README.md b/versioned_docs/version-0.50/build/modules/auth/README.md index 1d5e22b5d..c51d10634 100644 --- a/versioned_docs/version-0.50/build/modules/auth/README.md +++ b/versioned_docs/version-0.50/build/modules/auth/README.md @@ -447,6 +447,22 @@ simd tx multisign transaction.json k1k2k3 k1sig.json k2sig.json k3sig.json Where `k1k2k3` is the multisig account address, `k1sig.json` is the signature of the first signer, `k2sig.json` is the signature of the second signer, and `k3sig.json` is the signature of the third signer. +##### Nested multisig transactions + +To allow transactions to be signed by nested multisigs, meaning that a participant of a multisig account can be another multisig account, the `--skip-signature-verification` flag must be used. + +```bash +# First aggregate signatures of the multisig participant +simd tx multi-sign transaction.json ms1 ms1p1sig.json ms1p2sig.json --signature-only --skip-signature-verification > ms1sig.json + +# Then use the aggregated signatures and the other signatures to sign the final transaction +simd tx multi-sign transaction.json k1ms1 k1sig.json ms1sig.json --skip-signature-verification +``` + +Where `ms1` is the nested multisig account address, `ms1p1sig.json` is the signature of the first participant of the nested multisig account, `ms1p2sig.json` is the signature of the second participant of the nested multisig account, and `ms1sig.json` is the aggregated signature of the nested multisig account. + +`k1ms1` is a multisig account comprised of an individual signer and another nested multisig account (`ms1`). `k1sig.json` is the signature of the first signer of the individual member. + More information about the `multi-sign` command can be found running `simd tx multi-sign --help`. #### `multisign-batch` diff --git a/versioned_docs/version-0.50/learn/advanced/07-cli.md b/versioned_docs/version-0.50/learn/advanced/07-cli.md index 2762d83e6..3ee93c052 100644 --- a/versioned_docs/version-0.50/learn/advanced/07-cli.md +++ b/versioned_docs/version-0.50/learn/advanced/07-cli.md @@ -153,7 +153,7 @@ Flags are added to commands directly (generally in the [module's CLI file](../.. ## Environment variables -Each flag is bound to its respective named environment variable. Then name of the environment variable consist of two parts - capital case `basename` followed by flag name of the flag. `-` must be substituted with `_`. For example flag `--home` for application with basename `GAIA` is bound to `GAIA_HOME`. It allows reducing the amount of flags typed for routine operations. For example instead of: +Each flag is bound to its respective named environment variable. Then name of the environment variable consist of two parts - capital case `basename` followed by flag name of the flag. `-` must be substituted with `_`. For example flag `--node` for application with basename `GAIA` is bound to `GAIA_NODE`. It allows reducing the amount of flags typed for routine operations. For example instead of: ```shell gaia --home=./ --node= --chain-id="testchain-1" --keyring-backend=test tx ... --from= @@ -163,7 +163,7 @@ this will be more convenient: ```shell # define env variables in .env, .envrc etc -GAIA_HOME= +NODE_HOME= GAIA_NODE= GAIA_CHAIN_ID="testchain-1" GAIA_KEYRING_BACKEND="test" diff --git a/versioned_docs/version-0.50/learn/advanced/17-autocli.md b/versioned_docs/version-0.50/learn/advanced/17-autocli.md index ea917ce20..5bdce3e55 100644 --- a/versioned_docs/version-0.50/learn/advanced/17-autocli.md +++ b/versioned_docs/version-0.50/learn/advanced/17-autocli.md @@ -75,10 +75,10 @@ if err := rootCmd.Execute(); err != nil { ### Keyring -`autocli` uses a keyring for key name resolving and signing transactions. Providing a keyring is optional, but if you want to use the `autocli` generated commands to sign transactions, you must provide a keyring. +`autocli` uses a keyring for key name resolving names and signing transactions. :::tip -This provides a better UX as it allows to resolve key names directly from the keyring in all transactions and commands. +AutoCLI provides a better UX than normal CLI as it allows to resolve key names directly from the keyring in all transactions and commands. ```sh q bank balances alice @@ -87,8 +87,9 @@ This provides a better UX as it allows to resolve key names directly from the ke ::: -The keyring to be provided to `client/v2` must match the `client/v2` keyring interface. -The keyring should be provided in the `appOptions` struct as follows, and can be gotten from the client context: +The keyring used for resolving names and signing transactions is provided via the `client.Context`. +The keyring is then converted to the `client/v2/autocli/keyring` interface. +If no keyring is provided, the `autocli` generated command will not be able to sign transactions, but will still be able to query the chain. :::tip The Cosmos SDK keyring and Hubl keyring both implement the `client/v2/autocli/keyring` interface, thanks to the following wrapper: @@ -99,18 +100,6 @@ keyring.NewAutoCLIKeyring(kb) ::: -:::warning -When using AutoCLI the keyring will only be created once and before any command flag parsing. -::: - -```go -// Set the keyring in the appOptions -appOptions.Keyring = keyring - -err := autoCliOpts.EnhanceRootCommand(rootCmd) -... -``` - ## Signing `autocli` supports signing transactions with the keyring.