From 1a7d0df3679928d727e0c3115a60f35b721d6d02 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 6 Dec 2024 14:04:49 +0100 Subject: [PATCH] updates --- docs/build/building-apps/00-runtime.md | 18 +++++++++++++++ docs/build/building-modules/00-intro.md | 7 ++++++ .../building-modules/01-module-manager.md | 8 +++---- docs/build/building-modules/06-keeper.md | 22 +++++++++++++++---- .../learn/advanced/{17-core.md => 02-core.md} | 18 ++++++++++----- docs/learn/advanced/04-store.md | 4 +++- docs/learn/beginner/04-gas-fees.md | 12 ++++++---- 7 files changed, 70 insertions(+), 19 deletions(-) rename docs/learn/advanced/{17-core.md => 02-core.md} (85%) diff --git a/docs/build/building-apps/00-runtime.md b/docs/build/building-apps/00-runtime.md index a962019e2993..87c044900a34 100644 --- a/docs/build/building-apps/00-runtime.md +++ b/docs/build/building-apps/00-runtime.md @@ -5,5 +5,23 @@ sidebar_position: 1 # What is `runtime`? The `runtime` package is the Cosmos SDK package that combines the building blocks of your blockchain together. It wires together the modules, the applications, the codecs, and the stores. +It is a layer of abstraction between `baseapp` and the application modules that simplifies the process of building a Cosmos SDK application. +## Modules wiring + +Runtime is reponsible for wiring the modules together. It uses `depinject` to inject the dependencies of the modules. + +## App wiring + +Runtime is the base boilerplate of a Cosmos SDK application. A user only needs to import `runtime` in their `app.go` and instantiate a `runtime.App`. + +## Services + +Modules have access to a multitude of services that are provided by the runtime. +These services include the `store`, the `event manager`, the `context`, and the `logger`. +As runtime is doing the wiring of modules, it can ensure that the services are scoped to their respective modules. + +```go reference +https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/runtime/module.go#L250-L279 +``` diff --git a/docs/build/building-modules/00-intro.md b/docs/build/building-modules/00-intro.md index 6618a44caa61..bd8e78a42380 100644 --- a/docs/build/building-modules/00-intro.md +++ b/docs/build/building-modules/00-intro.md @@ -58,6 +58,13 @@ While there are no definitive guidelines for writing modules, here are some impo * **Specialization**: A direct consequence of the **composability** feature is that modules should be **specialized**. Developers should carefully establish the scope of their module and not batch multiple functionalities into the same module. This separation of concerns enables modules to be re-used in other projects and improves the upgradability of the application. **Specialization** also plays an important role in the [object-capabilities model](https://docs.cosmos.network/main/learn/advanced/ocap#ocaps-in-practice) of the Cosmos SDK. * **Capabilities**: Most modules need to read and/or write to the store(s) of other modules. However, in an open-source environment, it is possible for some modules to be malicious. That is why module developers need to carefully think not only about how their module interacts with other modules, but also about how to give access to the module's store(s). The Cosmos SDK takes a capabilities-oriented approach to inter-module security. This means that each store defined by a module is accessed by a `key`, which is held by the module's [`keeper`](./06-keeper.md). This `keeper` defines how to access the store(s) and under what conditions. Access to the module's store(s) is done by passing a reference to the module's `keeper`. +## Core APIs for Modules + +The SDK provides a set of APIs that a module can implement, and a set of services that a module can use. +Those APIs are defined in the `cosmossdk.io/core/appmodule` package, and are used to defined the module capabilities, which is used by `runtime` during the wiring of the application. + +Learn more about the core APIs for modules [here](../../learn/advanced/02-core.md). + ## Main Components of Cosmos SDK Modules Modules are by convention defined in the `./x/` subfolder (e.g. the `bank` module will be defined in the `./x/bank` folder). They generally share the same core components: diff --git a/docs/build/building-modules/01-module-manager.md b/docs/build/building-modules/01-module-manager.md index 1e3bf38aa95e..4b1d0baa3839 100644 --- a/docs/build/building-modules/01-module-manager.md +++ b/docs/build/building-modules/01-module-manager.md @@ -217,11 +217,9 @@ The module manager is used throughout the application whenever an action on a co * `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-preblock-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-preblock-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-preblock-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. +* `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-preblock-beginblock-endblock.md) function of each modules implementing the `appmodule.HasBeginBlocker` interface, in the order defined in `OrderBeginBlockers`. +* `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-preblock-beginblock-endblock.md) function of each modules implementing the `appmodule.HasEndBlocker` interface, in the order defined in `OrderEndBlockers`. 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-preblock-beginblock-endblock.md) function of each modules implementing the `module.HasABCIEndBlock` interface, in the order defined in `OrderEndBlockers`. The function returns an `abci` which contains the aforementioned events, as well as validator set updates (if any). * (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. diff --git a/docs/build/building-modules/06-keeper.md b/docs/build/building-modules/06-keeper.md index 59180170cfd7..943bd2c1c6fe 100644 --- a/docs/build/building-modules/06-keeper.md +++ b/docs/build/building-modules/06-keeper.md @@ -28,9 +28,9 @@ The core idea behind the object-capabilities approach is to only reveal what is ```go type Keeper struct { - // External keepers, if any + appmodule.Environment - // Store key(s) + // External keepers, if any // codec @@ -46,8 +46,8 @@ https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.1/x/staking/keeper/keeper Let us go through the different parameters: +* Environment is a struct that holds the necessary references to services available to the modules. This includes the [store services](../../advanced/04-store.md#store-services), the [event manager](../../learn/advanced/06-events.md) and more. * 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. -* `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 marshal and unmarshal 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,6 +55,21 @@ Of course, it is possible to define different types of internal `keeper`s for th ## Environment +Environment is a struct, part of the module Core APIs (`cosmossdk.io/core/appmodule`). +A keeper should embed the `environment` struct to get access to the necessary references to services available to the modules. [Runtime](../../build/building-apps/00-runtime.md) ensures that the `Environment` struct is scoped to the module. + +```go reference +https://github.com/cosmos/cosmos-sdk/blob/core/v1.0.0-alpha.6/core/appmodule/v2/environment.go#L14-L29 +``` + +All services are then easily available to the module wherever the `keeper` is used: + +```go reference +https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/x/gov/keeper/proposal.go#L110-L112 +``` + +Learn more about those services in the [core api](../../learn/advanced/02-core.md) documentation. + ## Implementing Methods `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. @@ -67,5 +82,4 @@ State management is recommended to be done via [Collections](../packages/collect In the Cosmos SDK, it is crucial to be methodical and selective when managing state within a module, as improper state management can lead to inefficiency, security risks, and scalability issues. Not all data belongs in the on-chain state; it's important to store only essential blockchain data that needs to be verified by consensus. Storing unnecessary information, especially client-side data, can bloat the state and slow down performance. Instead, developers should focus on using an off-chain database to handle supplementary data, extending the API as needed. This approach minimizes on-chain complexity, optimizes resource usage, and keeps the blockchain state lean and efficient, ensuring scalability and smooth operations. - The Cosmos SDK leverages Protocol Buffers (protobuf) for efficient state management, providing a well-structured, binary encoding format that ensures compatibility and performance across different modules. The SDK’s recommended approach for managing state is through the [collections package](../pacakges/02-collections.md), which simplifies state handling by offering predefined data structures like maps and indexed sets, reducing the complexity of managing raw state data. While users can opt for custom encoding schemes if they need more flexibility or have specialized requirements, they should be aware that such custom implementations may not integrate seamlessly with indexers that decode state data on the fly. This could lead to challenges in data retrieval, querying, and interoperability, making protobuf a safer and more future-proof choice for most use cases. diff --git a/docs/learn/advanced/17-core.md b/docs/learn/advanced/02-core.md similarity index 85% rename from docs/learn/advanced/17-core.md rename to docs/learn/advanced/02-core.md index b6a453fbb130..b1b93235e403 100644 --- a/docs/learn/advanced/17-core.md +++ b/docs/learn/advanced/02-core.md @@ -4,8 +4,7 @@ sidebar_position: 1 # Core -Core is package which specifies the interfaces for core components of the Cosmos SDK. Other -packages in the SDK implement these interfaces to provide the core functionality. This design +Core (`cosmossdk.io/core`) is package which specifies the interfaces for core components of the Cosmos SDK. Other packages in the SDK implement these interfaces to provide the core functionality. This design provides modularity and flexibility to the SDK, allowing developers to swap out implementations of core components as needed. As such it is often referred to as the Core API. @@ -16,19 +15,28 @@ services of the SDK, such as the KVStore, EventManager, and Logger. The `Enviro passed to modules and other components of the SDK to provide access to these services. ```go reference -https://github.com/cosmos/cosmos-sdk/blob/core/v1.0.0-alpha.4/core/appmodule/v2/environment.go#L16-L29 +https://github.com/cosmos/cosmos-sdk/blob/core/v1.0.0-alpha.6/core/appmodule/v2/environment.go#L16-L29 ``` -Historically the SDK has used an [sdk.Context](02-context.md) to pass around services and data. +Historically the SDK has used an [sdk.Context](https://docs.cosmos.network/v0.50/learn/advanced/context) to pass around services and data. `Environment` is a newer construct that is intended to replace an `sdk.Context` in many cases. `sdk.Context` will be deprecated in the future on the same timeline as [Baseapp](00-baseapp.md). +## Logger + +The [Logger](https://pkg.go.dev/cosmossdk.io/log) provides a structured logging interface to the SDK. It is used throughout the SDK to log messages at various levels of severity. The Logger service is a thin wrapper around the [zerolog](https://github.com/rs/zerolog) logging library. +When used via environment, the logger is scoped to the module that is using it. + +```go reference +https://github.com/cosmos/cosmos-sdk/blob/v0.52.0-beta.2/runtime/module.go#L274 +``` + ## Branch Service The [BranchService](https://pkg.go.dev/cosmossdk.io/core/branch#Service.Execute) provides an interface to execute arbitrary code in a branched store. This is useful for executing code that needs to make changes to the store, but may need to be rolled back if an error occurs. -Below is a contrived example based on the `x/epoch` module's BeginBlocker logic. +Below is a contrived example based on the `x/epochs` module's BeginBlocker logic. ```go func (k Keeper) BeginBlocker(ctx context.Context) error { diff --git a/docs/learn/advanced/04-store.md b/docs/learn/advanced/04-store.md index 9c5b7dd9913b..ac0a0c991281 100644 --- a/docs/learn/advanced/04-store.md +++ b/docs/learn/advanced/04-store.md @@ -45,7 +45,9 @@ The `GetStoreType` is a simple method that returns the type of store, whereas a https://github.com/cosmos/cosmos-sdk/blob/store/v1.1.1/store/types/store.go#L287-L303 ``` -Branching and cache is used ubiquitously in the Cosmos SDK and required to be implemented on every store type. A storage branch creates an isolated, ephemeral branch of a store that can be passed around and updated without affecting the main underlying store. This is used to trigger temporary state-transitions that may be reverted later should an error occur. Read more about it in [context](./02-context.md#store-branching) +Branching and cache is used ubiquitously in the Cosmos SDK and required to be implemented on every store type. A storage branch creates an isolated, ephemeral branch of a store that can be passed around and updated without affecting the main underlying store. This is used to trigger temporary state-transitions that may be reverted later should an error occur. + +Branching is available as a service for modules. Read more about it in the [core](./02-core.md#branch-service) documentation. ### Commit Store diff --git a/docs/learn/beginner/04-gas-fees.md b/docs/learn/beginner/04-gas-fees.md index ea9af2e492b7..de9a308f91c6 100644 --- a/docs/learn/beginner/04-gas-fees.md +++ b/docs/learn/beginner/04-gas-fees.md @@ -26,7 +26,7 @@ In the Cosmos SDK, `gas` is a special unit that is used to track the consumption In the Cosmos SDK, `gas` is a simple alias for `uint64`, and is managed by an object called a _gas meter_. Gas meters implement the `GasMeter` interface ```go reference -https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-alpha.0/store/types/gas.go#L40-L51 +https://github.com/cosmos/cosmos-sdk/blob/b795646/store/types/gas.go#L40-L51 ``` where: @@ -40,17 +40,21 @@ where: * `IsPastLimit()` returns `true` if the amount of gas consumed by the gas meter instance is strictly above the limit, `false` otherwise. * `IsOutOfGas()` returns `true` if the amount of gas consumed by the gas meter instance is above or equal to the limit, `false` otherwise. -The gas meter is generally held in [`ctx`](../advanced/02-context.md), and consuming gas is done with the following pattern: +The gas meter is held under the `GasMeterService` in [`Environment`](../advanced/02-core.md), and consuming gas is done with the following pattern: + +:::note +The gas.Service does not give access to all the methods of the gas meter. +::: ```go -ctx.GasMeter().ConsumeGas(amount, "description") +environment.GasMeter(ctx).Consume(amount, "description") ``` By default, the Cosmos SDK makes use of two different gas meters, the [main gas meter](#main-gas-meter) and the [block gas meter](#block-gas-meter). ### Main Gas Meter -`ctx.GasMeter()` is the main gas meter of the application. The main gas meter is initialized in `FinalizeBlock` via `setFinalizeBlockState`, and then tracks gas consumption during execution sequences that lead to state-transitions, i.e. those originally triggered by [`FinalizeBlock`](../advanced/00-baseapp.md#finalizeblock). At the beginning of each transaction execution, the main gas meter **must be set to 0** in the [`AnteHandler`](#antehandler), so that it can track gas consumption per-transaction. +The main gas meter is initialized in `FinalizeBlock` via `setFinalizeBlockState`, and then tracks gas consumption during execution sequences that lead to state-transitions, i.e. those originally triggered by [`FinalizeBlock`](../advanced/00-baseapp.md#finalizeblock). At the beginning of each transaction execution, the main gas meter **must be set to 0** in the [`AnteHandler`](#antehandler), so that it can track gas consumption per-transaction. Gas consumption can be done manually, generally by the module developer in the [`BeginBlocker`, `EndBlocker`](../../build/building-modules/06-preblock-beginblock-endblock.md) or [`Msg` service](../../build/building-modules/03-msg-services.md), but most of the time it is done automatically whenever there is a read or write to the store. This automatic gas consumption logic is implemented in a special store called [`GasKv`](../advanced/04-store.md#gaskv-store).