diff --git a/.circleci/config.yml b/.circleci/config.yml index 7a8fcab642..fbe4754bf7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -97,7 +97,7 @@ jobs: - "profiles/*" - store_artifacts: path: /tmp/logs - + test-system: executor: golang parallelism: 1 @@ -189,7 +189,7 @@ jobs: command: | IN_DOCKER=$(docker run --rm "cosmwasm/wasmd:${CIRCLE_SHA1}" /usr/bin/wasmd query wasm libwasmvm-version) echo "Runtime libwasmvm-version in docker: $IN_DOCKER" - IN_GOMOD=$(go list -m github.com/CosmWasm/wasmvm | cut -d" " -f2 | cut -d"v" -f2) + IN_GOMOD=$(go list -m github.com/CosmWasm/wasmvm/v2 | cut -d" " -f2 | cut -d"v" -f2) echo "wasmvm version in go.mod: $IN_GOMOD" if [[ "$IN_DOCKER" != "$IN_GOMOD" ]]; then echo "Mismatch of wasmvm versions detected" @@ -197,7 +197,7 @@ jobs: fi - when: condition: - equal: [ main, << pipeline.git.branch >> ] + equal: [main, << pipeline.git.branch >>] steps: - run: name: Push application Docker image to docker hub diff --git a/Dockerfile b/Dockerfile index 83131b6629..e5da4e7c73 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,13 +15,10 @@ RUN apk add git WORKDIR /code COPY . /code/ # See https://github.com/CosmWasm/wasmvm/releases -ADD https://github.com/CosmWasm/wasmvm/releases/download/v1.5.2/libwasmvm_muslc.aarch64.a /lib/libwasmvm_muslc.aarch64.a -ADD https://github.com/CosmWasm/wasmvm/releases/download/v1.5.2/libwasmvm_muslc.x86_64.a /lib/libwasmvm_muslc.x86_64.a -RUN sha256sum /lib/libwasmvm_muslc.aarch64.a | grep e78b224c15964817a3b75a40e59882b4d0e06fd055b39514d61646689cef8c6e -RUN sha256sum /lib/libwasmvm_muslc.x86_64.a | grep e660a38efb2930b34ee6f6b0bb12730adccb040b6ab701b8f82f34453a426ae7 - -# Copy the library you want to the final location that will be found by the linker flag `-lwasmvm_muslc` -RUN cp /lib/libwasmvm_muslc.${arch}.a /lib/libwasmvm_muslc.a +ADD https://github.com/CosmWasm/wasmvm/releases/download/v2.0.0-rc.2/libwasmvm_muslc.aarch64.a /lib/libwasmvm_muslc.aarch64.a +ADD https://github.com/CosmWasm/wasmvm/releases/download/v2.0.0-rc.2/libwasmvm_muslc.x86_64.a /lib/libwasmvm_muslc.x86_64.a +RUN sha256sum /lib/libwasmvm_muslc.aarch64.a | grep 6101550283308b4a57694faf558e47ec171c763321157825b48114e9d5a14bd2 +RUN sha256sum /lib/libwasmvm_muslc.x86_64.a | grep ec20d6df9c69a0fad61d224648a262d78996f7eb43afaf4775a30064148466b6 # force it to use static lib (from above) not standard libgo_cosmwasm.so file RUN LEDGER_ENABLED=false BUILD_TAGS=muslc LINK_STATICALLY=true make build @@ -45,4 +42,4 @@ EXPOSE 26656 # tendermint rpc EXPOSE 26657 -CMD ["/usr/bin/wasmd", "version"] \ No newline at end of file +CMD ["/usr/bin/wasmd", "version"] diff --git a/README.md b/README.md index d7475a5c64..6b59332236 100644 --- a/README.md +++ b/README.md @@ -28,15 +28,16 @@ Also CosmWasm 2.0 contracts remain compatible at the Wasm interface level. To extend the feature set over time, contracts can specify required [capabilities](https://github.com/CosmWasm/cosmwasm/blob/main/docs/CAPABILITIES.md) through cargo features in cosmwasm-std. The following table shows which of the [latest capabilities](https://github.com/CosmWasm/cosmwasm/blob/main/docs/CAPABILITIES-BUILT-IN.md) are supported by certain wasmd versions. -| capability | >= 0.42 | >= 0.41 | >= 0.31 | >= 0.29 | 0.28 | -| ------------ | ------- | ------- | ------- | ------- | ---- | -| iterator | x | x | x | x | x | -| stargate | x | x | x | x | x | -| staking | x | x | x | x | x | -| cosmwasm_1_1 | x | x | x | x | | -| cosmwasm_1_2 | x | x | x | | | -| cosmwasm_1_3 | x | x | | | | -| cosmwasm_1_4 | x | | | | | +| capability | >= 0.51 | >= 0.42 | >= 0.41 | >= 0.31 | >= 0.29 | 0.28 | +| ------------ | ------- | ------- | ------- | ------- | ------- | ---- | +| iterator | x | x | x | x | x | x | +| stargate | x | x | x | x | x | x | +| staking | x | x | x | x | x | x | +| cosmwasm_1_1 | x | x | x | x | x | | +| cosmwasm_1_2 | x | x | x | x | | | +| cosmwasm_1_3 | x | x | x | | | | +| cosmwasm_1_4 | x | x | | | | | +| cosmwasm_2_0 | x | | | | | | ### For node developers diff --git a/app/app.go b/app/app.go index 44934eae72..fa4789c926 100644 --- a/app/app.go +++ b/app/app.go @@ -7,7 +7,6 @@ import ( "os" "path/filepath" "sort" - "strings" "sync" abci "github.com/cometbft/cometbft/abci/types" @@ -629,7 +628,6 @@ func NewWasmApp( // The last arguments can contain custom message handlers, and custom query handlers, // if we want to allow any custom callbacks - availableCapabilities := strings.Join(AllCapabilities(), ",") app.WasmKeeper = wasmkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), @@ -646,7 +644,7 @@ func NewWasmApp( app.GRPCQueryRouter(), wasmDir, wasmConfig, - availableCapabilities, + AllCapabilities(), authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmOpts..., ) diff --git a/app/sim_test.go b/app/sim_test.go index 94fa34e66e..c4e1cebdc0 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -123,6 +123,8 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() + appOptions[flags.FlagHome] = t.TempDir() // ensure a unique folder for the new app + newApp := NewWasmApp(log.NewNopLogger(), newDB, nil, true, appOptions, emptyWasmOpts, fauxMerkleModeOpt, baseapp.SetChainID(SimAppChainID)) require.Equal(t, "WasmApp", newApp.Name()) @@ -318,7 +320,6 @@ func TestAppStateDeterminism(t *testing.T) { appOptions.SetDefault(key, value) } } - appOptions.SetDefault(flags.FlagHome, t.TempDir()) // ensure a unique folder appOptions.SetDefault(server.FlagInvCheckPeriod, simcli.FlagPeriodValue) for i := 0; i < numSeeds; i++ { @@ -331,6 +332,8 @@ func TestAppStateDeterminism(t *testing.T) { logger = log.NewNopLogger() } + appOptions.SetDefault(flags.FlagHome, t.TempDir()) // ensure a unique folder per run + db := dbm.NewMemDB() app := NewWasmApp(logger, db, nil, true, appOptions, emptyWasmOpts, interBlockCacheOpt(), baseapp.SetChainID(SimAppChainID)) diff --git a/app/wasm.go b/app/wasm.go index 70f811bc18..9c9d4cb69e 100644 --- a/app/wasm.go +++ b/app/wasm.go @@ -12,5 +12,6 @@ func AllCapabilities() []string { "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", + "cosmwasm_2_0", } } diff --git a/go.mod b/go.mod index ac4486c9a4..4e5f8824c3 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/CosmWasm/wasmd go 1.21 require ( - github.com/CosmWasm/wasmvm v1.5.2 + github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.2 github.com/cosmos/cosmos-proto v1.0.0-beta.3 github.com/cosmos/cosmos-sdk v0.50.1 github.com/cosmos/gogogateway v1.2.0 // indirect @@ -188,7 +188,7 @@ require ( golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect diff --git a/go.sum b/go.sum index 7b8b1890f7..0d832a2fa2 100644 --- a/go.sum +++ b/go.sum @@ -228,8 +228,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.2 h1:+pKB1Mz9GZVt1vadxB+EDdD1FOz3dMNjIKq/58/lrag= -github.com/CosmWasm/wasmvm v1.5.2/go.mod h1:Q0bSEtlktzh7W2hhEaifrFp1Erx11ckQZmjq8FLCyys= +github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.2 h1:2rAO0MpNmKHKsrX/lsyo7lLjKoGDOWwMk+40hTNVfdE= +github.com/CosmWasm/wasmvm/v2 v2.0.0-rc.2/go.mod h1:su9lg5qLr7adV95eOfzjZWkGiky8WNaNIHDr7Fpu7Ck= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= @@ -1340,8 +1340,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.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.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/tests/e2e/gov_test.go b/tests/e2e/gov_test.go index f57e6b1051..a0abd64edf 100644 --- a/tests/e2e/gov_test.go +++ b/tests/e2e/gov_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -61,25 +61,25 @@ func TestGovVoteByContract(t *testing.T) { }{ "yes": { vote: &wasmvmtypes.VoteMsg{ - Vote: wasmvmtypes.Yes, + Option: wasmvmtypes.Yes, }, expPass: true, }, "no": { vote: &wasmvmtypes.VoteMsg{ - Vote: wasmvmtypes.No, + Option: wasmvmtypes.No, }, expPass: false, }, "abstain": { vote: &wasmvmtypes.VoteMsg{ - Vote: wasmvmtypes.Abstain, + Option: wasmvmtypes.Abstain, }, expPass: true, }, "no with veto": { vote: &wasmvmtypes.VoteMsg{ - Vote: wasmvmtypes.NoWithVeto, + Option: wasmvmtypes.NoWithVeto, }, expPass: false, }, diff --git a/tests/e2e/grants_test.go b/tests/e2e/grants_test.go index 82748be8b2..203e23f0d3 100644 --- a/tests/e2e/grants_test.go +++ b/tests/e2e/grants_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/tests/e2e/group_test.go b/tests/e2e/group_test.go index 9852d9793a..49ab9638bb 100644 --- a/tests/e2e/group_test.go +++ b/tests/e2e/group_test.go @@ -27,7 +27,7 @@ func TestGroupWithContract(t *testing.T) { coord := ibctesting.NewCoordinator(t, 1) chain := coord.GetChain(ibctesting.GetChainID(1)) - contractAddr := e2e.InstantiateReflectContract(t, chain) + contractAddr := e2e.InstantiateStargateReflectContract(t, chain) chain.Fund(contractAddr, sdkmath.NewIntFromUint64(1_000_000_000)) members := []group.MemberRequest{ @@ -74,3 +74,57 @@ func TestGroupWithContract(t *testing.T) { expBalanceAmount := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.OneInt()) assert.Equal(t, expBalanceAmount.String(), recipientBalance.String()) } + +func TestGroupWithNewReflectContract(t *testing.T) { + // Given a group with a contract as only member + // When contract submits a proposal with try_execute + // Then the payload msg is executed + + coord := ibctesting.NewCoordinator(t, 1) + chain := coord.GetChain(ibctesting.GetChainID(1)) + contractAddr := e2e.InstantiateReflectContract(t, chain) + chain.Fund(contractAddr, sdkmath.NewIntFromUint64(1_000_000_000)) + + members := []group.MemberRequest{ + { + Address: contractAddr.String(), + Weight: "1", + Metadata: "my contract", + }, + } + msg, err := group.NewMsgCreateGroupWithPolicy( + chain.SenderAccount.GetAddress().String(), + members, + "my group", + "my metadata", + false, + group.NewPercentageDecisionPolicy("1", time.Second, 0), + ) + require.NoError(t, err) + rsp, err := chain.SendMsgs(msg) + require.NoError(t, err) + + var createRsp group.MsgCreateGroupWithPolicyResponse + chain.UnwrapExecTXResult(rsp, &createRsp) + groupID, policyAddr := createRsp.GroupId, sdk.MustAccAddressFromBech32(createRsp.GroupPolicyAddress) + require.NotEmpty(t, groupID) + chain.Fund(policyAddr, sdkmath.NewIntFromUint64(1_000_000_000)) + // and a proposal submitted + recipientAddr := sdk.AccAddress(rand.Bytes(address.Len)) + + payload := []sdk.Msg{banktypes.NewMsgSend(policyAddr, recipientAddr, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.OneInt())))} + propMsg, err := group.NewMsgSubmitProposal(policyAddr.String(), []string{contractAddr.String()}, payload, "my proposal", group.Exec_EXEC_TRY, "my title", "my description") + require.NoError(t, err) + + rsp = e2e.MustExecViaAnyReflectContract(t, chain, contractAddr, propMsg) + var execRsp types.MsgExecuteContractResponse + chain.UnwrapExecTXResult(rsp, &execRsp) + + var groupRsp group.MsgSubmitProposalResponse + require.NoError(t, chain.Codec.Unmarshal(execRsp.Data, &groupRsp)) + + // and coins received + recipientBalance := chain.Balance(recipientAddr, sdk.DefaultBondDenom) + expBalanceAmount := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.OneInt()) + assert.Equal(t, expBalanceAmount.String(), recipientBalance.String()) +} diff --git a/tests/e2e/reflect_helper.go b/tests/e2e/reflect_helper.go index 2d8a4c4d79..f857c8dad0 100644 --- a/tests/e2e/reflect_helper.go +++ b/tests/e2e/reflect_helper.go @@ -1,10 +1,12 @@ package e2e import ( + "encoding/base64" "encoding/json" + "fmt" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/gogoproto/proto" "github.com/stretchr/testify/require" @@ -16,9 +18,18 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) -// InstantiateReflectContract store and instantiate a reflect contract instance +// InstantiateStargateReflectContract stores and instantiates the reflect contract shipped with CosmWasm 1.5.3. +// This instance still expects the old CosmosMsg.Stargate variant instead of the new CosmosMsg.Any. +func InstantiateStargateReflectContract(t *testing.T, chain *ibctesting.TestChain) sdk.AccAddress { + codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect_1_5.wasm").CodeID + contractAddr := chain.InstantiateContract(codeID, []byte(`{}`)) + require.NotEmpty(t, contractAddr) + return contractAddr +} + +// InstantiateReflectContract stores and instantiates a 2.0 reflect contract instance. func InstantiateReflectContract(t *testing.T, chain *ibctesting.TestChain) sdk.AccAddress { - codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect_1_1.wasm").CodeID + codeID := chain.StoreCodeFile("../../x/wasm/keeper/testdata/reflect_2_0.wasm").CodeID contractAddr := chain.InstantiateContract(codeID, []byte(`{}`)) require.NotEmpty(t, contractAddr) return contractAddr @@ -37,12 +48,35 @@ type sdkMessageType interface { } func MustExecViaStargateReflectContract[T sdkMessageType](t *testing.T, chain *ibctesting.TestChain, contractAddr sdk.AccAddress, msgs ...T) *abci.ExecTxResult { + require.NotEmpty(t, msgs) + // convert messages to stargate variant + vmMsgs := make([]string, len(msgs)) + for i, m := range msgs { + bz, err := chain.Codec.Marshal(m) + require.NoError(t, err) + // json is built manually because the wasmvm CosmosMsg does not have the `Stargate` variant anymore + vmMsgs[i] = fmt.Sprintf("{\"stargate\":{\"type_url\":\"%s\",\"value\":\"%s\"}}", sdk.MsgTypeURL(m), base64.StdEncoding.EncodeToString(bz)) + } + // build the complete reflect message + reflectSendBz := []byte(fmt.Sprintf("{\"reflect_msg\":{\"msgs\":%s}}", vmMsgs)) + + execMsg := &types.MsgExecuteContract{ + Sender: chain.SenderAccount.GetAddress().String(), + Contract: contractAddr.String(), + Msg: reflectSendBz, + } + rsp, err := chain.SendMsgs(execMsg) + require.NoError(t, err) + return rsp +} + +func MustExecViaAnyReflectContract[T sdkMessageType](t *testing.T, chain *ibctesting.TestChain, contractAddr sdk.AccAddress, msgs ...T) *abci.ExecTxResult { vmMsgs := make([]wasmvmtypes.CosmosMsg, len(msgs)) for i, m := range msgs { bz, err := chain.Codec.Marshal(m) require.NoError(t, err) vmMsgs[i] = wasmvmtypes.CosmosMsg{ - Stargate: &wasmvmtypes.StargateMsg{ + Any: &wasmvmtypes.AnyMsg{ TypeURL: sdk.MsgTypeURL(m), Value: bz, }, diff --git a/x/wasm/client/cli/gov_tx.go b/x/wasm/client/cli/gov_tx.go index ade701246d..9b95ae949d 100644 --- a/x/wasm/client/cli/gov_tx.go +++ b/x/wasm/client/cli/gov_tx.go @@ -7,7 +7,7 @@ import ( "strconv" "strings" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/distribution/reference" "github.com/pkg/errors" "github.com/spf13/cobra" diff --git a/x/wasm/client/cli/query.go b/x/wasm/client/cli/query.go index 9027c8050b..89f6790327 100644 --- a/x/wasm/client/cli/query.go +++ b/x/wasm/client/cli/query.go @@ -10,7 +10,7 @@ import ( "os" "strconv" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/spf13/cobra" flag "github.com/spf13/pflag" diff --git a/x/wasm/ibc.go b/x/wasm/ibc.go index b1a3e81a83..45adcf4d19 100644 --- a/x/wasm/ibc.go +++ b/x/wasm/ibc.go @@ -3,7 +3,7 @@ package wasm import ( "math" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" diff --git a/x/wasm/ibc_integration_test.go b/x/wasm/ibc_integration_test.go index eca8ca1ac1..d268a8c720 100644 --- a/x/wasm/ibc_integration_test.go +++ b/x/wasm/ibc_integration_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "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" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -52,8 +52,10 @@ func TestOnChanOpenInitVersion(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { myContract := &wasmtesting.MockIBCContractCallbacks{ - IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { - return spec.contractRsp, 0, nil + IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { + return &wasmvmtypes.IBCChannelOpenResult{ + Ok: spec.contractRsp, + }, 0, nil }, } var ( @@ -110,8 +112,10 @@ func TestOnChanOpenTryVersion(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { myContract := &wasmtesting.MockIBCContractCallbacks{ - IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { - return spec.contractRsp, 0, nil + IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { + return &wasmvmtypes.IBCChannelOpenResult{ + Ok: spec.contractRsp, + }, 0, nil }, } var ( @@ -190,7 +194,7 @@ func TestOnIBCPacketReceive(t *testing.T) { myMockContractAddr := chainA.SeedNewContractInstance() // setups env but uses mock contract // setup chain B contracts - reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect.wasm").CodeID + reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect_1_5.wasm").CodeID initMsg, err := json.Marshal(wasmkeeper.IBCReflectInitMsg{ReflectCodeID: reflectID}) require.NoError(t, err) codeID := chainB.StoreCodeFile("./keeper/testdata/ibc_reflect.wasm").CodeID @@ -249,11 +253,11 @@ type captureAckTestContractEngine struct { // NewCaptureAckTestContractEngine constructor func NewCaptureAckTestContractEngine() *captureAckTestContractEngine { m := wasmtesting.NewIBCContractMockWasmEngine(&wasmtesting.MockIBCContractCallbacks{ - IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { - return &wasmvmtypes.IBC3ChannelOpenResponse{}, 0, nil + IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { + return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, 0, nil }, - IBCChannelConnectFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - return &wasmvmtypes.IBCBasicResponse{}, 0, nil + IBCChannelConnectFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil }, }) return &captureAckTestContractEngine{m} @@ -263,18 +267,20 @@ func NewCaptureAckTestContractEngine() *captureAckTestContractEngine { func (x *captureAckTestContractEngine) SubmitIBCPacket(t *testing.T, path *wasmibctesting.Path, chainA *wasmibctesting.TestChain, senderContractAddr sdk.AccAddress, packetData []byte) *[]byte { t.Helper() // prepare a bridge to send an ibc packet by an ordinary wasm execute message - x.MockWasmEngine.ExecuteFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &wasmvmtypes.SendPacketMsg{ - ChannelID: path.EndpointA.ChannelID, Data: executeMsg, Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{Revision: 1, Height: 10000000}}, - }}}}}, + x.MockWasmEngine.ExecuteFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &wasmvmtypes.SendPacketMsg{ + ChannelID: path.EndpointA.ChannelID, Data: executeMsg, Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{Revision: 1, Height: 10000000}}, + }}}}}, + }, }, 0, nil } // capture acknowledgement var gotAck []byte - x.MockWasmEngine.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + x.MockWasmEngine.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { gotAck = msg.Acknowledgement.Data - return &wasmvmtypes.IBCBasicResponse{}, 0, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } // start the process diff --git a/x/wasm/ibc_reflect_test.go b/x/wasm/ibc_reflect_test.go index f0d3ced634..c73155da9e 100644 --- a/x/wasm/ibc_reflect_test.go +++ b/x/wasm/ibc_reflect_test.go @@ -3,7 +3,7 @@ package wasm_test import ( "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" "github.com/stretchr/testify/assert" @@ -16,7 +16,7 @@ import ( func TestIBCReflectContract(t *testing.T) { // scenario: // chain A: ibc_reflect_send.wasm - // chain B: reflect.wasm + ibc_reflect.wasm + // chain B: reflect_1_5.wasm + ibc_reflect.wasm // // Chain A "ibc_reflect_send" sends a IBC packet "on channel connect" event to chain B "ibc_reflect" // "ibc_reflect" sends a submessage to "reflect" which is returned as submessage. @@ -32,7 +32,7 @@ func TestIBCReflectContract(t *testing.T) { codeID := chainA.StoreCodeFile("./keeper/testdata/ibc_reflect_send.wasm").CodeID sendContractAddr := chainA.InstantiateContract(codeID, initMsg) - reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect.wasm").CodeID + reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect_1_5.wasm").CodeID initMsg = wasmkeeper.IBCReflectInitMsg{ ReflectCodeID: reflectID, }.GetBytes(t) @@ -116,7 +116,7 @@ type AccountQuery struct { } type AccountResponse struct { - LastUpdateTime uint64 `json:"last_update_time,string"` - RemoteAddr string `json:"remote_addr"` - RemoteBalance wasmvmtypes.Coins `json:"remote_balance"` + LastUpdateTime uint64 `json:"last_update_time,string"` + RemoteAddr string `json:"remote_addr"` + RemoteBalance wasmvmtypes.Array[wasmvmtypes.Coin] `json:"remote_balance"` } diff --git a/x/wasm/ibc_test.go b/x/wasm/ibc_test.go index 271141e569..032c25f6e0 100644 --- a/x/wasm/ibc_test.go +++ b/x/wasm/ibc_test.go @@ -3,7 +3,7 @@ package wasm import ( "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/rand" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck diff --git a/x/wasm/keeper/api.go b/x/wasm/keeper/api.go index 0a6f37c123..c25a63860c 100644 --- a/x/wasm/keeper/api.go +++ b/x/wasm/keeper/api.go @@ -1,8 +1,10 @@ package keeper import ( - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "errors" + + wasmvm "github.com/CosmWasm/wasmvm/v2" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,6 +16,8 @@ const ( DefaultGasCostHumanAddress = 5 // DefaultGasCostCanonicalAddress is how much SDK gas we charge to convert to a canonical address format DefaultGasCostCanonicalAddress = 4 + // DefaultGasCostValidateAddress is how much SDK gas we charge to validate an address + DefaultGasCostValidateAddress = DefaultGasCostHumanAddress + DefaultGasCostCanonicalAddress // DefaultDeserializationCostPerByte The formula should be `len(data) * deserializationCostPerByte` DefaultDeserializationCostPerByte = 1 @@ -22,25 +26,39 @@ const ( var ( costHumanize = DefaultGasCostHumanAddress * types.DefaultGasMultiplier costCanonical = DefaultGasCostCanonicalAddress * types.DefaultGasMultiplier + costValidate = DefaultGasCostValidateAddress * types.DefaultGasMultiplier costJSONDeserialization = wasmvmtypes.UFraction{ Numerator: DefaultDeserializationCostPerByte * types.DefaultGasMultiplier, Denominator: 1, } ) -func humanAddress(canon []byte) (string, uint64, error) { +func humanizeAddress(canon []byte) (string, uint64, error) { if err := sdk.VerifyAddressFormat(canon); err != nil { return "", costHumanize, err } return sdk.AccAddress(canon).String(), costHumanize, nil } -func canonicalAddress(human string) ([]byte, uint64, error) { +func canonicalizeAddress(human string) ([]byte, uint64, error) { bz, err := sdk.AccAddressFromBech32(human) return bz, costCanonical, err } +func validateAddress(human string) (uint64, error) { + canonicalized, err := sdk.AccAddressFromBech32(human) + if err != nil { + return costValidate, err + } + // AccAddressFromBech32 already calls VerifyAddressFormat, so we can just humanize and compare + if canonicalized.String() != human { + return costValidate, errors.New("address not normalized") + } + return costValidate, nil +} + var cosmwasmAPI = wasmvm.GoAPI{ - HumanAddress: humanAddress, - CanonicalAddress: canonicalAddress, + HumanizeAddress: humanizeAddress, + CanonicalizeAddress: canonicalizeAddress, + ValidateAddress: validateAddress, } diff --git a/x/wasm/keeper/api_test.go b/x/wasm/keeper/api_test.go new file mode 100644 index 0000000000..752ac1dc4a --- /dev/null +++ b/x/wasm/keeper/api_test.go @@ -0,0 +1,34 @@ +package keeper + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestValidateAddress(t *testing.T) { + specs := map[string]struct { + human string + valid bool + }{ + "valid address": { + human: RandomBech32AccountAddress(t), + valid: true, + }, + "invalid address": { + human: "cosmos1invalid", + valid: false, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + _, err := validateAddress(spec.human) + + if spec.valid { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +} diff --git a/x/wasm/keeper/events.go b/x/wasm/keeper/events.go index b50719d461..5cfb075b2e 100644 --- a/x/wasm/keeper/events.go +++ b/x/wasm/keeper/events.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" @@ -28,7 +28,7 @@ func newWasmModuleEvent(customAttributes []wasmvmtypes.EventAttribute, contractA const eventTypeMinLength = 2 // newCustomEvents converts wasmvm events from a contract response to sdk type events -func newCustomEvents(evts wasmvmtypes.Events, contractAddr sdk.AccAddress) (sdk.Events, error) { +func newCustomEvents(evts wasmvmtypes.Array[wasmvmtypes.Event], contractAddr sdk.AccAddress) (sdk.Events, error) { events := make(sdk.Events, 0, len(evts)) for _, e := range evts { typ := strings.TrimSpace(e.Type) diff --git a/x/wasm/keeper/events_test.go b/x/wasm/keeper/events_test.go index f3e5cc73f2..6516703ec5 100644 --- a/x/wasm/keeper/events_test.go +++ b/x/wasm/keeper/events_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" sdk "github.com/cosmos/cosmos-sdk/types" @@ -56,12 +56,12 @@ func TestHasWasmModuleEvent(t *testing.T) { func TestNewCustomEvents(t *testing.T) { myContract := RandomAccountAddress(t) specs := map[string]struct { - src wasmvmtypes.Events + src wasmvmtypes.Array[wasmvmtypes.Event] exp sdk.Events isError bool }{ "all good": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myVal"}}, }}, @@ -70,7 +70,7 @@ func TestNewCustomEvents(t *testing.T) { sdk.NewAttribute("myKey", "myVal"))}, }, "multiple attributes": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{ {Key: "myKey", Value: "myVal"}, @@ -83,7 +83,7 @@ func TestNewCustomEvents(t *testing.T) { sdk.NewAttribute("myOtherKey", "myOtherVal"))}, }, "multiple events": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myVal"}}, }, { @@ -100,14 +100,14 @@ func TestNewCustomEvents(t *testing.T) { }, }, "without attributes": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", }}, exp: sdk.Events{sdk.NewEvent("wasm-foo", sdk.NewAttribute("_contract_address", myContract.String()))}, }, "empty value can be solved": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: ""}}, }}, @@ -116,7 +116,7 @@ func TestNewCustomEvents(t *testing.T) { sdk.NewAttribute("myKey", ""))}, }, "good on whitespace value": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "\n\n\n"}}, }}, exp: sdk.Events{sdk.NewEvent("wasm-foo", @@ -124,20 +124,20 @@ func TestNewCustomEvents(t *testing.T) { sdk.NewAttribute("myKey", ""))}, }, "error on short event type": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "f", }}, isError: true, }, "error on _contract_address": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "_contract_address", Value: RandomBech32AccountAddress(t)}}, }}, isError: true, }, "error on reserved prefix": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "wasm", Attributes: []wasmvmtypes.EventAttribute{ {Key: "_reserved", Value: "is skipped"}, @@ -147,7 +147,7 @@ func TestNewCustomEvents(t *testing.T) { isError: true, }, "error on empty key": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "boom", Attributes: []wasmvmtypes.EventAttribute{ {Key: "some", Value: "data"}, @@ -157,7 +157,7 @@ func TestNewCustomEvents(t *testing.T) { isError: true, }, "error on whitespace type": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: " f ", Attributes: []wasmvmtypes.EventAttribute{ {Key: "some", Value: "data"}, @@ -166,7 +166,7 @@ func TestNewCustomEvents(t *testing.T) { isError: true, }, "error on only whitespace key": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: "boom", Attributes: []wasmvmtypes.EventAttribute{ {Key: "some", Value: "data"}, @@ -176,7 +176,7 @@ func TestNewCustomEvents(t *testing.T) { isError: true, }, "strip out whitespace": { - src: wasmvmtypes.Events{{ + src: wasmvmtypes.Array[wasmvmtypes.Event]{{ Type: " food\n", Attributes: []wasmvmtypes.EventAttribute{{Key: "my Key", Value: "\tmyVal"}}, }}, @@ -185,7 +185,7 @@ func TestNewCustomEvents(t *testing.T) { sdk.NewAttribute("my Key", "myVal"))}, }, "empty event elements": { - src: make(wasmvmtypes.Events, 10), + src: make(wasmvmtypes.Array[wasmvmtypes.Event], 10), isError: true, }, "nil": { diff --git a/x/wasm/keeper/genesis_test.go b/x/wasm/keeper/genesis_test.go index b391ee0ba1..f16b151a4b 100644 --- a/x/wasm/keeper/genesis_test.go +++ b/x/wasm/keeper/genesis_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" abci "github.com/cometbft/cometbft/abci/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" dbm "github.com/cosmos/cosmos-db" diff --git a/x/wasm/keeper/handler_plugin.go b/x/wasm/keeper/handler_plugin.go index 74dea048a7..50bd1a1b67 100644 --- a/x/wasm/keeper/handler_plugin.go +++ b/x/wasm/keeper/handler_plugin.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -66,18 +67,19 @@ func NewSDKMessageHandler(cdc codec.Codec, router MessageRouter, encoders msgEnc } } -func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { +func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { sdkMsgs, err := h.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg) if err != nil { - return nil, nil, err + return nil, nil, nil, err } for _, sdkMsg := range sdkMsgs { res, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg) if err != nil { - return nil, nil, err + return nil, nil, nil, err } - // append data + // append data and msgResponses data = append(data, res.Data) + msgResponses = append(msgResponses, res.MsgResponses) // append events sdkEvents := make([]sdk.Event, len(res.Events)) for i := range res.Events { @@ -141,19 +143,19 @@ func NewMessageHandlerChain(first Messenger, others ...Messenger) *MessageHandle // order to find the right one to process given message. If a handler cannot // process given message (returns ErrUnknownMsg), its result is ignored and the // next handler is executed. -func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { +func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { for _, h := range m.handlers { - events, data, err := h.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) + events, data, msgResponses, err := h.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) switch { case err == nil: - return events, data, nil + return events, data, msgResponses, nil case errors.Is(err, types.ErrUnknownMsg): continue default: - return events, data, err + return events, data, msgResponses, err } } - return nil, nil, errorsmod.Wrap(types.ErrUnknownMsg, "no handler found") + return nil, nil, nil, errorsmod.Wrap(types.ErrUnknownMsg, "no handler found") } // IBCRawPacketHandler handles IBC.SendPacket messages which are published to an IBC channel. @@ -173,67 +175,72 @@ func NewIBCRawPacketHandler(ics4Wrapper types.ICS4Wrapper, channelKeeper types.C } // DispatchMsg publishes a raw IBC packet onto the channel. -func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { +func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, [][]*codectypes.Any, error) { if msg.IBC == nil || msg.IBC.SendPacket == nil { - return nil, nil, types.ErrUnknownMsg + return nil, nil, nil, types.ErrUnknownMsg } if contractIBCPortID == "" { - return nil, nil, errorsmod.Wrapf(types.ErrUnsupportedForContract, "ibc not supported") + return nil, nil, nil, errorsmod.Wrapf(types.ErrUnsupportedForContract, "ibc not supported") } contractIBCChannelID := msg.IBC.SendPacket.ChannelID if contractIBCChannelID == "" { - return nil, nil, errorsmod.Wrapf(types.ErrEmpty, "ibc channel") + return nil, nil, nil, errorsmod.Wrapf(types.ErrEmpty, "ibc channel") } channelCap, ok := h.capabilityKeeper.GetCapability(ctx, host.ChannelCapabilityPath(contractIBCPortID, contractIBCChannelID)) if !ok { - return nil, nil, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + return nil, nil, nil, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } seq, err := h.ics4Wrapper.SendPacket(ctx, channelCap, contractIBCPortID, contractIBCChannelID, ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.IBC.SendPacket.Timeout.Block), msg.IBC.SendPacket.Timeout.Timestamp, msg.IBC.SendPacket.Data) if err != nil { - return nil, nil, errorsmod.Wrap(err, "channel") + return nil, nil, nil, errorsmod.Wrap(err, "channel") } moduleLogger(ctx).Debug("ibc packet set", "seq", seq) resp := &types.MsgIBCSendResponse{Sequence: seq} val, err := resp.Marshal() if err != nil { - return nil, nil, errorsmod.Wrap(err, "failed to marshal IBC send response") + return nil, nil, nil, errorsmod.Wrap(err, "failed to marshal IBC send response") } + any, err := codectypes.NewAnyWithValue(resp) + if err != nil { + return nil, nil, nil, errorsmod.Wrap(err, "failed to convert IBC send response to Any") + } + msgResponses := [][]*codectypes.Any{{any}} - return nil, [][]byte{val}, nil + return nil, [][]byte{val}, msgResponses, nil } var _ Messenger = MessageHandlerFunc(nil) // MessageHandlerFunc is a helper to construct a function based message handler. -type MessageHandlerFunc func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) +type MessageHandlerFunc func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) // DispatchMsg delegates dispatching of provided message into the MessageHandlerFunc. -func (m MessageHandlerFunc) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { +func (m MessageHandlerFunc) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { return m(ctx, contractAddr, contractIBCPortID, msg) } // NewBurnCoinMessageHandler handles wasmvm.BurnMsg messages func NewBurnCoinMessageHandler(burner types.Burner) MessageHandlerFunc { - return func(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return func(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { if msg.Bank != nil && msg.Bank.Burn != nil { coins, err := ConvertWasmCoinsToSdkCoins(msg.Bank.Burn.Amount) if err != nil { - return nil, nil, err + return nil, nil, nil, err } if coins.IsZero() { - return nil, nil, types.ErrEmpty.Wrap("amount") + return nil, nil, nil, types.ErrEmpty.Wrap("amount") } if err := burner.SendCoinsFromAccountToModule(ctx, contractAddr, types.ModuleName, coins); err != nil { - return nil, nil, errorsmod.Wrap(err, "transfer to module") + return nil, nil, nil, errorsmod.Wrap(err, "transfer to module") } if err := burner.BurnCoins(ctx, types.ModuleName, coins); err != nil { - return nil, nil, errorsmod.Wrap(err, "burn coins") + return nil, nil, nil, errorsmod.Wrap(err, "burn coins") } moduleLogger(ctx).Info("Burned", "amount", coins) - return nil, nil, nil + return nil, nil, nil, nil } - return nil, nil, types.ErrUnknownMsg + return nil, nil, nil, types.ErrUnknownMsg } } diff --git a/x/wasm/keeper/handler_plugin_encoders.go b/x/wasm/keeper/handler_plugin_encoders.go index 9e783c98ca..5ae2313e9b 100644 --- a/x/wasm/keeper/handler_plugin_encoders.go +++ b/x/wasm/keeper/handler_plugin_encoders.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -28,7 +28,7 @@ type ( CustomEncoder func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) DistributionEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error) StakingEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error) - StargateEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) + AnyEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error) WasmEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error) IBCEncoder func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) ) @@ -39,7 +39,7 @@ type MessageEncoders struct { Distribution func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error) IBC func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) Staking func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error) - Stargate func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) + Any func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error) Wasm func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error) Gov func(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error) } @@ -51,7 +51,7 @@ func DefaultEncoders(unpacker codectypes.AnyUnpacker, portSource types.ICS20Tran Distribution: EncodeDistributionMsg, IBC: EncodeIBCMsg(portSource), Staking: EncodeStakingMsg, - Stargate: EncodeStargateMsg(unpacker), + Any: EncodeAnyMsg(unpacker), Wasm: EncodeWasmMsg, Gov: EncodeGovMsg, } @@ -76,8 +76,8 @@ func (e MessageEncoders) Merge(o *MessageEncoders) MessageEncoders { if o.Staking != nil { e.Staking = o.Staking } - if o.Stargate != nil { - e.Stargate = o.Stargate + if o.Any != nil { + e.Any = o.Any } if o.Wasm != nil { e.Wasm = o.Wasm @@ -100,8 +100,8 @@ func (e MessageEncoders) Encode(ctx sdk.Context, contractAddr sdk.AccAddress, co return e.IBC(ctx, contractAddr, contractIBCPortID, msg.IBC) case msg.Staking != nil: return e.Staking(contractAddr, msg.Staking) - case msg.Stargate != nil: - return e.Stargate(contractAddr, msg.Stargate) + case msg.Any != nil: + return e.Any(contractAddr, msg.Any) case msg.Wasm != nil: return e.Wasm(contractAddr, msg.Wasm) case msg.Gov != nil: @@ -204,8 +204,8 @@ func EncodeStakingMsg(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk } } -func EncodeStargateMsg(unpacker codectypes.AnyUnpacker) StargateEncoder { - return func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) { +func EncodeAnyMsg(unpacker codectypes.AnyUnpacker) AnyEncoder { + return func(sender sdk.AccAddress, msg *wasmvmtypes.AnyMsg) ([]sdk.Msg, error) { codecAny := codectypes.Any{ TypeUrl: msg.TypeURL, Value: msg.Value, @@ -317,6 +317,7 @@ func EncodeIBCMsg(portSource types.ICS20TransferPortSource) func(ctx sdk.Context Receiver: msg.Transfer.ToAddress, TimeoutHeight: ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.Transfer.Timeout.Block), TimeoutTimestamp: msg.Transfer.Timeout.Timestamp, + Memo: msg.Transfer.Memo, } return []sdk.Msg{msg}, nil default: @@ -328,7 +329,7 @@ func EncodeIBCMsg(portSource types.ICS20TransferPortSource) func(ctx sdk.Context func EncodeGovMsg(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error) { switch { case msg.Vote != nil: - voteOption, err := convertVoteOption(msg.Vote.Vote) + voteOption, err := convertVoteOption(msg.Vote.Option) if err != nil { return nil, errorsmod.Wrap(err, "vote option") } diff --git a/x/wasm/keeper/handler_plugin_encoders_test.go b/x/wasm/keeper/handler_plugin_encoders_test.go index 1374f03509..f5536a3355 100644 --- a/x/wasm/keeper/handler_plugin_encoders_test.go +++ b/x/wasm/keeper/handler_plugin_encoders_test.go @@ -3,7 +3,7 @@ package keeper import ( "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/gogoproto/proto" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck @@ -56,10 +56,8 @@ func TestEncoding(t *testing.T) { require.NoError(t, err) cases := map[string]struct { - sender sdk.AccAddress - srcMsg wasmvmtypes.CosmosMsg - srcContractIBCPort string - transferPortSource types.ICS20TransferPortSource + sender sdk.AccAddress + srcMsg wasmvmtypes.CosmosMsg // set if valid output []sdk.Msg // set if expect mapping fails @@ -381,7 +379,7 @@ func TestEncoding(t *testing.T) { srcMsg: wasmvmtypes.CosmosMsg{ Distribution: &wasmvmtypes.DistributionMsg{ FundCommunityPool: &wasmvmtypes.FundCommunityPoolMsg{ - Amount: wasmvmtypes.Coins{ + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{ wasmvmtypes.NewCoin(200, "stones"), wasmvmtypes.NewCoin(200, "feathers"), }, @@ -401,7 +399,7 @@ func TestEncoding(t *testing.T) { "stargate encoded bank msg": { sender: addr2, srcMsg: wasmvmtypes.CosmosMsg{ - Stargate: &wasmvmtypes.StargateMsg{ + Any: &wasmvmtypes.AnyMsg{ TypeURL: "/cosmos.bank.v1beta1.MsgSend", Value: bankMsgBin, }, @@ -411,7 +409,7 @@ func TestEncoding(t *testing.T) { "stargate encoded msg with any type": { sender: addr2, srcMsg: wasmvmtypes.CosmosMsg{ - Stargate: &wasmvmtypes.StargateMsg{ + Any: &wasmvmtypes.AnyMsg{ TypeURL: "/cosmos.gov.v1.MsgSubmitProposal", Value: proposalMsgBin, }, @@ -421,13 +419,45 @@ func TestEncoding(t *testing.T) { "stargate encoded invalid typeUrl": { sender: addr2, srcMsg: wasmvmtypes.CosmosMsg{ - Stargate: &wasmvmtypes.StargateMsg{ + Any: &wasmvmtypes.AnyMsg{ TypeURL: "/cosmos.bank.v2.MsgSend", Value: bankMsgBin, }, }, expError: true, }, + } + encodingConfig := MakeEncodingConfig(t) + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + encoder := DefaultEncoders(encodingConfig.Codec, wasmtesting.MockIBCTransferKeeper{}) + res, err := encoder.Encode(sdk.Context{}, tc.sender, "", tc.srcMsg) + if tc.expError { + assert.Error(t, err) + return + } + require.NoError(t, err) + assert.Equal(t, tc.output, res) + }) + } +} + +func TestEncodeIbcMsg(t *testing.T) { + var ( + addr1 = RandomAccountAddress(t) + addr2 = RandomAccountAddress(t) + ) + + cases := map[string]struct { + sender sdk.AccAddress + srcMsg wasmvmtypes.CosmosMsg + srcContractIBCPort string + transferPortSource types.ICS20TransferPortSource + // set if valid + output []sdk.Msg + // set if expect mapping fails + expError bool + }{ "IBC transfer with block timeout": { sender: addr1, srcContractIBCPort: "myIBCPort", @@ -530,6 +560,41 @@ func TestEncoding(t *testing.T) { }, }, }, + "IBC transfer with memo": { + sender: addr1, + srcContractIBCPort: "myIBCPort", + srcMsg: wasmvmtypes.CosmosMsg{ + IBC: &wasmvmtypes.IBCMsg{ + Transfer: &wasmvmtypes.TransferMsg{ + ChannelID: "myChanID", + ToAddress: addr2.String(), + Amount: wasmvmtypes.Coin{ + Denom: "ALX", + Amount: "1", + }, + Timeout: wasmvmtypes.IBCTimeout{Timestamp: 100}, + Memo: "myMemo", + }, + }, + }, + transferPortSource: wasmtesting.MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }}, + output: []sdk.Msg{ + &ibctransfertypes.MsgTransfer{ + SourcePort: "myTransferPort", + SourceChannel: "myChanID", + Token: sdk.Coin{ + Denom: "ALX", + Amount: sdkmath.NewInt(1), + }, + Sender: addr1.String(), + Receiver: addr2.String(), + TimeoutTimestamp: 100, + Memo: "myMemo", + }, + }, + }, "IBC close channel": { sender: addr1, srcContractIBCPort: "myIBCPort", @@ -581,7 +646,7 @@ func TestEncodeGovMsg(t *testing.T) { sender: myAddr, srcMsg: wasmvmtypes.CosmosMsg{ Gov: &wasmvmtypes.GovMsg{ - Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.Yes}, + Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Option: wasmvmtypes.Yes}, }, }, output: []sdk.Msg{ @@ -596,7 +661,7 @@ func TestEncodeGovMsg(t *testing.T) { sender: myAddr, srcMsg: wasmvmtypes.CosmosMsg{ Gov: &wasmvmtypes.GovMsg{ - Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.No}, + Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Option: wasmvmtypes.No}, }, }, output: []sdk.Msg{ @@ -611,7 +676,7 @@ func TestEncodeGovMsg(t *testing.T) { sender: myAddr, srcMsg: wasmvmtypes.CosmosMsg{ Gov: &wasmvmtypes.GovMsg{ - Vote: &wasmvmtypes.VoteMsg{ProposalId: 10, Vote: wasmvmtypes.Abstain}, + Vote: &wasmvmtypes.VoteMsg{ProposalId: 10, Option: wasmvmtypes.Abstain}, }, }, output: []sdk.Msg{ @@ -626,7 +691,7 @@ func TestEncodeGovMsg(t *testing.T) { sender: myAddr, srcMsg: wasmvmtypes.CosmosMsg{ Gov: &wasmvmtypes.GovMsg{ - Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.NoWithVeto}, + Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Option: wasmvmtypes.NoWithVeto}, }, }, output: []sdk.Msg{ diff --git a/x/wasm/keeper/handler_plugin_test.go b/x/wasm/keeper/handler_plugin_test.go index 3a657a3ef1..01d23ccd39 100644 --- a/x/wasm/keeper/handler_plugin_test.go +++ b/x/wasm/keeper/handler_plugin_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "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" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -17,6 +17,7 @@ import ( sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/baseapp" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -29,13 +30,13 @@ func TestMessageHandlerChainDispatch(t *testing.T) { capturingHandler, gotMsgs := wasmtesting.NewCapturingMessageHandler() alwaysUnknownMsgHandler := &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, types.ErrUnknownMsg + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, types.ErrUnknownMsg }, } assertNotCalledHandler := &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { t.Fatal("not expected to be called") return }, @@ -58,8 +59,8 @@ func TestMessageHandlerChainDispatch(t *testing.T) { }, "stops iteration on handler error": { handlers: []Messenger{&wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, types.ErrInvalidMsg + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, types.ErrInvalidMsg }, }, assertNotCalledHandler}, expErr: types.ErrInvalidMsg, @@ -67,9 +68,9 @@ func TestMessageHandlerChainDispatch(t *testing.T) { "return events when handle": { handlers: []Messenger{ &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - _, data, _ = capturingHandler.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) - return []sdk.Event{sdk.NewEvent("myEvent", sdk.NewAttribute("foo", "bar"))}, data, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + _, data, msgResponses, _ = capturingHandler.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) + return []sdk.Event{sdk.NewEvent("myEvent", sdk.NewAttribute("foo", "bar"))}, data, msgResponses, nil }, }, }, @@ -86,7 +87,7 @@ func TestMessageHandlerChainDispatch(t *testing.T) { // when h := MessageHandlerChain{spec.handlers} - gotEvents, gotData, gotErr := h.DispatchMsg(sdk.Context{}, RandomAccountAddress(t), "anyPort", myMsg) + gotEvents, gotData, gotMsgResponses, gotErr := h.DispatchMsg(sdk.Context{}, RandomAccountAddress(t), "anyPort", myMsg) // then require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) @@ -95,6 +96,7 @@ func TestMessageHandlerChainDispatch(t *testing.T) { } assert.Equal(t, []wasmvmtypes.CosmosMsg{myMsg}, *gotMsgs) assert.Equal(t, [][]byte{{1}}, gotData) // {1} is default in capturing handler + assert.Equal(t, [][]*codectypes.Any{}, gotMsgResponses) assert.Equal(t, spec.expEvents, gotEvents) }) } @@ -208,7 +210,7 @@ func TestSDKMessageHandlerDispatch(t *testing.T) { // when ctx := sdk.Context{} h := NewSDKMessageHandler(MakeTestCodec(t), spec.srcRoute, MessageEncoders{Custom: spec.srcEncoder}) - gotEvents, gotData, gotErr := h.DispatchMsg(ctx, myContractAddr, "myPort", myContractMessage) + gotEvents, gotData, gotMsgResponses, gotErr := h.DispatchMsg(ctx, myContractAddr, "myPort", myContractMessage) // then require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) @@ -217,9 +219,11 @@ func TestSDKMessageHandlerDispatch(t *testing.T) { return } assert.Len(t, gotMsg, spec.expMsgDispatched) + assert.Len(t, gotMsgResponses, spec.expMsgDispatched) for i := 0; i < spec.expMsgDispatched; i++ { assert.Equal(t, myEvent, gotEvents[i]) assert.Equal(t, []byte(myData), gotData[i]) + assert.Equal(t, []*codectypes.Any(nil), gotMsgResponses[i]) } }) } @@ -308,7 +312,7 @@ func TestIBCRawPacketHandler(t *testing.T) { capturedPacket = nil // when h := NewIBCRawPacketHandler(capturePacketsSenderMock, spec.chanKeeper, spec.capKeeper) - evts, data, gotErr := h.DispatchMsg(ctx, RandomAccountAddress(t), ibcPort, wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &spec.srcMsg}}) //nolint:gosec + evts, data, msgResponses, gotErr := h.DispatchMsg(ctx, RandomAccountAddress(t), ibcPort, wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &spec.srcMsg}}) //nolint:gosec // then require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) if spec.expErr != nil { @@ -317,6 +321,8 @@ func TestIBCRawPacketHandler(t *testing.T) { assert.Nil(t, evts) require.NotNil(t, data) + assert.Len(t, msgResponses, 1) + assert.Equal(t, "/cosmwasm.wasm.v1.MsgIBCSendResponse", msgResponses[0][0].TypeUrl) expMsg := types.MsgIBCSendResponse{Sequence: 1} @@ -350,7 +356,7 @@ func TestBurnCoinMessageHandlerIntegration(t *testing.T) { }{ "all good": { msg: wasmvmtypes.BurnMsg{ - Amount: wasmvmtypes.Coins{{ + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{{ Denom: "denom", Amount: "100", }}, @@ -358,7 +364,7 @@ func TestBurnCoinMessageHandlerIntegration(t *testing.T) { }, "not enough funds in contract": { msg: wasmvmtypes.BurnMsg{ - Amount: wasmvmtypes.Coins{{ + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{{ Denom: "denom", Amount: "101", }}, @@ -367,7 +373,7 @@ func TestBurnCoinMessageHandlerIntegration(t *testing.T) { }, "zero amount rejected": { msg: wasmvmtypes.BurnMsg{ - Amount: wasmvmtypes.Coins{{ + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{{ Denom: "denom", Amount: "0", }}, @@ -376,7 +382,7 @@ func TestBurnCoinMessageHandlerIntegration(t *testing.T) { }, "unknown denom - insufficient funds": { msg: wasmvmtypes.BurnMsg{ - Amount: wasmvmtypes.Coins{{ + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{{ Denom: "unknown", Amount: "1", }}, @@ -388,10 +394,12 @@ func TestBurnCoinMessageHandlerIntegration(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { ctx, _ = parentCtx.CacheContext() - k.wasmVM = &wasmtesting.MockWasmEngine{ExecuteFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - {Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{Burn: &spec.msg}}, ReplyOn: wasmvmtypes.ReplyNever}, //nolint:gosec + k.wasmVM = &wasmtesting.MockWasmEngine{ExecuteFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + {Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{Burn: &spec.msg}}, ReplyOn: wasmvmtypes.ReplyNever}, //nolint:gosec + }, }, }, 0, nil }} diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 3f63546a8c..cee0e83435 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -12,8 +12,8 @@ import ( "strings" "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" "cosmossdk.io/collections" corestoretypes "cosmossdk.io/core/store" @@ -168,8 +168,9 @@ func (k Keeper) create(ctx context.Context, creator sdk.AccAddress, wasmCode []b } } - sdkCtx.GasMeter().ConsumeGas(k.gasRegister.CompileCosts(len(wasmCode)), "Compiling wasm bytecode") - checksum, err = k.wasmVM.StoreCode(wasmCode) + gasLeft := k.runtimeGasForContract(sdkCtx) + checksum, gasUsed, err := k.wasmVM.StoreCode(wasmCode, gasLeft) + k.consumeRuntimeGas(sdkCtx, gasUsed) if err != nil { return 0, checksum, errorsmod.Wrap(types.ErrCreateFailed, err.Error()) } @@ -323,7 +324,14 @@ func (k Keeper) instantiate( res, gasUsed, err := k.wasmVM.Instantiate(codeInfo.CodeHash, env, info, initMsg, vmStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), gas, costJSONDeserialization) k.consumeRuntimeGas(sdkCtx, gasUsed) if err != nil { - return nil, nil, errorsmod.Wrap(types.ErrInstantiateFailed, err.Error()) + return nil, nil, errorsmod.Wrap(types.ErrVMError, err.Error()) + } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } + if res.Err != "" { + return nil, nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrInstantiateFailed, res.Err)) } // persist instance first @@ -333,7 +341,7 @@ func (k Keeper) instantiate( // check for IBC flag report, err := k.wasmVM.AnalyzeCode(codeInfo.CodeHash) if err != nil { - return nil, nil, errorsmod.Wrap(types.ErrInstantiateFailed, err.Error()) + return nil, nil, errorsmod.Wrap(types.ErrVMError, err.Error()) } if report.HasIBCEntryPoints { // register IBC port @@ -368,7 +376,7 @@ func (k Keeper) instantiate( )) sdkCtx = types.WithSubMsgAuthzPolicy(sdkCtx, authPolicy.SubMessageAuthorizationPolicy(types.AuthZActionInstantiate)) - data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Data, res.Ok.Events) if err != nil { return nil, nil, errorsmod.Wrap(err, "dispatch") } @@ -404,7 +412,14 @@ func (k Keeper) execute(ctx context.Context, contractAddress, caller sdk.AccAddr res, gasUsed, execErr := k.wasmVM.Execute(codeInfo.CodeHash, env, info, msg, prefixStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), gas, costJSONDeserialization) k.consumeRuntimeGas(sdkCtx, gasUsed) if execErr != nil { - return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) + } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } + if res.Err != "" { + return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } sdkCtx.EventManager().EmitEvent(sdk.NewEvent( @@ -412,7 +427,7 @@ func (k Keeper) execute(ctx context.Context, contractAddress, caller sdk.AccAddr sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), )) - data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Data, res.Ok.Events) if err != nil { return nil, errorsmod.Wrap(err, "dispatch") } @@ -454,7 +469,7 @@ func (k Keeper) migrate( // check for IBC flag switch report, err := k.wasmVM.AnalyzeCode(newCodeInfo.CodeHash); { case err != nil: - return nil, errorsmod.Wrap(types.ErrMigrationFailed, err.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, err.Error()) case !report.HasIBCEntryPoints && contractInfo.IBCPortID != "": // prevent update to non ibc contract return nil, errorsmod.Wrap(types.ErrMigrationFailed, "requires ibc callbacks") @@ -478,7 +493,14 @@ func (k Keeper) migrate( res, gasUsed, err := k.wasmVM.Migrate(newCodeInfo.CodeHash, env, msg, vmStore, cosmwasmAPI, &querier, k.gasMeter(sdkCtx), gas, costJSONDeserialization) k.consumeRuntimeGas(sdkCtx, gasUsed) if err != nil { - return nil, errorsmod.Wrap(types.ErrMigrationFailed, err.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, err.Error()) + } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } + if res.Err != "" { + return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrMigrationFailed, res.Err)) } // delete old secondary index entry err = k.removeFromContractCodeSecondaryIndex(ctx, contractAddress, k.mustGetLastContractHistoryEntry(sdkCtx, contractAddress)) @@ -504,7 +526,7 @@ func (k Keeper) migrate( )) sdkCtx = types.WithSubMsgAuthzPolicy(sdkCtx, authZ.SubMessageAuthorizationPolicy(types.AuthZActionMigrateContract)) - data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Data, res.Ok.Events) if err != nil { return nil, errorsmod.Wrap(err, "dispatch") } @@ -540,7 +562,14 @@ func (k Keeper) Sudo(ctx context.Context, contractAddress sdk.AccAddress, msg [] res, gasUsed, execErr := k.wasmVM.Sudo(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), gas, costJSONDeserialization) k.consumeRuntimeGas(sdkCtx, gasUsed) if execErr != nil { - return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) + } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } + if res.Err != "" { + return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } sdkCtx.EventManager().EmitEvent(sdk.NewEvent( @@ -549,7 +578,7 @@ func (k Keeper) Sudo(ctx context.Context, contractAddress sdk.AccAddress, msg [] )) // sudo submessages are executed with the default authorization policy - data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + data, err := k.handleContractResponse(sdkCtx, contractAddress, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Data, res.Ok.Events) if err != nil { return nil, errorsmod.Wrap(err, "dispatch") } @@ -577,7 +606,14 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply was res, gasUsed, execErr := k.wasmVM.Reply(codeInfo.CodeHash, env, reply, prefixStore, cosmwasmAPI, querier, k.gasMeter(ctx), gas, costJSONDeserialization) k.consumeRuntimeGas(ctx, gasUsed) if execErr != nil { - return nil, errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, execErr.Error()) + } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } + if res.Err != "" { + return nil, types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) } ctx.EventManager().EmitEvent(sdk.NewEvent( @@ -585,7 +621,7 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply was sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), )) - data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Data, res.Ok.Events) if err != nil { return nil, errorsmod.Wrap(err, "dispatch") } @@ -760,9 +796,12 @@ func (k Keeper) QuerySmart(ctx context.Context, contractAddr sdk.AccAddress, req queryResult, gasUsed, qErr := k.wasmVM.Query(codeInfo.CodeHash, env, req, prefixStore, cosmwasmAPI, querier, k.gasMeter(sdkCtx), k.runtimeGasForContract(sdkCtx), costJSONDeserialization) k.consumeRuntimeGas(sdkCtx, gasUsed) if qErr != nil { - return nil, errorsmod.Wrap(types.ErrQueryFailed, qErr.Error()) + return nil, errorsmod.Wrap(types.ErrVMError, qErr.Error()) + } + if queryResult.Err != "" { + return nil, errorsmod.Wrap(types.ErrQueryFailed, queryResult.Err) } - return queryResult, nil + return queryResult.Ok, nil } func checkAndIncreaseQueryStackSize(ctx context.Context, maxQueryStackSize uint32) (sdk.Context, error) { @@ -1078,7 +1117,7 @@ func (k *Keeper) handleContractResponse( msgs []wasmvmtypes.SubMsg, attrs []wasmvmtypes.EventAttribute, data []byte, - evts wasmvmtypes.Events, + evts wasmvmtypes.Array[wasmvmtypes.Event], ) ([]byte, error) { attributeGasCost := k.gasRegister.EventCosts(attrs, evts) ctx.GasMeter().ConsumeGas(attributeGasCost, "Custom contract event attributes") diff --git a/x/wasm/keeper/keeper_cgo.go b/x/wasm/keeper/keeper_cgo.go index cb5baaa359..020fef834d 100644 --- a/x/wasm/keeper/keeper_cgo.go +++ b/x/wasm/keeper/keeper_cgo.go @@ -5,7 +5,7 @@ package keeper import ( "path/filepath" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "cosmossdk.io/collections" corestoretypes "cosmossdk.io/core/store" @@ -33,7 +33,7 @@ func NewKeeper( _ GRPCQueryRouter, homeDir string, wasmConfig types.WasmConfig, - availableCapabilities string, + availableCapabilities []string, authority string, opts ...Option, ) Keeper { diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go index d81ee793c4..d6336521a7 100644 --- a/x/wasm/keeper/keeper_test.go +++ b/x/wasm/keeper/keeper_test.go @@ -11,8 +11,8 @@ import ( "testing" "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" abci "github.com/cometbft/cometbft/abci/types" "github.com/cometbft/cometbft/libs/rand" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" @@ -43,7 +43,9 @@ import ( //go:embed testdata/hackatom.wasm var hackatomWasm []byte -const AvailableCapabilities = "iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4" +var AvailableCapabilities = []string{ + "iterator", "staking", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", "cosmwasm_2_0", +} func TestNewKeeper(t *testing.T) { _, keepers := CreateTestInput(t, false, AvailableCapabilities) @@ -710,12 +712,100 @@ func TestInstantiateWithNonExistingCodeID(t *testing.T) { require.Nil(t, addr) } +func TestContractErrorRedacting(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len)) + keepers.Faucet.Fund(ctx, creator, deposit...) + example := StoreHackatomExampleContract(t, ctx, keepers) + + initMsg := HackatomExampleInitMsg{ + Verifier: []byte{1, 2, 3}, // invalid length + Beneficiary: RandomAccountAddress(t), + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + em := sdk.NewEventManager() + + _, _, err = keepers.ContractKeeper.Instantiate(ctx.WithEventManager(em), example.CodeID, creator, nil, initMsgBz, "demo contract 1", nil) + require.Error(t, err) + require.Contains(t, err.Error(), "addr_validate errored: invalid address") + + err = redactError(err) + // contract error should not be redacted + require.Contains(t, err.Error(), "addr_validate errored: invalid address") +} + +func TestContractErrorGetsForwarded(t *testing.T) { + // This test makes sure that a contract gets the error message from its submessage execution + // in a non-redacted form if that error comes from the contract in the submessage. + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + + reflect1 := InstantiateReflectExampleContract(t, ctx, keepers) + // reflect2 will be the contract that errors. It is owned by the other reflect contract. + // This is necessary because the reflect contract only accepts messages from its owner. + reflect2, _, err := keepers.ContractKeeper.Instantiate(ctx, reflect1.CodeID, reflect1.Contract, reflect1.Contract, []byte("{}"), "reflect2", sdk.NewCoins()) + require.NoError(t, err) + + const SubMsgID = 1 + // Make the reflect1 contract send a submessage to reflect2. That sub-message will error. + execMsg := testdata.ReflectHandleMsg{ + ReflectSubMsg: &testdata.ReflectSubPayload{ + Msgs: []wasmvmtypes.SubMsg{ + { + ID: SubMsgID, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Execute: &wasmvmtypes.ExecuteMsg{ + ContractAddr: reflect2.String(), + // This message will error in the reflect contract as an empty "msgs" array is not allowed + Msg: mustMarshal(t, testdata.ReflectHandleMsg{ + Reflect: &testdata.ReflectPayload{ + Msgs: []wasmvmtypes.CosmosMsg{}, + }, + }), + }, + }, + }, + ReplyOn: wasmvmtypes.ReplyError, // we want to see the error + }, + }, + }, + } + execMsgBz := mustMarshal(t, execMsg) + + em := sdk.NewEventManager() + _, err = keepers.ContractKeeper.Execute( + ctx.WithEventManager(em), + reflect1.Contract, + reflect1.CreatorAddr, + execMsgBz, + nil, + ) + require.NoError(t, err) + + // now query the submessage reply + queryMsgBz := mustMarshal(t, testdata.ReflectQueryMsg{ + SubMsgResult: &testdata.SubCall{ + ID: SubMsgID, + }, + }) + queryResponse, err := keepers.WasmKeeper.QuerySmart(ctx, reflect1.Contract, queryMsgBz) + require.NoError(t, err) + var submsgReply wasmvmtypes.Reply + mustUnmarshal(t, queryResponse, &submsgReply) + + assert.Equal(t, "Messages empty. Must reflect at least one message: execute wasm contract failed", submsgReply.Result.Err) +} + func TestInstantiateWithContractDataResponse(t *testing.T) { ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) wasmEngineMock := &wasmtesting.MockWasmEngine{ - InstantiateFn: func(codeID 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) { - return &wasmvmtypes.Response{Data: []byte("my-response-data")}, 0, nil + InstantiateFn: func(codeID 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) { + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: []byte("my-response-data")}}, 0, nil }, AnalyzeCodeFn: wasmtesting.WithoutIBCAnalyzeFn, StoreCodeFn: wasmtesting.NoOpStoreCodeFn, @@ -739,10 +829,10 @@ func TestInstantiateWithContractFactoryChildQueriesParent(t *testing.T) { keeper := keepers.WasmKeeper var instantiationCount int - callbacks := make([]func(codeID 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), 2) + callbacks := make([]func(codeID 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), 2) wasmEngineMock := &wasmtesting.MockWasmEngine{ // dispatch instantiation calls to callbacks - InstantiateFn: func(codeID 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) { + InstantiateFn: func(codeID 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) { require.Greater(t, len(callbacks), instantiationCount, "unexpected call to instantiation") do := callbacks[instantiationCount] instantiationCount++ @@ -762,24 +852,28 @@ func TestInstantiateWithContractFactoryChildQueriesParent(t *testing.T) { example := StoreRandomContract(t, ctx, keepers, wasmEngineMock) // factory contract - callbacks[0] = func(codeID 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) { + callbacks[0] = func(codeID 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) { t.Log("called factory") - return &wasmvmtypes.Response{Data: []byte("parent"), Messages: []wasmvmtypes.SubMsg{ - { - ID: 1, ReplyOn: wasmvmtypes.ReplyNever, - Msg: wasmvmtypes.CosmosMsg{ - Wasm: &wasmvmtypes.WasmMsg{ - Instantiate: &wasmvmtypes.InstantiateMsg{CodeID: example.CodeID, Msg: []byte(`{}`), Label: "child"}, + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Data: []byte("parent"), + Messages: []wasmvmtypes.SubMsg{ + { + ID: 1, ReplyOn: wasmvmtypes.ReplyNever, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Instantiate: &wasmvmtypes.InstantiateMsg{CodeID: example.CodeID, Msg: []byte(`{}`), Label: "child"}, + }, + }, }, - }, - }, - }}, 0, nil + }}, + }, 0, nil } // child contract var capturedSenderAddr string var capturedCodeInfo []byte - callbacks[1] = func(codeID 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) { + callbacks[1] = func(codeID 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) { t.Log("called child") capturedSenderAddr = info.Sender var err error @@ -789,7 +883,7 @@ func TestInstantiateWithContractFactoryChildQueriesParent(t *testing.T) { }, }, gasLimit) require.NoError(t, err) - return &wasmvmtypes.Response{Data: []byte("child")}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: []byte("child")}}, 0, nil } // when @@ -1017,9 +1111,9 @@ func TestExecuteWithPanic(t *testing.T) { // let's make sure we get a reasonable error, no panic/crash _, err = keepers.ContractKeeper.Execute(ctx, addr, fred, []byte(`{"panic":{}}`), topUp) require.Error(t, err) - require.True(t, errors.Is(err, types.ErrExecuteFailed)) + require.True(t, errors.Is(err, types.ErrVMError)) // test with contains as "Display" implementation of the Wasmer "RuntimeError" is different for Mac and Linux - assert.Contains(t, err.Error(), "Error calling the VM: Error executing Wasm: Wasmer runtime error: RuntimeError: Aborted: panicked at 'This page intentionally faulted', src/contract.rs:169:5: execute wasm contract failed") + assert.Contains(t, err.Error(), "Error calling the VM: Error executing Wasm: Wasmer runtime error: RuntimeError: Aborted: panicked at 'This page intentionally faulted', src/contract.rs:169:5: wasmvm error") } func TestExecuteWithCpuLoop(t *testing.T) { @@ -1245,7 +1339,7 @@ func TestMigrate(t *testing.T) { initMsg: initMsgBz, fromCodeID: originalCodeID, toCodeID: originalCodeID, - expErr: types.ErrMigrationFailed, + expErr: types.ErrVMError, }, "fail when no IBC callbacks": { admin: fred, @@ -1472,8 +1566,8 @@ func TestIterateContractsByCode(t *testing.T) { func TestIterateContractsByCodeWithMigration(t *testing.T) { // mock migration so that it does not fail when migrate example1 to example2.codeID - mockWasmVM := wasmtesting.MockWasmEngine{MigrateFn: func(codeID 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) { - return &wasmvmtypes.Response{}, 1, nil + mockWasmVM := wasmtesting.MockWasmEngine{MigrateFn: func(codeID 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) { + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 1, nil }} wasmtesting.MakeInstantiable(&mockWasmVM) ctx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithWasmEngine(&mockWasmVM)) @@ -1510,8 +1604,8 @@ type sudoMsg struct { } type stealFundsMsg struct { - Recipient string `json:"recipient"` - Amount wasmvmtypes.Coins `json:"amount"` + Recipient string `json:"recipient"` + Amount wasmvmtypes.Array[wasmvmtypes.Coin] `json:"amount"` } func TestSudo(t *testing.T) { @@ -1549,7 +1643,7 @@ func TestSudo(t *testing.T) { // to end users (via Tx/Execute). StealFunds: stealFundsMsg{ Recipient: community.String(), - Amount: wasmvmtypes.Coins{wasmvmtypes.NewCoin(76543, "denom")}, + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{wasmvmtypes.NewCoin(76543, "denom")}, }, } sudoMsg, err := json.Marshal(msg) @@ -1842,18 +1936,20 @@ func TestPinnedContractLoops(t *testing.T) { require.NoError(t, k.pinCode(ctx, example.CodeID)) var loops int anyMsg := []byte(`{}`) - mock.ExecuteFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + mock.ExecuteFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { loops++ - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - { - ID: 1, - ReplyOn: wasmvmtypes.ReplyNever, - Msg: wasmvmtypes.CosmosMsg{ - Wasm: &wasmvmtypes.WasmMsg{ - Execute: &wasmvmtypes.ExecuteMsg{ - ContractAddr: example.Contract.String(), - Msg: anyMsg, + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + { + ID: 1, + ReplyOn: wasmvmtypes.ReplyNever, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Execute: &wasmvmtypes.ExecuteMsg{ + ContractAddr: example.Contract.String(), + Msg: anyMsg, + }, }, }, }, @@ -2005,7 +2101,12 @@ func TestReply(t *testing.T) { } for name, spec := range specs { t.Run(name, func(t *testing.T) { - mock.ReplyFn = spec.replyFn + mock.ReplyFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + resp, gasUsed, err := spec.replyFn(codeID, env, reply, store, goapi, querier, gasMeter, gasLimit, deserCost) + return &wasmvmtypes.ContractResult{ + Ok: resp, + }, gasUsed, err + } em := sdk.NewEventManager() gotData, gotErr := k.reply(ctx.WithEventManager(em), example.Contract, wasmvmtypes.Reply{}) if spec.expErr { @@ -2037,12 +2138,12 @@ func TestQueryIsolation(t *testing.T) { }).apply(k) // when - mock.ReplyFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + mock.ReplyFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { _, err := querier.Query(wasmvmtypes.QueryRequest{ Custom: []byte(`{}`), }, 10000*types.DefaultGasMultiplier) require.NoError(t, err) - return &wasmvmtypes.Response{}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 0, nil } em := sdk.NewEventManager() _, gotErr := k.reply(ctx.WithEventManager(em), example.Contract, wasmvmtypes.Reply{}) @@ -2446,13 +2547,13 @@ func TestGasConsumed(t *testing.T) { originalMeter: storetypes.NewGasMeter(100), gasRegister: types.NewWasmGasRegister(types.DefaultGasRegisterConfig()), consumeGas: storetypes.Gas(1), - expMultipliedGasConsumed: 140000000, + expMultipliedGasConsumed: 140000, }, "consumeGas = limit": { originalMeter: storetypes.NewGasMeter(1), gasRegister: types.NewWasmGasRegister(types.DefaultGasRegisterConfig()), consumeGas: storetypes.Gas(1), - expMultipliedGasConsumed: 140000000, + expMultipliedGasConsumed: 140000, }, "consumeGas > limit": { originalMeter: storetypes.NewGasMeter(10), diff --git a/x/wasm/keeper/metrics.go b/x/wasm/keeper/metrics.go index 93f88581ca..37d7cd4300 100644 --- a/x/wasm/keeper/metrics.go +++ b/x/wasm/keeper/metrics.go @@ -1,7 +1,7 @@ package keeper import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/prometheus/client_golang/prometheus" ) diff --git a/x/wasm/keeper/msg_dispatcher.go b/x/wasm/keeper/msg_dispatcher.go index cbd66eed1f..e663b9d393 100644 --- a/x/wasm/keeper/msg_dispatcher.go +++ b/x/wasm/keeper/msg_dispatcher.go @@ -5,22 +5,30 @@ import ( "sort" "strings" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting" "github.com/CosmWasm/wasmd/x/wasm/types" ) +var ( + _ Messenger = &wasmtesting.MockMessageHandler{} + _ Messenger = MessageHandlerChain{} + _ Messenger = SDKMessageHandler{} +) + // Messenger is an extension point for custom wasmd message handling type Messenger interface { // DispatchMsg encodes the wasmVM message and dispatches it. - DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) + DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) } // replyer is a subset of keeper that can handle replies to submessages @@ -42,7 +50,7 @@ func NewMessageDispatcher(messenger Messenger, keeper replyer) *MessageDispatche // DispatchMessages sends all messages. func (d MessageDispatcher) DispatchMessages(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.CosmosMsg) error { for _, msg := range msgs { - events, _, err := d.messenger.DispatchMsg(ctx, contractAddr, ibcPort, msg) + events, _, _, err := d.messenger.DispatchMsg(ctx, contractAddr, ibcPort, msg) if err != nil { return err } @@ -53,7 +61,7 @@ func (d MessageDispatcher) DispatchMessages(ctx sdk.Context, contractAddr sdk.Ac } // dispatchMsgWithGasLimit sends a message with gas limit applied -func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msg wasmvmtypes.CosmosMsg, gasLimit uint64) (events []sdk.Event, data [][]byte, err error) { +func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msg wasmvmtypes.CosmosMsg, gasLimit uint64) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { limitedMeter := storetypes.NewGasMeter(gasLimit) subCtx := ctx.WithGasMeter(limitedMeter) @@ -70,13 +78,13 @@ func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr err = errorsmod.Wrap(sdkerrors.ErrOutOfGas, "SubMsg hit gas limit") } }() - events, data, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg) + events, data, msgResponses, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg) // make sure we charge the parent what was spent spent := subCtx.GasMeter().GasConsumed() ctx.GasMeter().ConsumeGas(spent, "From limited Sub-Message") - return events, data, err + return events, data, msgResponses, err } // DispatchSubmessages builds a sandbox to execute these messages and returns the execution result to the contract @@ -101,10 +109,11 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk var err error var events []sdk.Event var data [][]byte + var msgResponses [][]*codectypes.Any if limitGas { - events, data, err = d.dispatchMsgWithGasLimit(subCtx, contractAddr, ibcPort, msg.Msg, *msg.GasLimit) + events, data, msgResponses, err = d.dispatchMsgWithGasLimit(subCtx, contractAddr, ibcPort, msg.Msg, *msg.GasLimit) } else { - events, data, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg.Msg) + events, data, msgResponses, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg.Msg) } // if it succeeds, commit state changes from submessage, and pass on events to Event Manager @@ -142,10 +151,26 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk if len(data) > 0 { responseData = data[0] } + + // For msgResponses we flatten the nested list into a flat list. In the majority of cases + // we only expect one message to be emitted and one response per message. But it might be possible + // to create multiple SDK messages from one CosmWasm message or we have multiple responses for one message. + // See https://github.com/CosmWasm/cosmwasm/issues/2009 for more information. + var msgResponsesFlattened []wasmvmtypes.MsgResponse + for _, singleMsgResponses := range msgResponses { + for _, singleMsgResponse := range singleMsgResponses { + msgResponsesFlattened = append(msgResponsesFlattened, wasmvmtypes.MsgResponse{ + TypeURL: singleMsgResponse.TypeUrl, + Value: singleMsgResponse.Value, + }) + } + } + result = wasmvmtypes.SubMsgResult{ Ok: &wasmvmtypes.SubMsgResponse{ - Events: sdkEventsToWasmVMEvents(filteredEvents), - Data: responseData, + Events: sdkEventsToWasmVMEvents(filteredEvents), + Data: responseData, + MsgResponses: msgResponsesFlattened, }, } } else { @@ -158,8 +183,9 @@ func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk // now handle the reply, we use the parent context, and abort on error reply := wasmvmtypes.Reply{ - ID: msg.ID, - Result: result, + ID: msg.ID, + Result: result, + Payload: msg.Payload, } // we can ignore any result returned as there is nothing to do with the data @@ -183,6 +209,13 @@ func redactError(err error) error { return err } + // If it is a DeterministicError, we can safely return it without redaction. + // We only check the top level error to avoid changes in the error chain becoming + // consensus-breaking. + if _, ok := err.(types.DeterministicError); ok { + return err + } + // FIXME: do we want to hardcode some constant string mappings here as well? // Or better document them? (SDK error string may change on a patch release to fix wording) // sdk/11 is out of gas diff --git a/x/wasm/keeper/msg_dispatcher_test.go b/x/wasm/keeper/msg_dispatcher_test.go index 3cecfe6639..a17a73281d 100644 --- a/x/wasm/keeper/msg_dispatcher_test.go +++ b/x/wasm/keeper/msg_dispatcher_test.go @@ -3,9 +3,10 @@ package keeper import ( "errors" "fmt" + "reflect" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -13,6 +14,7 @@ import ( "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting" @@ -34,8 +36,8 @@ func TestDispatchSubmessages(t *testing.T) { msgs: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyError}}, replyer: noReplyCalled, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, [][]byte{[]byte("myData")}, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, [][]byte{[]byte("myData")}, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{true}, @@ -44,8 +46,8 @@ func TestDispatchSubmessages(t *testing.T) { msgs: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplySuccess}}, replyer: noReplyCalled, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("test, ignore") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("test, ignore") }, }, expCommits: []bool{false}, @@ -61,8 +63,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, [][]byte{[]byte("myData")}, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, [][]byte{[]byte("myData")}, [][]*codectypes.Any{}, nil }, }, expData: []byte("myReplyData"), @@ -78,8 +80,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("my error") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("my error") }, }, expData: []byte("myReplyData"), @@ -96,9 +98,9 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { myEvents := []sdk.Event{{Type: "myEvent", Attributes: []abci.EventAttribute{{Key: "foo", Value: "bar"}}}} - return myEvents, [][]byte{[]byte("myData")}, nil + return myEvents, [][]byte{[]byte("myData")}, [][]*codectypes.Any{}, nil }, }, expData: []byte("myReplyData"), @@ -117,10 +119,10 @@ func TestDispatchSubmessages(t *testing.T) { }}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { myEvents := []sdk.Event{{Type: "myEvent", Attributes: []abci.EventAttribute{{Key: "foo", Value: "bar"}}}} ctx.EventManager().EmitEvents(myEvents) - return nil, nil, nil + return nil, nil, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{true}, @@ -135,10 +137,10 @@ func TestDispatchSubmessages(t *testing.T) { }}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { myEvents := []sdk.Event{{Type: "myEvent", Attributes: []abci.EventAttribute{{Key: "foo", Value: "bar"}}}} ctx.EventManager().EmitEvents(myEvents) - return nil, nil, errors.New("testing") + return nil, nil, [][]*codectypes.Any{}, errors.New("testing") }, }, expCommits: []bool{false}, @@ -154,8 +156,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{false}, @@ -172,9 +174,9 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { ctx.GasMeter().ConsumeGas(storetypes.Gas(101), "testing") - return nil, [][]byte{[]byte("someData")}, nil + return nil, [][]byte{[]byte("someData")}, [][]*codectypes.Any{}, nil }, }, expData: []byte("myReplyData"), @@ -187,9 +189,9 @@ func TestDispatchSubmessages(t *testing.T) { }}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { ctx.GasMeter().ConsumeGas(storetypes.Gas(1), "testing") - return nil, [][]byte{[]byte("someData")}, nil + return nil, [][]byte{[]byte("someData")}, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{true}, @@ -198,8 +200,8 @@ func TestDispatchSubmessages(t *testing.T) { msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever}, {ID: 2, ReplyOn: wasmvmtypes.ReplyNever}}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, [][]byte{nil}, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, [][]byte{nil}, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{true, true}, @@ -208,8 +210,8 @@ func TestDispatchSubmessages(t *testing.T) { msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever}, {ID: 2, ReplyOn: wasmvmtypes.ReplyNever}}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, [][]byte{{}}, nil + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, [][]byte{{}}, [][]*codectypes.Any{}, nil }, }, expCommits: []bool{true, true}, @@ -218,8 +220,8 @@ func TestDispatchSubmessages(t *testing.T) { msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever}, {ID: 2, ReplyOn: wasmvmtypes.ReplyNever}}, replyer: &mockReplyer{}, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, [][]byte{{}}, errors.New("testing") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, [][]byte{{}}, [][]*codectypes.Any{}, errors.New("testing") }, }, expCommits: []bool{false, false}, @@ -233,8 +235,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("my error") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("my error") }, }, expData: []byte("myReplyData:2"), @@ -251,8 +253,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("my error") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("my error") }, }, expData: []byte("myReplyData:1"), @@ -269,8 +271,8 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("my error") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("my error") }, }, expData: []byte{}, @@ -286,12 +288,12 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { myEvents := []sdk.Event{ sdk.NewEvent("message"), sdk.NewEvent("execute", sdk.NewAttribute("foo", "bar")), } - return myEvents, [][]byte{[]byte("myData")}, nil + return myEvents, [][]byte{[]byte("myData")}, [][]*codectypes.Any{}, nil }, }, expData: nil, @@ -328,14 +330,14 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { events = []sdk.Event{ sdk.NewEvent("message", sdk.NewAttribute("_contract_address", contractAddr.String())), // we don't know what the contarctAddr will be so we can't use it in the final tests sdk.NewEvent("execute", sdk.NewAttribute("_contract_address", "placeholder-random-addr")), sdk.NewEvent("wasm", sdk.NewAttribute("random", "data")), } - return events, [][]byte{[]byte("subData")}, nil + return events, [][]byte{[]byte("subData")}, [][]*codectypes.Any{}, nil }, }, expData: []byte("subData"), @@ -346,9 +348,34 @@ func TestDispatchSubmessages(t *testing.T) { sdk.NewEvent("wasm-reply"), }, }, + "wasm reply gets payload": { + // put fake wasmmsg in here to show where it comes from + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyAlways, Payload: []byte("payloadData"), Msg: wasmvmtypes.CosmosMsg{Wasm: &wasmvmtypes.WasmMsg{}}}}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + if reply.Result.Err != "" { + return nil, errors.New(reply.Result.Err) + } + + // ensure we got the payload + if !reflect.DeepEqual(reply.Payload, []byte("payloadData")) { + return nil, fmt.Errorf("payload mismatch: %s != 'payloadData'", reply.Payload) + } + + // update data from what we got in + return reply.Result.Ok.Data, nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, nil + }, + }, + expCommits: []bool{true}, + }, "non-wasm reply events get filtered": { // show events from a stargate message gets filtered out - msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Stargate: &wasmvmtypes.StargateMsg{}}}}, + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Any: &wasmvmtypes.AnyMsg{}}}}, replyer: &mockReplyer{ replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { if reply.Result.Err != "" { @@ -370,14 +397,14 @@ func TestDispatchSubmessages(t *testing.T) { }, }, msgHandler: &wasmtesting.MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { events = []sdk.Event{ // this is filtered out sdk.NewEvent("message", sdk.NewAttribute("stargate", "something-something")), // we still emit this to the client, but not the contract sdk.NewEvent("non-determinstic"), } - return events, [][]byte{[]byte("subData")}, nil + return events, [][]byte{[]byte("subData")}, [][]*codectypes.Any{}, nil }, }, expData: []byte("subData"), diff --git a/x/wasm/keeper/msg_server_integration_test.go b/x/wasm/keeper/msg_server_integration_test.go index 5d737a93cc..fad2b112b6 100644 --- a/x/wasm/keeper/msg_server_integration_test.go +++ b/x/wasm/keeper/msg_server_integration_test.go @@ -6,8 +6,8 @@ import ( "testing" "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" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -20,7 +20,7 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) -//go:embed testdata/reflect.wasm +//go:embed testdata/reflect_1_5.wasm var wasmContract []byte //go:embed testdata/hackatom.wasm diff --git a/x/wasm/keeper/options_test.go b/x/wasm/keeper/options_test.go index ff3523a8c1..1ac311c14c 100644 --- a/x/wasm/keeper/options_test.go +++ b/x/wasm/keeper/options_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -143,10 +143,11 @@ func TestConstructorOptions(t *testing.T) { } for name, spec := range specs { t.Run(name, func(t *testing.T) { + tempDir := t.TempDir() opt := spec.srcOpt _, gotPostOptMarker := opt.(postOptsFn) require.Equal(t, spec.isPostOpt, gotPostOptMarker) - k := NewKeeper(codec, runtime.NewKVStoreService(storeKey), authkeeper.AccountKeeper{}, &bankkeeper.BaseKeeper{}, stakingkeeper.Keeper{}, nil, nil, nil, nil, nil, nil, nil, nil, "tempDir", types.DefaultWasmConfig(), AvailableCapabilities, "", spec.srcOpt) + k := NewKeeper(codec, runtime.NewKVStoreService(storeKey), authkeeper.AccountKeeper{}, &bankkeeper.BaseKeeper{}, stakingkeeper.Keeper{}, nil, nil, nil, nil, nil, nil, nil, nil, tempDir, types.DefaultWasmConfig(), AvailableCapabilities, "", spec.srcOpt) spec.verify(t, k) }) } diff --git a/x/wasm/keeper/proposal_integration_test.go b/x/wasm/keeper/proposal_integration_test.go index cb5256e462..c228424180 100644 --- a/x/wasm/keeper/proposal_integration_test.go +++ b/x/wasm/keeper/proposal_integration_test.go @@ -6,7 +6,7 @@ import ( "fmt" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -23,7 +23,10 @@ import ( ) func TestLoadStoredGovV1Beta1LegacyTypes(t *testing.T) { - pCtx, keepers := CreateTestInput(t, false, ReflectCapabilities+",iterator") + capabilities := make([]string, len(ReflectCapabilities)+1) + copy(capabilities, ReflectCapabilities) + capabilities = append(capabilities, "iterator") + pCtx, keepers := CreateTestInput(t, false, capabilities) k := keepers.WasmKeeper keepers.GovKeeper.SetLegacyRouter(v1beta1.NewRouter(). AddRoute(types.ModuleName, NewLegacyWasmProposalHandler(k, types.EnableAllProposals)), diff --git a/x/wasm/keeper/querier_test.go b/x/wasm/keeper/querier_test.go index 2036095f0d..afd4ad3cc5 100644 --- a/x/wasm/keeper/querier_test.go +++ b/x/wasm/keeper/querier_test.go @@ -9,8 +9,8 @@ import ( "testing" "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" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" @@ -198,9 +198,9 @@ func TestQuerySmartContractPanics(t *testing.T) { } for msg, spec := range specs { t.Run(msg, func(t *testing.T) { - keepers.WasmKeeper.wasmVM = &wasmtesting.MockWasmEngine{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) { + keepers.WasmKeeper.wasmVM = &wasmtesting.MockWasmEngine{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) { spec.doInContract() - return nil, 0, nil + return &wasmvmtypes.QueryResult{}, 0, nil }} // when q := Querier(keepers.WasmKeeper) diff --git a/x/wasm/keeper/query_plugin_integration_test.go b/x/wasm/keeper/query_plugin_integration_test.go index 644c4ed093..f9d126e20e 100644 --- a/x/wasm/keeper/query_plugin_integration_test.go +++ b/x/wasm/keeper/query_plugin_integration_test.go @@ -3,11 +3,12 @@ package keeper import ( "bytes" "encoding/json" + "errors" "fmt" "strings" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/gogoproto/proto" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "github.com/stretchr/testify/assert" @@ -116,6 +117,58 @@ func TestReflectStargateQuery(t *testing.T) { assert.Equal(t, simpleBalance.Amount[0].Denom, expectedBalance[0].Denom) } +func TestReflectGrpcQuery(t *testing.T) { + queryPlugins := (*reflectPlugins()).Merge(&QueryPlugins{ + Grpc: func(ctx sdk.Context, request *wasmvmtypes.GrpcQuery) (proto.Message, error) { + if request.Path == "cosmos.bank.v1beta1.Query/AllBalances" { + return &banktypes.QueryAllBalancesResponse{ + Balances: sdk.NewCoins(), + }, nil + } + return nil, errors.New("unsupported request") + }, + }) + cdc := MakeEncodingConfig(t).Codec + ctx, keepers := CreateTestInput(t, false, ReflectCapabilities, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(&queryPlugins)) + keeper := keepers.WasmKeeper + + creator := RandomAccountAddress(t) + + // upload code + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), codeID) + + // creator instantiates a contract + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, []byte("{}"), "reflect contract 1", sdk.NewCoins()) + require.NoError(t, err) + require.NotEmpty(t, contractAddr) + + // now grpc query for the bank balance + cosmosBankQuery := banktypes.NewQueryAllBalancesRequest(creator, nil, false) + cosmosBankQueryBz, err := proto.Marshal(cosmosBankQuery) + require.NoError(t, err) + reflectQuery := wasmvmtypes.QueryRequest{ + Grpc: &wasmvmtypes.GrpcQuery{ + Path: "cosmos.bank.v1beta1.Query/AllBalances", + Data: cosmosBankQueryBz, + }, + } + reflectQueryBz, err := json.Marshal(testdata.ReflectQueryMsg{ + Chain: &testdata.ChainQuery{Request: &reflectQuery}, + }) + require.NoError(t, err) + // query the reflect contract + reflectRespBz, err := keeper.QuerySmart(ctx, contractAddr, reflectQueryBz) + require.NoError(t, err) + var reflectResp testdata.ChainResponse + mustUnmarshal(t, reflectRespBz, &reflectResp) + // now unmarshal the protobuf response + var grpcBalance banktypes.QueryAllBalancesResponse + err = proto.Unmarshal(reflectResp.Data, &grpcBalance) + require.NoError(t, err) +} + func TestReflectTotalSupplyQuery(t *testing.T) { cdc := MakeEncodingConfig(t).Codec ctx, keepers := CreateTestInput(t, false, ReflectCapabilities, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(reflectPlugins())) @@ -794,7 +847,7 @@ func TestIBCListChannelsQuery(t *testing.T) { query: &wasmvmtypes.IBCQuery{ListChannels: &wasmvmtypes.ListChannelsQuery{}}, assert: func(t *testing.T, d []byte) { rsp := unmarshalReflect[wasmvmtypes.ListChannelsResponse](t, d) - assert.Nil(t, rsp.Channels) + assert.Empty(t, rsp.Channels) }, }, "no matching channels": { diff --git a/x/wasm/keeper/query_plugins.go b/x/wasm/keeper/query_plugins.go index 6e2cfa09b8..2bb2246968 100644 --- a/x/wasm/keeper/query_plugins.go +++ b/x/wasm/keeper/query_plugins.go @@ -6,7 +6,7 @@ import ( "errors" "fmt" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" abci "github.com/cometbft/cometbft/abci/types" "github.com/cosmos/gogoproto/proto" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -90,6 +90,7 @@ type QueryPlugins struct { IBC func(ctx sdk.Context, caller sdk.AccAddress, request *wasmvmtypes.IBCQuery) ([]byte, error) Staking func(ctx sdk.Context, request *wasmvmtypes.StakingQuery) ([]byte, error) Stargate func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) + Grpc func(ctx sdk.Context, request *wasmvmtypes.GrpcQuery) (proto.Message, error) Wasm func(ctx sdk.Context, request *wasmvmtypes.WasmQuery) ([]byte, error) Distribution func(ctx sdk.Context, request *wasmvmtypes.DistributionQuery) ([]byte, error) } @@ -113,12 +114,15 @@ func DefaultQueryPlugins( channelKeeper types.ChannelKeeper, wasm wasmQueryKeeper, ) QueryPlugins { + // By default, we reject all stargate and gRPC queries. + // The chain needs to provide a querier plugin that only allows deterministic queries. return QueryPlugins{ Bank: BankQuerier(bank), Custom: NoCustomQuerier, IBC: IBCQuerier(wasm, channelKeeper), Staking: StakingQuerier(staking, distKeeper), Stargate: RejectStargateQuerier(), + Grpc: RejectGrpcQuerier, Wasm: WasmQuerier(wasm), Distribution: DistributionQuerier(distKeeper), } @@ -144,6 +148,9 @@ func (e QueryPlugins) Merge(o *QueryPlugins) QueryPlugins { if o.Stargate != nil { e.Stargate = o.Stargate } + if o.Grpc != nil { + e.Grpc = o.Grpc + } if o.Wasm != nil { e.Wasm = o.Wasm } @@ -167,6 +174,14 @@ func (e QueryPlugins) HandleQuery(ctx sdk.Context, caller sdk.AccAddress, req wa return e.Staking(ctx, req.Staking) case req.Stargate != nil: return e.Stargate(ctx, req.Stargate) + case req.Grpc != nil: + resp, err := e.Grpc(ctx, req.Grpc) + if err != nil { + return nil, err + } + // Marshaling the response here instead of inside the query + // plugin makes sure that the response is always protobuf encoded. + return proto.Marshal(resp) case req.Wasm != nil: return e.Wasm(ctx, req.Wasm) case req.Distribution != nil: @@ -255,10 +270,10 @@ func IBCQuerier(wasm contractMetaDataSource, channelKeeper types.ChannelKeeper) if portID == "" { // then fallback to contract port address portID = wasm.GetContractInfo(ctx, caller).IBCPortID } - var channels wasmvmtypes.IBCChannels + var channels wasmvmtypes.Array[wasmvmtypes.IBCChannel] if portID != "" { // then return empty list for non ibc contracts; no channels possible gotChannels := channelKeeper.GetAllChannelsWithPortPrefix(ctx, portID) - channels = make(wasmvmtypes.IBCChannels, 0, len(gotChannels)) + channels = make(wasmvmtypes.Array[wasmvmtypes.IBCChannel], 0, len(gotChannels)) for _, ch := range gotChannels { if ch.State != channeltypes.OPEN { continue @@ -317,6 +332,48 @@ func IBCQuerier(wasm contractMetaDataSource, channelKeeper types.ChannelKeeper) } } +func RejectGrpcQuerier(ctx sdk.Context, request *wasmvmtypes.GrpcQuery) (proto.Message, error) { + return nil, wasmvmtypes.UnsupportedRequest{Kind: "gRPC queries are disabled"} +} + +// AcceptListGrpcQuerier supports a preconfigured set of gRPC queries only. +// All arguments must be non nil. +// +// Warning: Chains need to test and maintain their accept list carefully. +// There were critical consensus breaking issues in the past with non-deterministic behavior in the SDK. +// +// These queries can be set via WithQueryPlugins option in the wasm keeper constructor: +// WithQueryPlugins(&QueryPlugins{Grpc: AcceptListGrpcQuerier(acceptList, queryRouter, codec)}) +func AcceptListGrpcQuerier(acceptList AcceptedQueries, queryRouter GRPCQueryRouter, codec codec.Codec) func(ctx sdk.Context, request *wasmvmtypes.GrpcQuery) (proto.Message, error) { + return func(ctx sdk.Context, request *wasmvmtypes.GrpcQuery) (proto.Message, error) { + protoResponse, accepted := acceptList[request.Path] + if !accepted { + return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("'%s' path is not allowed from the contract", request.Path)} + } + + handler := queryRouter.Route(request.Path) + if handler == nil { + return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("No route to query '%s'", request.Path)} + } + + res, err := handler(ctx, &abci.RequestQuery{ + Data: request.Data, + Path: request.Path, + }) + if err != nil { + return nil, err + } + + // decode the query response into the expected protobuf message + err = codec.Unmarshal(res.Value, protoResponse) + if err != nil { + return nil, err + } + + return protoResponse, nil + } +} + // RejectStargateQuerier rejects all stargate queries func RejectStargateQuerier() func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { @@ -324,10 +381,10 @@ func RejectStargateQuerier() func(ctx sdk.Context, request *wasmvmtypes.Stargate } } -// AcceptedStargateQueries define accepted Stargate queries as a map with path as key and response type as value. +// AcceptedQueries define accepted Stargate or gRPC queries as a map with path as key and response type as value. // For example: // acceptList["/cosmos.auth.v1beta1.Query/Account"]= &authtypes.QueryAccountResponse{} -type AcceptedStargateQueries map[string]proto.Message +type AcceptedQueries map[string]proto.Message // AcceptListStargateQuerier supports a preconfigured set of stargate queries only. // All arguments must be non nil. @@ -335,9 +392,9 @@ type AcceptedStargateQueries map[string]proto.Message // Warning: Chains need to test and maintain their accept list carefully. // There were critical consensus breaking issues in the past with non-deterministic behavior in the SDK. // -// This queries can be set via WithQueryPlugins option in the wasm keeper constructor: +// These queries can be set via WithQueryPlugins option in the wasm keeper constructor: // WithQueryPlugins(&QueryPlugins{Stargate: AcceptListStargateQuerier(acceptList, queryRouter, codec)}) -func AcceptListStargateQuerier(acceptList AcceptedStargateQueries, queryRouter GRPCQueryRouter, codec codec.Codec) func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { +func AcceptListStargateQuerier(acceptList AcceptedQueries, queryRouter GRPCQueryRouter, codec codec.Codec) func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { protoResponse, accepted := acceptList[request.Path] if !accepted { @@ -461,7 +518,7 @@ func StakingQuerier(keeper types.StakingKeeper, distKeeper types.DistributionKee } } -func sdkToDelegations(ctx sdk.Context, keeper types.StakingKeeper, delegations []stakingtypes.Delegation) (wasmvmtypes.Delegations, error) { +func sdkToDelegations(ctx sdk.Context, keeper types.StakingKeeper, delegations []stakingtypes.Delegation) (wasmvmtypes.Array[wasmvmtypes.Delegation], error) { result := make([]wasmvmtypes.Delegation, len(delegations)) bondDenom, err := keeper.BondDenom(ctx) if err != nil { @@ -706,8 +763,8 @@ func ConvertSDKDecCoinsToWasmDecCoins(src sdk.DecCoins) []wasmvmtypes.DecCoin { } // ConvertSdkCoinsToWasmCoins covert sdk type to wasmvm coins type -func ConvertSdkCoinsToWasmCoins(coins []sdk.Coin) wasmvmtypes.Coins { - converted := make(wasmvmtypes.Coins, len(coins)) +func ConvertSdkCoinsToWasmCoins(coins []sdk.Coin) wasmvmtypes.Array[wasmvmtypes.Coin] { + converted := make(wasmvmtypes.Array[wasmvmtypes.Coin], len(coins)) for i, c := range coins { converted[i] = ConvertSdkCoinToWasmCoin(c) } diff --git a/x/wasm/keeper/query_plugins_test.go b/x/wasm/keeper/query_plugins_test.go index 57b0ddaef8..1fea83a25f 100644 --- a/x/wasm/keeper/query_plugins_test.go +++ b/x/wasm/keeper/query_plugins_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/proto" @@ -576,7 +576,7 @@ func TestAcceptListStargateQuerier(t *testing.T) { require.NoError(t, err) addrs := app.AddTestAddrsIncremental(wasmApp, ctx, 2, sdkmath.NewInt(1_000_000)) - accepted := keeper.AcceptedStargateQueries{ + accepted := keeper.AcceptedQueries{ "/cosmos.auth.v1beta1.Query/Account": &authtypes.QueryAccountResponse{}, "/no/route/to/this": &authtypes.QueryAccountResponse{}, } diff --git a/x/wasm/keeper/recurse_test.go b/x/wasm/keeper/recurse_test.go index ebd7ef85f9..a0a2bae54a 100644 --- a/x/wasm/keeper/recurse_test.go +++ b/x/wasm/keeper/recurse_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/reflect_test.go b/x/wasm/keeper/reflect_test.go index 95d9dff4a6..d6a14ae361 100644 --- a/x/wasm/keeper/reflect_test.go +++ b/x/wasm/keeper/reflect_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -23,9 +23,9 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) -const ( - CyberpunkCapabilities = "staking,mask,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4" - ReflectCapabilities = CyberpunkCapabilities +var ( + CyberpunkCapabilities = []string{"staking", "mask", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4"} + ReflectCapabilities = []string{"staking", "mask", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", "cosmwasm_2_0"} ) func mustUnmarshal(t *testing.T, data []byte, res interface{}) { @@ -222,7 +222,7 @@ func TestRustPanicIsHandled(t *testing.T) { // when panic is triggered msg := []byte(`{"panic":{}}`) gotData, err := keeper.Execute(ctx, contractAddr, creator, msg, nil) - require.ErrorIs(t, err, types.ErrExecuteFailed) + require.ErrorIs(t, err, types.ErrVMError) assert.Contains(t, err.Error(), "panicked at 'This page intentionally faulted'") assert.Nil(t, gotData) } diff --git a/x/wasm/keeper/relay.go b/x/wasm/keeper/relay.go index c542f6c04e..2ccec39eca 100644 --- a/x/wasm/keeper/relay.go +++ b/x/wasm/keeper/relay.go @@ -3,7 +3,7 @@ package keeper import ( "time" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" @@ -42,8 +42,8 @@ func (k Keeper) OnOpenChannel( if execErr != nil { return "", errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } - if res != nil { - return res.Version, nil + if res != nil && res.Ok != nil { + return res.Ok.Version, nil } return "", nil } @@ -75,8 +75,15 @@ func (k Keeper) OnConnectChannel( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } + if res.Err != "" { + return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) + } - return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) } // OnCloseChannel calls the contract to let it know the IBC channel is closed. @@ -106,8 +113,15 @@ func (k Keeper) OnCloseChannel( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } + if res.Err != "" { + return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) + } - return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) } // OnRecvPacket calls the contract to process the incoming IBC packet. The contract fully owns the data processing and @@ -139,6 +153,10 @@ func (k Keeper) OnRecvPacket( // all state downstream and not persist any data in ibc-go. // This can be triggered by throwing a panic in the contract } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return nil, errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } if res.Err != "" { // return error ACK with non-redacted contract message, state will be reverted return channeltypes.Acknowledgement{ @@ -194,7 +212,15 @@ func (k Keeper) OnAckPacket( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } - return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) + if res == nil { + // If this gets executed, that's a bug in wasmvm + return errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } + if res.Err != "" { + return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) + } + + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) } // OnTimeoutPacket calls the contract to let it know the packet was never received on the destination chain within @@ -221,8 +247,15 @@ func (k Keeper) OnTimeoutPacket( if execErr != nil { return errorsmod.Wrap(types.ErrExecuteFailed, execErr.Error()) } + if res == nil { + // If this gets executed, that's a bug in wasmvm + return errorsmod.Wrap(types.ErrVMError, "internal wasmvm error") + } + if res.Err != "" { + return types.MarkErrorDeterministic(errorsmod.Wrap(types.ErrExecuteFailed, res.Err)) + } - return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok) } func (k Keeper) handleIBCBasicContractResponse(ctx sdk.Context, addr sdk.AccAddress, id string, res *wasmvmtypes.IBCBasicResponse) error { diff --git a/x/wasm/keeper/relay_test.go b/x/wasm/keeper/relay_test.go index 4008fd7bfa..8fbd83be3a 100644 --- a/x/wasm/keeper/relay_test.go +++ b/x/wasm/keeper/relay_test.go @@ -6,8 +6,8 @@ import ( "math" "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" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -59,9 +59,9 @@ func TestOnOpenChannel(t *testing.T) { t.Run(name, func(t *testing.T) { myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"} myMsg := wasmvmtypes.IBCChannelOpenMsg{OpenTry: &wasmvmtypes.IBCOpenTry{Channel: myChannel, CounterpartyVersion: "foo"}} - m.IBCChannelOpenFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { + m.IBCChannelOpenFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { assert.Equal(t, myMsg, msg) - return &wasmvmtypes.IBC3ChannelOpenResponse{}, spec.contractGas * types.DefaultGasMultiplier, spec.contractErr + return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, spec.contractGas * types.DefaultGasMultiplier, spec.contractErr } ctx, _ := parentCtx.CacheContext() @@ -156,9 +156,9 @@ func TestOnConnectChannel(t *testing.T) { t.Run(name, func(t *testing.T) { myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"} myMsg := wasmvmtypes.IBCChannelConnectMsg{OpenConfirm: &wasmvmtypes.IBCOpenConfirm{Channel: myChannel}} - m.IBCChannelConnectFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + m.IBCChannelConnectFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { assert.Equal(t, msg, myMsg) - return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr + return &wasmvmtypes.IBCBasicResult{Ok: spec.contractResp}, myContractGas * types.DefaultGasMultiplier, spec.contractErr } ctx, _ := parentCtx.CacheContext() @@ -268,9 +268,9 @@ func TestOnCloseChannel(t *testing.T) { t.Run(name, func(t *testing.T) { myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"} myMsg := wasmvmtypes.IBCChannelCloseMsg{CloseInit: &wasmvmtypes.IBCCloseInit{Channel: myChannel}} - m.IBCChannelCloseFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + m.IBCChannelCloseFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { assert.Equal(t, msg, myMsg) - return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr + return &wasmvmtypes.IBCBasicResult{Ok: spec.contractResp}, myContractGas * types.DefaultGasMultiplier, spec.contractErr } ctx, _ := parentCtx.CacheContext() @@ -325,7 +325,7 @@ func TestOnRecvPacket(t *testing.T) { contractResp *wasmvmtypes.IBCReceiveResult contractErr error overwriteMessenger *wasmtesting.MockMessageHandler - mockReplyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + mockReplyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) expContractGas storetypes.Gas expAck []byte expErr bool @@ -426,8 +426,8 @@ func TestOnRecvPacket(t *testing.T) { Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}}, }, }, - mockReplyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{Data: []byte("myBetterAck")}, 0, nil + mockReplyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Data: []byte("myBetterAck")}}, 0, nil }, expAck: []byte("myBetterAck"), expEventTypes: []string{types.EventTypeReply}, @@ -567,9 +567,9 @@ func TestOnAckPacket(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { myAck := wasmvmtypes.IBCPacketAckMsg{Acknowledgement: wasmvmtypes.IBCAcknowledgement{Data: []byte("myAck")}} - m.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + m.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { assert.Equal(t, myAck, msg) - return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr + return &wasmvmtypes.IBCBasicResult{Ok: spec.contractResp}, myContractGas * types.DefaultGasMultiplier, spec.contractErr } ctx, _ := parentCtx.CacheContext() @@ -687,9 +687,9 @@ func TestOnTimeoutPacket(t *testing.T) { for name, spec := range specs { t.Run(name, func(t *testing.T) { myPacket := wasmvmtypes.IBCPacket{Data: []byte("my test packet")} - m.IBCPacketTimeoutFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + m.IBCPacketTimeoutFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { assert.Equal(t, myPacket, msg.Packet) - return spec.contractResp, myContractGas * types.DefaultGasMultiplier, spec.contractErr + return &wasmvmtypes.IBCBasicResult{Ok: spec.contractResp}, myContractGas * types.DefaultGasMultiplier, spec.contractErr } ctx, _ := parentCtx.CacheContext() diff --git a/x/wasm/keeper/snapshotter_integration_test.go b/x/wasm/keeper/snapshotter_integration_test.go index 2262198597..ed9af49f99 100644 --- a/x/wasm/keeper/snapshotter_integration_test.go +++ b/x/wasm/keeper/snapshotter_integration_test.go @@ -5,8 +5,8 @@ import ( "testing" "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" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" tmtypes "github.com/cometbft/cometbft/types" "github.com/stretchr/testify/assert" @@ -30,13 +30,13 @@ func TestSnapshotter(t *testing.T) { wasmFiles []string }{ "single contract": { - wasmFiles: []string{"./testdata/reflect.wasm"}, + wasmFiles: []string{"./testdata/reflect_1_5.wasm"}, }, "multiple contract": { - wasmFiles: []string{"./testdata/reflect.wasm", "./testdata/burner.wasm", "./testdata/reflect.wasm"}, + wasmFiles: []string{"./testdata/reflect_1_5.wasm", "./testdata/burner.wasm", "./testdata/reflect_1_5.wasm"}, }, "duplicate contracts": { - wasmFiles: []string{"./testdata/reflect.wasm", "./testdata/reflect.wasm"}, + wasmFiles: []string{"./testdata/reflect_1_5.wasm", "./testdata/reflect_1_5.wasm"}, }, } for name, spec := range specs { diff --git a/x/wasm/keeper/staking_test.go b/x/wasm/keeper/staking_test.go index 6e1023d98f..292094a52e 100644 --- a/x/wasm/keeper/staking_test.go +++ b/x/wasm/keeper/staking_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/submsg_test.go b/x/wasm/keeper/submsg_test.go index abb9088ead..971f0d9648 100644 --- a/x/wasm/keeper/submsg_test.go +++ b/x/wasm/keeper/submsg_test.go @@ -7,8 +7,8 @@ import ( "strconv" "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" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -243,7 +243,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { "send tokens": { submsgID: 5, msg: validBankSend, - resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(107_000, 108_000)}, + resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(110_000, 111_000)}, }, "not enough tokens": { submsgID: 6, @@ -263,7 +263,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { msg: validBankSend, gasLimit: &subGasLimit, // uses same gas as call without limit (note we do not charge the 40k on reply) - resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(107_000, 108_000)}, + resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(110_000, 112_000)}, }, "not enough tokens with limit": { submsgID: 16, @@ -271,7 +271,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { subMsgError: true, gasLimit: &subGasLimit, // uses same gas as call without limit (note we do not charge the 40k on reply) - resultAssertions: []assertion{assertGasUsed(79_700, 79_800), assertErrorString("codespace: sdk, code: 5")}, + resultAssertions: []assertion{assertGasUsed(78_000, 81_000), assertErrorString("codespace: sdk, code: 5")}, }, "out of gas caught with gas limit": { submsgID: 17, @@ -279,7 +279,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) { subMsgError: true, gasLimit: &subGasLimit, // uses all the subGasLimit, plus the 52k or so for the main contract - resultAssertions: []assertion{assertGasUsed(subGasLimit+75_000, subGasLimit+76_000), assertErrorString("codespace: sdk, code: 11")}, + resultAssertions: []assertion{assertGasUsed(subGasLimit+75_000, subGasLimit+77_000), assertErrorString("codespace: sdk, code: 11")}, }, "instantiate contract gets address in data and events": { submsgID: 21, @@ -563,20 +563,22 @@ func TestInstantiateGovSubMsgAuthzPropagated(t *testing.T) { wasmtesting.MakeInstantiable(mockWasmVM) var instanceLevel int // mock wasvm to return new instantiate msgs with the response - mockWasmVM.InstantiateFn = func(codeID 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) { + mockWasmVM.InstantiateFn = func(codeID 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 instanceLevel == 2 { - return &wasmvmtypes.Response{}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 0, nil } instanceLevel++ submsgPayload := fmt.Sprintf(`{"sub":%d}`, instanceLevel) - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - { - ReplyOn: wasmvmtypes.ReplyNever, - Msg: wasmvmtypes.CosmosMsg{ - Wasm: &wasmvmtypes.WasmMsg{Instantiate: &wasmvmtypes.InstantiateMsg{ - CodeID: 1, Msg: []byte(submsgPayload), Label: "from sub-msg", - }}, + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + { + ReplyOn: wasmvmtypes.ReplyNever, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{Instantiate: &wasmvmtypes.InstantiateMsg{ + CodeID: 1, Msg: []byte(submsgPayload), Label: "from sub-msg", + }}, + }, }, }, }, @@ -650,22 +652,24 @@ func TestMigrateGovSubMsgAuthzPropagated(t *testing.T) { var instanceLevel int // mock wasvm to return new migrate msgs with the response - mockWasmVM.MigrateFn = func(codeID 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) { + mockWasmVM.MigrateFn = func(codeID 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 instanceLevel == 1 { - return &wasmvmtypes.Response{}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 0, nil } instanceLevel++ submsgPayload := fmt.Sprintf(`{"sub":%d}`, instanceLevel) - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - { - ReplyOn: wasmvmtypes.ReplyNever, - Msg: wasmvmtypes.CosmosMsg{ - Wasm: &wasmvmtypes.WasmMsg{Migrate: &wasmvmtypes.MigrateMsg{ - ContractAddr: example1.Contract.String(), - NewCodeID: example2.CodeID, - Msg: []byte(submsgPayload), - }}, + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + { + ReplyOn: wasmvmtypes.ReplyNever, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{Migrate: &wasmvmtypes.MigrateMsg{ + ContractAddr: example1.Contract.String(), + NewCodeID: example2.CodeID, + Msg: []byte(submsgPayload), + }}, + }, }, }, }, diff --git a/x/wasm/keeper/test_common.go b/x/wasm/keeper/test_common.go index a6809702ac..dbf52df037 100644 --- a/x/wasm/keeper/test_common.go +++ b/x/wasm/keeper/test_common.go @@ -197,11 +197,11 @@ type TestKeepers struct { // CreateDefaultTestInput common settings for CreateTestInput func CreateDefaultTestInput(t testing.TB) (sdk.Context, TestKeepers) { - return CreateTestInput(t, false, "staking") + return CreateTestInput(t, false, []string{"staking"}) } // CreateTestInput encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default) -func CreateTestInput(t testing.TB, isCheckTx bool, availableCapabilities string, opts ...Option) (sdk.Context, TestKeepers) { +func CreateTestInput(t testing.TB, isCheckTx bool, availableCapabilities []string, opts ...Option) (sdk.Context, TestKeepers) { // Load default wasm config return createTestInput(t, isCheckTx, availableCapabilities, types.DefaultWasmConfig(), dbm.NewMemDB(), opts...) } @@ -210,7 +210,7 @@ func CreateTestInput(t testing.TB, isCheckTx bool, availableCapabilities string, func createTestInput( t testing.TB, isCheckTx bool, - availableCapabilities string, + availableCapabilities []string, wasmConfig types.WasmConfig, db dbm.DB, opts ...Option, @@ -679,7 +679,7 @@ type ExampleInstance struct { Deposit sdk.Coins } -// InstantiateReflectExampleContract load and instantiate the "./testdata/reflect.wasm" contract +// InstantiateReflectExampleContract load and instantiate the "./testdata/reflect_2_0.wasm" contract func InstantiateReflectExampleContract(t testing.TB, ctx sdk.Context, keepers TestKeepers) ExampleInstance { example := StoreReflectContract(t, ctx, keepers) initialAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 100)) diff --git a/x/wasm/keeper/testdata/contracts.go b/x/wasm/keeper/testdata/contracts.go index 299fc9a324..eb63bdeef6 100644 --- a/x/wasm/keeper/testdata/contracts.go +++ b/x/wasm/keeper/testdata/contracts.go @@ -3,7 +3,7 @@ package testdata import ( _ "embed" - typwasmvmtypes "github.com/CosmWasm/wasmvm/types" + typwasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/cosmos-sdk/types" ) @@ -13,7 +13,7 @@ const ( ) var ( - //go:embed reflect.wasm + //go:embed reflect_2_0.wasm reflectContract []byte //go:embed reflect_1_1.wasm migrateReflectContract []byte diff --git a/x/wasm/keeper/testdata/reflect.wasm b/x/wasm/keeper/testdata/reflect.wasm deleted file mode 100644 index 28a64acbf8..0000000000 Binary files a/x/wasm/keeper/testdata/reflect.wasm and /dev/null differ diff --git a/x/wasm/keeper/testdata/reflect_1_5.wasm b/x/wasm/keeper/testdata/reflect_1_5.wasm new file mode 100644 index 0000000000..073a4f4064 Binary files /dev/null and b/x/wasm/keeper/testdata/reflect_1_5.wasm differ diff --git a/x/wasm/keeper/testdata/reflect_2_0.wasm b/x/wasm/keeper/testdata/reflect_2_0.wasm new file mode 100644 index 0000000000..9791208ace Binary files /dev/null and b/x/wasm/keeper/testdata/reflect_2_0.wasm differ diff --git a/x/wasm/keeper/wasmtesting/gas_register.go b/x/wasm/keeper/wasmtesting/gas_register.go index fd7abe5491..a16de3b32d 100644 --- a/x/wasm/keeper/wasmtesting/gas_register.go +++ b/x/wasm/keeper/wasmtesting/gas_register.go @@ -1,14 +1,13 @@ package wasmtesting import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" storetypes "cosmossdk.io/store/types" ) // MockGasRegister mock that implements keeper.GasRegister type MockGasRegister struct { - CompileCostFn func(byteLength int) storetypes.Gas SetupContractCostFn func(discount bool, msgLen int) storetypes.Gas ReplyCostFn func(discount bool, reply wasmvmtypes.Reply) storetypes.Gas EventCostsFn func(evts []wasmvmtypes.EventAttribute) storetypes.Gas @@ -17,13 +16,6 @@ type MockGasRegister struct { UncompressCostsFn func(byteLength int) storetypes.Gas } -func (m MockGasRegister) CompileCosts(byteLength int) storetypes.Gas { - if m.CompileCostFn == nil { - panic("not expected to be called") - } - return m.CompileCostFn(byteLength) -} - func (m MockGasRegister) UncompressCosts(byteLength int) storetypes.Gas { if m.UncompressCostsFn == nil { panic("not expected to be called") @@ -45,7 +37,7 @@ func (m MockGasRegister) ReplyCosts(discount bool, reply wasmvmtypes.Reply) stor return m.ReplyCostFn(discount, reply) } -func (m MockGasRegister) EventCosts(evts []wasmvmtypes.EventAttribute, _ wasmvmtypes.Events) storetypes.Gas { +func (m MockGasRegister) EventCosts(evts []wasmvmtypes.EventAttribute, _ wasmvmtypes.Array[wasmvmtypes.Event]) storetypes.Gas { if m.EventCostsFn == nil { panic("not expected to be called") } diff --git a/x/wasm/keeper/wasmtesting/messenger.go b/x/wasm/keeper/wasmtesting/messenger.go index 8f613cf667..6c133406a5 100644 --- a/x/wasm/keeper/wasmtesting/messenger.go +++ b/x/wasm/keeper/wasmtesting/messenger.go @@ -3,16 +3,17 @@ package wasmtesting import ( "errors" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" ) type MockMessageHandler struct { - DispatchMsgFn func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) + DispatchMsgFn func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) } -func (m *MockMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { +func (m *MockMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { if m.DispatchMsgFn == nil { panic("not expected to be called") } @@ -22,18 +23,18 @@ func (m *MockMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAd func NewCapturingMessageHandler() (*MockMessageHandler, *[]wasmvmtypes.CosmosMsg) { var messages []wasmvmtypes.CosmosMsg return &MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { messages = append(messages, msg) // return one data item so that this doesn't cause an error in submessage processing (it takes the first element from data) - return nil, [][]byte{{1}}, nil + return nil, [][]byte{{1}}, [][]*codectypes.Any{}, nil }, }, &messages } func NewErroringMessageHandler() *MockMessageHandler { return &MockMessageHandler{ - DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { - return nil, nil, errors.New("test, ignore") + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + return nil, nil, [][]*codectypes.Any{}, errors.New("test, ignore") }, } } diff --git a/x/wasm/keeper/wasmtesting/mock_engine.go b/x/wasm/keeper/wasmtesting/mock_engine.go index b1c7b11d04..9ef1c583a2 100644 --- a/x/wasm/keeper/wasmtesting/mock_engine.go +++ b/x/wasm/keeper/wasmtesting/mock_engine.go @@ -3,8 +3,8 @@ package wasmtesting import ( "bytes" - 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/cometbft/cometbft/libs/rand" errorsmod "cosmossdk.io/errors" @@ -12,48 +12,53 @@ import ( "github.com/CosmWasm/wasmd/x/wasm/types" ) +const ( + // The amount of gas to be consumed by the default MockWasmEngine.StoreCode functions per byte + MockStoreCodeCostPerByte = 3 * 140_000 +) + var _ types.WasmEngine = &MockWasmEngine{} // MockWasmEngine implements types.WasmEngine for testing purpose. One or multiple messages can be stubbed. // Without a stub function a panic is thrown. type MockWasmEngine struct { - StoreCodeFn func(codeID wasmvm.WasmCode) (wasmvm.Checksum, error) + StoreCodeFn func(codeID wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) StoreCodeUncheckedFn func(codeID wasmvm.WasmCode) (wasmvm.Checksum, error) AnalyzeCodeFn func(codeID wasmvm.Checksum) (*wasmvmtypes.AnalysisReport, error) - InstantiateFn func(codeID 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) - ExecuteFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) - QueryFn func(codeID 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) - MigrateFn func(codeID 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) - SudoFn func(codeID 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) - ReplyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + InstantiateFn func(codeID 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) + ExecuteFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) + QueryFn func(codeID 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) + MigrateFn func(codeID 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) + SudoFn func(codeID 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) + ReplyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) GetCodeFn func(codeID wasmvm.Checksum) (wasmvm.WasmCode, error) CleanupFn func() - IBCChannelOpenFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) - IBCChannelConnectFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCChannelCloseFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCChannelOpenFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) + IBCChannelConnectFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) + IBCChannelCloseFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) IBCPacketReceiveFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketReceiveMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) - IBCPacketAckFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCPacketTimeoutFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCPacketAckFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) + IBCPacketTimeoutFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) PinFn func(checksum wasmvm.Checksum) error UnpinFn func(checksum wasmvm.Checksum) error GetMetricsFn func() (*wasmvmtypes.Metrics, error) } -func (m *MockWasmEngine) IBCChannelOpen(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { +func (m *MockWasmEngine) IBCChannelOpen(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { if m.IBCChannelOpenFn == nil { panic("not supposed to be called!") } return m.IBCChannelOpenFn(codeID, env, msg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) IBCChannelConnect(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m *MockWasmEngine) IBCChannelConnect(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCChannelConnectFn == nil { panic("not supposed to be called!") } return m.IBCChannelConnectFn(codeID, env, msg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) IBCChannelClose(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m *MockWasmEngine) IBCChannelClose(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCChannelCloseFn == nil { panic("not supposed to be called!") } @@ -67,30 +72,25 @@ func (m *MockWasmEngine) IBCPacketReceive(codeID wasmvm.Checksum, env wasmvmtype return m.IBCPacketReceiveFn(codeID, env, msg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) IBCPacketAck(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m *MockWasmEngine) IBCPacketAck(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCPacketAckFn == nil { panic("not supposed to be called!") } return m.IBCPacketAckFn(codeID, env, msg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) IBCPacketTimeout(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m *MockWasmEngine) IBCPacketTimeout(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCPacketTimeoutFn == nil { panic("not supposed to be called!") } return m.IBCPacketTimeoutFn(codeID, env, msg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -// Deprecated: use StoreCode instead. -func (m *MockWasmEngine) Create(codeID wasmvm.WasmCode) (wasmvm.Checksum, error) { - panic("Deprecated: use StoreCode instead") -} - -func (m *MockWasmEngine) StoreCode(codeID wasmvm.WasmCode) (wasmvm.Checksum, error) { +func (m *MockWasmEngine) StoreCode(codeID wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) { if m.StoreCodeFn == nil { panic("not supposed to be called!") } - return m.StoreCodeFn(codeID) + return m.StoreCodeFn(codeID, gasLimit) } func (m *MockWasmEngine) StoreCodeUnchecked(codeID wasmvm.WasmCode) (wasmvm.Checksum, error) { @@ -107,42 +107,42 @@ func (m *MockWasmEngine) AnalyzeCode(codeID wasmvm.Checksum) (*wasmvmtypes.Analy return m.AnalyzeCodeFn(codeID) } -func (m *MockWasmEngine) Instantiate(codeID 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(codeID 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("not supposed to be called!") } return m.InstantiateFn(codeID, env, info, initMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) Execute(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []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) Execute(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if m.ExecuteFn == nil { panic("not supposed to be called!") } return m.ExecuteFn(codeID, env, info, executeMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) Query(codeID 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(codeID 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) { if m.QueryFn == nil { panic("not supposed to be called!") } return m.QueryFn(codeID, env, queryMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) Migrate(codeID 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(codeID 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("not supposed to be called!") } return m.MigrateFn(codeID, env, migrateMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) Sudo(codeID 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(codeID 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) { if m.SudoFn == nil { panic("not supposed to be called!") } return m.SudoFn(codeID, env, sudoMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m *MockWasmEngine) Reply(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (m *MockWasmEngine) Reply(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { if m.ReplyFn == nil { panic("not supposed to be called!") } @@ -189,23 +189,25 @@ var AlwaysPanicMockWasmEngine = &MockWasmEngine{} // SelfCallingInstMockWasmEngine prepares a WasmEngine mock that calls itself on instantiation. func SelfCallingInstMockWasmEngine(executeCalled *bool) *MockWasmEngine { return &MockWasmEngine{ - StoreCodeFn: func(code wasmvm.WasmCode) (wasmvm.Checksum, error) { + StoreCodeFn: func(code wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) { anyCodeID := bytes.Repeat([]byte{0x1}, 32) - return anyCodeID, nil + return anyCodeID, 0, nil }, - InstantiateFn: func(codeID 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) { - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - {Msg: wasmvmtypes.CosmosMsg{ - Wasm: &wasmvmtypes.WasmMsg{Execute: &wasmvmtypes.ExecuteMsg{ContractAddr: env.Contract.Address, Msg: []byte(`{}`)}}, - }}, + InstantiateFn: func(codeID 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) { + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + {Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{Execute: &wasmvmtypes.ExecuteMsg{ContractAddr: env.Contract.Address, Msg: []byte(`{}`)}}, + }}, + }, }, }, 1, nil }, AnalyzeCodeFn: WithoutIBCAnalyzeFn, - ExecuteFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + ExecuteFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { *executeCalled = true - return &wasmvmtypes.Response{}, 1, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{}}, 1, nil }, } } @@ -223,7 +225,7 @@ type IBCContractCallbacks interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) + ) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) IBCChannelConnect( codeID wasmvm.Checksum, @@ -235,7 +237,7 @@ type IBCContractCallbacks interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) IBCChannelClose( codeID wasmvm.Checksum, @@ -247,7 +249,7 @@ type IBCContractCallbacks interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) IBCPacketReceive( codeID wasmvm.Checksum, @@ -271,7 +273,7 @@ type IBCContractCallbacks interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) IBCPacketTimeout( codeID wasmvm.Checksum, @@ -283,7 +285,7 @@ type IBCContractCallbacks interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) } type contractExecutable interface { @@ -298,7 +300,7 @@ type contractExecutable interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) } // MakeInstantiable adds some noop functions to not fail when contract is used for instantiation @@ -334,19 +336,20 @@ func NewIBCContractMockWasmEngine(c IBCContractCallbacks) *MockWasmEngine { return m } -func HashOnlyStoreCodeFn(code wasmvm.WasmCode) (wasmvm.Checksum, error) { +func HashOnlyStoreCodeFn(code wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) { if code == nil { - return nil, errorsmod.Wrap(types.ErrInvalid, "wasm code must not be nil") + return nil, 0, errorsmod.Wrap(types.ErrInvalid, "wasm code must not be nil") } - return wasmvm.CreateChecksum(code) + checksum, err := wasmvm.CreateChecksum(code) + return checksum, 0, err } -func NoOpInstantiateFn(wasmvm.Checksum, wasmvmtypes.Env, wasmvmtypes.MessageInfo, []byte, wasmvm.KVStore, wasmvm.GoAPI, wasmvm.Querier, wasmvm.GasMeter, uint64, wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { - return &wasmvmtypes.Response{}, 0, nil +func NoOpInstantiateFn(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{Ok: &wasmvmtypes.Response{}}, 0, nil } -func NoOpStoreCodeFn(_ wasmvm.WasmCode) (wasmvm.Checksum, error) { - return rand.Bytes(32), nil +func NoOpStoreCodeFn(wasm wasmvm.WasmCode, gasLimit uint64) (wasmvm.Checksum, uint64, error) { + return rand.Bytes(32), uint64(MockStoreCodeCostPerByte * len(wasm)), nil } func HasIBCAnalyzeFn(wasmvm.Checksum) (*wasmvmtypes.AnalysisReport, error) { @@ -362,29 +365,29 @@ func WithoutIBCAnalyzeFn(wasmvm.Checksum) (*wasmvmtypes.AnalysisReport, error) { var _ IBCContractCallbacks = &MockIBCContractCallbacks{} type MockIBCContractCallbacks struct { - IBCChannelOpenFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) - IBCChannelConnectFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCChannelCloseFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCChannelOpenFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) + IBCChannelConnectFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) + IBCChannelCloseFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) IBCPacketReceiveFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketReceiveMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) - IBCPacketAckFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCPacketTimeoutFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCPacketAckFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) + IBCPacketTimeoutFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) } -func (m MockIBCContractCallbacks) IBCChannelOpen(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { +func (m MockIBCContractCallbacks) IBCChannelOpen(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { if m.IBCChannelOpenFn == nil { panic("not expected to be called") } return m.IBCChannelOpenFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m MockIBCContractCallbacks) IBCChannelConnect(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m MockIBCContractCallbacks) IBCChannelConnect(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCChannelConnectFn == nil { panic("not expected to be called") } return m.IBCChannelConnectFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m MockIBCContractCallbacks) IBCChannelClose(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m MockIBCContractCallbacks) IBCChannelClose(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCChannelCloseFn == nil { panic("not expected to be called") } @@ -398,14 +401,14 @@ func (m MockIBCContractCallbacks) IBCPacketReceive(codeID wasmvm.Checksum, env w return m.IBCPacketReceiveFn(codeID, env, packet, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m MockIBCContractCallbacks) IBCPacketAck(codeID wasmvm.Checksum, env wasmvmtypes.Env, ack wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m MockIBCContractCallbacks) IBCPacketAck(codeID wasmvm.Checksum, env wasmvmtypes.Env, ack wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCPacketAckFn == nil { panic("not expected to be called") } return m.IBCPacketAckFn(codeID, env, ack, store, goapi, querier, gasMeter, gasLimit, deserCost) } -func (m MockIBCContractCallbacks) IBCPacketTimeout(codeID wasmvm.Checksum, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (m MockIBCContractCallbacks) IBCPacketTimeout(codeID wasmvm.Checksum, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { if m.IBCPacketTimeoutFn == nil { panic("not expected to be called") } diff --git a/x/wasm/keeper/wasmtesting/msg_dispatcher.go b/x/wasm/keeper/wasmtesting/msg_dispatcher.go index 4d016f4741..2229fedab5 100644 --- a/x/wasm/keeper/wasmtesting/msg_dispatcher.go +++ b/x/wasm/keeper/wasmtesting/msg_dispatcher.go @@ -1,7 +1,7 @@ package wasmtesting import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/x/wasm/keeper/wasmtesting/query_handler.go b/x/wasm/keeper/wasmtesting/query_handler.go index e70495b52f..5f4a4501bb 100644 --- a/x/wasm/keeper/wasmtesting/query_handler.go +++ b/x/wasm/keeper/wasmtesting/query_handler.go @@ -1,7 +1,7 @@ package wasmtesting import ( - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" sdk "github.com/cosmos/cosmos-sdk/types" ) diff --git a/x/wasm/migrations/v1/store_test.go b/x/wasm/migrations/v1/store_test.go index 7afec80b59..4e57da1ee2 100644 --- a/x/wasm/migrations/v1/store_test.go +++ b/x/wasm/migrations/v1/store_test.go @@ -15,7 +15,7 @@ import ( ) func TestMigrate1To2(t *testing.T) { - const AvailableCapabilities = "iterator,staking,stargate,cosmwasm_1_1" + var AvailableCapabilities = []string{"iterator", "staking", "stargate", "cosmwasm_1_1"} ctx, keepers := keeper.CreateTestInput(t, false, AvailableCapabilities) wasmKeeper := keepers.WasmKeeper diff --git a/x/wasm/migrations/v3/store_test.go b/x/wasm/migrations/v3/store_test.go index 0bd217d299..4f7100f67b 100644 --- a/x/wasm/migrations/v3/store_test.go +++ b/x/wasm/migrations/v3/store_test.go @@ -19,7 +19,7 @@ import ( ) func TestMigrate3To4(t *testing.T) { - const AvailableCapabilities = "iterator,staking,stargate,cosmwasm_1_1" + var AvailableCapabilities = []string{"iterator", "staking", "stargate", "cosmwasm_1_1"} ctx, keepers := keeper.CreateTestInput(t, false, AvailableCapabilities) store := ctx.KVStore(keepers.WasmStoreKey) cdc := moduletestutil.MakeTestEncodingConfig(wasm.AppModuleBasic{}).Codec diff --git a/x/wasm/module.go b/x/wasm/module.go index 8d5c8dc7f8..4fdf8f9dd4 100644 --- a/x/wasm/module.go +++ b/x/wasm/module.go @@ -7,7 +7,7 @@ import ( "runtime/debug" "strings" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" abci "github.com/cometbft/cometbft/abci/types" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cast" @@ -280,7 +280,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/x/wasm/module_test.go b/x/wasm/module_test.go index c08ab1455e..d75838a2a5 100644 --- a/x/wasm/module_test.go +++ b/x/wasm/module_test.go @@ -63,7 +63,7 @@ func setupTest(t *testing.T) testData { InstantiateDefaultPermission: v2.AccessTypeEverybody, } - ctx, keepers := keeper.CreateTestInput(t, false, "iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4") + ctx, keepers := keeper.CreateTestInput(t, false, []string{"iterator", "staking", "stargate", "cosmwasm_1_1", "cosmwasm_1_2", "cosmwasm_1_3", "cosmwasm_1_4", "cosmwasm_2_0"}) encConf := keeper.MakeEncodingConfig(t) queryRouter := baseapp.NewGRPCQueryRouter() serviceRouter := baseapp.NewMsgServiceRouter() diff --git a/x/wasm/relay_pingpong_test.go b/x/wasm/relay_pingpong_test.go index 2cf6a2634b..d06a460714 100644 --- a/x/wasm/relay_pingpong_test.go +++ b/x/wasm/relay_pingpong_test.go @@ -5,8 +5,8 @@ import ( "fmt" "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" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -137,7 +137,7 @@ type player struct { // Execute starts the ping pong game // Contracts finds all connected channels and broadcasts a ping message -func (p *player) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (p *player) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { p.execCalls++ // start game var start startGame @@ -153,39 +153,41 @@ func (p *player) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.Mes p.incrementCounter(sentBallsCountKey, store) store.Set(lastBallSentKey, sdk.Uint64ToBigEndian(start.Value)) - return &wasmvmtypes.Response{ - Messages: []wasmvmtypes.SubMsg{ - { - Msg: wasmvmtypes.CosmosMsg{ - IBC: &wasmvmtypes.IBCMsg{ - SendPacket: &wasmvmtypes.SendPacketMsg{ - ChannelID: start.ChannelID, - Data: service.GetBytes(), - Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{ - Revision: doNotTimeout.RevisionNumber, - Height: doNotTimeout.RevisionHeight, - }}, + return &wasmvmtypes.ContractResult{ + Ok: &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + { + Msg: wasmvmtypes.CosmosMsg{ + IBC: &wasmvmtypes.IBCMsg{ + SendPacket: &wasmvmtypes.SendPacketMsg{ + ChannelID: start.ChannelID, + Data: service.GetBytes(), + Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{ + Revision: doNotTimeout.RevisionNumber, + Height: doNotTimeout.RevisionHeight, + }}, + }, }, }, + ReplyOn: wasmvmtypes.ReplyNever, }, - ReplyOn: wasmvmtypes.ReplyNever, }, }, }, 0, nil } // OnIBCChannelOpen ensures to accept only configured version -func (p player) IBCChannelOpen(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { +func (p player) IBCChannelOpen(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { if msg.GetChannel().Version != p.actor { - return &wasmvmtypes.IBC3ChannelOpenResponse{}, 0, nil + return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, 0, nil } - return &wasmvmtypes.IBC3ChannelOpenResponse{}, 0, nil + return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, 0, nil } // OnIBCChannelConnect persists connection endpoints -func (p player) IBCChannelConnect(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (p player) IBCChannelConnect(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { p.storeEndpoint(store, msg.GetChannel()) - return &wasmvmtypes.IBCBasicResponse{}, 0, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } // connectedChannelsModel is a simple persistence model to store endpoint addresses within the contract's store @@ -210,7 +212,7 @@ func (p player) storeEndpoint(store wasmvm.KVStore, channel wasmvmtypes.IBCChann store.Set(ibcEndpointsKey, bz) } -func (p player) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (p player) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { panic("implement me") } @@ -262,7 +264,7 @@ func (p player) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmv return &wasmvmtypes.IBCReceiveResult{ Ok: &wasmvmtypes.IBCReceiveResponse{ - Attributes: wasmvmtypes.EventAttributes{ + Attributes: wasmvmtypes.Array[wasmvmtypes.EventAttribute]{ {Key: "empty-value-test"}, }, Acknowledgement: receivedBall.BuildAck().GetBytes(), @@ -272,7 +274,7 @@ func (p player) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmv } // OnIBCPacketAcknowledgement handles the packet acknowledgment frame. Stops the game on an any error -func (p player) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (p player) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { // parse received data and store var sentBall hit if err := json.Unmarshal(msg.OriginalPacket.Data, &sentBall); err != nil { @@ -291,10 +293,10 @@ func (p player) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtyp } p.incrementCounter(confirmedBallsCountKey, store) - return &wasmvmtypes.IBCBasicResponse{}, 0, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } -func (p player) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (p player) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { panic("implement me") } diff --git a/x/wasm/relay_test.go b/x/wasm/relay_test.go index 91f1f34d72..bfb906db6b 100644 --- a/x/wasm/relay_test.go +++ b/x/wasm/relay_test.go @@ -6,8 +6,8 @@ import ( "testing" "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" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -551,9 +551,9 @@ type captureCloseContract struct { closeCalled bool } -func (c *captureCloseContract) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (c *captureCloseContract) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { c.closeCalled = true - return &wasmvmtypes.IBCBasicResponse{}, 1, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 1, nil } var _ wasmtesting.IBCContractCallbacks = &sendViaIBCTransferContract{} @@ -564,7 +564,7 @@ type sendViaIBCTransferContract struct { t *testing.T } -func (s *sendViaIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (s *sendViaIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var in startTransfer if err := json.Unmarshal(executeMsg, &in); err != nil { return nil, 0, err @@ -581,7 +581,7 @@ func (s *sendViaIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.En }, } - return &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}}, 0, nil } var _ wasmtesting.IBCContractCallbacks = &sendEmulatedIBCTransferContract{} @@ -594,7 +594,7 @@ type sendEmulatedIBCTransferContract struct { contractAddr string } -func (s *sendEmulatedIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (s *sendEmulatedIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var in startTransfer if err := json.Unmarshal(executeMsg, &in); err != nil { return nil, 0, err @@ -616,10 +616,10 @@ func (s *sendEmulatedIBCTransferContract) Execute(_ wasmvm.Checksum, _ wasmvmtyp Timeout: wasmvmtypes.IBCTimeout{Timestamp: in.Timeout}, }, } - return &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}}, 0, nil } -func (s *sendEmulatedIBCTransferContract) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (s *sendEmulatedIBCTransferContract) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { packet := msg.Packet var data ibctransfertypes.FungibleTokenPacketData @@ -634,11 +634,11 @@ func (s *sendEmulatedIBCTransferContract) IBCPacketTimeout(_ wasmvm.Checksum, _ returnTokens := &wasmvmtypes.BankMsg{ Send: &wasmvmtypes.SendMsg{ ToAddress: data.Sender, - Amount: wasmvmtypes.Coins{wasmvmtypes.NewCoin(amount.Uint64(), data.Denom)}, + Amount: wasmvmtypes.Array[wasmvmtypes.Coin]{wasmvmtypes.NewCoin(amount.Uint64(), data.Denom)}, }, } - return &wasmvmtypes.IBCBasicResponse{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: returnTokens}}}}, 0, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: returnTokens}}}}}, 0, nil } var _ wasmtesting.IBCContractCallbacks = &closeChannelContract{} @@ -647,11 +647,11 @@ type closeChannelContract struct { contractStub } -func (c *closeChannelContract) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - return &wasmvmtypes.IBCBasicResponse{}, 1, nil +func (c *closeChannelContract) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 1, nil } -func (c *closeChannelContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { +func (c *closeChannelContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.MessageInfo, executeMsg []byte, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.ContractResult, uint64, error) { var in closeIBCChannel if err := json.Unmarshal(executeMsg, &in); err != nil { return nil, 0, err @@ -662,7 +662,7 @@ func (c *closeChannelContract) Execute(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ w }, } - return &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}, 0, nil + return &wasmvmtypes.ContractResult{Ok: &wasmvmtypes.Response{Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{IBC: ibcMsg}}}}}, 0, nil } type closeIBCChannel struct { @@ -725,7 +725,7 @@ func (c *ackReceiverContract) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes. return &wasmvmtypes.IBCReceiveResult{Ok: &wasmvmtypes.IBCReceiveResponse{Acknowledgement: ack, Attributes: log}}, 0, nil } -func (c *ackReceiverContract) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (c *ackReceiverContract) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { var data ibctransfertypes.FungibleTokenPacketData if err := ibctransfertypes.ModuleCdc.UnmarshalJSON(msg.OriginalPacket.Data, &data); err != nil { return nil, 0, err @@ -745,7 +745,7 @@ func (c *ackReceiverContract) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, return nil, 0, errorsmod.Wrap(err, "within our smart contract") } - return &wasmvmtypes.IBCBasicResponse{}, 0, nil + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } // contract that acts as the receiving side for an ics-20 transfer and always returns a nack. @@ -785,15 +785,15 @@ func (c *errorReceiverContract) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtype // simple helper struct that implements connection setup methods. type contractStub struct{} -func (s *contractStub) IBCChannelOpen(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelOpenMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { - return &wasmvmtypes.IBC3ChannelOpenResponse{}, 0, nil +func (s *contractStub) IBCChannelOpen(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelOpenMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) { + return &wasmvmtypes.IBCChannelOpenResult{Ok: &wasmvmtypes.IBC3ChannelOpenResponse{}}, 0, nil } -func (s *contractStub) IBCChannelConnect(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelConnectMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - return &wasmvmtypes.IBCBasicResponse{}, 0, nil +func (s *contractStub) IBCChannelConnect(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelConnectMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } -func (s *contractStub) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (s *contractStub) IBCChannelClose(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCChannelCloseMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { panic("implement me") } @@ -801,11 +801,11 @@ func (s *contractStub) IBCPacketReceive(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ panic("implement me") } -func (s *contractStub) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketAckMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - return &wasmvmtypes.IBCBasicResponse{}, 0, nil +func (s *contractStub) IBCPacketAck(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketAckMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { + return &wasmvmtypes.IBCBasicResult{Ok: &wasmvmtypes.IBCBasicResponse{}}, 0, nil } -func (s *contractStub) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { +func (s *contractStub) IBCPacketTimeout(_ wasmvm.Checksum, _ wasmvmtypes.Env, _ wasmvmtypes.IBCPacketTimeoutMsg, _ wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResult, uint64, error) { panic("implement me") } diff --git a/x/wasm/simulation/operations.go b/x/wasm/simulation/operations.go index 845aa33963..c284a33342 100644 --- a/x/wasm/simulation/operations.go +++ b/x/wasm/simulation/operations.go @@ -6,7 +6,7 @@ import ( "math/rand" "os" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" errorsmod "cosmossdk.io/errors" diff --git a/x/wasm/types/authz.go b/x/wasm/types/authz.go index e0b4945961..0e8279703f 100644 --- a/x/wasm/types/authz.go +++ b/x/wasm/types/authz.go @@ -5,7 +5,7 @@ import ( "context" "strings" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/cosmos/gogoproto/proto" errorsmod "cosmossdk.io/errors" diff --git a/x/wasm/types/authz_test.go b/x/wasm/types/authz_test.go index 12ea9e07b5..f846691988 100644 --- a/x/wasm/types/authz_test.go +++ b/x/wasm/types/authz_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/types/errors.go b/x/wasm/types/errors.go index 58aa5caf1a..00ea45dc68 100644 --- a/x/wasm/types/errors.go +++ b/x/wasm/types/errors.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" ) @@ -86,6 +86,9 @@ var ( ErrNoSuchCodeFn = WasmVMFlavouredErrorFactory(errorsmod.Register(DefaultCodespace, 28, "no such code"), func(id uint64) error { return wasmvmtypes.NoSuchCode{CodeID: id} }, ) + + // ErrVMError means an error occurred in wasmvm (not in the contract itself, but in the host environment) + ErrVMError = errorsmod.Register(DefaultCodespace, 29, "wasmvm error") ) // WasmVMErrorable mapped error type in wasmvm and are not redacted @@ -149,3 +152,34 @@ func (e WasmVMFlavouredError) Wrap(desc string) error { return errorsmod.Wrap(e, func (e WasmVMFlavouredError) Wrapf(desc string, args ...interface{}) error { return errorsmod.Wrapf(e, desc, args...) } + +// DeterministicError is a wrapper type around an error that the creator guarantees to have +// a deterministic error message. +// This means that the `Error()` function must always return the same string on all nodes. +// The DeterministicError has the same error message as the wrapped error. +// DeterministicErrors are not redacted when returned to a contract, +// so not upholding this guarantee can lead to consensus failures. +type DeterministicError struct { + error +} + +var _ error = DeterministicError{} + +// MarkErrorDeterministic marks an error as deterministic. +// Make sure to only do that if the error message is deterministic between systems. +// See [DeterministicError] for more details. +func MarkErrorDeterministic(e error) DeterministicError { + return DeterministicError{error: e} +} + +// Unwrap implements the built-in errors.Unwrap +func (e DeterministicError) Unwrap() error { + return e.error +} + +// Cause is the same as unwrap but used by ABCIInfo +// By returning the wrapped error here, we ensure that the DeterministicError inherits +// the ABCIInfo of the wrapped error. +func (e DeterministicError) Cause() error { + return e.Unwrap() +} diff --git a/x/wasm/types/errors_test.go b/x/wasm/types/errors_test.go index 5e1034f628..45d98c9299 100644 --- a/x/wasm/types/errors_test.go +++ b/x/wasm/types/errors_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -94,3 +94,19 @@ func TestWasmVMFlavouredError(t *testing.T) { t.Run(name, spec.exec) } } + +func TestDeterministicError(t *testing.T) { + inner := ErrInstantiateFailed + err := MarkErrorDeterministic(inner) + + // behaves like a wrapper around inner error + assert.Equal(t, inner.Error(), err.Error()) + assert.Equal(t, inner, err.Cause()) + assert.Equal(t, inner, err.Unwrap()) + + // also works with ABCIInfo + codespace, code, _ := errorsmod.ABCIInfo(err, false) + innerCodeSpace, innerCode, _ := errorsmod.ABCIInfo(inner, false) + assert.Equal(t, innerCodeSpace, codespace) + assert.Equal(t, innerCode, code) +} diff --git a/x/wasm/types/exported_keepers.go b/x/wasm/types/exported_keepers.go index d00b39ce67..918ad214e3 100644 --- a/x/wasm/types/exported_keepers.go +++ b/x/wasm/types/exported_keepers.go @@ -3,7 +3,7 @@ package types import ( "context" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" diff --git a/x/wasm/types/gas_register.go b/x/wasm/types/gas_register.go index 0011d64163..ca6e11c235 100644 --- a/x/wasm/types/gas_register.go +++ b/x/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,7 +31,7 @@ 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 @@ -74,8 +75,6 @@ func DefaultPerByteUncompressCost() wasmvmtypes.UFraction { // GasRegister abstract source for gas costs type GasRegister interface { - // 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 // SetupContractCost are charged when interacting with a Wasm contract, i.e. every time @@ -84,7 +83,7 @@ type GasRegister interface { // ReplyCosts costs to to handle a message reply 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 @@ -165,14 +164,6 @@ func NewWasmGasRegister(c WasmGasRegisterConfig) WasmGasRegister { } } -// 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 { @@ -216,7 +207,7 @@ func (g WasmGasRegister) ReplyCosts(discount bool, reply wasmvmtypes.Reply) stor } // 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/x/wasm/types/gas_register_test.go b/x/wasm/types/gas_register_test.go index da7d123a9a..45e9719cbf 100644 --- a/x/wasm/types/gas_register_test.go +++ b/x/wasm/types/gas_register_test.go @@ -5,49 +5,12 @@ import ( "strings" "testing" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/stretchr/testify/assert" storetypes "cosmossdk.io/store/types" ) -func TestCompileCosts(t *testing.T) { - specs := map[string]struct { - srcLen int - srcConfig WasmGasRegisterConfig - exp storetypes.Gas - expPanic bool - }{ - "one byte": { - srcLen: 1, - srcConfig: DefaultGasRegisterConfig(), - exp: storetypes.Gas(3), // DefaultCompileCost - }, - "zero byte": { - srcLen: 0, - srcConfig: DefaultGasRegisterConfig(), - exp: storetypes.Gas(0), - }, - "negative len": { - srcLen: -1, - srcConfig: DefaultGasRegisterConfig(), - expPanic: true, - }, - } - for name, spec := range specs { - t.Run(name, func(t *testing.T) { - if spec.expPanic { - assert.Panics(t, func() { - NewWasmGasRegister(spec.srcConfig).CompileCosts(spec.srcLen) - }) - return - } - gotGas := NewWasmGasRegister(spec.srcConfig).CompileCosts(spec.srcLen) - assert.Equal(t, spec.exp, gotGas) - }) - } -} - func TestSetupContractCost(t *testing.T) { specs := map[string]struct { srcLen int @@ -258,7 +221,7 @@ func TestEventCosts(t *testing.T) { // most cases are covered in TestReplyCost already. This ensures some edge cases specs := map[string]struct { srcAttrs []wasmvmtypes.EventAttribute - srcEvents wasmvmtypes.Events + srcEvents wasmvmtypes.Array[wasmvmtypes.Event] expGas storetypes.Gas }{ "empty events": { diff --git a/x/wasm/types/test_fixtures.go b/x/wasm/types/test_fixtures.go index f1e0164973..e1d03c59c7 100644 --- a/x/wasm/types/test_fixtures.go +++ b/x/wasm/types/test_fixtures.go @@ -4,7 +4,7 @@ import ( _ "embed" "math/rand" - wasmvm "github.com/CosmWasm/wasmvm" + wasmvm "github.com/CosmWasm/wasmvm/v2" sdkmath "cosmossdk.io/math" diff --git a/x/wasm/types/types.go b/x/wasm/types/types.go index fdf390cf86..4b2a83e0d9 100644 --- a/x/wasm/types/types.go +++ b/x/wasm/types/types.go @@ -4,7 +4,7 @@ import ( "fmt" "reflect" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cosmos/gogoproto/proto" errorsmod "cosmossdk.io/errors" @@ -281,7 +281,7 @@ func NewEnv(ctx sdk.Context, contractAddr sdk.AccAddress) wasmvmtypes.Env { env := wasmvmtypes.Env{ Block: wasmvmtypes.BlockInfo{ Height: uint64(ctx.BlockHeight()), - Time: uint64(nano), + Time: wasmvmtypes.Uint64(nano), ChainID: ctx.ChainID(), }, Contract: wasmvmtypes.ContractInfo{ diff --git a/x/wasm/types/types_test.go b/x/wasm/types/types_test.go index 0734937eef..d00cf5ca3a 100644 --- a/x/wasm/types/types_test.go +++ b/x/wasm/types/types_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types" "github.com/cometbft/cometbft/libs/rand" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/types/wasmer_engine.go b/x/wasm/types/wasmer_engine.go index e27715bf74..f3829e9146 100644 --- a/x/wasm/types/wasmer_engine.go +++ b/x/wasm/types/wasmer_engine.go @@ -1,8 +1,8 @@ package types 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" storetypes "cosmossdk.io/store/types" ) @@ -12,30 +12,20 @@ const DefaultMaxQueryStackSize uint32 = 10 // WasmEngine defines the WASM contract runtime engine. type WasmEngine interface { - // Create will compile the wasm code, and store the resulting pre-compile - // as well as the original code. Both can be referenced later via CodeID + // 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 - // instatitated many times, and each instance called many times. + // instantiated many times, and each instance called many times. // - // For example, the code for all ERC-20 contracts should be the same. - // This function stores the code for that contract only once, but it can - // be instantiated with custom inputs in the future. - // - // Deprecated: use StoreCode instead. - Create(code wasmvm.WasmCode) (wasmvm.Checksum, error) - - // Create will compile the wasm code, and store the resulting pre-compile - // 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 - // instatitated 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) (wasmvm.Checksum, uint64, error) - // Create will compile the wasm code, and store the resulting pre-compile + // 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 // This must be done one time for given code, after which it can be - // instatitated many times, and each instance called many times. + // instantiated many times, and each instance called many times. // It does the same as StoreCode but without the static checks. + // Use this for adding code that was checked before, particularly in the case of state sync. StoreCodeUnchecked(code wasmvm.WasmCode) (wasmvm.Checksum, error) // AnalyzeCode will statically analyze the code. @@ -61,7 +51,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // Execute calls a given contract. Since the only difference between contracts with the same CodeID is the // data in their local storage, and their address in the outside world, we need no ContractID here. @@ -80,7 +70,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. @@ -95,7 +85,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) ([]byte, uint64, error) + ) (*wasmvmtypes.QueryResult, uint64, error) // Migrate will migrate an existing contract to a new code binary. // This takes storage of the data from the original contract and the CodeID of the new contract that should @@ -113,7 +103,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // Sudo runs an existing contract in read/write mode (like Execute), but is never exposed to external callers // (either transactions or government proposals), but can only be called by other native Go modules directly. @@ -130,7 +120,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.Response, uint64, error) + ) (*wasmvmtypes.ContractResult, uint64, error) // Reply is called on the original dispatching contract after running a submessage Reply( @@ -143,7 +133,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 code id. // This will only succeed if that code id was previously returned from @@ -169,7 +159,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) + ) (*wasmvmtypes.IBCChannelOpenResult, uint64, error) // IBCChannelConnect is available on IBC-enabled contracts and is a hook to call into // during the handshake phase @@ -183,7 +173,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) // IBCChannelClose is available on IBC-enabled contracts and is a hook to call into // at the end of the channel lifetime @@ -197,7 +187,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) // IBCPacketReceive is available on IBC-enabled contracts and is called when an incoming // packet is received on a channel belonging to this contract @@ -226,7 +216,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) // IBCPacketTimeout is available on IBC-enabled contracts and is called when an // outgoing packet (previously sent by this contract) will probably never be executed. @@ -241,7 +231,7 @@ type WasmEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + ) (*wasmvmtypes.IBCBasicResult, uint64, error) // Pin pins a code to an in-memory cache, such that is // always loaded quickly when executed.