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 6eee6ac28b7..2ed9b4d301d 100644 --- a/docs/docs/03-light-clients/04-wasm/03-integration.md +++ b/docs/docs/03-light-clients/04-wasm/03-integration.md @@ -130,13 +130,13 @@ func NewSimApp( ## 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. Both available constructor functions accept a querier parameter that should implement the [`Querier` interface of `wasmvm`](https://github.com/CosmWasm/wasmvm/blob/v1.5.0/types/queries.go#L37). If `nil` is provided, then a default querier implementation is used that returns error for any query type. +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. Both available constructor functions accept a querier parameter that should implement the [`Querier` interface of `wasmvm`](https://github.com/CosmWasm/wasmvm/blob/v2.0.0/types/queries.go#L37). If `nil` is provided, then a default querier implementation is used that returns error for any query type. ### 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. +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 (from `x/wasm` v0.51 and `08-wasm` v0.2.0.0+ibc-go-v8.2-wasmvm-v2.0 this will be forbidden anyway, since wasmvm v2.0.0 and above will not allow two different Wasm VM instances to shared the same data folder). -In order to share the Wasm VM instance please follow the guideline below. Please note that this requires `x/wasm`v0.41 or above. +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). @@ -150,8 +150,8 @@ The code to set this up would look something like this: import ( ... "github.com/cosmos/cosmos-sdk/runtime" - - wasmvm "github.com/CosmWasm/wasmvm" + + wasmvm "github.com/CosmWasm/wasmvm/v2" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" ... ) @@ -219,10 +219,10 @@ app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( 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: -- `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. +- `DataDir` is the [directory for Wasm blobs and various caches](https://github.com/CosmWasm/wasmvm/blob/v2.0.0/lib.go#L25). As an example, in `wasmd` this is set to the [`wasm` folder under the home directory](https://github.com/CosmWasm/wasmd/blob/36416def20effe47fb77f29f5ba35a003970fdba/app/app.go#L578). In the code snippet below we set this field to the `ibc_08-wasm_client_data` folder under the home directory. +- `SupportedCapabilities` is a [list of capabilities supported by the chain](https://github.com/CosmWasm/wasmvm/blob/v2.0.0/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/v2.0.0/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/v2.0.0/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`. @@ -239,9 +239,12 @@ import ( ... ) ... -wasmConfig := wasmtypes.WasmConfig{ - DataDir: "ibc_08-wasm_client_data", - SupportedCapabilities: "iterator", + +// homePath is the path to the directory where the data +// directory for Wasm blobs and caches will be created +wasmConfig := ibcwasmtypes.WasmConfig{ + DataDir: filepath.Join(homePath, "ibc_08-wasm_client_data"), + SupportedCapabilities: []string{"iterator"}, ContractDebugMode: false, } app.WasmClientKeeper = wasmkeeper.NewKeeperWithConfig( diff --git a/docs/docs/03-light-clients/04-wasm/09-migrations.md b/docs/docs/03-light-clients/04-wasm/09-migrations.md new file mode 100644 index 00000000000..ff4800e74ec --- /dev/null +++ b/docs/docs/03-light-clients/04-wasm/09-migrations.md @@ -0,0 +1,103 @@ +--- +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`. + +## From v0.1.0+ibc-go-v8.0-wasmvm-v1.5 to v0.2.0-ibc-go-v8.2-wasmvm-v2.0 + +The `WasmEngine` interface has been updated to reflect changes in the function signatures of Wasm VM: + +```diff +type WasmEngine interface { +- StoreCode(code wasmvm.WasmCode) (wasmvm.Checksum, error) ++ StoreCode(code wasmvm.WasmCode, gasLimit uint64) (wasmvmtypes.Checksum, uint64, error) + + StoreCodeUnchecked(code wasmvm.WasmCode) (wasmvm.Checksum, error) + + Instantiate( + checksum wasmvm.Checksum, + env wasmvmtypes.Env, + info wasmvmtypes.MessageInfo, + initMsg []byte, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + deserCost wasmvmtypes.UFraction, +- ) (*wasmvmtypes.Response, uint64, error) ++ ) (*wasmvmtypes.ContractResult, uint64, error) + + Query( + checksum wasmvm.Checksum, + env wasmvmtypes.Env, + queryMsg []byte, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + deserCost wasmvmtypes.UFraction, +- ) ([]byte, uint64, error) ++ ) (*wasmvmtypes.QueryResult, uint64, error) + + Migrate( + checksum wasmvm.Checksum, + env wasmvmtypes.Env, + migrateMsg []byte, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + deserCost wasmvmtypes.UFraction, +- ) (*wasmvmtypes.Response, uint64, error) ++ ) (*wasmvmtypes.ContractResult, uint64, error) + + Sudo( + checksum wasmvm.Checksum, + env wasmvmtypes.Env, + sudoMsg []byte, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + deserCost wasmvmtypes.UFraction, +- ) (*wasmvmtypes.Response, uint64, error) ++ ) (*wasmvmtypes.ContractResult, uint64, error) + + GetCode(checksum wasmvm.Checksum) (wasmvm.WasmCode, error) + + Pin(checksum wasmvm.Checksum) error + + Unpin(checksum wasmvm.Checksum) error +} +``` + +Similar changes were required in the functions of `MockWasmEngine` interface. + +### Chains + +The `SupportedCapabilities` field of `WasmConfig` is now of type `[]string`: + +```diff +type WasmConfig struct { + DataDir string +- SupportedCapabilities string ++ SupportedCapabilities []string + ContractDebugMode bool +} +``` diff --git a/modules/light-clients/08-wasm/CHANGELOG.md b/modules/light-clients/08-wasm/CHANGELOG.md index 5599c8a3987..7a0e63ed64e 100644 --- a/modules/light-clients/08-wasm/CHANGELOG.md +++ b/modules/light-clients/08-wasm/CHANGELOG.md @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Dependencies * [#\5975](https://github.com/cosmos/ibc-go/pull/5975) Upgrade Cosmos SDK to v0.50.5. +* [#\5909](https://github.com/cosmos/ibc-go/pull/5909) Update wasmvm to v2.0.0 and cometBFT to v0.38.6. ### API Breaking diff --git a/modules/light-clients/08-wasm/go.mod b/modules/light-clients/08-wasm/go.mod index 0fd8728cb7e..0e3eb54722f 100644 --- a/modules/light-clients/08-wasm/go.mod +++ b/modules/light-clients/08-wasm/go.mod @@ -20,9 +20,9 @@ require ( cosmossdk.io/x/evidence v0.1.0 cosmossdk.io/x/feegrant v0.1.0 cosmossdk.io/x/tx v0.13.1 - cosmossdk.io/x/upgrade v0.1.0 - github.com/CosmWasm/wasmvm v1.5.0 - github.com/cometbft/cometbft v0.38.5 + cosmossdk.io/x/upgrade v0.1.1 + github.com/CosmWasm/wasmvm/v2 v2.0.0 + github.com/cometbft/cometbft v0.38.6 github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-sdk v0.50.5 github.com/cosmos/gogoproto v1.4.11 @@ -115,7 +115,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.1 // indirect + github.com/hashicorp/go-getter v1.7.3 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.2 // indirect @@ -187,7 +187,7 @@ require ( golang.org/x/net v0.21.0 // indirect golang.org/x/oauth2 v0.16.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.17.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/term v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect diff --git a/modules/light-clients/08-wasm/go.sum b/modules/light-clients/08-wasm/go.sum index 208435aae21..3a805f29f72 100644 --- a/modules/light-clients/08-wasm/go.sum +++ b/modules/light-clients/08-wasm/go.sum @@ -212,8 +212,8 @@ cosmossdk.io/x/feegrant v0.1.0 h1:c7s3oAq/8/UO0EiN1H5BIjwVntujVTkYs35YPvvrdQk= cosmossdk.io/x/feegrant v0.1.0/go.mod h1:4r+FsViJRpcZif/yhTn+E0E6OFfg4n0Lx+6cCtnZElU= cosmossdk.io/x/tx v0.13.1 h1:Mg+EMp67Pz+NukbJqYxuo8uRp7N/a9uR+oVS9pONtj8= cosmossdk.io/x/tx v0.13.1/go.mod h1:CBCU6fsRVz23QGFIQBb1DNX2DztJCf3jWyEkHY2nJQ0= -cosmossdk.io/x/upgrade v0.1.0 h1:z1ZZG4UL9ICTNbJDYZ6jOnF9GdEK9wyoEFi4BUScHXE= -cosmossdk.io/x/upgrade v0.1.0/go.mod h1:/6jjNGbiPCNtmA1N+rBtP601sr0g4ZXuj3yC6ClPCGY= +cosmossdk.io/x/upgrade v0.1.1 h1:aoPe2gNvH+Gwt/Pgq3dOxxQVU3j5P6Xf+DaUJTDZATc= +cosmossdk.io/x/upgrade v0.1.1/go.mod h1:MNLptLPcIFK9CWt7Ra//8WUZAxweyRDNcbs5nkOcQy0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -225,8 +225,8 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CosmWasm/wasmvm v1.5.0 h1:3hKeT9SfwfLhxTGKH3vXaKFzBz1yuvP8SlfwfQXbQfw= -github.com/CosmWasm/wasmvm v1.5.0/go.mod h1:fXB+m2gyh4v9839zlIXdMZGeLAxqUdYdFQqYsTha2hc= +github.com/CosmWasm/wasmvm/v2 v2.0.0 h1:IqNCI2G0mvs7K6ej17/I28805rVqnu+Y1cWDqIdwb08= +github.com/CosmWasm/wasmvm/v2 v2.0.0/go.mod h1:su9lg5qLr7adV95eOfzjZWkGiky8WNaNIHDr7Fpu7Ck= github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= @@ -337,8 +337,8 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/cometbft/cometbft v0.38.5 h1:4lOcK5VTPrfbLOhNHmPYe6c7eDXHtBdMCQuKbAfFJdU= -github.com/cometbft/cometbft v0.38.5/go.mod h1:0tqKin+KQs8zDwzYD8rPHzSBIDNPuB4NrwwGDNb/hUg= +github.com/cometbft/cometbft v0.38.6 h1:QSgpCzrGWJ2KUq1qpw+FCfASRpE27T6LQbfEHscdyOk= +github.com/cometbft/cometbft v0.38.6/go.mod h1:8rSPxzUJYquCN8uuBgbUHOMg2KAwvr7CyUw+6ukO4nw= github.com/cometbft/cometbft-db v0.9.1 h1:MIhVX5ja5bXNHF8EYrThkG9F7r9kSfv8BX4LWaxWJ4M= github.com/cometbft/cometbft-db v0.9.1/go.mod h1:iliyWaoV0mRwBJoizElCwwRA9Tf7jZJOURcRZF9m60U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= @@ -656,8 +656,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= -github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-getter v1.7.3 h1:bN2+Fw9XPFvOCjB0UOevFIMICZ7G2XSQHzfvLUyOM5E= +github.com/hashicorp/go-getter v1.7.3/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -1335,8 +1335,8 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/modules/light-clients/08-wasm/internal/ibcwasm/expected_interfaces.go b/modules/light-clients/08-wasm/internal/ibcwasm/expected_interfaces.go index 964b3b1469e..e15ff322c33 100644 --- a/modules/light-clients/08-wasm/internal/ibcwasm/expected_interfaces.go +++ b/modules/light-clients/08-wasm/internal/ibcwasm/expected_interfaces.go @@ -1,8 +1,8 @@ package ibcwasm import ( - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,12 +11,13 @@ import ( var _ WasmEngine = (*wasmvm.VM)(nil) type WasmEngine interface { - // StoreCode will compile the wasm code, and store the resulting pre-compile - // as well as the original code. Both can be referenced later via checksum + // StoreCode will compile the Wasm code, and store the resulting compiled module + // as well as the original code. Both can be referenced later via Checksum. // This must be done one time for given code, after which it can be // instantiated many times, and each instance called many times. - // It does the same as StoreCodeUnchecked plus the static checks. - StoreCode(code wasmvm.WasmCode) (wasmvm.Checksum, error) + // + // Returns both the checksum, as well as the gas cost of compilation (in CosmWasm Gas) or an error. + StoreCode(code wasmvm.WasmCode, gasLimit uint64) (wasmvmtypes.Checksum, uint64, error) // StoreCodeUnchecked will compile the wasm code, and store the resulting pre-compile // as well as the original code. Both can be referenced later via checksum @@ -45,7 +46,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // Query allows a client to execute a contract-specific query. If the result is not empty, it should be // valid json-encoded data to return to the client. @@ -60,9 +61,9 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) ([]byte, uint64, error) + ) (*wasmvmtypes.QueryResult, uint64, error) - // Migrate migrates an existing contract to a new code binary. + // Migrate will migrate an existing contract to a new code binary. // This takes storage of the data from the original contract and the checksum of the new contract that should // replace it. This allows it to run a migration step if needed, or return an error if unable to migrate // the given data. @@ -78,7 +79,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // Sudo allows native Go modules to make priviledged (sudo) calls on the contract. // The contract can expose entry points that cannot be triggered by any transaction, but only via @@ -96,7 +97,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // GetCode will load the original wasm code for the given checksum. // This will only succeed if that checksum was previously returned from diff --git a/modules/light-clients/08-wasm/keeper/genesis.go b/modules/light-clients/08-wasm/keeper/genesis.go index 6ab642097fb..d7c813c7086 100644 --- a/modules/light-clients/08-wasm/keeper/genesis.go +++ b/modules/light-clients/08-wasm/keeper/genesis.go @@ -1,6 +1,8 @@ package keeper import ( + wasmvm "github.com/CosmWasm/wasmvm/v2" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" @@ -10,8 +12,13 @@ import ( // InitGenesis initializes the 08-wasm module's state from a provided genesis // state. func (k Keeper) InitGenesis(ctx sdk.Context, gs types.GenesisState) error { + storeFn := func(code wasmvm.WasmCode, _ uint64) (wasmvm.Checksum, uint64, error) { + checksum, err := ibcwasm.GetVM().StoreCodeUnchecked(code) + return checksum, 0, err + } + for _, contract := range gs.Contracts { - _, err := k.storeWasmCode(ctx, contract.CodeBytes, ibcwasm.GetVM().StoreCodeUnchecked) + _, err := k.storeWasmCode(ctx, contract.CodeBytes, storeFn) if err != nil { return err } diff --git a/modules/light-clients/08-wasm/keeper/keeper.go b/modules/light-clients/08-wasm/keeper/keeper.go index 8676601a230..f8884ef4b4a 100644 --- a/modules/light-clients/08-wasm/keeper/keeper.go +++ b/modules/light-clients/08-wasm/keeper/keeper.go @@ -7,7 +7,7 @@ import ( "fmt" "strings" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" storetypes "cosmossdk.io/core/store" errorsmod "cosmossdk.io/errors" @@ -107,7 +107,7 @@ func (k Keeper) GetAuthority() string { return k.authority } -func (Keeper) storeWasmCode(ctx sdk.Context, code []byte, storeFn func(code wasmvm.WasmCode) (wasmvm.Checksum, error)) ([]byte, error) { +func (Keeper) storeWasmCode(ctx sdk.Context, code []byte, storeFn func(code wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error)) ([]byte, error) { var err error if types.IsGzip(code) { ctx.GasMeter().ConsumeGas(types.VMGasRegister.UncompressCosts(len(code)), "Uncompress gzip bytecode") @@ -133,8 +133,9 @@ func (Keeper) storeWasmCode(ctx sdk.Context, code []byte, storeFn func(code wasm } // create the code in the vm - ctx.GasMeter().ConsumeGas(types.VMGasRegister.CompileCosts(len(code)), "Compiling wasm bytecode") - vmChecksum, err := storeFn(code) + gasLeft := types.VMGasRegister.RuntimeGasForContract(ctx) + vmChecksum, gasUsed, err := storeFn(code, gasLeft) + types.VMGasRegister.ConsumeRuntimeGas(ctx, gasUsed) if err != nil { return nil, errorsmod.Wrap(err, "failed to store contract") } diff --git a/modules/light-clients/08-wasm/keeper/keeper_test.go b/modules/light-clients/08-wasm/keeper/keeper_test.go index d6d26173419..92573fdec92 100644 --- a/modules/light-clients/08-wasm/keeper/keeper_test.go +++ b/modules/light-clients/08-wasm/keeper/keeper_test.go @@ -5,8 +5,8 @@ import ( "errors" "testing" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" dbm "github.com/cosmos/cosmos-db" testifysuite "github.com/stretchr/testify/suite" @@ -86,7 +86,7 @@ func (suite *KeeperTestSuite) SetupWasmWithMockVM() { func (suite *KeeperTestSuite) setupWasmWithMockVM() (ibctesting.TestingApp, map[string]json.RawMessage) { suite.mockVM = wasmtesting.NewMockWasmEngine() - suite.mockVM.InstantiateFn = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.InstantiateMessage err := json.Unmarshal(initMsg, &payload) suite.Require().NoError(err) @@ -104,13 +104,13 @@ func (suite *KeeperTestSuite) setupWasmWithMockVM() (ibctesting.TestingApp, map[ resp, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: resp}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, 0, nil } - suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { resp, err := json.Marshal(types.StatusResult{Status: exported.Active.String()}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) db := dbm.NewMemDB() diff --git a/modules/light-clients/08-wasm/keeper/msg_server_test.go b/modules/light-clients/08-wasm/keeper/msg_server_test.go index 76329fa93ba..ce65581812b 100644 --- a/modules/light-clients/08-wasm/keeper/msg_server_test.go +++ b/modules/light-clients/08-wasm/keeper/msg_server_test.go @@ -5,8 +5,8 @@ import ( "encoding/json" "errors" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -172,11 +172,11 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { func() { msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, newChecksum, []byte("{}")) - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, nil, @@ -186,7 +186,7 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { func() { msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, newChecksum, []byte("{}")) - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { // the checksum written in the client state will later be overwritten by the message server. expClientStateBz := wasmtesting.CreateMockClientStateBz(suite.chainA.App.AppCodec(), []byte("invalid checksum")) expClientState = clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), expClientStateBz).(*types.ClientState) @@ -195,7 +195,7 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, nil, @@ -205,7 +205,7 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { func() { msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, oldChecksum, []byte("{}")) - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { panic("unreachable") } }, @@ -232,13 +232,24 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { }, clienttypes.ErrClientTypeNotFound, }, + { + "failure: vm returns error", + func() { + msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, newChecksum, []byte("{}")) + + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockVM + } + }, + types.ErrVMError, + }, { "failure: contract returns error", func() { msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, newChecksum, []byte("{}")) - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockContract + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmContractCallFailed, @@ -248,7 +259,7 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { func() { msg = types.NewMsgMigrateContract(govAcc, defaultWasmClientID, newChecksum, []byte("{}")) - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { // the checksum written in here will be overwritten newClientState := localhost.NewClientState(clienttypes.NewHeight(1, 1)) @@ -257,7 +268,7 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmInvalidContractModification, diff --git a/modules/light-clients/08-wasm/keeper/options_test.go b/modules/light-clients/08-wasm/keeper/options_test.go index 3f4680491ca..61b686927ee 100644 --- a/modules/light-clients/08-wasm/keeper/options_test.go +++ b/modules/light-clients/08-wasm/keeper/options_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/modules/light-clients/08-wasm/testing/mock_engine.go b/modules/light-clients/08-wasm/testing/mock_engine.go index 6e6e985e65a..cef0c525547 100644 --- a/modules/light-clients/08-wasm/testing/mock_engine.go +++ b/modules/light-clients/08-wasm/testing/mock_engine.go @@ -7,8 +7,8 @@ import ( "fmt" "reflect" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -28,20 +28,20 @@ var ( type ( // queryFn is a callback function that is invoked when a specific query message type is received. - queryFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) + queryFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) // sudoFn is a callback function that is invoked when a specific sudo message type is received. - sudoFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + sudoFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) ) // MockWasmEngine implements types.WasmEngine for testing purposes. One or multiple messages can be stubbed. // Without a stub function a panic is thrown. // ref: https://github.com/CosmWasm/wasmd/blob/v0.42.0/x/wasm/keeper/wasmtesting/mock_engine.go#L19 type MockWasmEngine struct { - StoreCodeFn func(code wasmvm.WasmCode) (wasmvm.Checksum, error) + StoreCodeFn func(code wasmvm.WasmCode, gasLimit uint64) (wasmvmtypes.Checksum, uint64, error) StoreCodeUncheckedFn func(code wasmvm.WasmCode) (wasmvm.Checksum, error) - InstantiateFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) - MigrateFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + InstantiateFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) + MigrateFn func(checksum wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) GetCodeFn func(checksum wasmvm.Checksum) (wasmvm.WasmCode, error) PinFn func(checksum wasmvm.Checksum) error UnpinFn func(checksum wasmvm.Checksum) error @@ -68,24 +68,24 @@ func NewMockWasmEngine() *MockWasmEngine { for _, msgType := range queryTypes { typeName := reflect.TypeOf(msgType).Name() - m.queryCallbacks[typeName] = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + m.queryCallbacks[typeName] = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { panic(fmt.Errorf("no callback specified for type %s", typeName)) } } for _, msgType := range sudoTypes { typeName := reflect.TypeOf(msgType).Name() - m.sudoCallbacks[typeName] = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + m.sudoCallbacks[typeName] = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { panic(fmt.Errorf("no callback specified for type %s", typeName)) } } // Set up default behavior for Store/Pin/Get - m.StoreCodeFn = func(code wasmvm.WasmCode) (wasmvm.Checksum, error) { + m.StoreCodeFn = func(code wasmvm.WasmCode, gasLimit uint64) (wasmvmtypes.Checksum, uint64, error) { checkSum, _ := types.CreateChecksum(code) m.storedContracts[binary.LittleEndian.Uint32(checkSum)] = code - return checkSum, nil + return checkSum, 0, nil } m.StoreCodeUncheckedFn = func(code wasmvm.WasmCode) (wasmvm.Checksum, error) { @@ -133,11 +133,11 @@ func (m *MockWasmEngine) RegisterSudoCallback(sudoMessage any, fn sudoFn) { } // StoreCode implements the WasmEngine interface. -func (m *MockWasmEngine) StoreCode(code wasmvm.WasmCode) (wasmvm.Checksum, error) { +func (m *MockWasmEngine) StoreCode(code wasmvm.WasmCode, gasLimit uint64) (wasmvmtypes.Checksum, uint64, error) { if m.StoreCodeFn == nil { panic(errors.New("mock engine is not properly initialized: StoreCodeFn is nil")) } - return m.StoreCodeFn(code) + return m.StoreCodeFn(code, gasLimit) } // StoreCode implements the WasmEngine interface. @@ -149,7 +149,7 @@ func (m *MockWasmEngine) StoreCodeUnchecked(code wasmvm.WasmCode) (wasmvm.Checks } // Instantiate implements the WasmEngine interface. -func (m *MockWasmEngine) Instantiate(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (m *MockWasmEngine) Instantiate(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if m.InstantiateFn == nil { panic(errors.New("mock engine is not properly initialized: InstantiateFn is nil")) } @@ -157,7 +157,7 @@ func (m *MockWasmEngine) Instantiate(checksum wasmvm.Checksum, env wasmvmtypes.E } // Query implements the WasmEngine interface. -func (m *MockWasmEngine) Query(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { +func (m *MockWasmEngine) Query(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { msgTypeName := getQueryMsgPayloadTypeName(queryMsg) callbackFn, ok := m.queryCallbacks[msgTypeName] @@ -169,7 +169,7 @@ func (m *MockWasmEngine) Query(checksum wasmvm.Checksum, env wasmvmtypes.Env, qu } // Migrate implements the WasmEngine interface. -func (m *MockWasmEngine) Migrate(checksum wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (m *MockWasmEngine) Migrate(checksum wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if m.MigrateFn == nil { panic(errors.New("mock engine is not properly initialized: MigrateFn is nil")) } @@ -177,7 +177,7 @@ func (m *MockWasmEngine) Migrate(checksum wasmvm.Checksum, env wasmvmtypes.Env, } // Sudo implements the WasmEngine interface. -func (m *MockWasmEngine) Sudo(checksum wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (m *MockWasmEngine) Sudo(checksum wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { msgTypeName := getSudoMsgPayloadTypeName(sudoMsg) sudoFn, ok := m.sudoCallbacks[msgTypeName] diff --git a/modules/light-clients/08-wasm/testing/simapp/app.go b/modules/light-clients/08-wasm/testing/simapp/app.go index caf8a841bca..27215ebcc01 100644 --- a/modules/light-clients/08-wasm/testing/simapp/app.go +++ b/modules/light-clients/08-wasm/testing/simapp/app.go @@ -4,8 +4,10 @@ import ( "encoding/json" "fmt" "io" + "math/rand" "os" "path/filepath" + "strconv" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/proto" @@ -462,9 +464,14 @@ func NewSimApp( // Function DefaultWasmConfig can also be used to use default values. // // In the code below we use the second method because we are not using x/wasm in this app.go. + + // NOTE: a random string is appended to the data directory to ensure that every test + // runs using a different data directory. This is required because wasm VM forbids 2 or more + // different VM instances running in the same data directory. In production environments, the + // appended random string is not needed. wasmConfig := wasmtypes.WasmConfig{ - DataDir: "ibc_08-wasm_client_data", - SupportedCapabilities: "iterator", + DataDir: filepath.Join(homePath, "ibc_08-wasm_client_data", strconv.Itoa(rand.Intn(10000))), + SupportedCapabilities: []string{"iterator"}, ContractDebugMode: false, } if mockVM != nil { diff --git a/modules/light-clients/08-wasm/testing/simapp/simd/cmd/root.go b/modules/light-clients/08-wasm/testing/simapp/simd/cmd/root.go index 615728f7baf..58d433f30ce 100644 --- a/modules/light-clients/08-wasm/testing/simapp/simd/cmd/root.go +++ b/modules/light-clients/08-wasm/testing/simapp/simd/cmd/root.go @@ -8,7 +8,7 @@ import ( "runtime/debug" "strings" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" dbm "github.com/cosmos/cosmos-db" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -416,7 +416,7 @@ func getExpectedLibwasmVersion() string { panic("can't read build info") } for _, d := range buildInfo.Deps { - if d.Path != "github.com/CosmWasm/wasmvm" { + if d.Path != "github.com/CosmWasm/wasmvm/v2" { continue } if d.Replace != nil { diff --git a/modules/light-clients/08-wasm/types/client_state_test.go b/modules/light-clients/08-wasm/types/client_state_test.go index 3a0f240b2d9..3373626c2be 100644 --- a/modules/light-clients/08-wasm/types/client_state_test.go +++ b/modules/light-clients/08-wasm/types/client_state_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "time" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" storetypes "cosmossdk.io/store/types" @@ -36,10 +36,10 @@ func (suite *TypesTestSuite) TestStatus() { { "client is frozen", func() { - suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { resp, err := json.Marshal(types.StatusResult{Status: exported.Frozen.String()}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) }, exported.Frozen, @@ -47,10 +47,10 @@ func (suite *TypesTestSuite) TestStatus() { { "client status is expired", func() { - suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { resp, err := json.Marshal(types.StatusResult{Status: exported.Expired.String()}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) }, exported.Expired, @@ -58,7 +58,7 @@ func (suite *TypesTestSuite) TestStatus() { { "client status is unknown: vm returns an error", func() { - suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { return nil, 0, wasmtesting.ErrMockContract }) }, @@ -106,7 +106,7 @@ func (suite *TypesTestSuite) TestGetTimestampAtHeight() { { "success", func() { - suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { var payload types.QueryMsg err := json.Unmarshal(queryMsg, &payload) suite.Require().NoError(err) @@ -120,16 +120,25 @@ func (suite *TypesTestSuite) TestGetTimestampAtHeight() { resp, err := json.Marshal(types.TimestampAtHeightResult{Timestamp: expectedTimestamp}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) }, nil, }, + { + "failure: vm returns error", + func() { + suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { + return nil, 0, wasmtesting.ErrMockVM + }) + }, + types.ErrVMError, + }, { "failure: contract returns error", func() { - suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { - return nil, 0, wasmtesting.ErrMockContract + suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { + return &wasmvmtypes.QueryResult{Err: wasmtesting.ErrMockContract.Error()}, 0, nil }) }, types.ErrWasmContractCallFailed, @@ -250,7 +259,7 @@ func (suite *TypesTestSuite) TestInitialize() { { "success: validate contract address", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, env wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, env wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.InstantiateMessage err := json.Unmarshal(initMsg, &payload) suite.Require().NoError(err) @@ -270,7 +279,7 @@ func (suite *TypesTestSuite) TestInitialize() { resp, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: resp}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, 0, nil } }, nil, @@ -280,7 +289,7 @@ func (suite *TypesTestSuite) TestInitialize() { func() { clientStore = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), ibctesting.InvalidID) }, - types.ErrWasmContractCallFailed, + types.ErrVMError, }, { "failure: invalid consensus state", @@ -298,10 +307,19 @@ func (suite *TypesTestSuite) TestInitialize() { types.ErrInvalidChecksum, }, { - "failure: InstantiateFn returns error", + "failure: vm returns error", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, 0, wasmtesting.ErrMockContract + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, 0, wasmtesting.ErrMockVM + } + }, + types.ErrVMError, + }, + { + "failure: contract returns error", + func() { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, 0, nil } }, types.ErrWasmContractCallFailed, @@ -361,7 +379,7 @@ func (suite *TypesTestSuite) TestVerifyMembership() { expClientStateBz = GetSimApp(suite.chainA).GetIBCKeeper().ClientKeeper.MustMarshalClientState(clientState) suite.mockVM.RegisterSudoCallback(types.VerifyMembershipMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) { + ) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.SudoMsg err := json.Unmarshal(sudoMsg, &payload) suite.Require().NoError(err) @@ -379,7 +397,7 @@ func (suite *TypesTestSuite) TestVerifyMembership() { bz, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: bz}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: bz}}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -389,7 +407,7 @@ func (suite *TypesTestSuite) TestVerifyMembership() { func() { suite.mockVM.RegisterSudoCallback(types.VerifyMembershipMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) { + ) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.SudoMsg err := json.Unmarshal(sudoMsg, &payload) suite.Require().NoError(err) @@ -410,20 +428,20 @@ func (suite *TypesTestSuite) TestVerifyMembership() { expClientStateBz = wasmtesting.CreateMockClientStateBz(suite.chainA.Codec, suite.checksum) store.Set(host.ClientStateKey(), expClientStateBz) - return &wasmvmtypes.Response{Data: bz}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: bz}}, wasmtesting.DefaultGasUsed, nil }) }, nil, }, { - "wasm vm returns invalid proof error", + "contract returns invalid proof error", func() { proof = wasmtesting.MockInvalidProofBz suite.mockVM.RegisterSudoCallback(types.VerifyMembershipMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) { - return nil, wasmtesting.DefaultGasUsed, commitmenttypes.ErrInvalidProof + ) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: commitmenttypes.ErrInvalidProof.Error()}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmContractCallFailed, @@ -504,7 +522,7 @@ func (suite *TypesTestSuite) TestVerifyNonMembership() { expClientStateBz = GetSimApp(suite.chainA).GetIBCKeeper().ClientKeeper.MustMarshalClientState(clientState) suite.mockVM.RegisterSudoCallback(types.VerifyNonMembershipMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) { + ) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.SudoMsg err := json.Unmarshal(sudoMsg, &payload) suite.Require().NoError(err) @@ -521,7 +539,7 @@ func (suite *TypesTestSuite) TestVerifyNonMembership() { bz, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: bz}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: bz}}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -531,7 +549,7 @@ func (suite *TypesTestSuite) TestVerifyNonMembership() { func() { suite.mockVM.RegisterSudoCallback(types.VerifyNonMembershipMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) { + ) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.SudoMsg err := json.Unmarshal(sudoMsg, &payload) suite.Require().NoError(err) @@ -551,20 +569,33 @@ func (suite *TypesTestSuite) TestVerifyNonMembership() { expClientStateBz = wasmtesting.CreateMockClientStateBz(suite.chainA.Codec, suite.checksum) store.Set(host.ClientStateKey(), expClientStateBz) - return &wasmvmtypes.Response{Data: bz}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: bz}}, wasmtesting.DefaultGasUsed, nil }) }, nil, }, { - "wasm vm returns invalid proof error", + "wasm vm returns error", + func() { + proof = wasmtesting.MockInvalidProofBz + + suite.mockVM.RegisterSudoCallback(types.VerifyNonMembershipMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, + _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction, + ) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockVM + }) + }, + types.ErrVMError, + }, + { + "contract returns invalid proof error", func() { proof = wasmtesting.MockInvalidProofBz suite.mockVM.RegisterSudoCallback(types.VerifyNonMembershipMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) { - return nil, wasmtesting.DefaultGasUsed, commitmenttypes.ErrInvalidProof + ) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: commitmenttypes.ErrInvalidProof.Error()}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmContractCallFailed, diff --git a/modules/light-clients/08-wasm/types/config.go b/modules/light-clients/08-wasm/types/config.go index da4ac531cd0..1cc10fbfcf5 100644 --- a/modules/light-clients/08-wasm/types/config.go +++ b/modules/light-clients/08-wasm/types/config.go @@ -1,6 +1,9 @@ package types -import "path/filepath" +import ( + "path/filepath" + "strings" +) const ( // ContractMemoryLimit is the memory limit of each contract execution (in MiB) @@ -21,10 +24,10 @@ const ( type WasmConfig struct { // DataDir is the directory for Wasm blobs and various caches DataDir string - // SupportedCapabilities is a comma separated list of capabilities supported by the chain - // See https://github.com/CosmWasm/wasmd/blob/e5049ba686ab71164a01f6e71e54347710a1f740/app/wasm.go#L3-L15 + // SupportedCapabilities is a slice of capabilities supported by the chain + // See https://github.com/CosmWasm/wasmd/blob/9e44af168570391b0b69822952f206d35320d473/app/wasm.go#L3-L16 // for more information. - SupportedCapabilities string + SupportedCapabilities []string // ContractDebugMode is a flag to log what contracts print. It must be false on all // production nodes, and only enabled in test environments or debug non-validating nodes. ContractDebugMode bool @@ -36,7 +39,7 @@ type WasmConfig struct { func DefaultWasmConfig(homePath string) WasmConfig { return WasmConfig{ DataDir: filepath.Join(homePath, defaultDataDir), - SupportedCapabilities: defaultSupportedCapabilities, + SupportedCapabilities: strings.Split(defaultSupportedCapabilities, ","), ContractDebugMode: defaultContractDebugMode, } } diff --git a/modules/light-clients/08-wasm/types/errors.go b/modules/light-clients/08-wasm/types/errors.go index 570e045e4fb..5e1a037fc84 100644 --- a/modules/light-clients/08-wasm/types/errors.go +++ b/modules/light-clients/08-wasm/types/errors.go @@ -19,4 +19,5 @@ var ( ErrWasmContractCallFailed = errorsmod.Register(ModuleName, 14, "wasm contract call failed") ErrWasmInvalidResponseData = errorsmod.Register(ModuleName, 15, "wasm contract returned invalid response data") ErrWasmInvalidContractModification = errorsmod.Register(ModuleName, 16, "wasm contract made invalid state modifications") + ErrVMError = errorsmod.Register(ModuleName, 17, "wasm VM error") ) diff --git a/modules/light-clients/08-wasm/types/gas_register.go b/modules/light-clients/08-wasm/types/gas_register.go index 4ccbcf401af..54f15bc83fc 100644 --- a/modules/light-clients/08-wasm/types/gas_register.go +++ b/modules/light-clients/08-wasm/types/gas_register.go @@ -1,7 +1,7 @@ package types import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" @@ -21,6 +21,7 @@ const ( // Rough timing have 88k gas at 90us, which is equal to 1k sdk gas... (one read)" // as well as manual Wasmer benchmarks from 2019. This was then multiplied by 150_000 // in the 0.16 -> 1.0 upgrade (https://github.com/CosmWasm/cosmwasm/pull/1120). + // In the 2.0 upgrade, this was reduced by a factor of 1000 (https://github.com/CosmWasm/cosmwasm/pull/1884). // // The multiplier deserves more reproducible benchmarking and a strategy that allows easy adjustments. // This is tracked in https://github.com/CosmWasm/wasmd/issues/566 and https://github.com/CosmWasm/wasmd/issues/631. @@ -30,11 +31,16 @@ const ( // // Please note that all gas prices returned to wasmvm should have this multiplied. // Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938055852 - DefaultGasMultiplier uint64 = 140_000_000 + DefaultGasMultiplier uint64 = 140_000 // DefaultInstanceCost is how much SDK gas we charge each time we load a WASM instance. // Creating a new instance is costly, and this helps put a recursion limit to contracts calling contracts. // Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938056803 DefaultInstanceCost uint64 = 60_000 + // DefaultInstanceCostDiscount is charged instead of DefaultInstanceCost for cases where + // we assume the contract is loaded from an in-memory cache. + // For a long time it was implicitly just 0 in those cases. + // Now we use something small that roughly reflects the 45µs startup time (30x cheaper than DefaultInstanceCost). + DefaultInstanceCostDiscount uint64 = 2_000 // DefaultCompileCost is how much SDK gas is charged *per byte* for compiling WASM code. // Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938056803 DefaultCompileCost uint64 = 3 @@ -69,18 +75,15 @@ func DefaultPerByteUncompressCost() wasmvmtypes.UFraction { // GasRegister abstract source for gas costs type GasRegister interface { - // NewContractInstanceCosts costs to create a new contract instance from code - NewContractInstanceCosts(pinned bool, msgLen int) storetypes.Gas - // CompileCosts costs to persist and "compile" a new wasm contract - CompileCosts(byteLength int) storetypes.Gas // UncompressCosts costs to unpack a new wasm contract UncompressCosts(byteLength int) storetypes.Gas - // InstantiateContractCosts costs when interacting with a wasm contract - InstantiateContractCosts(pinned bool, msgLen int) storetypes.Gas + // SetupContractCost are charged when interacting with a Wasm contract, i.e. every time + // the contract is prepared for execution through any entry point (execute/instantiate/sudo/query/ibc_*/...). + SetupContractCost(discount bool, msgLen int) storetypes.Gas // ReplyCosts costs to to handle a message reply - ReplyCosts(pinned bool, reply wasmvmtypes.Reply) storetypes.Gas + ReplyCosts(discount bool, reply wasmvmtypes.Reply) storetypes.Gas // EventCosts costs to persist an event - EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Events) storetypes.Gas + EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Array[wasmvmtypes.Event]) storetypes.Gas // ToWasmVMGas converts from Cosmos SDK gas units to [CosmWasm gas] (aka. wasmvm gas) // // [CosmWasm gas]: https://github.com/CosmWasm/cosmwasm/blob/v1.3.1/docs/GAS.md @@ -93,8 +96,16 @@ type GasRegister interface { // WasmGasRegisterConfig config type type WasmGasRegisterConfig struct { - // InstanceCost costs when interacting with a wasm contract + // InstanceCost are charged when interacting with a Wasm contract. + // "Instance" refers to the in-memory Instance of the Wasm runtime, not the contract address on chain. + // InstanceCost are part of a contract's setup cost. InstanceCost storetypes.Gas + // InstanceCostDiscount is a discounted version of InstanceCost. It is charged whenever + // we can reasonably assume that a contract is in one of the in-memory caches. E.g. + // when the contract is pinned or we send a reply to a contract that was executed before. + // See also https://github.com/CosmWasm/wasmd/issues/1798 for more thinking around + // discount cases. + InstanceCostDiscount storetypes.Gas // CompileCosts costs to persist and "compile" a new wasm contract CompileCost storetypes.Gas // UncompressCost costs per byte to unpack a contract @@ -121,6 +132,7 @@ type WasmGasRegisterConfig struct { func DefaultGasRegisterConfig() WasmGasRegisterConfig { return WasmGasRegisterConfig{ InstanceCost: DefaultInstanceCost, + InstanceCostDiscount: DefaultInstanceCostDiscount, CompileCost: DefaultCompileCost, GasMultiplier: DefaultGasMultiplier, EventPerAttributeCost: DefaultPerAttributeCost, @@ -152,19 +164,6 @@ func NewWasmGasRegister(c WasmGasRegisterConfig) WasmGasRegister { } } -// NewContractInstanceCosts costs to create a new contract instance from code -func (g WasmGasRegister) NewContractInstanceCosts(pinned bool, msgLen int) storetypes.Gas { - return g.InstantiateContractCosts(pinned, msgLen) -} - -// CompileCosts costs to persist and "compile" a new wasm contract -func (g WasmGasRegister) CompileCosts(byteLength int) storetypes.Gas { - if byteLength < 0 { - panic(errorsmod.Wrap(ErrInvalid, "negative length")) - } - return g.c.CompileCost * uint64(byteLength) -} - // UncompressCosts costs to unpack a new wasm contract func (g WasmGasRegister) UncompressCosts(byteLength int) storetypes.Gas { if byteLength < 0 { @@ -173,20 +172,24 @@ func (g WasmGasRegister) UncompressCosts(byteLength int) storetypes.Gas { return g.c.UncompressCost.Mul(uint64(byteLength)).Floor() } -// InstantiateContractCosts costs when interacting with a wasm contract -func (g WasmGasRegister) InstantiateContractCosts(pinned bool, msgLen int) storetypes.Gas { +// SetupContractCost costs when interacting with a wasm contract. +// Set discount to true in cases where you can reasonably assume the contract +// is loaded from an in-memory cache (e.g. pinned contracts or replys). +func (g WasmGasRegister) SetupContractCost(discount bool, msgLen int) storetypes.Gas { if msgLen < 0 { panic(errorsmod.Wrap(ErrInvalid, "negative length")) } - dataCosts := storetypes.Gas(msgLen) * g.c.ContractMessageDataCost - if pinned { - return dataCosts + dataCost := storetypes.Gas(msgLen) * g.c.ContractMessageDataCost + if discount { + return g.c.InstanceCostDiscount + dataCost } - return g.c.InstanceCost + dataCosts + return g.c.InstanceCost + dataCost } -// ReplyCosts costs to to handle a message reply -func (g WasmGasRegister) ReplyCosts(pinned bool, reply wasmvmtypes.Reply) storetypes.Gas { +// ReplyCosts costs to to handle a message reply. +// Set discount to true in cases where you can reasonably assume the contract +// is loaded from an in-memory cache (e.g. pinned contracts or replys). +func (g WasmGasRegister) ReplyCosts(discount bool, reply wasmvmtypes.Reply) storetypes.Gas { var eventGas storetypes.Gas msgLen := len(reply.Result.Err) if reply.Result.Ok != nil { @@ -199,11 +202,11 @@ func (g WasmGasRegister) ReplyCosts(pinned bool, reply wasmvmtypes.Reply) storet // apply free tier on the whole set not per event eventGas += g.EventCosts(attrs, nil) } - return eventGas + g.InstantiateContractCosts(pinned, msgLen) + return eventGas + g.SetupContractCost(discount, msgLen) } // EventCosts costs to persist an event -func (g WasmGasRegister) EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Events) storetypes.Gas { +func (g WasmGasRegister) EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Array[wasmvmtypes.Event]) storetypes.Gas { gas, remainingFreeTier := g.eventAttributeCosts(attrs, g.c.EventAttributeDataFreeTier) for _, e := range events { gas += g.c.CustomEventCost diff --git a/modules/light-clients/08-wasm/types/gas_register_custom.go b/modules/light-clients/08-wasm/types/gas_register_custom.go index e5a710f9e8e..80b41663f2a 100644 --- a/modules/light-clients/08-wasm/types/gas_register_custom.go +++ b/modules/light-clients/08-wasm/types/gas_register_custom.go @@ -3,8 +3,8 @@ package types import ( "math" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" storetypes "cosmossdk.io/store/types" @@ -24,7 +24,7 @@ var costJSONDeserialization = wasmvmtypes.UFraction{ Denominator: 1, } -func (g WasmGasRegister) runtimeGasForContract(ctx sdk.Context) uint64 { +func (g WasmGasRegister) RuntimeGasForContract(ctx sdk.Context) uint64 { meter := ctx.GasMeter() if meter.IsOutOfGas() { return 0 @@ -36,7 +36,7 @@ func (g WasmGasRegister) runtimeGasForContract(ctx sdk.Context) uint64 { return g.ToWasmVMGas(meter.Limit() - meter.GasConsumedToLimit()) } -func (g WasmGasRegister) consumeRuntimeGas(ctx sdk.Context, gas uint64) { +func (g WasmGasRegister) ConsumeRuntimeGas(ctx sdk.Context, gas uint64) { consumed := g.FromWasmVMGas(gas) ctx.GasMeter().ConsumeGas(consumed, "wasm contract") // throw OutOfGas error if we ran out (got exactly to zero due to better limit enforcing) diff --git a/modules/light-clients/08-wasm/types/genesis_test.go b/modules/light-clients/08-wasm/types/genesis_test.go index 026b6a901c8..319db1cabf2 100644 --- a/modules/light-clients/08-wasm/types/genesis_test.go +++ b/modules/light-clients/08-wasm/types/genesis_test.go @@ -3,8 +3,8 @@ package types_test import ( "encoding/json" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" @@ -59,7 +59,7 @@ func (suite *TypesTestSuite) TestExportMetatada() { { "success", func() { - suite.mockVM.RegisterQueryCallback(types.ExportMetadataMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.ExportMetadataMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { var msg types.QueryMsg err := json.Unmarshal(queryMsg, &msg) @@ -76,7 +76,7 @@ func (suite *TypesTestSuite) TestExportMetatada() { }) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -85,11 +85,11 @@ func (suite *TypesTestSuite) TestExportMetatada() { { "failure: contract returns an error", func() { - suite.mockVM.RegisterQueryCallback(types.ExportMetadataMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.ExportMetadataMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { return nil, 0, wasmtesting.ErrMockContract }) }, - errorsmod.Wrapf(types.ErrWasmContractCallFailed, wasmtesting.ErrMockContract.Error()), + errorsmod.Wrapf(types.ErrVMError, wasmtesting.ErrMockContract.Error()), nil, }, } diff --git a/modules/light-clients/08-wasm/types/migrate_contract_test.go b/modules/light-clients/08-wasm/types/migrate_contract_test.go index 8ab8f0a6c12..78724712888 100644 --- a/modules/light-clients/08-wasm/types/migrate_contract_test.go +++ b/modules/light-clients/08-wasm/types/migrate_contract_test.go @@ -4,8 +4,8 @@ import ( "encoding/hex" "encoding/json" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" @@ -36,7 +36,7 @@ func (suite *TypesTestSuite) TestMigrateContract() { payload = []byte{1} expChecksum := wasmvmtypes.ForceNewChecksum(hex.EncodeToString(newHash)) - suite.mockVM.MigrateFn = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, msg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, msg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { suite.Require().Equal(expChecksum, checksum) suite.Require().Equal(defaultWasmClientID, env.Contract.Address) suite.Require().Equal(payload, msg) @@ -44,7 +44,7 @@ func (suite *TypesTestSuite) TestMigrateContract() { data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, nil, @@ -52,14 +52,14 @@ func (suite *TypesTestSuite) TestMigrateContract() { { "success: update client state", func() { - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { expClientState = types.NewClientState([]byte{1}, newHash, clienttypes.NewHeight(2000, 2)) store.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), expClientState)) data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, nil, @@ -69,7 +69,7 @@ func (suite *TypesTestSuite) TestMigrateContract() { func() { newHash = oldHash // this should not be called - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { panic("unreachable") } }, @@ -83,14 +83,26 @@ func (suite *TypesTestSuite) TestMigrateContract() { }, types.ErrWasmChecksumNotFound, }, + { + "failure: vm returns error", + func() { + err := ibcwasm.Checksums.Set(suite.chainA.GetContext(), newHash) + suite.Require().NoError(err) + + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockVM + } + }, + types.ErrVMError, + }, { "failure: contract returns error", func() { err := ibcwasm.Checksums.Set(suite.chainA.GetContext(), newHash) suite.Require().NoError(err) - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockContract + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmContractCallFailed, diff --git a/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go b/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go index 05fd12e7566..51e36033d25 100644 --- a/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go +++ b/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "errors" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -25,36 +25,44 @@ func (suite *TypesTestSuite) TestCheckForMisbehaviour() { { "success: no misbehaviour", func() { - suite.mockVM.RegisterQueryCallback(types.CheckForMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.CheckForMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { resp, err := json.Marshal(types.CheckForMisbehaviourResult{FoundMisbehaviour: false}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) }, false, }, { "success: misbehaviour found", func() { - suite.mockVM.RegisterQueryCallback(types.CheckForMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.CheckForMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { resp, err := json.Marshal(types.CheckForMisbehaviourResult{FoundMisbehaviour: true}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) }, true, }, { "success: contract error, resp cannot be marshalled", func() { - suite.mockVM.RegisterQueryCallback(types.CheckForMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.CheckForMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { resp := "cannot be unmarshalled" - return []byte(resp), wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: []byte(resp)}, wasmtesting.DefaultGasUsed, nil + }) + }, + false, + }, + { + "success: contract returns error", func() { + suite.mockVM.RegisterQueryCallback(types.CheckForMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { + return &wasmvmtypes.QueryResult{Err: wasmtesting.ErrMockContract.Error()}, wasmtesting.DefaultGasUsed, nil }) }, false, }, { "success: vm returns error, ", func() { - suite.mockVM.RegisterQueryCallback(types.CheckForMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.CheckForMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { return nil, 0, errors.New("invalid block ID") }) }, diff --git a/modules/light-clients/08-wasm/types/proposal_handle_test.go b/modules/light-clients/08-wasm/types/proposal_handle_test.go index 7e4ba10aa96..5123c31ac24 100644 --- a/modules/light-clients/08-wasm/types/proposal_handle_test.go +++ b/modules/light-clients/08-wasm/types/proposal_handle_test.go @@ -3,8 +3,8 @@ package types_test import ( "encoding/json" - cosmwasm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + cosmwasm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -28,7 +28,7 @@ func (suite *TypesTestSuite) TestCheckSubstituteAndUpdateState() { func() { suite.mockVM.RegisterSudoCallback( types.MigrateClientStoreMsg{}, - func(_ cosmwasm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store cosmwasm.KVStore, _ cosmwasm.GoAPI, _ cosmwasm.Querier, _ cosmwasm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + func(_ cosmwasm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store cosmwasm.KVStore, _ cosmwasm.GoAPI, _ cosmwasm.Querier, _ cosmwasm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.SudoMsg err := json.Unmarshal(sudoMsg, &payload) suite.Require().NoError(err) @@ -48,7 +48,7 @@ func (suite *TypesTestSuite) TestCheckSubstituteAndUpdateState() { expectedClientStateBz = wasmtesting.CreateMockClientStateBz(suite.chainA.Codec, suite.checksum) store.Set(prefixedKey, expectedClientStateBz) - return &wasmvmtypes.Response{Data: bz}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: bz}}, wasmtesting.DefaultGasUsed, nil }, ) }, @@ -70,13 +70,25 @@ func (suite *TypesTestSuite) TestCheckSubstituteAndUpdateState() { }, clienttypes.ErrInvalidClient, }, + { + "failure: vm returns error", + func() { + suite.mockVM.RegisterSudoCallback( + types.MigrateClientStoreMsg{}, + func(_ cosmwasm.Checksum, _ wasmvmtypes.Env, _ []byte, _ cosmwasm.KVStore, _ cosmwasm.GoAPI, _ cosmwasm.Querier, _ cosmwasm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockVM + }, + ) + }, + types.ErrVMError, + }, { "failure: contract returns error", func() { suite.mockVM.RegisterSudoCallback( types.MigrateClientStoreMsg{}, - func(_ cosmwasm.Checksum, _ wasmvmtypes.Env, _ []byte, _ cosmwasm.KVStore, _ cosmwasm.GoAPI, _ cosmwasm.Querier, _ cosmwasm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockContract + func(_ cosmwasm.Checksum, _ wasmvmtypes.Env, _ []byte, _ cosmwasm.KVStore, _ cosmwasm.GoAPI, _ cosmwasm.Querier, _ cosmwasm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, wasmtesting.DefaultGasUsed, nil }, ) }, diff --git a/modules/light-clients/08-wasm/types/querier.go b/modules/light-clients/08-wasm/types/querier.go index d9eb1376492..5fbd7a57bf4 100644 --- a/modules/light-clients/08-wasm/types/querier.go +++ b/modules/light-clients/08-wasm/types/querier.go @@ -5,7 +5,7 @@ import ( "fmt" "slices" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" diff --git a/modules/light-clients/08-wasm/types/querier_test.go b/modules/light-clients/08-wasm/types/querier_test.go index f912480864b..c550ee14ee8 100644 --- a/modules/light-clients/08-wasm/types/querier_test.go +++ b/modules/light-clients/08-wasm/types/querier_test.go @@ -6,8 +6,8 @@ import ( "fmt" "math" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -57,7 +57,7 @@ func (suite *TypesTestSuite) TestCustomQuery() { } ibcwasm.SetQueryPlugins(&querierPlugin) - suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, querier wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, querier wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { echo := CustomQuery{ Echo: &QueryEcho{ Data: "hello world", @@ -79,14 +79,14 @@ func (suite *TypesTestSuite) TestCustomQuery() { resp, err = json.Marshal(types.StatusResult{Status: exported.Active.String()}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) }, }, { "failure: default query", func() { - suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, querier wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, querier wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { resp, err := querier.Query(wasmvmtypes.QueryRequest{Custom: json.RawMessage("{}")}, math.MaxUint64) suite.Require().ErrorIs(err, wasmvmtypes.UnsupportedRequest{Kind: "Custom queries are not allowed"}) suite.Require().Nil(resp) @@ -142,7 +142,7 @@ func (suite *TypesTestSuite) TestStargateQuery() { ibcwasm.SetQueryPlugins(&querierPlugin) - suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, querier wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, querier wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { queryRequest := types.QueryChecksumsRequest{} bz, err := queryRequest.Marshal() suite.Require().NoError(err) @@ -169,7 +169,7 @@ func (suite *TypesTestSuite) TestStargateQuery() { result, err := json.Marshal(types.TimestampAtHeightResult{}) suite.Require().NoError(err) - return result, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: result}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -199,7 +199,7 @@ func (suite *TypesTestSuite) TestStargateQuery() { merklePath, err := commitmenttypes.ApplyPrefix(suite.chainA.GetPrefix(), merklePath) suite.Require().NoError(err) - suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, querier wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, querier wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { queryRequest := clienttypes.QueryVerifyMembershipRequest{ ClientId: endpoint.ClientID, Proof: proof, @@ -228,12 +228,12 @@ func (suite *TypesTestSuite) TestStargateQuery() { result, err := json.Marshal(types.TimestampAtHeightResult{}) suite.Require().NoError(err) - return result, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: result}, wasmtesting.DefaultGasUsed, nil }) suite.mockVM.RegisterSudoCallback(types.VerifyMembershipMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) { + ) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.SudoMsg err := json.Unmarshal(sudoMsg, &payload) suite.Require().NoError(err) @@ -252,7 +252,7 @@ func (suite *TypesTestSuite) TestStargateQuery() { expDiscardedState = true store.Set(testKey, value) - return &wasmvmtypes.Response{Data: bz}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: bz}}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -260,7 +260,7 @@ func (suite *TypesTestSuite) TestStargateQuery() { { "failure: default querier", func() { - suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, querier wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.TimestampAtHeightMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, querier wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { queryRequest := types.QueryChecksumsRequest{} bz, err := queryRequest.Marshal() suite.Require().NoError(err) diff --git a/modules/light-clients/08-wasm/types/store.go b/modules/light-clients/08-wasm/types/store.go index 9f6cbcb49b7..975bccb8b0c 100644 --- a/modules/light-clients/08-wasm/types/store.go +++ b/modules/light-clients/08-wasm/types/store.go @@ -8,8 +8,8 @@ import ( "reflect" "strings" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" "cosmossdk.io/store/cachekv" diff --git a/modules/light-clients/08-wasm/types/types_test.go b/modules/light-clients/08-wasm/types/types_test.go index 866f0535a6f..7c4a83130bb 100644 --- a/modules/light-clients/08-wasm/types/types_test.go +++ b/modules/light-clients/08-wasm/types/types_test.go @@ -5,8 +5,8 @@ import ( "errors" "testing" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" dbm "github.com/cosmos/cosmos-db" testifysuite "github.com/stretchr/testify/suite" @@ -86,7 +86,7 @@ func (suite *TypesTestSuite) SetupWasmWithMockVM() { func (suite *TypesTestSuite) setupWasmWithMockVM() (ibctesting.TestingApp, map[string]json.RawMessage) { suite.mockVM = wasmtesting.NewMockWasmEngine() - suite.mockVM.InstantiateFn = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.InstantiateMessage err := json.Unmarshal(initMsg, &payload) suite.Require().NoError(err) @@ -104,13 +104,13 @@ func (suite *TypesTestSuite) setupWasmWithMockVM() (ibctesting.TestingApp, map[s resp, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: resp}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, 0, nil } - suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { resp, err := json.Marshal(types.StatusResult{Status: exported.Active.String()}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) db := dbm.NewMemDB() diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index b1e4a4a9525..8e9cf33ce35 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "fmt" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" @@ -37,7 +37,7 @@ func (suite *TypesTestSuite) TestUpdateState() { { "success: no update", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, env wasmvmtypes.Env, sudoMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var msg types.SudoMsg err := json.Unmarshal(sudoMsg, &msg) suite.Require().NoError(err) @@ -61,9 +61,7 @@ func (suite *TypesTestSuite) TestUpdateState() { return nil, 0, err } - return &wasmvmtypes.Response{ - Data: resp, - }, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -72,7 +70,7 @@ func (suite *TypesTestSuite) TestUpdateState() { { "success: update client", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var msg types.SudoMsg err := json.Unmarshal(sudoMsg, &msg) suite.Require().NoError(err) @@ -93,9 +91,7 @@ func (suite *TypesTestSuite) TestUpdateState() { return nil, 0, err } - return &wasmvmtypes.Response{ - Data: resp, - }, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -106,7 +102,7 @@ func (suite *TypesTestSuite) TestUpdateState() { func() { clientStore = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), ibctesting.InvalidID) }, - errorsmod.Wrap(types.ErrWasmContractCallFailed, errorsmod.Wrap(errorsmod.Wrapf(types.ErrRetrieveClientID, "prefix does not contain a valid clientID: %s", errorsmod.Wrapf(host.ErrInvalidID, "invalid client identifier %s", ibctesting.InvalidID)), "failed to retrieve clientID for wasm contract call").Error()), + errorsmod.Wrap(types.ErrVMError, errorsmod.Wrap(errorsmod.Wrapf(types.ErrRetrieveClientID, "prefix does not contain a valid clientID: %s", errorsmod.Wrapf(host.ErrInvalidID, "invalid client identifier %s", ibctesting.InvalidID)), "failed to retrieve clientID for wasm contract call").Error()), nil, }, { @@ -118,11 +114,21 @@ func (suite *TypesTestSuite) TestUpdateState() { fmt.Errorf("expected type %T, got %T", (*types.ClientMessage)(nil), (*ibctm.Misbehaviour)(nil)), nil, }, + { + "failure: VM returns error", + func() { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, 0, wasmtesting.ErrMockVM + }) + }, + errorsmod.Wrap(types.ErrVMError, wasmtesting.ErrMockVM.Error()), + nil, + }, { "failure: callbackFn returns error", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, 0, wasmtesting.ErrMockContract + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, 0, nil }) }, errorsmod.Wrap(types.ErrWasmContractCallFailed, wasmtesting.ErrMockContract.Error()), @@ -184,7 +190,7 @@ func (suite *TypesTestSuite) TestUpdateStateOnMisbehaviour() { { "success: no update", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateOnMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateOnMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var msg types.SudoMsg err := json.Unmarshal(sudoMsg, &msg) @@ -203,9 +209,7 @@ func (suite *TypesTestSuite) TestUpdateStateOnMisbehaviour() { return nil, 0, err } - return &wasmvmtypes.Response{ - Data: resp, - }, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -214,7 +218,7 @@ func (suite *TypesTestSuite) TestUpdateStateOnMisbehaviour() { { "success: client state updated on valid misbehaviour", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateOnMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateOnMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var msg types.SudoMsg err := json.Unmarshal(sudoMsg, &msg) suite.Require().NoError(err) @@ -232,7 +236,7 @@ func (suite *TypesTestSuite) TestUpdateStateOnMisbehaviour() { return nil, 0, err } - return &wasmvmtypes.Response{Data: resp}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -248,10 +252,20 @@ func (suite *TypesTestSuite) TestUpdateStateOnMisbehaviour() { nil, }, { - "failure: err return from contract vm", + "failure: err return from vm", + func() { + suite.mockVM.RegisterSudoCallback(types.UpdateStateOnMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, 0, wasmtesting.ErrMockVM + }) + }, + errorsmod.Wrap(types.ErrVMError, wasmtesting.ErrMockVM.Error()), + nil, + }, + { + "failure: err return from contract", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateOnMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, 0, wasmtesting.ErrMockContract + suite.mockVM.RegisterSudoCallback(types.UpdateStateOnMisbehaviourMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, 0, nil }) }, errorsmod.Wrap(types.ErrWasmContractCallFailed, wasmtesting.ErrMockContract.Error()), diff --git a/modules/light-clients/08-wasm/types/upgrade_test.go b/modules/light-clients/08-wasm/types/upgrade_test.go index 6006066ecc7..a42617a9919 100644 --- a/modules/light-clients/08-wasm/types/upgrade_test.go +++ b/modules/light-clients/08-wasm/types/upgrade_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "time" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" storetypes "cosmossdk.io/store/types" @@ -35,7 +35,7 @@ func (suite *TypesTestSuite) TestVerifyClientMessage() { { "success: valid misbehaviour", func() { - suite.mockVM.RegisterQueryCallback(types.VerifyClientMessageMsg{}, func(_ wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.VerifyClientMessageMsg{}, func(_ wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { var msg *types.QueryMsg err := json.Unmarshal(queryMsg, &msg) @@ -53,7 +53,7 @@ func (suite *TypesTestSuite) TestVerifyClientMessage() { resp, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -63,27 +63,36 @@ func (suite *TypesTestSuite) TestVerifyClientMessage() { func() { clientStore = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), ibctesting.InvalidID) }, - types.ErrWasmContractCallFailed, + types.ErrVMError, }, { "failure: invalid client message", func() { clientMsg = &ibctm.Header{} - suite.mockVM.RegisterQueryCallback(types.VerifyClientMessageMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.VerifyClientMessageMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { resp, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) }, ibcerrors.ErrInvalidType, }, { - "failure: error return from contract vm", + "failure: error return from vm", + func() { + suite.mockVM.RegisterQueryCallback(types.VerifyClientMessageMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { + return nil, 0, wasmtesting.ErrMockVM + }) + }, + types.ErrVMError, + }, + { + "failure: error return from contract", func() { - suite.mockVM.RegisterQueryCallback(types.VerifyClientMessageMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { - return nil, 0, wasmtesting.ErrMockContract + suite.mockVM.RegisterQueryCallback(types.VerifyClientMessageMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, queryMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { + return &wasmvmtypes.QueryResult{Err: wasmtesting.ErrMockContract.Error()}, 0, nil }) }, types.ErrWasmContractCallFailed, @@ -136,7 +145,7 @@ func (suite *TypesTestSuite) TestVerifyUpgradeAndUpdateState() { { "success: successful upgrade", func() { - suite.mockVM.RegisterSudoCallback(types.VerifyUpgradeAndUpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.VerifyUpgradeAndUpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.SudoMsg err := json.Unmarshal(sudoMsg, &payload) @@ -167,7 +176,7 @@ func (suite *TypesTestSuite) TestVerifyUpgradeAndUpdateState() { store.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), upgradedClient)) store.Set(host.ConsensusStateKey(wrappedUpgradedClient.GetLatestHeight()), clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState)) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil }) }, nil, @@ -188,11 +197,20 @@ func (suite *TypesTestSuite) TestVerifyUpgradeAndUpdateState() { }, clienttypes.ErrInvalidConsensus, }, + { + "failure: vm returns error", + func() { + suite.mockVM.RegisterSudoCallback(types.VerifyUpgradeAndUpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, 0, wasmtesting.ErrMockVM + }) + }, + types.ErrVMError, + }, { "failure: contract returns error", func() { - suite.mockVM.RegisterSudoCallback(types.VerifyUpgradeAndUpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, 0, wasmtesting.ErrMockContract + suite.mockVM.RegisterSudoCallback(types.VerifyUpgradeAndUpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, 0, nil }) }, types.ErrWasmContractCallFailed, diff --git a/modules/light-clients/08-wasm/types/vm.go b/modules/light-clients/08-wasm/types/vm.go index 1a894ae0843..70115968cea 100644 --- a/modules/light-clients/08-wasm/types/vm.go +++ b/modules/light-clients/08-wasm/types/vm.go @@ -6,8 +6,8 @@ import ( "encoding/json" "errors" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" @@ -26,16 +26,17 @@ var ( // wasmvmAPI is a wasmvm.GoAPI implementation that is passed to the wasmvm, it // doesn't implement any functionality, directly returning an error. wasmvmAPI = wasmvm.GoAPI{ - HumanAddress: humanAddress, - CanonicalAddress: canonicalAddress, + HumanizeAddress: humanizeAddress, + CanonicalizeAddress: canonicalizeAddress, + ValidateAddress: validateAddress, } ) // instantiateContract calls vm.Instantiate with appropriate arguments. -func instantiateContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.Response, error) { +func instantiateContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.ContractResult, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) - gasLimit := VMGasRegister.runtimeGasForContract(ctx) + gasLimit := VMGasRegister.RuntimeGasForContract(ctx) clientID, err := getClientID(clientStore) if err != nil { @@ -48,17 +49,17 @@ func instantiateContract(ctx sdk.Context, clientStore storetypes.KVStore, checks Funds: nil, } - ctx.GasMeter().ConsumeGas(VMGasRegister.NewContractInstanceCosts(true, len(msg)), "Loading CosmWasm module: instantiate") - response, gasUsed, err := ibcwasm.GetVM().Instantiate(checksum, env, msgInfo, msg, newStoreAdapter(clientStore), wasmvmAPI, newQueryHandler(ctx, clientID), multipliedGasMeter, gasLimit, costJSONDeserialization) - VMGasRegister.consumeRuntimeGas(ctx, gasUsed) - return response, err + ctx.GasMeter().ConsumeGas(VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: instantiate") + resp, gasUsed, err := ibcwasm.GetVM().Instantiate(checksum, env, msgInfo, msg, newStoreAdapter(clientStore), wasmvmAPI, newQueryHandler(ctx, clientID), multipliedGasMeter, gasLimit, costJSONDeserialization) + VMGasRegister.ConsumeRuntimeGas(ctx, gasUsed) + return resp, err } // callContract calls vm.Sudo with internally constructed gas meter and environment. -func callContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.Response, error) { +func callContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.ContractResult, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) - gasLimit := VMGasRegister.runtimeGasForContract(ctx) + gasLimit := VMGasRegister.RuntimeGasForContract(ctx) clientID, err := getClientID(clientStore) if err != nil { @@ -66,31 +67,31 @@ func callContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Chec } env := getEnv(ctx, clientID) - ctx.GasMeter().ConsumeGas(VMGasRegister.InstantiateContractCosts(true, len(msg)), "Loading CosmWasm module: sudo") + ctx.GasMeter().ConsumeGas(VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: sudo") resp, gasUsed, err := ibcwasm.GetVM().Sudo(checksum, env, msg, newStoreAdapter(clientStore), wasmvmAPI, newQueryHandler(ctx, clientID), multipliedGasMeter, gasLimit, costJSONDeserialization) - VMGasRegister.consumeRuntimeGas(ctx, gasUsed) + VMGasRegister.ConsumeRuntimeGas(ctx, gasUsed) return resp, err } // migrateContract calls vm.Migrate with internally constructed gas meter and environment. -func migrateContract(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.Response, error) { +func migrateContract(ctx sdk.Context, clientID string, clientStore storetypes.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.ContractResult, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) - gasLimit := VMGasRegister.runtimeGasForContract(ctx) + gasLimit := VMGasRegister.RuntimeGasForContract(ctx) env := getEnv(ctx, clientID) - ctx.GasMeter().ConsumeGas(VMGasRegister.InstantiateContractCosts(true, len(msg)), "Loading CosmWasm module: migrate") + ctx.GasMeter().ConsumeGas(VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: migrate") resp, gasUsed, err := ibcwasm.GetVM().Migrate(checksum, env, msg, newStoreAdapter(clientStore), wasmvmAPI, newQueryHandler(ctx, clientID), multipliedGasMeter, gasLimit, costJSONDeserialization) - VMGasRegister.consumeRuntimeGas(ctx, gasUsed) + VMGasRegister.ConsumeRuntimeGas(ctx, gasUsed) return resp, err } // queryContract calls vm.Query. -func queryContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Checksum, msg []byte) ([]byte, error) { +func queryContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Checksum, msg []byte) (*wasmvmtypes.QueryResult, error) { sdkGasMeter := ctx.GasMeter() multipliedGasMeter := NewMultipliedGasMeter(sdkGasMeter, VMGasRegister) - gasLimit := VMGasRegister.runtimeGasForContract(ctx) + gasLimit := VMGasRegister.RuntimeGasForContract(ctx) clientID, err := getClientID(clientStore) if err != nil { @@ -98,9 +99,9 @@ func queryContract(ctx sdk.Context, clientStore storetypes.KVStore, checksum Che } env := getEnv(ctx, clientID) - ctx.GasMeter().ConsumeGas(VMGasRegister.InstantiateContractCosts(true, len(msg)), "Loading CosmWasm module: query") + ctx.GasMeter().ConsumeGas(VMGasRegister.SetupContractCost(true, len(msg)), "Loading CosmWasm module: query") resp, gasUsed, err := ibcwasm.GetVM().Query(checksum, env, msg, newStoreAdapter(clientStore), wasmvmAPI, newQueryHandler(ctx, clientID), multipliedGasMeter, gasLimit, costJSONDeserialization) - VMGasRegister.consumeRuntimeGas(ctx, gasUsed) + VMGasRegister.ConsumeRuntimeGas(ctx, gasUsed) return resp, err } @@ -112,12 +113,15 @@ func wasmInstantiate(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storety } checksum := cs.Checksum - resp, err := instantiateContract(ctx, clientStore, checksum, encodedData) + res, err := instantiateContract(ctx, clientStore, checksum, encodedData) if err != nil { - return errorsmod.Wrap(ErrWasmContractCallFailed, err.Error()) + return errorsmod.Wrap(ErrVMError, err.Error()) + } + if res.Err != "" { + return errorsmod.Wrap(ErrWasmContractCallFailed, res.Err) } - if err = checkResponse(resp); err != nil { + if err = checkResponse(res.Ok); err != nil { return errorsmod.Wrapf(err, "checksum (%s)", hex.EncodeToString(cs.Checksum)) } @@ -151,16 +155,19 @@ func wasmSudo[T ContractResult](ctx sdk.Context, cdc codec.BinaryCodec, clientSt } checksum := cs.Checksum - resp, err := callContract(ctx, clientStore, checksum, encodedData) + res, err := callContract(ctx, clientStore, checksum, encodedData) if err != nil { - return result, errorsmod.Wrap(ErrWasmContractCallFailed, err.Error()) + return result, errorsmod.Wrap(ErrVMError, err.Error()) + } + if res.Err != "" { + return result, errorsmod.Wrap(ErrWasmContractCallFailed, res.Err) } - if err = checkResponse(resp); err != nil { + if err = checkResponse(res.Ok); err != nil { return result, errorsmod.Wrapf(err, "checksum (%s)", hex.EncodeToString(cs.Checksum)) } - if err := json.Unmarshal(resp.Data, &result); err != nil { + if err := json.Unmarshal(res.Ok.Data, &result); err != nil { return result, errorsmod.Wrap(ErrWasmInvalidResponseData, err.Error()) } @@ -181,12 +188,15 @@ func wasmSudo[T ContractResult](ctx sdk.Context, cdc codec.BinaryCodec, clientSt // wasmMigrate returns an error if: // - the contract migration returns an error func wasmMigrate(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, cs *ClientState, clientID string, payload []byte) error { - resp, err := migrateContract(ctx, clientID, clientStore, cs.Checksum, payload) + res, err := migrateContract(ctx, clientID, clientStore, cs.Checksum, payload) if err != nil { - return errorsmod.Wrapf(ErrWasmContractCallFailed, err.Error()) + return errorsmod.Wrap(ErrVMError, err.Error()) + } + if res.Err != "" { + return errorsmod.Wrap(ErrWasmContractCallFailed, res.Err) } - if err = checkResponse(resp); err != nil { + if err = checkResponse(res.Ok); err != nil { return errorsmod.Wrapf(err, "checksum (%s)", hex.EncodeToString(cs.Checksum)) } @@ -207,12 +217,15 @@ func wasmQuery[T ContractResult](ctx sdk.Context, clientStore storetypes.KVStore return result, errorsmod.Wrap(err, "failed to marshal payload for wasm query") } - resp, err := queryContract(ctx, clientStore, cs.Checksum, encodedData) + res, err := queryContract(ctx, clientStore, cs.Checksum, encodedData) if err != nil { - return result, errorsmod.Wrap(ErrWasmContractCallFailed, err.Error()) + return result, errorsmod.Wrap(ErrVMError, err.Error()) + } + if res.Err != "" { + return result, errorsmod.Wrap(ErrWasmContractCallFailed, res.Err) } - if err := json.Unmarshal(resp, &result); err != nil { + if err := json.Unmarshal(res.Ok, &result); err != nil { return result, errorsmod.Wrapf(ErrWasmInvalidResponseData, "failed to unmarshal result of wasm query: %v", err) } @@ -276,7 +289,7 @@ func getEnv(ctx sdk.Context, contractAddr string) wasmvmtypes.Env { env := wasmvmtypes.Env{ Block: wasmvmtypes.BlockInfo{ Height: uint64(height), - Time: uint64(nsec), + Time: wasmvmtypes.Uint64(nsec), ChainID: chainID, }, Contract: wasmvmtypes.ContractInfo{ @@ -287,12 +300,16 @@ func getEnv(ctx sdk.Context, contractAddr string) wasmvmtypes.Env { return env } -func humanAddress(canon []byte) (string, uint64, error) { - return "", 0, errors.New("humanAddress not implemented") +func humanizeAddress(canon []byte) (string, uint64, error) { + return "", 0, errors.New("humanizeAddress not implemented") +} + +func canonicalizeAddress(human string) ([]byte, uint64, error) { + return nil, 0, errors.New("canonicalizeAddress not implemented") } -func canonicalAddress(human string) ([]byte, uint64, error) { - return nil, 0, errors.New("canonicalAddress not implemented") +func validateAddress(human string) (uint64, error) { + return 0, errors.New("validateAddress not implemented") } // checkResponse returns an error if the response from a sudo, instantiate or migrate call diff --git a/modules/light-clients/08-wasm/types/vm_test.go b/modules/light-clients/08-wasm/types/vm_test.go index 7b56857a55e..57a54188cf7 100644 --- a/modules/light-clients/08-wasm/types/vm_test.go +++ b/modules/light-clients/08-wasm/types/vm_test.go @@ -3,8 +3,8 @@ package types_test import ( "encoding/json" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" @@ -23,10 +23,11 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { { "success", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { // Ensure GoAPI is set - suite.Require().NotNil(goapi.CanonicalAddress) - suite.Require().NotNil(goapi.HumanAddress) + suite.Require().NotNil(goapi.CanonicalizeAddress) + suite.Require().NotNil(goapi.HumanizeAddress) + suite.Require().NotNil(goapi.ValidateAddress) var payload types.InstantiateMessage err := json.Unmarshal(initMsg, &payload) @@ -42,16 +43,25 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { consensusStateBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), consensusState) store.Set(host.ConsensusStateKey(clientState.GetLatestHeight()), consensusStateBz) - return &wasmvmtypes.Response{}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 0, nil } }, nil, }, + { + "failure: vm returns error", + func() { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, 0, wasmtesting.ErrMockVM + } + }, + types.ErrVMError, + }, { "failure: contract returns error", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, 0, wasmtesting.ErrMockContract + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, 0, nil } }, types.ErrWasmContractCallFailed, @@ -59,10 +69,10 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { { "failure: contract returns non-empty messages", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { resp := wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{}}} - return &resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &resp}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmSubMessagesNotAllowed, @@ -70,10 +80,10 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { { "failure: contract returns non-empty events", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { resp := wasmvmtypes.Response{Events: []wasmvmtypes.Event{{}}} - return &resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &resp}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmEventsNotAllowed, @@ -81,10 +91,10 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { { "failure: contract returns non-empty attributes", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { resp := wasmvmtypes.Response{Attributes: []wasmvmtypes.EventAttribute{{}}} - return &resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &resp}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmAttributesNotAllowed, @@ -92,13 +102,13 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { { "failure: change clientstate type", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { newClientState := localhost.NewClientState(clienttypes.NewHeight(1, 1)) store.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), newClientState)) data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmInvalidContractModification, @@ -106,11 +116,11 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { { "failure: delete clientstate", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { store.Delete(host.ClientStateKey()) data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmInvalidContractModification, @@ -118,11 +128,11 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { { "failure: unmarshallable clientstate", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { store.Set(host.ClientStateKey(), []byte("invalid json")) data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmInvalidContractModification, @@ -130,7 +140,7 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { { "failure: change checksum", func() { - suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.InstantiateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var payload types.InstantiateMessage err := json.Unmarshal(initMsg, &payload) suite.Require().NoError(err) @@ -143,7 +153,7 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { resp, err := json.Marshal(types.UpdateStateResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: resp}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmInvalidContractModification, @@ -185,24 +195,34 @@ func (suite *TypesTestSuite) TestWasmMigrate() { { "success", func() { - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, goapi wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, goapi wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { // Ensure GoAPI is set - suite.Require().NotNil(goapi.CanonicalAddress) - suite.Require().NotNil(goapi.HumanAddress) + suite.Require().NotNil(goapi.CanonicalizeAddress) + suite.Require().NotNil(goapi.HumanizeAddress) + suite.Require().NotNil(goapi.ValidateAddress) resp, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: resp}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, 0, nil } }, nil, }, + { + "failure: vm returns error", + func() { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, 0, wasmtesting.ErrMockVM + } + }, + types.ErrVMError, + }, { "failure: contract returns error", func() { - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, 0, wasmtesting.ErrMockContract + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, 0, nil } }, types.ErrWasmContractCallFailed, @@ -210,10 +230,10 @@ func (suite *TypesTestSuite) TestWasmMigrate() { { "failure: contract returns non-empty messages", func() { - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { resp := wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{}}} - return &resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &resp}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmSubMessagesNotAllowed, @@ -221,10 +241,10 @@ func (suite *TypesTestSuite) TestWasmMigrate() { { "failure: contract returns non-empty events", func() { - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { resp := wasmvmtypes.Response{Events: []wasmvmtypes.Event{{}}} - return &resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &resp}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmEventsNotAllowed, @@ -232,10 +252,10 @@ func (suite *TypesTestSuite) TestWasmMigrate() { { "failure: contract returns non-empty attributes", func() { - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { resp := wasmvmtypes.Response{Attributes: []wasmvmtypes.EventAttribute{{}}} - return &resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &resp}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmAttributesNotAllowed, @@ -243,13 +263,13 @@ func (suite *TypesTestSuite) TestWasmMigrate() { { "failure: change clientstate type", func() { - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { newClientState := localhost.NewClientState(clienttypes.NewHeight(1, 1)) store.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), newClientState)) data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmInvalidContractModification, @@ -257,11 +277,11 @@ func (suite *TypesTestSuite) TestWasmMigrate() { { "failure: delete clientstate", func() { - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { store.Delete(host.ClientStateKey()) data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmInvalidContractModification, @@ -269,11 +289,11 @@ func (suite *TypesTestSuite) TestWasmMigrate() { { "failure: unmarshallable clientstate", func() { - suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.MigrateFn = func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { store.Set(host.ClientStateKey(), []byte("invalid json")) data, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: data}}, wasmtesting.DefaultGasUsed, nil } }, types.ErrWasmInvalidContractModification, @@ -315,24 +335,34 @@ func (suite *TypesTestSuite) TestWasmQuery() { { "success", func() { - suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, goapi wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, goapi wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { // Ensure GoAPI is set - suite.Require().NotNil(goapi.CanonicalAddress) - suite.Require().NotNil(goapi.HumanAddress) + suite.Require().NotNil(goapi.CanonicalizeAddress) + suite.Require().NotNil(goapi.HumanizeAddress) + suite.Require().NotNil(goapi.ValidateAddress) resp, err := json.Marshal(types.StatusResult{Status: exported.Frozen.String()}) suite.Require().NoError(err) - return resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil }) }, nil, }, + { + "failure: vm returns error", + func() { + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { + return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockVM + }) + }, + types.ErrVMError, + }, { "failure: contract returns error", func() { - suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { - return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockContract + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { + return &wasmvmtypes.QueryResult{Err: wasmtesting.ErrMockContract.Error()}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmContractCallFailed, @@ -340,8 +370,8 @@ func (suite *TypesTestSuite) TestWasmQuery() { { "failure: response fails to unmarshal", func() { - suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) ([]byte, uint64, error) { - return []byte("invalid json"), wasmtesting.DefaultGasUsed, nil + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { + return &wasmvmtypes.QueryResult{Ok: []byte("invalid json")}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmInvalidResponseData, @@ -391,24 +421,34 @@ func (suite *TypesTestSuite) TestWasmSudo() { { "success", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, goapi wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, goapi wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { // Ensure GoAPI is set - suite.Require().NotNil(goapi.CanonicalAddress) - suite.Require().NotNil(goapi.HumanAddress) + suite.Require().NotNil(goapi.CanonicalizeAddress) + suite.Require().NotNil(goapi.HumanizeAddress) + suite.Require().NotNil(goapi.ValidateAddress) resp, err := json.Marshal(types.UpdateStateResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: resp}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, wasmtesting.DefaultGasUsed, nil }) }, nil, }, + { + "failure: vm returns error", + func() { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockVM + }) + }, + types.ErrVMError, + }, { "failure: contract returns error", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return nil, wasmtesting.DefaultGasUsed, wasmtesting.ErrMockContract + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Err: wasmtesting.ErrMockContract.Error()}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmContractCallFailed, @@ -416,10 +456,10 @@ func (suite *TypesTestSuite) TestWasmSudo() { { "failure: contract returns non-empty messages", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { resp := wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{}}} - return &resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &resp}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmSubMessagesNotAllowed, @@ -427,10 +467,10 @@ func (suite *TypesTestSuite) TestWasmSudo() { { "failure: contract returns non-empty events", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { resp := wasmvmtypes.Response{Events: []wasmvmtypes.Event{{}}} - return &resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &resp}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmEventsNotAllowed, @@ -438,10 +478,10 @@ func (suite *TypesTestSuite) TestWasmSudo() { { "failure: contract returns non-empty attributes", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { resp := wasmvmtypes.Response{Attributes: []wasmvmtypes.EventAttribute{{}}} - return &resp, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &resp}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmAttributesNotAllowed, @@ -449,8 +489,8 @@ func (suite *TypesTestSuite) TestWasmSudo() { { "failure: response fails to unmarshal", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{Data: []byte("invalid json")}, wasmtesting.DefaultGasUsed, nil + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: []byte("invalid json")}}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmInvalidResponseData, @@ -458,14 +498,14 @@ func (suite *TypesTestSuite) TestWasmSudo() { { "failure: invalid clientstate type", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { newClientState := localhost.NewClientState(clienttypes.NewHeight(1, 1)) store.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), newClientState)) resp, err := json.Marshal(types.UpdateStateResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: resp}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmInvalidContractModification, @@ -473,13 +513,13 @@ func (suite *TypesTestSuite) TestWasmSudo() { { "failure: unmarshallable clientstate bytes", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { store.Set(host.ClientStateKey(), []byte("invalid json")) resp, err := json.Marshal(types.UpdateStateResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: resp}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmInvalidContractModification, @@ -487,13 +527,13 @@ func (suite *TypesTestSuite) TestWasmSudo() { { "failure: delete clientstate", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { store.Delete(host.ClientStateKey()) resp, err := json.Marshal(types.UpdateStateResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: resp}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmInvalidContractModification, @@ -501,7 +541,7 @@ func (suite *TypesTestSuite) TestWasmSudo() { { "failure: change checksum", func() { - suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + suite.mockVM.RegisterSudoCallback(types.UpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { clientState := suite.chainA.GetClientState(defaultWasmClientID) clientState.(*types.ClientState).Checksum = []byte("new checksum") store.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState)) @@ -509,7 +549,7 @@ func (suite *TypesTestSuite) TestWasmSudo() { resp, err := json.Marshal(types.UpdateStateResult{}) suite.Require().NoError(err) - return &wasmvmtypes.Response{Data: resp}, wasmtesting.DefaultGasUsed, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, wasmtesting.DefaultGasUsed, nil }) }, types.ErrWasmInvalidContractModification, diff --git a/modules/light-clients/08-wasm/wasm_test.go b/modules/light-clients/08-wasm/wasm_test.go new file mode 100644 index 00000000000..e51ea3efde8 --- /dev/null +++ b/modules/light-clients/08-wasm/wasm_test.go @@ -0,0 +1,127 @@ +package wasm_test + +import ( + "encoding/json" + "errors" + "testing" + + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" + dbm "github.com/cosmos/cosmos-db" + testifysuite "github.com/stretchr/testify/suite" + + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" + simapp "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing/simapp" + "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +type WasmTestSuite struct { + testifysuite.Suite + coordinator *ibctesting.Coordinator + chainA *ibctesting.TestChain + mockVM *wasmtesting.MockWasmEngine + + checksum types.Checksum +} + +func TestWasmTestSuite(t *testing.T) { + testifysuite.Run(t, new(WasmTestSuite)) +} + +func (suite *WasmTestSuite) SetupTest() { + ibctesting.DefaultTestingAppInit = setupTestingApp + + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 1) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) +} + +func init() { + ibctesting.DefaultTestingAppInit = setupTestingApp +} + +// GetSimApp returns the duplicated SimApp from within the 08-wasm directory. +// This must be used instead of chain.GetSimApp() for tests within this directory. +func GetSimApp(chain *ibctesting.TestChain) *simapp.SimApp { + app, ok := chain.App.(*simapp.SimApp) + if !ok { + panic(errors.New("chain is not a simapp.SimApp")) + } + return app +} + +// setupTestingApp provides the duplicated simapp which is specific to the 08-wasm module on chain creation. +func setupTestingApp() (ibctesting.TestingApp, map[string]json.RawMessage) { + db := dbm.NewMemDB() + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, simtestutil.EmptyAppOptions{}, nil) + return app, app.DefaultGenesis() +} + +// SetupWasmWithMockVM sets up mock cometbft chain with a mock vm. +func (suite *WasmTestSuite) SetupWasmWithMockVM() { + ibctesting.DefaultTestingAppInit = suite.setupWasmWithMockVM + + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 1) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.checksum = storeWasmCode(suite, wasmtesting.Code) +} + +func (suite *WasmTestSuite) setupWasmWithMockVM() (ibctesting.TestingApp, map[string]json.RawMessage) { + suite.mockVM = wasmtesting.NewMockWasmEngine() + + suite.mockVM.InstantiateFn = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + var payload types.InstantiateMessage + err := json.Unmarshal(initMsg, &payload) + suite.Require().NoError(err) + + wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState).(*ibctm.ClientState) + + clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.LatestHeight) + clientStateBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) + store.Set(host.ClientStateKey(), clientStateBz) + + consensusState := types.NewConsensusState(payload.ConsensusState) + consensusStateBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), consensusState) + store.Set(host.ConsensusStateKey(clientState.LatestHeight), consensusStateBz) + + resp, err := json.Marshal(types.EmptyResult{}) + suite.Require().NoError(err) + + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: resp}}, 0, nil + } + + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.QueryResult, uint64, error) { + resp, err := json.Marshal(types.StatusResult{Status: exported.Active.String()}) + suite.Require().NoError(err) + return &wasmvmtypes.QueryResult{Ok: resp}, wasmtesting.DefaultGasUsed, nil + }) + + db := dbm.NewMemDB() + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, simtestutil.EmptyAppOptions{}, suite.mockVM) + + // reset DefaultTestingAppInit to its original value + ibctesting.DefaultTestingAppInit = setupTestingApp + return app, app.DefaultGenesis() +} + +// storeWasmCode stores the wasm code on chain and returns the checksum. +func storeWasmCode(suite *WasmTestSuite, wasmCode []byte) types.Checksum { + ctx := suite.chainA.GetContext().WithBlockGasMeter(storetypes.NewInfiniteGasMeter()) + + msg := types.NewMsgStoreCode(authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmCode) + response, err := GetSimApp(suite.chainA).WasmClientKeeper.StoreCode(ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(response.Checksum) + return response.Checksum +} diff --git a/scripts/get-libwasm-version.py b/scripts/get-libwasm-version.py index ac46d8251a7..6a776cc0ee4 100755 --- a/scripts/get-libwasm-version.py +++ b/scripts/get-libwasm-version.py @@ -21,7 +21,7 @@ import argparse import requests -WASM_IMPORT = "github.com/CosmWasm/wasmvm" +WASM_IMPORT = "github.com/CosmWasm/wasmvm/v2" def _get_wasm_version(wasm_go_mod_path: str) -> str: