diff --git a/docs/docs/03-light-clients/04-wasm/03-integration.md b/docs/docs/03-light-clients/04-wasm/03-integration.md index bfb0716698e..911dca19f5a 100644 --- a/docs/docs/03-light-clients/04-wasm/03-integration.md +++ b/docs/docs/03-light-clients/04-wasm/03-integration.md @@ -21,9 +21,9 @@ import ( cmtos "github.com/cometbft/cometbft/libs/os" - wasm "github.com/cosmos/ibc-go/modules/light-clients/08-wasm" - wasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" - wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ibcwasm "github.com/cosmos/ibc-go/modules/light-clients/08-wasm" + ibcwasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" ... ) @@ -32,14 +32,14 @@ import ( // Register the AppModule for the 08-wasm module ModuleBasics = module.NewBasicManager( ... - wasm.AppModuleBasic{}, + ibcwasm.AppModuleBasic{}, ... ) // Add 08-wasm Keeper type SimApp struct { ... - WasmClientKeeper wasmkeeper.Keeper + WasmClientKeeper ibcwasmkeeper.Keeper ... } @@ -54,7 +54,7 @@ func NewSimApp( ... keys := sdk.NewKVStoreKeys( ... - wasmtypes.StoreKey, + ibcwasmtypes.StoreKey, ) // Instantiate 08-wasm's keeper @@ -63,9 +63,9 @@ func NewSimApp( // This is the recommended approach when the chain // also uses `x/wasm`, and then the Wasm VM instance // can be shared. - app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( + app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( appCodec, - runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), app.IBCKeeper.ClientKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmVM, @@ -74,21 +74,21 @@ func NewSimApp( app.ModuleManager = module.NewManager( // SDK app modules ... - wasm.NewAppModule(app.WasmClientKeeper), + ibcwasm.NewAppModule(app.WasmClientKeeper), ) app.ModuleManager.SetOrderBeginBlockers( ... - wasmtypes.ModuleName, + ibcwasmtypes.ModuleName, ... ) app.ModuleManager.SetOrderEndBlockers( ... - wasmtypes.ModuleName, + ibcwasmtypes.ModuleName, ... ) genesisModuleOrder := []string{ ... - wasmtypes.ModuleName, + ibcwasmtypes.ModuleName, ... } app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...) @@ -102,7 +102,7 @@ func NewSimApp( // must be before Loading version if manager := app.SnapshotManager(); manager != nil { err := manager.RegisterExtensions( - wasmkeeper.NewWasmSnapshotter(app.CommitMultiStore(), &app.WasmClientKeeper), + ibcwasmkeeper.NewWasmSnapshotter(app.CommitMultiStore(), &app.WasmClientKeeper), ) if err != nil { panic(fmt.Errorf("failed to register snapshot extension: %s", err)) @@ -116,7 +116,7 @@ func NewSimApp( ctx := app.BaseApp.NewUncachedContext(true, cmtproto.Header{}) // Initialize pinned codes in wasmvm as they are not persisted there - if err := wasmkeeper.InitializePinnedCodes(ctx); err != nil { + if err := ibcwasmkeeper.InitializePinnedCodes(ctx); err != nil { cmtos.Exit(fmt.Sprintf("failed initialize pinned codes %s", err)) } } @@ -136,7 +136,7 @@ In order to share the Wasm VM instance please follow the guideline below. Please - Instantiate the Wasm VM in `app.go` with the parameters of your choice. - [Create an `Option` with this Wasm VM instance](https://github.com/CosmWasm/wasmd/blob/db93d7b6c7bb6f4a340d74b96a02cec885729b59/x/wasm/keeper/options.go#L21-L25). - Add the option created in the previous step to a slice and [pass it to the `x/wasm NewKeeper` constructor function](https://github.com/CosmWasm/wasmd/blob/db93d7b6c7bb6f4a340d74b96a02cec885729b59/x/wasm/keeper/keeper_cgo.go#L36). -- Pass the pointer to the Wasm VM instance to `08-wasm` [NewKeeperWithVM constructor function](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/keeper/keeper.go#L33-L38). +- Pass the pointer to the Wasm VM instance to `08-wasm` [NewKeeperWithVM constructor function](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/keeper/keeper.go#L39-L47). The code to set this up would look something like this: @@ -147,7 +147,7 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" wasmvm "github.com/CosmWasm/wasmvm" - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + ibcwasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" ... ) @@ -167,15 +167,15 @@ if err != nil { // create an Option slice (or append to an existing one) // with the option to use a custom Wasm VM instance -wasmOpts = []wasmkeeper.Option{ - wasmkeeper.WithWasmEngine(wasmer), +wasmOpts = []ibcwasmkeeper.Option{ + ibcwasmkeeper.WithWasmEngine(wasmer), } // the keeper will use the provided Wasm VM instance, // instead of instantiating a new one -app.WasmKeeper = wasmkeeper.NewKeeper( +app.WasmKeeper = ibcwasmkeeper.NewKeeper( appCodec, - keys[wasmtypes.StoreKey], + keys[ibcwasmtypes.StoreKey], app.AccountKeeper, app.BankKeeper, app.StakingKeeper, @@ -194,9 +194,9 @@ app.WasmKeeper = wasmkeeper.NewKeeper( wasmOpts..., ) -app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( appCodec, - runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), app.IBCKeeper.ClientKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmer, // pass the Wasm VM instance to `08-wasm` keeper constructor @@ -208,14 +208,14 @@ app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( ### If `x/wasm` is not present If the chain does not use [`x/wasm`](https://github.com/CosmWasm/wasmd/tree/main/x/wasm), even though it is still possible to use the method above from the previous section -(e.g. instantiating a Wasm VM in app.go an pass it to 08-wasm's [`NewKeeperWithVM` constructor function](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/keeper/keeper.go#L33-L38), since there would be no need in this case to share the Wasm VM instance with another module, you can use the [`NewKeeperWithConfig`` constructor function](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/keeper/keeper.go#L52-L57) and provide the Wasm VM configuration parameters of your choice instead. A Wasm VM instance will be created in`NewKeeperWithConfig`. The parameters that can set are: +(e.g. instantiating a Wasm VM in app.go an pass it to 08-wasm's [`NewKeeperWithVM` constructor function](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/keeper/keeper.go#L39-L47), since there would be no need in this case to share the Wasm VM instance with another module, you can use the [`NewKeeperWithConfig`` constructor function](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/keeper/keeper.go#L88-L96) and provide the Wasm VM configuration parameters of your choice instead. A Wasm VM instance will be created in`NewKeeperWithConfig`. The parameters that can set are: - `DataDir` is the [directory for Wasm blobs and various caches](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L25). In `wasmd` this is set to the [`wasm` folder under the home directory](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L578). - `SupportedCapabilities` is a comma separated [list of capabilities supported by the chain](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L26). [`wasmd` sets this to all the available capabilities](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L586), but 08-wasm only requires `iterator`. - `MemoryCacheSize` sets [the size in MiB of an in-memory cache for e.g. module caching](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L29C16-L29C104). It is not consensus-critical and should be defined on a per-node basis, often in the range 100 to 1000 MB. [`wasmd` reads this value of](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L579). Default value is 256. - `ContractDebugMode` is a [flag to enable/disable printing debug logs from the contract to STDOUT](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L28). This should be false in production environments. Default value is false. -Another configuration parameter of the Wasm VM is the contract memory limit (in MiB), which is [set to 32](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/types/config.go#L5), [following the example of `wasmd`](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/x/wasm/keeper/keeper.go#L32-L34). This parameter is not configurable by users of `08-wasm`. +Another configuration parameter of the Wasm VM is the contract memory limit (in MiB), which is [set to 32](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/types/config.go#L8), [following the example of `wasmd`](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/x/wasm/keeper/keeper.go#L32-L34). This parameter is not configurable by users of `08-wasm`. The following sample code shows how the keeper would be constructed using this method: @@ -225,19 +225,19 @@ import ( ... "github.com/cosmos/cosmos-sdk/runtime" - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ibcwasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" ... ) ... -wasmConfig := wasmtypes.WasmConfig{ +wasmConfig := ibcwasmtypes.WasmConfig{ DataDir: "ibc_08-wasm_client_data", SupportedCapabilities: "iterator", ContractDebugMode: false, } -app.WasmClientKeeper = wasmkeeper.NewKeeperWithConfig( +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithConfig( appCodec, - runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), app.IBCKeeper.ClientKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmConfig, @@ -245,7 +245,7 @@ app.WasmClientKeeper = wasmkeeper.NewKeeperWithConfig( ) ``` -Check out also the [`WasmConfig` type definition](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/types/config.go#L7-L20) for more information on each of the configurable parameters. Some parameters allow node-level configurations. There is additionally the function [`DefaultWasmConfig`](https://github.com/cosmos/ibc-go/blob/6d8cee53a72524b7cf396d65f6c19fed45803321/modules/light-clients/08-wasm/types/config.go#L30) available that returns a configuration with the default values. +Check out also the [`WasmConfig` type definition](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/types/config.go#L21-L31) for more information on each of the configurable parameters. Some parameters allow node-level configurations. There is additionally the function [`DefaultWasmConfig`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/types/config.go#L36-L42) available that returns a configuration with the default values. ### Options @@ -282,9 +282,9 @@ querierOption := ibcwasmkeeper.WithQueryPlugins(&queryPlugins) Finally, we pass the option to the `NewKeeperWithConfig` or `NewKeeperWithVM` constructor function during [Keeper instantiation](#keeper-instantiation): ```diff -app.WasmClientKeeper = wasmkeeper.NewKeeperWithConfig( +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithConfig( appCodec, - runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), app.IBCKeeper.ClientKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmConfig, @@ -294,9 +294,9 @@ app.WasmClientKeeper = wasmkeeper.NewKeeperWithConfig( ``` ```diff -app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( appCodec, - runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), app.IBCKeeper.ClientKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmer, // pass the Wasm VM instance to `08-wasm` keeper constructor @@ -307,12 +307,12 @@ app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( ## Updating `AllowedClients` -In order to use the `08-wasm` module chains must update the [`AllowedClients` parameter in the 02-client submodule](https://github.com/cosmos/ibc-go/blob/main/proto/ibc/core/client/v1/client.proto#L103) of core IBC. This can be configured directly in the application upgrade handler with the sample code below: +In order to use the `08-wasm` module chains must update the [`AllowedClients` parameter in the 02-client submodule](https://github.com/cosmos/ibc-go/blob/v8.0.0/proto/ibc/core/client/v1/client.proto#L64) of core IBC. This can be configured directly in the application upgrade handler with the sample code below: ```go import ( ... - wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" ... ) @@ -327,7 +327,7 @@ func CreateWasmUpgradeHandler( sdkCtx := sdk.UnwrapSDKContext(ctx) // explicitly update the IBC 02-client params, adding the wasm client type params := clientKeeper.GetParams(ctx) - params.AllowedClients = append(params.AllowedClients, wasmtypes.Wasm) + params.AllowedClients = append(params.AllowedClients, ibcwasmtypes.Wasm) clientKeeper.SetParams(ctx, params) return mm.RunMigrations(ctx, configurator, vm) @@ -361,8 +361,8 @@ func (app SimApp) RegisterUpgradeHandlers() { ## Adding snapshot support -In order to use the `08-wasm` module chains are required to register the `WasmSnapshotter` extension in the snapshot manager. This snapshotter takes care of persisting the external state, in the form of contract code, of the Wasm VM instance to disk when the chain is snapshotted. [This code](https://github.com/cosmos/ibc-go/blob/2bd29c08fd1fe50b461fc33a25735aa792dc896e/modules/light-clients/08-wasm/testing/simapp/app.go#L768-L776) should be placed in `NewSimApp` function in `app.go`. +In order to use the `08-wasm` module chains are required to register the `WasmSnapshotter` extension in the snapshot manager. This snapshotter takes care of persisting the external state, in the form of contract code, of the Wasm VM instance to disk when the chain is snapshotted. [This code](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/testing/simapp/app.go#L775-L782) should be placed in `NewSimApp` function in `app.go`. ## Pin byte codes at start -Wasm byte codes should be pinned to the WasmVM cache on every application start, therefore [this code](https://github.com/cosmos/ibc-go/blob/0ed221f687ffce75984bc57402fd678e07aa6cc5/modules/light-clients/08-wasm/testing/simapp/app.go#L821-L826) should be placed in `NewSimApp` function in `app.go`. +Wasm byte codes should be pinned to the WasmVM cache on every application start, therefore [this code](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/testing/simapp/app.go#L825-L830) should be placed in `NewSimApp` function in `app.go`. diff --git a/docs/docs/03-light-clients/04-wasm/04-messages.md b/docs/docs/03-light-clients/04-wasm/04-messages.md index 6757788099c..6b8321583c2 100644 --- a/docs/docs/03-light-clients/04-wasm/04-messages.md +++ b/docs/docs/03-light-clients/04-wasm/04-messages.md @@ -27,7 +27,7 @@ This message is expected to fail if: Only light client contracts stored using `MsgStoreCode` are allowed to be instantiated. An attempt to create a light client from contracts uploaded via other means (e.g. through `x/wasm` if the module shares the same Wasm VM instance with 08-wasm) will fail. Due to the idempotent nature of the Wasm VM's `StoreCode` function, it is possible to store the same byte code multiple times. -When execution of `MsgStoreCode` succeeds, the checksum of the contract (i.e. the sha256 hash of the contract's byte code) is stored in an allow list. When a relayer submits [`MsgCreateClient`](https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/core/client/v1/tx.proto#L25-L37) with 08-wasm's `ClientState`, the client state includes the checksum of the Wasm byte code that should be called. Then 02-client calls [08-wasm's implementation of `Initialize` function](https://github.com/cosmos/ibc-go/blob/v7.2.0/modules/core/02-client/keeper/client.go#L34) (which is an interface function part of `ClientState`), and it will check that the checksum in the client state matches one of the checksums in the allow list. If a match is found, the light client is initialized; otherwise, the transaction is aborted. +When execution of `MsgStoreCode` succeeds, the checksum of the contract (i.e. the sha256 hash of the contract's byte code) is stored in an allow list. When a relayer submits [`MsgCreateClient`](https://github.com/cosmos/ibc-go/blob/v8.0.0/proto/ibc/core/client/v1/tx.proto#L25-L37) with 08-wasm's `ClientState`, the client state includes the checksum of the Wasm byte code that should be called. Then 02-client calls [08-wasm's implementation of `Initialize` function](https://github.com/cosmos/ibc-go/blob/v8.0.0/modules/core/02-client/keeper/client.go#L36) (which is an interface function part of `ClientState`), and it will check that the checksum in the client state matches one of the checksums in the allow list. If a match is found, the light client is initialized; otherwise, the transaction is aborted. ## `MsgMigrateContract` @@ -72,4 +72,4 @@ This message is expected to fail if: - `Signer` is an invalid Bech32 address, or it does not match the designated authority address. - `Checksum` is not exactly 32 bytes long or it is not found in the list of allowed checksums (a new checksum is added to the list when executing `MsgStoreCode`). -When a checksum is removed from the list of allowed checksums, then the corresponding Wasm byte code will not be available for instantiation in [08-wasm's implementation of `Initialize` function](https://github.com/cosmos/ibc-go/blob/v7.2.0/modules/core/02-client/keeper/client.go#L34). +When a checksum is removed from the list of allowed checksums, then the corresponding Wasm byte code will not be available for instantiation in [08-wasm's implementation of `Initialize` function](https://github.com/cosmos/ibc-go/blob/v8.0.0/modules/core/02-client/keeper/client.go#L36). diff --git a/docs/docs/03-light-clients/04-wasm/05-governance.md b/docs/docs/03-light-clients/04-wasm/05-governance.md index afac0d3ec99..31286bce28d 100644 --- a/docs/docs/03-light-clients/04-wasm/05-governance.md +++ b/docs/docs/03-light-clients/04-wasm/05-governance.md @@ -11,7 +11,7 @@ Learn how to upload Wasm light client byte code on a chain, and how to migrate a ## Setting an authority -Both the storage of Wasm light client byte code as well as the migration of an existing Wasm light client contract are permissioned (i.e. only allowed to an authority such as governance). The designated authority is specified when instantiating `08-wasm`'s keeper: both [`NewKeeperWithVM`](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/keeper/keeper.go#L33-L38) and [`NewKeeperWithConfig`](https://github.com/cosmos/ibc-go/blob/c95c22f45cb217d27aca2665af9ac60b0d2f3a0c/modules/light-clients/08-wasm/keeper/keeper.go#L52-L57) constructor functions accept an `authority` argument that must be the address of the authorized actor. For example, in `app.go`, when instantiating the keeper, you can pass the address of the governance module: +Both the storage of Wasm light client byte code as well as the migration of an existing Wasm light client contract are permissioned (i.e. only allowed to an authority such as governance). The designated authority is specified when instantiating `08-wasm`'s keeper: both [`NewKeeperWithVM`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/keeper/keeper.go#L39-L47) and [`NewKeeperWithConfig`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/keeper/keeper.go#L88-L96) constructor functions accept an `authority` argument that must be the address of the authorized actor. For example, in `app.go`, when instantiating the keeper, you can pass the address of the governance module: ```go // app.go @@ -21,15 +21,15 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - wasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" - wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ibcwasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" ... ) // app.go -app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( appCodec, - runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), app.IBCKeeper.ClientKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), // authority wasmVM, @@ -39,7 +39,7 @@ app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( ## Storing new Wasm light client byte code - If governance is the allowed authority, the governance v1 proposal that needs to be submitted to upload a new light client contract should contain the message [`MsgStoreCode`](https://github.com/cosmos/ibc-go/blob/f822b4fa7932a657420aba219c563e06c4465221/proto/ibc/lightclients/wasm/v1/tx.proto#L16-L23) with the base64-encoded byte code of the Wasm contract. Use the following CLI command and JSON as an example: + If governance is the allowed authority, the governance v1 proposal that needs to be submitted to upload a new light client contract should contain the message [`MsgStoreCode`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/proto/ibc/lightclients/wasm/v1/tx.proto#L23-L30) with the base64-encoded byte code of the Wasm contract. Use the following CLI command and JSON as an example: ```shell simd tx gov submit-proposal --from @@ -69,7 +69,7 @@ Alternatively, the process of submitting the proposal may be simpler if you use ## Migrating an existing Wasm light client contract -If governance is the allowed authority, the governance v1 proposal that needs to be submitted to migrate an existing new Wasm light client contract should contain the message [`MsgMigrateContract`](https://github.com/cosmos/ibc-go/blob/729cb090951b1e996427b2258cf72c49787b885a/proto/ibc/lightclients/wasm/v1/tx.proto#L51-L63) with the checksum of the Wasm byte code to migrate to. Use the following CLI command and JSON as an example: +If governance is the allowed authority, the governance v1 proposal that needs to be submitted to migrate an existing new Wasm light client contract should contain the message [`MsgMigrateContract`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/proto/ibc/lightclients/wasm/v1/tx.proto#L52-L63) with the checksum of the Wasm byte code to migrate to. Use the following CLI command and JSON as an example: ```shell simd tx gov submit-proposal --from @@ -99,7 +99,7 @@ To learn more about the `submit-proposal` CLI command, please check out [the rel ## Removing an existing checksum -If governance is the allowed authority, the governance v1 proposal that needs to be submitted to remove a specific checksum from the list of allowed checksums should contain the message [`MsgRemoveChecksum`](https://github.com/cosmos/ibc-go/blob/729cb090951b1e996427b2258cf72c49787b885a/proto/ibc/lightclients/wasm/v1/tx.proto#L38-L46) with the checksum (of a corresponding Wasm byte code). Use the following CLI command and JSON as an example: +If governance is the allowed authority, the governance v1 proposal that needs to be submitted to remove a specific checksum from the list of allowed checksums should contain the message [`MsgRemoveChecksum`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/proto/ibc/lightclients/wasm/v1/tx.proto#L39-L46) with the checksum (of a corresponding Wasm byte code). Use the following CLI command and JSON as an example: ```shell simd tx gov submit-proposal --from diff --git a/docs/docs/03-light-clients/04-wasm/07-contracts.md b/docs/docs/03-light-clients/04-wasm/07-contracts.md index 2c8c8e84028..1f6759d06c0 100644 --- a/docs/docs/03-light-clients/04-wasm/07-contracts.md +++ b/docs/docs/03-light-clients/04-wasm/07-contracts.md @@ -15,7 +15,7 @@ The `08-wasm` light client proxy performs calls to the Wasm light client via the ## `InstantiateMessage` -This is the message sent to the contract's `instantiate` entry point. It contains the bytes of the protobuf-encoded client and consensus states of the underlying light client, both provided in [`MsgCreateClient`](https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/core/client/v1/tx.proto#L25-L37). Please note that the bytes contained within the JSON message are represented as base64-encoded strings. +This is the message sent to the contract's `instantiate` entry point. It contains the bytes of the protobuf-encoded client and consensus states of the underlying light client, both provided in [`MsgCreateClient`](https://github.com/cosmos/ibc-go/blob/v8.0.0/proto/ibc/core/client/v1/tx.proto#L40-L52). Please note that the bytes contained within the JSON message are represented as base64-encoded strings. ```go type InstantiateMessage struct { diff --git a/docs/docs/03-light-clients/04-wasm/09-migrations.md b/docs/docs/03-light-clients/04-wasm/09-migrations.md index 61082f5699f..2e85079168e 100644 --- a/docs/docs/03-light-clients/04-wasm/09-migrations.md +++ b/docs/docs/03-light-clients/04-wasm/09-migrations.md @@ -13,4 +13,4 @@ This guide provides instructions for migrating 08-wasm versions. ## Chains -In the 08-wasm versions compatible with ibc-go v7.3.x and above from the v7 release line, the checksums of the uploaded Wasm bytecodes are all stored under a single key. From ibc-go v8.0.x the checksums are stored using [`collections.KeySet`](https://docs.cosmos.network/v0.50/build/packages/collections#keyset), whose full functionality became available in Cosmos SDK v0.50. There is therefore an [automatic migration handler](https://github.com/cosmos/ibc-go/blob/51469420d8b14021768eacf0d8a61c5036a7eb91/modules/light-clients/08-wasm/module.go#L115-L118) configured in the 08-wasm module to migrate the stored checksums to `collections.KeySet`. +In the 08-wasm versions compatible with ibc-go v7.3.x and above from the v7 release line, the checksums of the uploaded Wasm bytecodes are all stored under a single key. From ibc-go v8.0.x the checksums are stored using [`collections.KeySet`](https://docs.cosmos.network/v0.50/build/packages/collections#keyset), whose full functionality became available in Cosmos SDK v0.50. There is therefore an [automatic migration handler](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/module.go#L115-L118) configured in the 08-wasm module to migrate the stored checksums to `collections.KeySet`. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/01-overview.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/01-overview.md new file mode 100644 index 00000000000..b4c901a020f --- /dev/null +++ b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/01-overview.md @@ -0,0 +1,26 @@ +--- +title: Overview +sidebar_label: Overview +sidebar_position: 1 +slug: /ibc/light-clients/wasm/overview +--- + +# `08-wasm` + +## Overview + +Learn about the `08-wasm` light client proxy module. {synopsis} + +### Context + +Traditionally, light clients used by ibc-go have been implemented only in Go, and since ibc-go v7 (with the release of the 02-client refactor), they are [first-class Cosmos SDK modules](../../../../architecture/adr-010-light-clients-as-sdk-modules.md). This means that updating existing light client implementations or adding support for new light clients is a multi-step, time-consuming process involving on-chain governance: it is necessary to modify the codebase of ibc-go (if the light client is part of its codebase), re-build chains' binaries, pass a governance proposal and have validators upgrade their nodes. + +### Motivation + +To break the limitation of being able to write light client implementations only in Go, the `08-wasm` adds support to run light clients written in a Wasm-compilable language. The light client byte code implements the entry points of a [CosmWasm](https://docs.cosmwasm.com/docs/) smart contract, and runs inside a Wasm VM. The `08-wasm` module exposes a proxy light client interface that routes incoming messages to the appropriate handler function, inside the Wasm VM, for execution. + +Adding a new light client to a chain is just as simple as submitting a governance proposal with the message that stores the byte code of the light client contract. No coordinated upgrade is needed. When the governance proposal passes and the message is executed, the contract is ready to be instantiated upon receiving a relayer-submitted `MsgCreateClient`. The process of creating a Wasm light client is the same as with a regular light client implemented in Go. + +### Use cases + +- Development of light clients for non-Cosmos ecosystem chains: state machines in other ecosystems are, in many cases, implemented in Rust, and thus there are probably libraries used in their light client implementations for which there is no equivalent in Go. This makes the development of a light client in Go very difficult, but relatively simple to do it in Rust. Therefore, writing a CosmWasm smart contract in Rust that implements the light client algorithm becomes a lower effort. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/02-concepts.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/02-concepts.md new file mode 100644 index 00000000000..e3f293bae16 --- /dev/null +++ b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/02-concepts.md @@ -0,0 +1,74 @@ +--- +title: Concepts +sidebar_label: Concepts +sidebar_position: 2 +slug: /ibc/light-clients/wasm/concepts +--- + +# Concepts + +Learn about the differences between a proxy light client and a Wasm light client. {synopsis} + +## Proxy light client + +The `08-wasm` module is not a regular light client in the same sense as, for example, the 07-tendermint light client. `08-wasm` is instead a *proxy* light client module, and this means that the module acts a proxy to the actual implementations of light clients. The module will act as a wrapper for the actual light clients uploaded as Wasm byte code and will delegate all operations to them (i.e. `08-wasm` just passes through the requests to the Wasm light clients). Still, the `08-wasm` module implements all the required interfaces necessary to integrate with core IBC, so that 02-client can call into it as it would for any other light client module. These interfaces are `ClientState`, `ConsensusState` and `ClientMessage`, and we will describe them in the context of `08-wasm` in the following sections. For more information about this set of interfaces, please read section [Overview of the light client module developer guide](../01-developer-guide/01-overview.md#overview). + +### `ClientState` + +The `08-wasm`'s `ClientState` data structure contains three fields: + +- `Data` contains the bytes of the Protobuf-encoded client state of the underlying light client implemented as a Wasm contract. For example, if the Wasm light client contract implements the GRANDPA light client algorithm, then `Data` will contain the bytes for a [GRANDPA client state](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L35-L60). +- `Checksum` is the sha256 hash of the Wasm contract's byte code. This hash is used as an identifier to call the right contract. +- `LatestHeight` is the latest height of the counterparty state machine (i.e. the height of the blockchain), whose consensus state the light client tracks. + +```go +type ClientState struct { + // bytes encoding the client state of the underlying + // light client implemented as a Wasm contract + Data []byte + // sha256 hash of Wasm contract byte code + Checksum []byte + // latest height of the counterparty ledger + LatestHeight types.Height +} +``` + +See section [`ClientState` of the light client module developer guide](../01-developer-guide/01-overview.md#clientstate) for more information about the `ClientState` interface. + +### `ConsensusState` + +The `08-wasm`'s `ConsensusState` data structure maintains one field: + +- `Data` contains the bytes of the Protobuf-encoded consensus state of the underlying light client implemented as a Wasm contract. For example, if the Wasm light client contract implements the GRANDPA light client algorithm, then `Data` will contain the bytes for a [GRANDPA consensus state](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L87-L94). + +```go +type ConsensusState struct { + // bytes encoding the consensus state of the underlying light client + // implemented as a Wasm contract. + Data []byte +} +``` + +See section [`ConsensusState` of the light client module developer guide](../01-developer-guide/01-overview.md#consensusstate) for more information about the `ConsensusState` interface. + +### `ClientMessage` + +`ClientMessage` is used for performing updates to a `ClientState` stored on chain. The `08-wasm`'s `ClientMessage` data structure maintains one field: + +- `Data` contains the bytes of the Protobuf-encoded header(s) or misbehaviour for the underlying light client implemented as a Wasm contract. For example, if the Wasm light client contract implements the GRANDPA light client algorithm, then `Data` will contain the bytes of either [header](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L96-L104) or [misbehaviour](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L106-L112) for a GRANDPA light client. + +```go +type ClientMessage struct { + // bytes encoding the header(s) or misbehaviour for the underlying light client + // implemented as a Wasm contract. + Data []byte +} +``` + +See section [`ClientMessage` of the light client module developer guide](../01-developer-guide/01-overview.md#clientmessage) for more information about the `ClientMessage` interface. + +## Wasm light client + +The actual light client can be implemented in any language that compiles to Wasm and implements the interfaces of a [CosmWasm](https://docs.cosmwasm.com/docs/) contract. Even though in theory other languages could be used, in practice (at least for the time being) the most suitable language to use would be Rust, since there is already good support for it for developing CosmWasm smart contracts. + +At the moment of writing there are two contracts available: one for [Tendermint](https://github.com/ComposableFi/composable-ibc/tree/master/light-clients/ics07-tendermint-cw) and one [GRANDPA](https://github.com/ComposableFi/composable-ibc/tree/master/light-clients/ics10-grandpa-cw) (which is being used in production in [Composable Finance's Centauri bridge](https://github.com/ComposableFi/composable-ibc)). And there are others in development (e.g. for Near). diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/03-integration.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/03-integration.md new file mode 100644 index 00000000000..0b36ef4d17a --- /dev/null +++ b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/03-integration.md @@ -0,0 +1,368 @@ +--- +title: Integration +sidebar_label: Integration +sidebar_position: 3 +slug: /ibc/light-clients/wasm/integration +--- + +# Integration + +Learn how to integrate the `08-wasm` module in a chain binary and about the recommended approaches depending on whether the [`x/wasm` module](https://github.com/CosmWasm/wasmd/tree/main/x/wasm) is already used in the chain. The following document only applies for Cosmos SDK chains. {synopsis} + +## `app.go` setup + +The sample code below shows the relevant integration points in `app.go` required to setup the `08-wasm` module in a chain binary. Since `08-wasm` is a light client module itself, please check out as well the section [Integrating light clients](../../01-ibc/02-integration.md#integrating-light-clients) for more information: + +```go +// app.go +import ( + ... + "github.com/cosmos/cosmos-sdk/runtime" + + cmtos "github.com/cometbft/cometbft/libs/os" + + ibcwasm "github.com/cosmos/ibc-go/modules/light-clients/08-wasm" + ibcwasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ... +) + +... + +// Register the AppModule for the 08-wasm module +ModuleBasics = module.NewBasicManager( + ... + ibcwasm.AppModuleBasic{}, + ... +) + +// Add 08-wasm Keeper +type SimApp struct { + ... + WasmClientKeeper ibcwasmkeeper.Keeper + ... +} + +func NewSimApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + loadLatest bool, + appOpts servertypes.AppOptions, + baseAppOptions ...func(*baseapp.BaseApp), +) *SimApp { + ... + keys := sdk.NewKVStoreKeys( + ... + ibcwasmtypes.StoreKey, + ) + + // Instantiate 08-wasm's keeper + // This sample code uses a constructor function that + // accepts a pointer to an existing instance of Wasm VM. + // This is the recommended approach when the chain + // also uses `x/wasm`, and then the Wasm VM instance + // can be shared. + app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( + appCodec, + keys[wasmtypes.StoreKey], + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmVM, + app.GRPCQueryRouter(), + ) + app.ModuleManager = module.NewManager( + // SDK app modules + ... + ibcwasm.NewAppModule(app.WasmClientKeeper), + ) + app.ModuleManager.SetOrderBeginBlockers( + ... + ibcwasmtypes.ModuleName, + ... + ) + app.ModuleManager.SetOrderEndBlockers( + ... + ibcwasmtypes.ModuleName, + ... + ) + genesisModuleOrder := []string{ + ... + ibcwasmtypes.ModuleName, + ... + } + app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...) + app.ModuleManager.SetOrderExportGenesis(genesisModuleOrder...) + ... + + // initialize BaseApp + app.SetInitChainer(app.InitChainer) + ... + + // must be before Loading version + if manager := app.SnapshotManager(); manager != nil { + err := manager.RegisterExtensions( + ibcwasmkeeper.NewWasmSnapshotter(app.CommitMultiStore(), &app.WasmClientKeeper), + ) + if err != nil { + panic(fmt.Errorf("failed to register snapshot extension: %s", err)) + } + } + ... + + if loadLatest { + ... + + ctx := app.BaseApp.NewUncachedContext(true, cmtproto.Header{}) + + // Initialize pinned codes in wasmvm as they are not persisted there + if err := ibcwasmkeeper.InitializePinnedCodes(ctx, app.appCodec); err != nil { + cmtos.Exit(fmt.Sprintf("failed initialize pinned codes %s", err)) + } + } +} +``` + +## Keeper instantiation + +When it comes to instantiating `08-wasm`'s keeper there are two recommended ways of doing it. Choosing one or the other will depend on whether the chain already integrates [`x/wasm`](https://github.com/CosmWasm/wasmd/tree/main/x/wasm) or not. + +### If `x/wasm` is present + +If the chain where the module is integrated uses `x/wasm` then we recommend that both `08-wasm` and `x/wasm` share the same Wasm VM instance. Having two separate Wasm VM instances is still possible, but care should be taken to make sure that both instances do not share the directory when the VM stores blobs and various caches, otherwise unexpected behaviour is likely to happen. + +In order to share the Wasm VM instance please follow the guideline below. Please note that this requires `x/wasm`v0.41 or above. + +- Instantiate the Wasm VM in `app.go` with the parameters of your choice. +- [Create an `Option` with this Wasm VM instance](https://github.com/CosmWasm/wasmd/blob/db93d7b6c7bb6f4a340d74b96a02cec885729b59/x/wasm/keeper/options.go#L21-L25). +- Add the option created in the previous step to a slice and [pass it to the `x/wasm NewKeeper` constructor function](https://github.com/CosmWasm/wasmd/blob/db93d7b6c7bb6f4a340d74b96a02cec885729b59/x/wasm/keeper/keeper_cgo.go#L36). +- Pass the pointer to the Wasm VM instance to `08-wasm` [NewKeeperWithVM constructor function](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/keeper/keeper.go#L38-L46). + +The code to set this up would look something like this: + +```go +// app.go +import ( + ... + "github.com/cosmos/cosmos-sdk/runtime" + + wasmvm "github.com/CosmWasm/wasmvm" + ibcwasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + ... +) + +... + +// instantiate the Wasm VM with the chosen parameters +wasmer, err := wasmvm.NewVM( + dataDir, + availableCapabilities, + contractMemoryLimit, + contractDebugMode, + memoryCacheSize, +) +if err != nil { + panic(err) +} + +// create an Option slice (or append to an existing one) +// with the option to use a custom Wasm VM instance +wasmOpts = []ibcwasmkeeper.Option{ + ibcwasmkeeper.WithWasmEngine(wasmer), +} + +// the keeper will use the provided Wasm VM instance, +// instead of instantiating a new one +app.WasmKeeper = ibcwasmkeeper.NewKeeper( + appCodec, + keys[ibcwasmtypes.StoreKey], + app.AccountKeeper, + app.BankKeeper, + app.StakingKeeper, + distrkeeper.NewQuerier(app.DistrKeeper), + app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, + scopedWasmKeeper, + app.TransferKeeper, + app.MsgServiceRouter(), + app.GRPCQueryRouter(), + wasmDir, + wasmConfig, + availableCapabilities, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmOpts..., +) + +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( + appCodec, + keys[wasmtypes.StoreKey], + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmer, // pass the Wasm VM instance to `08-wasm` keeper constructor + app.GRPCQueryRouter(), +) +... +``` + +### If `x/wasm` is not present + +If the chain does not use [`x/wasm`](https://github.com/CosmWasm/wasmd/tree/main/x/wasm), even though it is still possible to use the method above from the previous section +(e.g. instantiating a Wasm VM in app.go an pass it to 08-wasm's [`NewKeeperWithVM` constructor function](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/keeper/keeper.go#L38-L46), since there would be no need in this case to share the Wasm VM instance with another module, you can use the [`NewKeeperWithConfig`` constructor function](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/keeper/keeper.go#L82-L90) and provide the Wasm VM configuration parameters of your choice instead. A Wasm VM instance will be created in`NewKeeperWithConfig`. The parameters that can set are: + +- `DataDir` is the [directory for Wasm blobs and various caches](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L25). In `wasmd` this is set to the [`wasm` folder under the home directory](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L578). +- `SupportedCapabilities` is a comma separated [list of capabilities supported by the chain](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L26). [`wasmd` sets this to all the available capabilities](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L586), but 08-wasm only requires `iterator`. +- `MemoryCacheSize` sets [the size in MiB of an in-memory cache for e.g. module caching](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L29C16-L29C104). It is not consensus-critical and should be defined on a per-node basis, often in the range 100 to 1000 MB. [`wasmd` reads this value of](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L579). Default value is 256. +- `ContractDebugMode` is a [flag to enable/disable printing debug logs from the contract to STDOUT](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L28). This should be false in production environments. Default value is false. + +Another configuration parameter of the Wasm VM is the contract memory limit (in MiB), which is [set to 32](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/types/config.go#L8), [following the example of `wasmd`](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/x/wasm/keeper/keeper.go#L32-L34). This parameter is not configurable by users of `08-wasm`. + +The following sample code shows how the keeper would be constructed using this method: + +```go +// app.go +import ( + ... + "github.com/cosmos/cosmos-sdk/runtime" + + ibcwasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ... +) +... +wasmConfig := ibcwasmtypes.WasmConfig{ + DataDir: "ibc_08-wasm_client_data", + SupportedCapabilities: "iterator", + ContractDebugMode: false, +} +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithConfig( + appCodec, + keys[ibcwasmtypes.StoreKey], + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmConfig, + app.GRPCQueryRouter(), +) +``` + +Check out also the [`WasmConfig` type definition](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/types/config.go#L21-L31) for more information on each of the configurable parameters. Some parameters allow node-level configurations. There is additionally the function [`DefaultWasmConfig`](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/types/config.go#L36) available that returns a configuration with the default values. + +### Options + +The `08-wasm` module comes with an options API inspired by the one in `x/wasm`. +Currently the only option available is the `WithQueryPlugins` option, which allows registration of custom query plugins for the `08-wasm` module. The use of this API is optional and it is only required if the chain wants to register custom query plugins for the `08-wasm` module. + +#### `WithQueryPlugins` + +By default, the `08-wasm` module does not support any queries. However, it is possible to register custom query plugins for [`QueryRequest::Custom`](https://github.com/CosmWasm/cosmwasm/blob/v1.5.0/packages/std/src/query/mod.rs#L45) and [`QueryRequest::Stargate`](https://github.com/CosmWasm/cosmwasm/blob/v1.5.0/packages/std/src/query/mod.rs#L54-L61). + +Assuming that the keeper is not yet instantiated, the following sample code shows how to register query plugins for the `08-wasm` module. + +We first construct a [`QueryPlugins`](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/types/querier.go#L78-L87) object with the desired query plugins: + +```go +queryPlugins := ibcwasmtypes.QueryPlugins { + Custom: MyCustomQueryPlugin(), + // `myAcceptList` is a `[]string` containing the list of gRPC query paths that the chain wants to allow for the `08-wasm` module to query. + // These queries must be registered in the chain's gRPC query router, be deterministic, and track their gas usage. + // The `AcceptListStargateQuerier` function will return a query plugin that will only allow queries for the paths in the `myAcceptList`. + // The query responses are encoded in protobuf unlike the implementation in `x/wasm`. + Stargate: ibcwasmtypes.AcceptListStargateQuerier(myAcceptList), +} +``` + +You may leave any of the fields in the `QueryPlugins` object as `nil` if you do not want to register a query plugin for that query type. + +Then, we pass the `QueryPlugins` object to the `WithQueryPlugins` option: + +```go +querierOption := ibcwasmtypes.WithQueryPlugins(&queryPlugins) +``` + +Finally, we pass the option to the `NewKeeperWithConfig` or `NewKeeperWithVM` constructor function during [Keeper instantiation](#keeper-instantiation): + +```diff +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithConfig( + appCodec, + keys[ibcwasmtypes.StoreKey], + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmConfig, + app.GRPCQueryRouter(), ++ querierOption, +) +``` + +```diff +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( + appCodec, + keys[wasmtypes.StoreKey], + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmer, // pass the Wasm VM instance to `08-wasm` keeper constructor + app.GRPCQueryRouter(), ++ querierOption, +) +``` + +## Updating `AllowedClients` + +In order to use the `08-wasm` module chains must update the [`AllowedClients` parameter in the 02-client submodule](https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/core/client/v1/client.proto#L104) of core IBC. This can be configured directly in the application upgrade handler with the sample code below: + +```go +import ( + ... + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ... +) + +... + +func CreateWasmUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + clientKeeper clientkeeper.Keeper, +) upgradetypes.UpgradeHandler { + return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + // explicitly update the IBC 02-client params, adding the wasm client type + params := clientKeeper.GetParams(ctx) + params.AllowedClients = append(params.AllowedClients, ibcwasmtypes.Wasm) + clientKeeper.SetParams(ctx, params) + + return mm.RunMigrations(ctx, configurator, vm) + } +} +``` + +Or alternatively the parameter can be updated via a governance proposal (see at the bottom of section [`Creating clients`](../01-developer-guide/09-setup.md#creating-clients) for an example of how to do this). + +## Adding the module to the store + +As part of the upgrade migration you must also add the module to the upgrades store. + +```go +func (app SimApp) RegisterUpgradeHandlers() { + + ... + + if upgradeInfo.Name == UpgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + storeUpgrades := storetypes.StoreUpgrades{ + Added: []string{ + ibcwasmtypes.ModuleName, + }, + } + + // configure store loader that checks if version == upgradeHeight and applies store upgrades + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + } +} +``` + +## Adding snapshot support + +In order to use the `08-wasm` module chains are required to register the `WasmSnapshotter` extension in the snapshot manager. This snapshotter takes care of persisting the external state, in the form of contract code, of the Wasm VM instance to disk when the chain is snapshotted. [This code](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/testing/simapp/app.go#L747-L755) should be placed in `NewSimApp` function in `app.go`. + +## Pin byte codes at start + +Wasm byte codes should be pinned to the WasmVM cache on every application start, therefore [this code](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/testing/simapp/app.go#L786-L791) should be placed in `NewSimApp` function in `app.go`. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/04-messages.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/04-messages.md new file mode 100644 index 00000000000..c15c6783813 --- /dev/null +++ b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/04-messages.md @@ -0,0 +1,75 @@ +--- +title: Messages +sidebar_label: Messages +sidebar_position: 4 +slug: /ibc/light-clients/wasm/messages +--- + +# Messages + +## `MsgStoreCode` + +Uploading the Wasm light client contract to the Wasm VM storage is achieved by means of `MsgStoreCode`: + +```go +type MsgStoreCode struct { + // signer address + Signer string + // wasm byte code of light client contract. It can be raw or gzip compressed + WasmByteCode []byte +} +``` + +This message is expected to fail if: + +- `Signer` is an invalid Bech32 address, or it does not match the designated authority address. +- `WasmByteCode` is empty or it exceeds the maximum size, currently set to 3MB. + +Only light client contracts stored using `MsgStoreCode` are allowed to be instantiated. An attempt to create a light client from contracts uploaded via other means (e.g. through `x/wasm` if the module shares the same Wasm VM instance with 08-wasm) will fail. Due to the idempotent nature of the Wasm VM's `StoreCode` function, it is possible to store the same byte code multiple times. + +When execution of `MsgStoreCode` succeeds, the checksum of the contract (i.e. the sha256 hash of the contract's byte code) is stored in an allow list. When a relayer submits [`MsgCreateClient`](https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/core/client/v1/tx.proto#L25-L37) with 08-wasm's `ClientState`, the client state includes the checksum of the Wasm byte code that should be called. Then 02-client calls [08-wasm's implementation of `Initialize` function](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/core/02-client/keeper/client.go#L34) (which is an interface function part of `ClientState`), and it will check that the checksum in the client state matches one of the checksums in the allow list. If a match is found, the light client is initialized; otherwise, the transaction is aborted. + +## `MsgMigrateContract` + +Migrating a contract to a new Wasm byte code is achieved by means of `MsgMigrateContract`: + +```go +type MsgMigrateContract struct { + // signer address + Signer string + // the client id of the contract + ClientId string + // the SHA-256 hash of the new wasm byte code for the contract + Checksum []byte + // the json-encoded migrate msg to be passed to the contract on migration + Msg []byte +} +``` + +This message is expected to fail if: + +- `Signer` is an invalid Bech32 address, or it does not match the designated authority address. +- `ClientId` is not a valid identifier prefixed by `08-wasm`. +- `Checksum` is not exactly 32 bytes long or it is not found in the list of allowed checksums (a new checksum is added to the list when executing `MsgStoreCode`), or it matches the current checksum of the contract. + +When a Wasm light client contract is migrated to a new Wasm byte code the checksum for the contract will be updated with the new checksum. + +## `MsgRemoveChecksum` + +Removing a checksum from the list of allowed checksums is achieved by means of `MsgRemoveChecksum`: + +```go +type MsgRemoveChecksum struct { + // signer address + Signer string + // Wasm byte code checksum to be removed from the store + Checksum []byte +} +``` + +This message is expected to fail if: + +- `Signer` is an invalid Bech32 address, or it does not match the designated authority address. +- `Checksum` is not exactly 32 bytes long or it is not found in the list of allowed checksums (a new checksum is added to the list when executing `MsgStoreCode`). + +When a checksum is removed from the list of allowed checksums, then the corresponding Wasm byte code will not be available for instantiation in [08-wasm's implementation of `Initialize` function](https://github.com/cosmos/ibc-go/blob/v7.3.0/modules/core/02-client/keeper/client.go#L34). diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/05-governance.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/05-governance.md new file mode 100644 index 00000000000..fd8804d9a58 --- /dev/null +++ b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/05-governance.md @@ -0,0 +1,126 @@ +--- +title: Governance +sidebar_label: Governance +sidebar_position: 5 +slug: /ibc/light-clients/wasm/governance +--- + +# Governance + +Learn how to upload Wasm light client byte code on a chain, and how to migrate an existing Wasm light client contract. {synopsis} + +## Setting an authority + +Both the storage of Wasm light client byte code as well as the migration of an existing Wasm light client contract are permissioned (i.e. only allowed to an authority such as governance). The designated authority is specified when instantiating `08-wasm`'s keeper: both [`NewKeeperWithVM`](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/keeper/keeper.go#L38-L46) and [`NewKeeperWithConfig`](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/modules/light-clients/08-wasm/keeper/keeper.go#L82-L90) constructor functions accept an `authority` argument that must be the address of the authorized actor. For example, in `app.go`, when instantiating the keeper, you can pass the address of the governance module: + +```go +// app.go +import ( + ... + "github.com/cosmos/cosmos-sdk/runtime" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + ibcwasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ... +) + +// app.go +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( + appCodec, + keys[wasmtypes.StoreKey], + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), // authority + wasmVM, + app.GRPCQueryRouter(), +) +``` + +## Storing new Wasm light client byte code + + If governance is the allowed authority, the governance v1 proposal that needs to be submitted to upload a new light client contract should contain the message [`MsgStoreCode`](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/proto/ibc/lightclients/wasm/v1/tx.proto#L22-L30) with the base64-encoded byte code of the Wasm contract. Use the following CLI command and JSON as an example: + +```shell +simd tx gov submit-proposal --from +``` + +where `proposal.json` contains: + +```json +{ + "title": "Upload IBC Wasm light client", + "summary": "Upload wasm client", + "messages": [ + { + "@type": "/ibc.lightclients.wasm.v1.MsgStoreCode", + "signer": "cosmos1...", // the authority address (e.g. the gov module account address) + "wasm_byte_code": "YWJ...PUB+" // standard base64 encoding of the Wasm contract byte code + } + ], + "metadata": "AQ==", + "deposit": "100stake" +} +``` + +To learn more about the `submit-proposal` CLI command, please check out [the relevant section in Cosmos SDK documentation](https://docs.cosmos.network/main/modules/gov#submit-proposal). + +Alternatively, the process of submitting the proposal may be simpler if you use the CLI command `store-code`. This CLI command accepts as argument the file of the Wasm light client contract and takes care of constructing the proposal message with `MsgStoreCode` and broadcasting it. See section [`store-code`](./08-client.md#store-code) for more information. + +## Migrating an existing Wasm light client contract + +If governance is the allowed authority, the governance v1 proposal that needs to be submitted to migrate an existing new Wasm light client contract should contain the message [`MsgMigrateContract`](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/proto/ibc/lightclients/wasm/v1/tx.proto#L51-L63) with the checksum of the Wasm byte code to migrate to. Use the following CLI command and JSON as an example: + +```shell +simd tx gov submit-proposal --from +``` + +where `proposal.json` contains: + +```json +{ + "title": "Migrate IBC Wasm light client", + "summary": "Migrate wasm client", + "messages": [ + { + "@type": "/ibc.lightclients.wasm.v1.MsgMigrateContract", + "signer": "cosmos1...", // the authority address (e.g. the gov module account address) + "client_id": "08-wasm-1", // client identifier of the Wasm light client contract that will be migrated + "checksum": "a8ad...4dc0", // SHA-256 hash of the Wasm byte code to migrate to, previously stored with MsgStoreCode + "msg": "{}" // JSON-encoded message to be passed to the contract on migration + } + ], + "metadata": "AQ==", + "deposit": "100stake" +} +``` + +To learn more about the `submit-proposal` CLI command, please check out [the relevant section in Cosmos SDK documentation](https://docs.cosmos.network/main/modules/gov#submit-proposal). + +## Removing an existing checksum + +If governance is the allowed authority, the governance v1 proposal that needs to be submitted to remove a specific checksum from the list of allowed checksums should contain the message [`MsgRemoveChecksum`](https://github.com/cosmos/ibc-go/blob/b306e7a706e1f84a5e11af0540987bd68de9bae5/proto/ibc/lightclients/wasm/v1/tx.proto#L38-L46) with the checksum (of a corresponding Wasm byte code). Use the following CLI command and JSON as an example: + +```shell +simd tx gov submit-proposal --from +``` + +where `proposal.json` contains: + +```json +{ + "title": "Remove checksum of Wasm light client byte code", + "summary": "Remove checksum", + "messages": [ + { + "@type": "/ibc.lightclients.wasm.v1.MsgRemoveChecksum", + "signer": "cosmos1...", // the authority address (e.g. the gov module account address) + "checksum": "a8ad...4dc0", // SHA-256 hash of the Wasm byte code that should be removed from the list of allowed checksums + } + ], + "metadata": "AQ==", + "deposit": "100stake" +} +``` + +To learn more about the `submit-proposal` CLI command, please check out [the relevant section in Cosmos SDK documentation](https://docs.cosmos.network/main/modules/gov#submit-proposal). diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/06-events.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/06-events.md new file mode 100644 index 00000000000..3f6e5b667f7 --- /dev/null +++ b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/06-events.md @@ -0,0 +1,26 @@ +--- +title: Events +sidebar_label: Events +sidebar_position: 6 +slug: /ibc/light-clients/wasm/events +--- + +# Events + +The `08-wasm` module emits the following events: + +## `MsgStoreCode` + +| Type | Attribute Key | Attribute Value | +|------------------|----------------|------------------------| +| store_wasm_code | wasm_checksum | {hex.Encode(checksum)} | +| message | module | 08-wasm | + +## `MsgMigrateContract` + +| Type | Attribute Key | Attribute Value | +|------------------|----------------|---------------------------| +| migrate_contract | client_id | {clientId} | +| migrate_contract | wasm_checksum | {hex.Encode(checksum)} | +| migrate_contract | new_checksum | {hex.Encode(newChecksum)} | +| message | module | 08-wasm | diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/07-contracts.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/07-contracts.md new file mode 100644 index 00000000000..b8da633d514 --- /dev/null +++ b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/07-contracts.md @@ -0,0 +1,113 @@ +--- +title: Contracts +sidebar_label: Contracts +sidebar_position: 7 +slug: /ibc/light-clients/wasm/contracts +--- + +# Contracts + +Learn about the expected behaviour of Wasm light client contracts and the between with `08-wasm`. {synopsis} + +## API + +The `08-wasm` light client proxy performs calls to the Wasm light client via the Wasm VM. The calls require as input JSON-encoded payload messages that fall in the three categories described in the next sections. + +## `InstantiateMessage` + +This is the message sent to the contract's `instantiate` entry point. It contains the bytes of the protobuf-encoded client and consensus states of the underlying light client, both provided in [`MsgCreateClient`](https://github.com/cosmos/ibc-go/blob/v7.3.0/proto/ibc/core/client/v1/tx.proto#L44-L54). Please note that the bytes contained within the JSON message are represented as base64-encoded strings. + +```go +type InstantiateMessage struct { + ClientState []byte `json:"client_state"` + ConsensusState []byte `json:"consensus_state"` + Checksum []byte `json:"checksum" +} +``` + +The Wasm light client contract is expected to store the client and consensus state in the corresponding keys of the client-prefixed store. + +## `QueryMsg` + +`QueryMsg` acts as a discriminated union type that is used to encode the messages that are sent to the contract's `query` entry point. Only one of the fields of the type should be set at a time, so that the other fields are omitted in the encoded JSON and the payload can be correctly translated to the corresponding element of the enumeration in Rust. + +```go +type QueryMsg struct { + Status *StatusMsg `json:"status,omitempty"` + ExportMetadata *ExportMetadataMsg `json:"export_metadata,omitempty"` + TimestampAtHeight *TimestampAtHeightMsg `json:"timestamp_at_height,omitempty"` + VerifyClientMessage *VerifyClientMessageMsg `json:"verify_client_message,omitempty"` + CheckForMisbehaviour *CheckForMisbehaviourMsg `json:"check_for_misbehaviour,omitempty"` +} +``` + +```rust +#[cw_serde] +pub enum QueryMsg { + Status(StatusMsg), + ExportMetadata(ExportMetadataMsg), + TimestampAtHeight(TimestampAtHeightMsg), + VerifyClientMessage(VerifyClientMessageRaw), + CheckForMisbehaviour(CheckForMisbehaviourMsgRaw), +} +``` + +To learn what it is expected from the Wasm light client contract when processing each message, please read the corresponding section of the [Light client developer guide](../01-developer-guide/01-overview.md): + +- For `StatusMsg`, see the section [`Status` method](../01-developer-guide/02-client-state.md#status-method). +- For `ExportMetadataMsg`, see the section [Genesis metadata](../01-developer-guide/08-genesis.md#genesis-metadata). +- For `TimestampAtHeightMsg`, see the section [`GetTimestampAtHeight` method](../01-developer-guide/02-client-state.md#gettimestampatheight-method). +- For `VerifyClientMessageMsg`, see the section [`VerifyClientMessage`](../01-developer-guide/04-updates-and-misbehaviour.md#verifyclientmessage). +- For `CheckForMisbehaviourMsg`, see the section [`CheckForMisbehaviour` method](../01-developer-guide/02-client-state.md#checkformisbehaviour-method). + +## `SudoMsg` + +`SudoMsg` acts as a discriminated union type that is used to encode the messages that are sent to the contract's `sudo` entry point. Only one of the fields of the type should be set at a time, so that the other fields are omitted in the encoded JSON and the payload can be correctly translated to the corresponding element of the enumeration in Rust. + +The `sudo` entry point is able to perform state-changing writes in the client-prefixed store. + +```go +type SudoMsg struct { + UpdateState *UpdateStateMsg `json:"update_state,omitempty"` + UpdateStateOnMisbehaviour *UpdateStateOnMisbehaviourMsg `json:"update_state_on_misbehaviour,omitempty"` + VerifyUpgradeAndUpdateState *VerifyUpgradeAndUpdateStateMsg `json:"verify_upgrade_and_update_state,omitempty"` + VerifyMembership *VerifyMembershipMsg `json:"verify_membership,omitempty"` + VerifyNonMembership *VerifyNonMembershipMsg `json:"verify_non_membership,omitempty"` + MigrateClientStore *MigrateClientStoreMsg `json:"migrate_client_store,omitempty"` +} +``` + +```rust +#[cw_serde] +pub enum SudoMsg { + UpdateState(UpdateStateMsgRaw), + UpdateStateOnMisbehaviour(UpdateStateOnMisbehaviourMsgRaw), + VerifyUpgradeAndUpdateState(VerifyUpgradeAndUpdateStateMsgRaw), + VerifyMembership(VerifyMembershipMsgRaw), + VerifyNonMembership(VerifyNonMembershipMsgRaw), + MigrateClientStore(MigrateClientStoreMsgRaw), +} +``` + +To learn what it is expected from the Wasm light client contract when processing each message, please read the corresponding section of the [Light client developer guide](../01-developer-guide/01-overview.md): + +- For `UpdateStateMsg`, see the section [`UpdateState`](../01-developer-guide/04-updates-and-misbehaviour.md#updatestate). +- For `UpdateStateOnMisbehaviourMsg`, see the section [`UpdateStateOnMisbehaviour`](../01-developer-guide/04-updates-and-misbehaviour.md#updatestateonmisbehaviour). +- For `VerifyUpgradeAndUpdateStateMsg`, see the section [`GetTimestampAtHeight` method](../01-developer-guide/05-upgrades.md#implementing-verifyupgradeandupdatestate). +- For `VerifyMembershipMsg`, see the section [`VerifyMembership` method](../01-developer-guide/02-client-state.md#verifymembership-method). +- For `VerifyNonMembershipMsg`, see the section [`VerifyNonMembership` method](../01-developer-guide/02-client-state.md#verifynonmembership-method). +- For `MigrateClientStoreMsg`, see the section [Implementing `CheckSubstituteAndUpdateState`](../01-developer-guide/07-proposals.md#implementing-checksubstituteandupdatestate). + +### Migration + +The `08-wasm` proxy light client exposes the `MigrateContract` RPC endpoint that can be used to migrate a given Wasm light client contract (specified by the client identifier) to a new Wasm byte code (specified by the hash of the byte code). The expected use case for this RPC endpoint is to enable contracts to migrate to new byte code in case the current byte code is found to have a bug or vulnerability. The Wasm byte code that contracts are migrated have to be uploaded beforehand using `MsgStoreCode` and must implement the `migrate` entry point. See section[`MsgMigrateContract`](./04-messages.md#msgmigratecontract) for information about the request message for this RPC endpoint. + +## Expected behaviour + +The `08-wasm` proxy light client modules expects the following behaviour from the Wasm light client contracts when executing messages that perform state-changing writes: + +- The contract must not delete the client state from the store. +- The contract must not change the client state to a client state of another type. +- The contract must not change the checksum in the client state. + +Any violation of these rules will result in an error returned from `08-wasm` that will abort the transaction. diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/08-client.md b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/08-client.md new file mode 100644 index 00000000000..dd24108f2d0 --- /dev/null +++ b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/08-client.md @@ -0,0 +1,141 @@ +--- +title: Client +sidebar_label: Client +sidebar_position: 7 +slug: /ibc/light-clients/wasm/client +--- + +# Client + +## CLI + +A user can query and interact with the `08-wasm` module using the CLI. Use the `--help` flag to discover the available commands: + +### Transactions + +The `tx` commands allow users to interact with the `08-wasm` submodule. + +```shell +simd tx ibc-wasm --help +``` + +#### `store-code` + +The `store-code` command allows users to submit a governance proposal with a `MsgStoreCode` to store the byte code of a Wasm light client contract. + +```shell +simd tx ibc-wasm store-code [path/to/wasm-file] [flags] +``` + +`path/to/wasm-file` is the path to the `.wasm` or `.wasm.gz` file. + +### Query + +The `query` commands allow users to query `08-wasm` state. + +```shell +simd query ibc-wasm --help +``` + +#### `checksums` + +The `checksums` command allows users to query the list of checksums of Wasm light client contracts stored in the Wasm VM via the `MsgStoreCode`. The checksums are hex-encoded. + +```shell +simd query ibc-wasm checksums [flags] +``` + +Example: + +```shell +simd query ibc-wasm checksums +``` + +Example Output: + +```shell +checksums: +- c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64 +pagination: + next_key: null + total: "1" +``` + +#### `code` + +The `code` command allows users to query the Wasm byte code of a light client contract given the provided input checksum. + +```shell +./simd q ibc-wasm code +``` + +Example: + +```shell +simd query ibc-wasm code c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64 +``` + +Example Output: + +```shell +code: AGFzb...AqBBE= +``` + +## gRPC + +A user can query the `08-wasm` module using gRPC endpoints. + +### `Checksums` + +The `Checksums` endpoint allows users to query the list of checksums of Wasm light client contracts stored in the Wasm VM via the `MsgStoreCode`. + +```shell +ibc.lightclients.wasm.v1.Query/Checksums +``` + +Example: + +```shell +grpcurl -plaintext \ + -d '{}' \ + localhost:9090 \ + ibc.lightclients.wasm.v1.Query/Checksums +``` + +Example output: + +```shell +{ + "checksums": [ + "c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64" + ], + "pagination": { + "total": "1" + } +} +``` + +### `Code` + +The `Code` endpoint allows users to query the Wasm byte code of a light client contract given the provided input checksum. + +```shell +ibc.lightclients.wasm.v1.Query/Code +``` + +Example: + +```shell +grpcurl -plaintext \ + -d '{"checksum":"c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64"}' \ + localhost:9090 \ + ibc.lightclients.wasm.v1.Query/Code +``` + +Example output: + +```shell +{ + "code": AGFzb...AqBBE= +} +``` diff --git a/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/_category_.json b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/_category_.json new file mode 100644 index 00000000000..6dc3d24d11a --- /dev/null +++ b/docs/versioned_docs/version-v7.3.x/03-light-clients/04-wasm/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Wasm", + "position": 4, + "link": null +} \ No newline at end of file diff --git a/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/01-overview.md b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/01-overview.md new file mode 100644 index 00000000000..b4c901a020f --- /dev/null +++ b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/01-overview.md @@ -0,0 +1,26 @@ +--- +title: Overview +sidebar_label: Overview +sidebar_position: 1 +slug: /ibc/light-clients/wasm/overview +--- + +# `08-wasm` + +## Overview + +Learn about the `08-wasm` light client proxy module. {synopsis} + +### Context + +Traditionally, light clients used by ibc-go have been implemented only in Go, and since ibc-go v7 (with the release of the 02-client refactor), they are [first-class Cosmos SDK modules](../../../../architecture/adr-010-light-clients-as-sdk-modules.md). This means that updating existing light client implementations or adding support for new light clients is a multi-step, time-consuming process involving on-chain governance: it is necessary to modify the codebase of ibc-go (if the light client is part of its codebase), re-build chains' binaries, pass a governance proposal and have validators upgrade their nodes. + +### Motivation + +To break the limitation of being able to write light client implementations only in Go, the `08-wasm` adds support to run light clients written in a Wasm-compilable language. The light client byte code implements the entry points of a [CosmWasm](https://docs.cosmwasm.com/docs/) smart contract, and runs inside a Wasm VM. The `08-wasm` module exposes a proxy light client interface that routes incoming messages to the appropriate handler function, inside the Wasm VM, for execution. + +Adding a new light client to a chain is just as simple as submitting a governance proposal with the message that stores the byte code of the light client contract. No coordinated upgrade is needed. When the governance proposal passes and the message is executed, the contract is ready to be instantiated upon receiving a relayer-submitted `MsgCreateClient`. The process of creating a Wasm light client is the same as with a regular light client implemented in Go. + +### Use cases + +- Development of light clients for non-Cosmos ecosystem chains: state machines in other ecosystems are, in many cases, implemented in Rust, and thus there are probably libraries used in their light client implementations for which there is no equivalent in Go. This makes the development of a light client in Go very difficult, but relatively simple to do it in Rust. Therefore, writing a CosmWasm smart contract in Rust that implements the light client algorithm becomes a lower effort. diff --git a/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/02-concepts.md b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/02-concepts.md new file mode 100644 index 00000000000..e3f293bae16 --- /dev/null +++ b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/02-concepts.md @@ -0,0 +1,74 @@ +--- +title: Concepts +sidebar_label: Concepts +sidebar_position: 2 +slug: /ibc/light-clients/wasm/concepts +--- + +# Concepts + +Learn about the differences between a proxy light client and a Wasm light client. {synopsis} + +## Proxy light client + +The `08-wasm` module is not a regular light client in the same sense as, for example, the 07-tendermint light client. `08-wasm` is instead a *proxy* light client module, and this means that the module acts a proxy to the actual implementations of light clients. The module will act as a wrapper for the actual light clients uploaded as Wasm byte code and will delegate all operations to them (i.e. `08-wasm` just passes through the requests to the Wasm light clients). Still, the `08-wasm` module implements all the required interfaces necessary to integrate with core IBC, so that 02-client can call into it as it would for any other light client module. These interfaces are `ClientState`, `ConsensusState` and `ClientMessage`, and we will describe them in the context of `08-wasm` in the following sections. For more information about this set of interfaces, please read section [Overview of the light client module developer guide](../01-developer-guide/01-overview.md#overview). + +### `ClientState` + +The `08-wasm`'s `ClientState` data structure contains three fields: + +- `Data` contains the bytes of the Protobuf-encoded client state of the underlying light client implemented as a Wasm contract. For example, if the Wasm light client contract implements the GRANDPA light client algorithm, then `Data` will contain the bytes for a [GRANDPA client state](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L35-L60). +- `Checksum` is the sha256 hash of the Wasm contract's byte code. This hash is used as an identifier to call the right contract. +- `LatestHeight` is the latest height of the counterparty state machine (i.e. the height of the blockchain), whose consensus state the light client tracks. + +```go +type ClientState struct { + // bytes encoding the client state of the underlying + // light client implemented as a Wasm contract + Data []byte + // sha256 hash of Wasm contract byte code + Checksum []byte + // latest height of the counterparty ledger + LatestHeight types.Height +} +``` + +See section [`ClientState` of the light client module developer guide](../01-developer-guide/01-overview.md#clientstate) for more information about the `ClientState` interface. + +### `ConsensusState` + +The `08-wasm`'s `ConsensusState` data structure maintains one field: + +- `Data` contains the bytes of the Protobuf-encoded consensus state of the underlying light client implemented as a Wasm contract. For example, if the Wasm light client contract implements the GRANDPA light client algorithm, then `Data` will contain the bytes for a [GRANDPA consensus state](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L87-L94). + +```go +type ConsensusState struct { + // bytes encoding the consensus state of the underlying light client + // implemented as a Wasm contract. + Data []byte +} +``` + +See section [`ConsensusState` of the light client module developer guide](../01-developer-guide/01-overview.md#consensusstate) for more information about the `ConsensusState` interface. + +### `ClientMessage` + +`ClientMessage` is used for performing updates to a `ClientState` stored on chain. The `08-wasm`'s `ClientMessage` data structure maintains one field: + +- `Data` contains the bytes of the Protobuf-encoded header(s) or misbehaviour for the underlying light client implemented as a Wasm contract. For example, if the Wasm light client contract implements the GRANDPA light client algorithm, then `Data` will contain the bytes of either [header](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L96-L104) or [misbehaviour](https://github.com/ComposableFi/composable-ibc/blob/02ce69e2843e7986febdcf795f69a757ce569272/light-clients/ics10-grandpa/src/proto/grandpa.proto#L106-L112) for a GRANDPA light client. + +```go +type ClientMessage struct { + // bytes encoding the header(s) or misbehaviour for the underlying light client + // implemented as a Wasm contract. + Data []byte +} +``` + +See section [`ClientMessage` of the light client module developer guide](../01-developer-guide/01-overview.md#clientmessage) for more information about the `ClientMessage` interface. + +## Wasm light client + +The actual light client can be implemented in any language that compiles to Wasm and implements the interfaces of a [CosmWasm](https://docs.cosmwasm.com/docs/) contract. Even though in theory other languages could be used, in practice (at least for the time being) the most suitable language to use would be Rust, since there is already good support for it for developing CosmWasm smart contracts. + +At the moment of writing there are two contracts available: one for [Tendermint](https://github.com/ComposableFi/composable-ibc/tree/master/light-clients/ics07-tendermint-cw) and one [GRANDPA](https://github.com/ComposableFi/composable-ibc/tree/master/light-clients/ics10-grandpa-cw) (which is being used in production in [Composable Finance's Centauri bridge](https://github.com/ComposableFi/composable-ibc)). And there are others in development (e.g. for Near). diff --git a/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/03-integration.md b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/03-integration.md new file mode 100644 index 00000000000..9e7974634f0 --- /dev/null +++ b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/03-integration.md @@ -0,0 +1,368 @@ +--- +title: Integration +sidebar_label: Integration +sidebar_position: 3 +slug: /ibc/light-clients/wasm/integration +--- + +# Integration + +Learn how to integrate the `08-wasm` module in a chain binary and about the recommended approaches depending on whether the [`x/wasm` module](https://github.com/CosmWasm/wasmd/tree/main/x/wasm) is already used in the chain. The following document only applies for Cosmos SDK chains. {synopsis} + +## `app.go` setup + +The sample code below shows the relevant integration points in `app.go` required to setup the `08-wasm` module in a chain binary. Since `08-wasm` is a light client module itself, please check out as well the section [Integrating light clients](../../01-ibc/02-integration.md#integrating-light-clients) for more information: + +```go +// app.go +import ( + ... + "github.com/cosmos/cosmos-sdk/runtime" + + cmtos "github.com/cometbft/cometbft/libs/os" + + ibcwasm "github.com/cosmos/ibc-go/modules/light-clients/08-wasm" + ibcwasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ... +) + +... + +// Register the AppModule for the 08-wasm module +ModuleBasics = module.NewBasicManager( + ... + ibcwasm.AppModuleBasic{}, + ... +) + +// Add 08-wasm Keeper +type SimApp struct { + ... + WasmClientKeeper ibcwasmkeeper.Keeper + ... +} + +func NewSimApp( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + loadLatest bool, + appOpts servertypes.AppOptions, + baseAppOptions ...func(*baseapp.BaseApp), +) *SimApp { + ... + keys := sdk.NewKVStoreKeys( + ... + ibcwasmtypes.StoreKey, + ) + + // Instantiate 08-wasm's keeper + // This sample code uses a constructor function that + // accepts a pointer to an existing instance of Wasm VM. + // This is the recommended approach when the chain + // also uses `x/wasm`, and then the Wasm VM instance + // can be shared. + app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( + appCodec, + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmVM, + app.GRPCQueryRouter(), + ) + app.ModuleManager = module.NewManager( + // SDK app modules + ... + ibcwasm.NewAppModule(app.WasmClientKeeper), + ) + app.ModuleManager.SetOrderBeginBlockers( + ... + ibcwasmtypes.ModuleName, + ... + ) + app.ModuleManager.SetOrderEndBlockers( + ... + ibcwasmtypes.ModuleName, + ... + ) + genesisModuleOrder := []string{ + ... + ibcwasmtypes.ModuleName, + ... + } + app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...) + app.ModuleManager.SetOrderExportGenesis(genesisModuleOrder...) + ... + + // initialize BaseApp + app.SetInitChainer(app.InitChainer) + ... + + // must be before Loading version + if manager := app.SnapshotManager(); manager != nil { + err := manager.RegisterExtensions( + ibcwasmkeeper.NewWasmSnapshotter(app.CommitMultiStore(), &app.WasmClientKeeper), + ) + if err != nil { + panic(fmt.Errorf("failed to register snapshot extension: %s", err)) + } + } + ... + + if loadLatest { + ... + + ctx := app.BaseApp.NewUncachedContext(true, cmtproto.Header{}) + + // Initialize pinned codes in wasmvm as they are not persisted there + if err := ibcwasmkeeper.InitializePinnedCodes(ctx); err != nil { + cmtos.Exit(fmt.Sprintf("failed initialize pinned codes %s", err)) + } + } +} +``` + +## Keeper instantiation + +When it comes to instantiating `08-wasm`'s keeper there are two recommended ways of doing it. Choosing one or the other will depend on whether the chain already integrates [`x/wasm`](https://github.com/CosmWasm/wasmd/tree/main/x/wasm) or not. + +### If `x/wasm` is present + +If the chain where the module is integrated uses `x/wasm` then we recommend that both `08-wasm` and `x/wasm` share the same Wasm VM instance. Having two separate Wasm VM instances is still possible, but care should be taken to make sure that both instances do not share the directory when the VM stores blobs and various caches, otherwise unexpected behaviour is likely to happen. + +In order to share the Wasm VM instance please follow the guideline below. Please note that this requires `x/wasm`v0.41 or above. + +- Instantiate the Wasm VM in `app.go` with the parameters of your choice. +- [Create an `Option` with this Wasm VM instance](https://github.com/CosmWasm/wasmd/blob/db93d7b6c7bb6f4a340d74b96a02cec885729b59/x/wasm/keeper/options.go#L21-L25). +- Add the option created in the previous step to a slice and [pass it to the `x/wasm NewKeeper` constructor function](https://github.com/CosmWasm/wasmd/blob/db93d7b6c7bb6f4a340d74b96a02cec885729b59/x/wasm/keeper/keeper_cgo.go#L36). +- Pass the pointer to the Wasm VM instance to `08-wasm` [NewKeeperWithVM constructor function](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/keeper/keeper.go#L39-L47). + +The code to set this up would look something like this: + +```go +// app.go +import ( + ... + "github.com/cosmos/cosmos-sdk/runtime" + + wasmvm "github.com/CosmWasm/wasmvm" + ibcwasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + ... +) + +... + +// instantiate the Wasm VM with the chosen parameters +wasmer, err := wasmvm.NewVM( + dataDir, + availableCapabilities, + contractMemoryLimit, + contractDebugMode, + memoryCacheSize, +) +if err != nil { + panic(err) +} + +// create an Option slice (or append to an existing one) +// with the option to use a custom Wasm VM instance +wasmOpts = []ibcwasmkeeper.Option{ + ibcwasmkeeper.WithWasmEngine(wasmer), +} + +// the keeper will use the provided Wasm VM instance, +// instead of instantiating a new one +app.WasmKeeper = ibcwasmkeeper.NewKeeper( + appCodec, + keys[ibcwasmtypes.StoreKey], + app.AccountKeeper, + app.BankKeeper, + app.StakingKeeper, + distrkeeper.NewQuerier(app.DistrKeeper), + app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, + scopedWasmKeeper, + app.TransferKeeper, + app.MsgServiceRouter(), + app.GRPCQueryRouter(), + wasmDir, + wasmConfig, + availableCapabilities, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmOpts..., +) + +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( + appCodec, + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmer, // pass the Wasm VM instance to `08-wasm` keeper constructor + app.GRPCQueryRouter(), +) +... +``` + +### If `x/wasm` is not present + +If the chain does not use [`x/wasm`](https://github.com/CosmWasm/wasmd/tree/main/x/wasm), even though it is still possible to use the method above from the previous section +(e.g. instantiating a Wasm VM in app.go an pass it to 08-wasm's [`NewKeeperWithVM` constructor function](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/keeper/keeper.go#L39-L47), since there would be no need in this case to share the Wasm VM instance with another module, you can use the [`NewKeeperWithConfig`` constructor function](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/keeper/keeper.go#L88-L96) and provide the Wasm VM configuration parameters of your choice instead. A Wasm VM instance will be created in`NewKeeperWithConfig`. The parameters that can set are: + +- `DataDir` is the [directory for Wasm blobs and various caches](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L25). In `wasmd` this is set to the [`wasm` folder under the home directory](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L578). +- `SupportedCapabilities` is a comma separated [list of capabilities supported by the chain](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L26). [`wasmd` sets this to all the available capabilities](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L586), but 08-wasm only requires `iterator`. +- `MemoryCacheSize` sets [the size in MiB of an in-memory cache for e.g. module caching](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L29C16-L29C104). It is not consensus-critical and should be defined on a per-node basis, often in the range 100 to 1000 MB. [`wasmd` reads this value of](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L579). Default value is 256. +- `ContractDebugMode` is a [flag to enable/disable printing debug logs from the contract to STDOUT](https://github.com/CosmWasm/wasmvm/blob/1638725b25d799f078d053391945399cb35664b1/lib.go#L28). This should be false in production environments. Default value is false. + +Another configuration parameter of the Wasm VM is the contract memory limit (in MiB), which is [set to 32](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/types/config.go#L8), [following the example of `wasmd`](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/x/wasm/keeper/keeper.go#L32-L34). This parameter is not configurable by users of `08-wasm`. + +The following sample code shows how the keeper would be constructed using this method: + +```go +// app.go +import ( + ... + "github.com/cosmos/cosmos-sdk/runtime" + + ibcwasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ... +) +... +wasmConfig := ibcwasmtypes.WasmConfig{ + DataDir: "ibc_08-wasm_client_data", + SupportedCapabilities: "iterator", + ContractDebugMode: false, +} +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithConfig( + appCodec, + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmConfig, + app.GRPCQueryRouter(), +) +``` + +Check out also the [`WasmConfig` type definition](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/types/config.go#L21-L31) for more information on each of the configurable parameters. Some parameters allow node-level configurations. There is additionally the function [`DefaultWasmConfig`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/types/config.go#L36-L42) available that returns a configuration with the default values. + +### Options + +The `08-wasm` module comes with an options API inspired by the one in `x/wasm`. +Currently the only option available is the `WithQueryPlugins` option, which allows registration of custom query plugins for the `08-wasm` module. The use of this API is optional and it is only required if the chain wants to register custom query plugins for the `08-wasm` module. + +#### `WithQueryPlugins` + +By default, the `08-wasm` module does not support any queries. However, it is possible to register custom query plugins for [`QueryRequest::Custom`](https://github.com/CosmWasm/cosmwasm/blob/v1.5.0/packages/std/src/query/mod.rs#L45) and [`QueryRequest::Stargate`](https://github.com/CosmWasm/cosmwasm/blob/v1.5.0/packages/std/src/query/mod.rs#L54-L61). + +Assuming that the keeper is not yet instantiated, the following sample code shows how to register query plugins for the `08-wasm` module. + +We first construct a [`QueryPlugins`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/types/querier.go#L78-L87) object with the desired query plugins: + +```go +queryPlugins := ibcwasmtypes.QueryPlugins { + Custom: MyCustomQueryPlugin(), + // `myAcceptList` is a `[]string` containing the list of gRPC query paths that the chain wants to allow for the `08-wasm` module to query. + // These queries must be registered in the chain's gRPC query router, be deterministic, and track their gas usage. + // The `AcceptListStargateQuerier` function will return a query plugin that will only allow queries for the paths in the `myAcceptList`. + // The query responses are encoded in protobuf unlike the implementation in `x/wasm`. + Stargate: ibcwasmtypes.AcceptListStargateQuerier(myAcceptList), +} +``` + +You may leave any of the fields in the `QueryPlugins` object as `nil` if you do not want to register a query plugin for that query type. + +Then, we pass the `QueryPlugins` object to the `WithQueryPlugins` option: + +```go +querierOption := ibcwasmtypes.WithQueryPlugins(&queryPlugins) +``` + +Finally, we pass the option to the `NewKeeperWithConfig` or `NewKeeperWithVM` constructor function during [Keeper instantiation](#keeper-instantiation): + +```diff +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithConfig( + appCodec, + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmConfig, + app.GRPCQueryRouter(), ++ querierOption, +) +``` + +```diff +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( + appCodec, + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmer, // pass the Wasm VM instance to `08-wasm` keeper constructor + app.GRPCQueryRouter(), ++ querierOption, +) +``` + +## Updating `AllowedClients` + +In order to use the `08-wasm` module chains must update the [`AllowedClients` parameter in the 02-client submodule](https://github.com/cosmos/ibc-go/blob/v8.0.0/proto/ibc/core/client/v1/client.proto#L64) of core IBC. This can be configured directly in the application upgrade handler with the sample code below: + +```go +import ( + ... + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ... +) + +... + +func CreateWasmUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + clientKeeper clientkeeper.Keeper, +) upgradetypes.UpgradeHandler { + return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + // explicitly update the IBC 02-client params, adding the wasm client type + params := clientKeeper.GetParams(ctx) + params.AllowedClients = append(params.AllowedClients, ibcwasmtypes.Wasm) + clientKeeper.SetParams(ctx, params) + + return mm.RunMigrations(ctx, configurator, vm) + } +} +``` + +Or alternatively the parameter can be updated via a governance proposal (see at the bottom of section [`Creating clients`](../01-developer-guide/09-setup.md#creating-clients) for an example of how to do this). + +## Adding the module to the store + +As part of the upgrade migration you must also add the module to the upgrades store. + +```go +func (app SimApp) RegisterUpgradeHandlers() { + + ... + + if upgradeInfo.Name == UpgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + storeUpgrades := storetypes.StoreUpgrades{ + Added: []string{ + ibcwasmtypes.ModuleName, + }, + } + + // configure store loader that checks if version == upgradeHeight and applies store upgrades + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + } +} +``` + +## Adding snapshot support + +In order to use the `08-wasm` module chains are required to register the `WasmSnapshotter` extension in the snapshot manager. This snapshotter takes care of persisting the external state, in the form of contract code, of the Wasm VM instance to disk when the chain is snapshotted. [This code](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/testing/simapp/app.go#L775-L782) should be placed in `NewSimApp` function in `app.go`. + +## Pin byte codes at start + +Wasm byte codes should be pinned to the WasmVM cache on every application start, therefore [this code](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/testing/simapp/app.go#L825-L830) should be placed in `NewSimApp` function in `app.go`. diff --git a/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/04-messages.md b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/04-messages.md new file mode 100644 index 00000000000..6b8321583c2 --- /dev/null +++ b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/04-messages.md @@ -0,0 +1,75 @@ +--- +title: Messages +sidebar_label: Messages +sidebar_position: 4 +slug: /ibc/light-clients/wasm/messages +--- + +# Messages + +## `MsgStoreCode` + +Uploading the Wasm light client contract to the Wasm VM storage is achieved by means of `MsgStoreCode`: + +```go +type MsgStoreCode struct { + // signer address + Signer string + // wasm byte code of light client contract. It can be raw or gzip compressed + WasmByteCode []byte +} +``` + +This message is expected to fail if: + +- `Signer` is an invalid Bech32 address, or it does not match the designated authority address. +- `WasmByteCode` is empty or it exceeds the maximum size, currently set to 3MB. + +Only light client contracts stored using `MsgStoreCode` are allowed to be instantiated. An attempt to create a light client from contracts uploaded via other means (e.g. through `x/wasm` if the module shares the same Wasm VM instance with 08-wasm) will fail. Due to the idempotent nature of the Wasm VM's `StoreCode` function, it is possible to store the same byte code multiple times. + +When execution of `MsgStoreCode` succeeds, the checksum of the contract (i.e. the sha256 hash of the contract's byte code) is stored in an allow list. When a relayer submits [`MsgCreateClient`](https://github.com/cosmos/ibc-go/blob/v8.0.0/proto/ibc/core/client/v1/tx.proto#L25-L37) with 08-wasm's `ClientState`, the client state includes the checksum of the Wasm byte code that should be called. Then 02-client calls [08-wasm's implementation of `Initialize` function](https://github.com/cosmos/ibc-go/blob/v8.0.0/modules/core/02-client/keeper/client.go#L36) (which is an interface function part of `ClientState`), and it will check that the checksum in the client state matches one of the checksums in the allow list. If a match is found, the light client is initialized; otherwise, the transaction is aborted. + +## `MsgMigrateContract` + +Migrating a contract to a new Wasm byte code is achieved by means of `MsgMigrateContract`: + +```go +type MsgMigrateContract struct { + // signer address + Signer string + // the client id of the contract + ClientId string + // the SHA-256 hash of the new wasm byte code for the contract + Checksum []byte + // the json-encoded migrate msg to be passed to the contract on migration + Msg []byte +} +``` + +This message is expected to fail if: + +- `Signer` is an invalid Bech32 address, or it does not match the designated authority address. +- `ClientId` is not a valid identifier prefixed by `08-wasm`. +- `Checksum` is not exactly 32 bytes long or it is not found in the list of allowed checksums (a new checksum is added to the list when executing `MsgStoreCode`), or it matches the current checksum of the contract. + +When a Wasm light client contract is migrated to a new Wasm byte code the checksum for the contract will be updated with the new checksum. + +## `MsgRemoveChecksum` + +Removing a checksum from the list of allowed checksums is achieved by means of `MsgRemoveChecksum`: + +```go +type MsgRemoveChecksum struct { + // signer address + Signer string + // Wasm byte code checksum to be removed from the store + Checksum []byte +} +``` + +This message is expected to fail if: + +- `Signer` is an invalid Bech32 address, or it does not match the designated authority address. +- `Checksum` is not exactly 32 bytes long or it is not found in the list of allowed checksums (a new checksum is added to the list when executing `MsgStoreCode`). + +When a checksum is removed from the list of allowed checksums, then the corresponding Wasm byte code will not be available for instantiation in [08-wasm's implementation of `Initialize` function](https://github.com/cosmos/ibc-go/blob/v8.0.0/modules/core/02-client/keeper/client.go#L36). diff --git a/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/05-governance.md b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/05-governance.md new file mode 100644 index 00000000000..b2e817080a4 --- /dev/null +++ b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/05-governance.md @@ -0,0 +1,126 @@ +--- +title: Governance +sidebar_label: Governance +sidebar_position: 5 +slug: /ibc/light-clients/wasm/governance +--- + +# Governance + +Learn how to upload Wasm light client byte code on a chain, and how to migrate an existing Wasm light client contract. {synopsis} + +## Setting an authority + +Both the storage of Wasm light client byte code as well as the migration of an existing Wasm light client contract are permissioned (i.e. only allowed to an authority such as governance). The designated authority is specified when instantiating `08-wasm`'s keeper: both [`NewKeeperWithVM`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/keeper/keeper.go#L39-L47) and [`NewKeeperWithConfig`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/keeper/keeper.go#L88-L96) constructor functions accept an `authority` argument that must be the address of the authorized actor. For example, in `app.go`, when instantiating the keeper, you can pass the address of the governance module: + +```go +// app.go +import ( + ... + "github.com/cosmos/cosmos-sdk/runtime" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + ibcwasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" + ibcwasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + ... +) + +// app.go +app.WasmClientKeeper = ibcwasmkeeper.NewKeeperWithVM( + appCodec, + runtime.NewKVStoreService(keys[ibcwasmtypes.StoreKey]), + app.IBCKeeper.ClientKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), // authority + wasmVM, + app.GRPCQueryRouter(), +) +``` + +## Storing new Wasm light client byte code + + If governance is the allowed authority, the governance v1 proposal that needs to be submitted to upload a new light client contract should contain the message [`MsgStoreCode`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/proto/ibc/lightclients/wasm/v1/tx.proto#L23-L30) with the base64-encoded byte code of the Wasm contract. Use the following CLI command and JSON as an example: + +```shell +simd tx gov submit-proposal --from +``` + +where `proposal.json` contains: + +```json +{ + "title": "Upload IBC Wasm light client", + "summary": "Upload wasm client", + "messages": [ + { + "@type": "/ibc.lightclients.wasm.v1.MsgStoreCode", + "signer": "cosmos1...", // the authority address (e.g. the gov module account address) + "wasm_byte_code": "YWJ...PUB+" // standard base64 encoding of the Wasm contract byte code + } + ], + "metadata": "AQ==", + "deposit": "100stake" +} +``` + +To learn more about the `submit-proposal` CLI command, please check out [the relevant section in Cosmos SDK documentation](https://docs.cosmos.network/main/modules/gov#submit-proposal). + +Alternatively, the process of submitting the proposal may be simpler if you use the CLI command `store-code`. This CLI command accepts as argument the file of the Wasm light client contract and takes care of constructing the proposal message with `MsgStoreCode` and broadcasting it. See section [`store-code`](./08-client.md#store-code) for more information. + +## Migrating an existing Wasm light client contract + +If governance is the allowed authority, the governance v1 proposal that needs to be submitted to migrate an existing new Wasm light client contract should contain the message [`MsgMigrateContract`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/proto/ibc/lightclients/wasm/v1/tx.proto#L52-L63) with the checksum of the Wasm byte code to migrate to. Use the following CLI command and JSON as an example: + +```shell +simd tx gov submit-proposal --from +``` + +where `proposal.json` contains: + +```json +{ + "title": "Migrate IBC Wasm light client", + "summary": "Migrate wasm client", + "messages": [ + { + "@type": "/ibc.lightclients.wasm.v1.MsgMigrateContract", + "signer": "cosmos1...", // the authority address (e.g. the gov module account address) + "client_id": "08-wasm-1", // client identifier of the Wasm light client contract that will be migrated + "checksum": "a8ad...4dc0", // SHA-256 hash of the Wasm byte code to migrate to, previously stored with MsgStoreCode + "msg": "{}" // JSON-encoded message to be passed to the contract on migration + } + ], + "metadata": "AQ==", + "deposit": "100stake" +} +``` + +To learn more about the `submit-proposal` CLI command, please check out [the relevant section in Cosmos SDK documentation](https://docs.cosmos.network/main/modules/gov#submit-proposal). + +## Removing an existing checksum + +If governance is the allowed authority, the governance v1 proposal that needs to be submitted to remove a specific checksum from the list of allowed checksums should contain the message [`MsgRemoveChecksum`](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/proto/ibc/lightclients/wasm/v1/tx.proto#L39-L46) with the checksum (of a corresponding Wasm byte code). Use the following CLI command and JSON as an example: + +```shell +simd tx gov submit-proposal --from +``` + +where `proposal.json` contains: + +```json +{ + "title": "Remove checksum of Wasm light client byte code", + "summary": "Remove checksum", + "messages": [ + { + "@type": "/ibc.lightclients.wasm.v1.MsgRemoveChecksum", + "signer": "cosmos1...", // the authority address (e.g. the gov module account address) + "checksum": "a8ad...4dc0", // SHA-256 hash of the Wasm byte code that should be removed from the list of allowed checksums + } + ], + "metadata": "AQ==", + "deposit": "100stake" +} +``` + +To learn more about the `submit-proposal` CLI command, please check out [the relevant section in Cosmos SDK documentation](https://docs.cosmos.network/main/modules/gov#submit-proposal). diff --git a/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/06-events.md b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/06-events.md new file mode 100644 index 00000000000..3f6e5b667f7 --- /dev/null +++ b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/06-events.md @@ -0,0 +1,26 @@ +--- +title: Events +sidebar_label: Events +sidebar_position: 6 +slug: /ibc/light-clients/wasm/events +--- + +# Events + +The `08-wasm` module emits the following events: + +## `MsgStoreCode` + +| Type | Attribute Key | Attribute Value | +|------------------|----------------|------------------------| +| store_wasm_code | wasm_checksum | {hex.Encode(checksum)} | +| message | module | 08-wasm | + +## `MsgMigrateContract` + +| Type | Attribute Key | Attribute Value | +|------------------|----------------|---------------------------| +| migrate_contract | client_id | {clientId} | +| migrate_contract | wasm_checksum | {hex.Encode(checksum)} | +| migrate_contract | new_checksum | {hex.Encode(newChecksum)} | +| message | module | 08-wasm | diff --git a/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/07-contracts.md b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/07-contracts.md new file mode 100644 index 00000000000..1f6759d06c0 --- /dev/null +++ b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/07-contracts.md @@ -0,0 +1,113 @@ +--- +title: Contracts +sidebar_label: Contracts +sidebar_position: 7 +slug: /ibc/light-clients/wasm/contracts +--- + +# Contracts + +Learn about the expected behaviour of Wasm light client contracts and the between with `08-wasm`. {synopsis} + +## API + +The `08-wasm` light client proxy performs calls to the Wasm light client via the Wasm VM. The calls require as input JSON-encoded payload messages that fall in the three categories described in the next sections. + +## `InstantiateMessage` + +This is the message sent to the contract's `instantiate` entry point. It contains the bytes of the protobuf-encoded client and consensus states of the underlying light client, both provided in [`MsgCreateClient`](https://github.com/cosmos/ibc-go/blob/v8.0.0/proto/ibc/core/client/v1/tx.proto#L40-L52). Please note that the bytes contained within the JSON message are represented as base64-encoded strings. + +```go +type InstantiateMessage struct { + ClientState []byte `json:"client_state"` + ConsensusState []byte `json:"consensus_state"` + Checksum []byte `json:"checksum" +} +``` + +The Wasm light client contract is expected to store the client and consensus state in the corresponding keys of the client-prefixed store. + +## `QueryMsg` + +`QueryMsg` acts as a discriminated union type that is used to encode the messages that are sent to the contract's `query` entry point. Only one of the fields of the type should be set at a time, so that the other fields are omitted in the encoded JSON and the payload can be correctly translated to the corresponding element of the enumeration in Rust. + +```go +type QueryMsg struct { + Status *StatusMsg `json:"status,omitempty"` + ExportMetadata *ExportMetadataMsg `json:"export_metadata,omitempty"` + TimestampAtHeight *TimestampAtHeightMsg `json:"timestamp_at_height,omitempty"` + VerifyClientMessage *VerifyClientMessageMsg `json:"verify_client_message,omitempty"` + CheckForMisbehaviour *CheckForMisbehaviourMsg `json:"check_for_misbehaviour,omitempty"` +} +``` + +```rust +#[cw_serde] +pub enum QueryMsg { + Status(StatusMsg), + ExportMetadata(ExportMetadataMsg), + TimestampAtHeight(TimestampAtHeightMsg), + VerifyClientMessage(VerifyClientMessageRaw), + CheckForMisbehaviour(CheckForMisbehaviourMsgRaw), +} +``` + +To learn what it is expected from the Wasm light client contract when processing each message, please read the corresponding section of the [Light client developer guide](../01-developer-guide/01-overview.md): + +- For `StatusMsg`, see the section [`Status` method](../01-developer-guide/02-client-state.md#status-method). +- For `ExportMetadataMsg`, see the section [Genesis metadata](../01-developer-guide/08-genesis.md#genesis-metadata). +- For `TimestampAtHeightMsg`, see the section [`GetTimestampAtHeight` method](../01-developer-guide/02-client-state.md#gettimestampatheight-method). +- For `VerifyClientMessageMsg`, see the section [`VerifyClientMessage`](../01-developer-guide/04-updates-and-misbehaviour.md#verifyclientmessage). +- For `CheckForMisbehaviourMsg`, see the section [`CheckForMisbehaviour` method](../01-developer-guide/02-client-state.md#checkformisbehaviour-method). + +## `SudoMsg` + +`SudoMsg` acts as a discriminated union type that is used to encode the messages that are sent to the contract's `sudo` entry point. Only one of the fields of the type should be set at a time, so that the other fields are omitted in the encoded JSON and the payload can be correctly translated to the corresponding element of the enumeration in Rust. + +The `sudo` entry point is able to perform state-changing writes in the client-prefixed store. + +```go +type SudoMsg struct { + UpdateState *UpdateStateMsg `json:"update_state,omitempty"` + UpdateStateOnMisbehaviour *UpdateStateOnMisbehaviourMsg `json:"update_state_on_misbehaviour,omitempty"` + VerifyUpgradeAndUpdateState *VerifyUpgradeAndUpdateStateMsg `json:"verify_upgrade_and_update_state,omitempty"` + VerifyMembership *VerifyMembershipMsg `json:"verify_membership,omitempty"` + VerifyNonMembership *VerifyNonMembershipMsg `json:"verify_non_membership,omitempty"` + MigrateClientStore *MigrateClientStoreMsg `json:"migrate_client_store,omitempty"` +} +``` + +```rust +#[cw_serde] +pub enum SudoMsg { + UpdateState(UpdateStateMsgRaw), + UpdateStateOnMisbehaviour(UpdateStateOnMisbehaviourMsgRaw), + VerifyUpgradeAndUpdateState(VerifyUpgradeAndUpdateStateMsgRaw), + VerifyMembership(VerifyMembershipMsgRaw), + VerifyNonMembership(VerifyNonMembershipMsgRaw), + MigrateClientStore(MigrateClientStoreMsgRaw), +} +``` + +To learn what it is expected from the Wasm light client contract when processing each message, please read the corresponding section of the [Light client developer guide](../01-developer-guide/01-overview.md): + +- For `UpdateStateMsg`, see the section [`UpdateState`](../01-developer-guide/04-updates-and-misbehaviour.md#updatestate). +- For `UpdateStateOnMisbehaviourMsg`, see the section [`UpdateStateOnMisbehaviour`](../01-developer-guide/04-updates-and-misbehaviour.md#updatestateonmisbehaviour). +- For `VerifyUpgradeAndUpdateStateMsg`, see the section [`GetTimestampAtHeight` method](../01-developer-guide/05-upgrades.md#implementing-verifyupgradeandupdatestate). +- For `VerifyMembershipMsg`, see the section [`VerifyMembership` method](../01-developer-guide/02-client-state.md#verifymembership-method). +- For `VerifyNonMembershipMsg`, see the section [`VerifyNonMembership` method](../01-developer-guide/02-client-state.md#verifynonmembership-method). +- For `MigrateClientStoreMsg`, see the section [Implementing `CheckSubstituteAndUpdateState`](../01-developer-guide/07-proposals.md#implementing-checksubstituteandupdatestate). + +### Migration + +The `08-wasm` proxy light client exposes the `MigrateContract` RPC endpoint that can be used to migrate a given Wasm light client contract (specified by the client identifier) to a new Wasm byte code (specified by the hash of the byte code). The expected use case for this RPC endpoint is to enable contracts to migrate to new byte code in case the current byte code is found to have a bug or vulnerability. The Wasm byte code that contracts are migrated have to be uploaded beforehand using `MsgStoreCode` and must implement the `migrate` entry point. See section[`MsgMigrateContract`](./04-messages.md#msgmigratecontract) for information about the request message for this RPC endpoint. + +## Expected behaviour + +The `08-wasm` proxy light client modules expects the following behaviour from the Wasm light client contracts when executing messages that perform state-changing writes: + +- The contract must not delete the client state from the store. +- The contract must not change the client state to a client state of another type. +- The contract must not change the checksum in the client state. + +Any violation of these rules will result in an error returned from `08-wasm` that will abort the transaction. diff --git a/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/08-client.md b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/08-client.md new file mode 100644 index 00000000000..dd24108f2d0 --- /dev/null +++ b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/08-client.md @@ -0,0 +1,141 @@ +--- +title: Client +sidebar_label: Client +sidebar_position: 7 +slug: /ibc/light-clients/wasm/client +--- + +# Client + +## CLI + +A user can query and interact with the `08-wasm` module using the CLI. Use the `--help` flag to discover the available commands: + +### Transactions + +The `tx` commands allow users to interact with the `08-wasm` submodule. + +```shell +simd tx ibc-wasm --help +``` + +#### `store-code` + +The `store-code` command allows users to submit a governance proposal with a `MsgStoreCode` to store the byte code of a Wasm light client contract. + +```shell +simd tx ibc-wasm store-code [path/to/wasm-file] [flags] +``` + +`path/to/wasm-file` is the path to the `.wasm` or `.wasm.gz` file. + +### Query + +The `query` commands allow users to query `08-wasm` state. + +```shell +simd query ibc-wasm --help +``` + +#### `checksums` + +The `checksums` command allows users to query the list of checksums of Wasm light client contracts stored in the Wasm VM via the `MsgStoreCode`. The checksums are hex-encoded. + +```shell +simd query ibc-wasm checksums [flags] +``` + +Example: + +```shell +simd query ibc-wasm checksums +``` + +Example Output: + +```shell +checksums: +- c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64 +pagination: + next_key: null + total: "1" +``` + +#### `code` + +The `code` command allows users to query the Wasm byte code of a light client contract given the provided input checksum. + +```shell +./simd q ibc-wasm code +``` + +Example: + +```shell +simd query ibc-wasm code c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64 +``` + +Example Output: + +```shell +code: AGFzb...AqBBE= +``` + +## gRPC + +A user can query the `08-wasm` module using gRPC endpoints. + +### `Checksums` + +The `Checksums` endpoint allows users to query the list of checksums of Wasm light client contracts stored in the Wasm VM via the `MsgStoreCode`. + +```shell +ibc.lightclients.wasm.v1.Query/Checksums +``` + +Example: + +```shell +grpcurl -plaintext \ + -d '{}' \ + localhost:9090 \ + ibc.lightclients.wasm.v1.Query/Checksums +``` + +Example output: + +```shell +{ + "checksums": [ + "c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64" + ], + "pagination": { + "total": "1" + } +} +``` + +### `Code` + +The `Code` endpoint allows users to query the Wasm byte code of a light client contract given the provided input checksum. + +```shell +ibc.lightclients.wasm.v1.Query/Code +``` + +Example: + +```shell +grpcurl -plaintext \ + -d '{"checksum":"c64f75091a6195b036f472cd8c9f19a56780b9eac3c3de7ced0ec2e29e985b64"}' \ + localhost:9090 \ + ibc.lightclients.wasm.v1.Query/Code +``` + +Example output: + +```shell +{ + "code": AGFzb...AqBBE= +} +``` diff --git a/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/09-migrations.md b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/09-migrations.md new file mode 100644 index 00000000000..2e85079168e --- /dev/null +++ b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/09-migrations.md @@ -0,0 +1,16 @@ +--- +title: Migrations +sidebar_label: Migrations +sidebar_position: 9 +slug: /ibc/light-clients/wasm/migrations +--- + +# Migrations + +This guide provides instructions for migrating 08-wasm versions. + +## From ibc-go v7.3.x to ibc-go v8.0.x + +## Chains + +In the 08-wasm versions compatible with ibc-go v7.3.x and above from the v7 release line, the checksums of the uploaded Wasm bytecodes are all stored under a single key. From ibc-go v8.0.x the checksums are stored using [`collections.KeySet`](https://docs.cosmos.network/v0.50/build/packages/collections#keyset), whose full functionality became available in Cosmos SDK v0.50. There is therefore an [automatic migration handler](https://github.com/cosmos/ibc-go/blob/57fcdb9a9a9db9b206f7df2f955866dc4e10fef4/modules/light-clients/08-wasm/module.go#L115-L118) configured in the 08-wasm module to migrate the stored checksums to `collections.KeySet`. diff --git a/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/_category_.json b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/_category_.json new file mode 100644 index 00000000000..6dc3d24d11a --- /dev/null +++ b/docs/versioned_docs/version-v8.0.x/03-light-clients/04-wasm/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Wasm", + "position": 4, + "link": null +} \ No newline at end of file