mirror of https://github.com/certusone/wasmd.git
659 lines
22 KiB
Go
659 lines
22 KiB
Go
package keeper
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"github.com/CosmWasm/wasmd/x/wasm/internal/keeper/wasmtesting"
|
|
wasmvm "github.com/CosmWasm/wasmvm"
|
|
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"testing"
|
|
)
|
|
|
|
func TestOnOpenChannel(t *testing.T) {
|
|
var m wasmtesting.MockWasmer
|
|
wasmtesting.MakeIBCInstantiable(&m)
|
|
parentCtx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil)
|
|
example := SeedNewContractInstance(t, parentCtx, keepers, &m)
|
|
|
|
specs := map[string]struct {
|
|
contractAddr sdk.AccAddress
|
|
contractGas sdk.Gas
|
|
contractErr error
|
|
expErr bool
|
|
}{
|
|
"consume contract gas": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 10,
|
|
},
|
|
"consume max gas": {
|
|
contractAddr: example.Contract,
|
|
contractGas: MaxGas,
|
|
},
|
|
"consume gas on error": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 20,
|
|
contractErr: errors.New("test, ignore"),
|
|
expErr: true,
|
|
},
|
|
"unknown contract address": {
|
|
contractAddr: RandomAccountAddress(t),
|
|
expErr: true,
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"}
|
|
m.IBCChannelOpenFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (uint64, error) {
|
|
assert.Equal(t, myChannel, channel)
|
|
return spec.contractGas * GasMultiplier, spec.contractErr
|
|
}
|
|
|
|
ctx, cancel := parentCtx.CacheContext()
|
|
defer cancel()
|
|
before := ctx.GasMeter().GasConsumed()
|
|
|
|
// when
|
|
err := keepers.WasmKeeper.OnOpenChannel(ctx, spec.contractAddr, myChannel)
|
|
|
|
// then
|
|
if spec.expErr {
|
|
require.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
// verify gas consumed
|
|
const storageCosts = sdk.Gas(0xa9d)
|
|
assert.Equal(t, spec.contractGas, ctx.GasMeter().GasConsumed()-before-storageCosts)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOnConnectChannel(t *testing.T) {
|
|
var m wasmtesting.MockWasmer
|
|
wasmtesting.MakeIBCInstantiable(&m)
|
|
parentCtx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil)
|
|
example := SeedNewContractInstance(t, parentCtx, keepers, &m)
|
|
|
|
specs := map[string]struct {
|
|
contractAddr sdk.AccAddress
|
|
contractGas sdk.Gas
|
|
contractResp *wasmvmtypes.IBCBasicResponse
|
|
contractErr error
|
|
overwriteMessenger messenger
|
|
expErr bool
|
|
expContractEventAttrs int
|
|
expNoEvents bool
|
|
}{
|
|
"consume contract gas": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 10,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{},
|
|
},
|
|
"consume gas on error, ignore events + messages": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 20,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}},
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
contractErr: errors.New("test, ignore"),
|
|
expErr: true,
|
|
expNoEvents: true,
|
|
},
|
|
"dispatch contract messages on success": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 30,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}, {Custom: json.RawMessage(`{"foo":"bar"}`)}},
|
|
},
|
|
},
|
|
"emit contract events on success": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 40,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
expContractEventAttrs: 1,
|
|
},
|
|
"messenger errors returned, events stored": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 50,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}, {Custom: json.RawMessage(`{"foo":"bar"}`)}},
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
overwriteMessenger: &wasmtesting.MockMessageHandler{
|
|
DispatchFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msgs ...wasmvmtypes.CosmosMsg) error {
|
|
return errors.New("test, ignore")
|
|
},
|
|
},
|
|
expErr: true,
|
|
expContractEventAttrs: 1,
|
|
},
|
|
"unknown contract address": {
|
|
contractAddr: RandomAccountAddress(t),
|
|
expErr: true,
|
|
expNoEvents: true,
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"}
|
|
m.IBCChannelConnectFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) {
|
|
assert.Equal(t, channel, myChannel)
|
|
return spec.contractResp, spec.contractGas * GasMultiplier, spec.contractErr
|
|
}
|
|
|
|
ctx, cancel := parentCtx.CacheContext()
|
|
ctx = ctx.WithEventManager(sdk.NewEventManager())
|
|
defer cancel()
|
|
before := ctx.GasMeter().GasConsumed()
|
|
msger, capturedMsgs := wasmtesting.NewCapturingMessageHandler()
|
|
keepers.WasmKeeper.messenger = msger
|
|
|
|
if spec.overwriteMessenger != nil {
|
|
keepers.WasmKeeper.messenger = spec.overwriteMessenger
|
|
}
|
|
|
|
// when
|
|
err := keepers.WasmKeeper.OnConnectChannel(ctx, spec.contractAddr, myChannel)
|
|
|
|
// then
|
|
events := ctx.EventManager().Events()
|
|
if spec.expErr {
|
|
require.Error(t, err)
|
|
assert.Empty(t, capturedMsgs) // no messages captured on error
|
|
if spec.expNoEvents {
|
|
require.Len(t, events, 0)
|
|
} else {
|
|
require.Len(t, events, 1)
|
|
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
|
|
}
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
// verify gas consumed
|
|
const storageCosts = sdk.Gas(0xa9d)
|
|
assert.Equal(t, spec.contractGas, ctx.GasMeter().GasConsumed()-before-storageCosts)
|
|
// verify msgs dispatched
|
|
assert.Equal(t, spec.contractResp.Messages, *capturedMsgs)
|
|
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOnCloseChannel(t *testing.T) {
|
|
var m wasmtesting.MockWasmer
|
|
wasmtesting.MakeIBCInstantiable(&m)
|
|
parentCtx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil)
|
|
example := SeedNewContractInstance(t, parentCtx, keepers, &m)
|
|
|
|
specs := map[string]struct {
|
|
contractAddr sdk.AccAddress
|
|
contractGas sdk.Gas
|
|
contractResp *wasmvmtypes.IBCBasicResponse
|
|
contractErr error
|
|
overwriteMessenger messenger
|
|
expErr bool
|
|
expContractEventAttrs int
|
|
expNoEvents bool
|
|
}{
|
|
"consume contract gas": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 10,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{},
|
|
},
|
|
"consume gas on error, ignore events + messages": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 20,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}},
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
contractErr: errors.New("test, ignore"),
|
|
expErr: true,
|
|
expNoEvents: true,
|
|
},
|
|
"dispatch contract messages on success": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 30,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}, {Custom: json.RawMessage(`{"foo":"bar"}`)}},
|
|
},
|
|
},
|
|
"emit contract events on success": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 40,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
expContractEventAttrs: 1,
|
|
},
|
|
"messenger errors returned, events stored": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 50,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}, {Custom: json.RawMessage(`{"foo":"bar"}`)}},
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
overwriteMessenger: &wasmtesting.MockMessageHandler{
|
|
DispatchFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msgs ...wasmvmtypes.CosmosMsg) error {
|
|
return errors.New("test, ignore")
|
|
},
|
|
},
|
|
expErr: true,
|
|
expContractEventAttrs: 1,
|
|
},
|
|
"unknown contract address": {
|
|
contractAddr: RandomAccountAddress(t),
|
|
expErr: true,
|
|
expNoEvents: true,
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"}
|
|
m.IBCChannelCloseFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) {
|
|
assert.Equal(t, channel, myChannel)
|
|
return spec.contractResp, spec.contractGas * GasMultiplier, spec.contractErr
|
|
}
|
|
|
|
ctx, cancel := parentCtx.CacheContext()
|
|
defer cancel()
|
|
before := ctx.GasMeter().GasConsumed()
|
|
msger, capturedMsgs := wasmtesting.NewCapturingMessageHandler()
|
|
keepers.WasmKeeper.messenger = msger
|
|
|
|
if spec.overwriteMessenger != nil {
|
|
keepers.WasmKeeper.messenger = spec.overwriteMessenger
|
|
}
|
|
|
|
// when
|
|
err := keepers.WasmKeeper.OnCloseChannel(ctx, spec.contractAddr, myChannel)
|
|
|
|
// then
|
|
events := ctx.EventManager().Events()
|
|
if spec.expErr {
|
|
require.Error(t, err)
|
|
assert.Empty(t, capturedMsgs) // no messages captured on error
|
|
if spec.expNoEvents {
|
|
require.Len(t, events, 0)
|
|
} else {
|
|
require.Len(t, events, 1)
|
|
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
|
|
}
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
// verify gas consumed
|
|
const storageCosts = sdk.Gas(0xa9d)
|
|
assert.Equal(t, spec.contractGas, ctx.GasMeter().GasConsumed()-before-storageCosts)
|
|
// verify msgs dispatched
|
|
assert.Equal(t, spec.contractResp.Messages, *capturedMsgs)
|
|
require.Len(t, events, 1)
|
|
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOnRecvPacket(t *testing.T) {
|
|
var m wasmtesting.MockWasmer
|
|
wasmtesting.MakeIBCInstantiable(&m)
|
|
parentCtx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil)
|
|
example := SeedNewContractInstance(t, parentCtx, keepers, &m)
|
|
|
|
specs := map[string]struct {
|
|
contractAddr sdk.AccAddress
|
|
contractGas sdk.Gas
|
|
contractResp *wasmvmtypes.IBCReceiveResponse
|
|
contractErr error
|
|
overwriteMessenger messenger
|
|
expErr bool
|
|
expContractEventAttrs int
|
|
expNoEvents bool
|
|
}{
|
|
"consume contract gas": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 10,
|
|
contractResp: &wasmvmtypes.IBCReceiveResponse{
|
|
Acknowledgement: []byte("myAck"),
|
|
},
|
|
},
|
|
"can return empty ack": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 10,
|
|
contractResp: &wasmvmtypes.IBCReceiveResponse{},
|
|
},
|
|
"consume gas on error, ignore events + messages": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 20,
|
|
contractResp: &wasmvmtypes.IBCReceiveResponse{
|
|
Acknowledgement: []byte("myAck"),
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}},
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
contractErr: errors.New("test, ignore"),
|
|
expErr: true,
|
|
expNoEvents: true,
|
|
},
|
|
"dispatch contract messages on success": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 30,
|
|
contractResp: &wasmvmtypes.IBCReceiveResponse{
|
|
Acknowledgement: []byte("myAck"),
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}, {Custom: json.RawMessage(`{"foo":"bar"}`)}},
|
|
},
|
|
},
|
|
"emit contract events on success": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 40,
|
|
contractResp: &wasmvmtypes.IBCReceiveResponse{
|
|
Acknowledgement: []byte("myAck"),
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
expContractEventAttrs: 1,
|
|
},
|
|
"messenger errors returned, events stored": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 50,
|
|
contractResp: &wasmvmtypes.IBCReceiveResponse{
|
|
Acknowledgement: []byte("myAck"),
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}, {Custom: json.RawMessage(`{"foo":"bar"}`)}},
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
overwriteMessenger: &wasmtesting.MockMessageHandler{
|
|
DispatchFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msgs ...wasmvmtypes.CosmosMsg) error {
|
|
return errors.New("test, ignore")
|
|
},
|
|
},
|
|
expErr: true,
|
|
expContractEventAttrs: 1,
|
|
},
|
|
"unknown contract address": {
|
|
contractAddr: RandomAccountAddress(t),
|
|
expErr: true,
|
|
expNoEvents: true,
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
myPacket := wasmvmtypes.IBCPacket{Data: []byte("my data")}
|
|
|
|
m.IBCPacketReceiveFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCReceiveResponse, uint64, error) {
|
|
assert.Equal(t, myPacket, packet)
|
|
return spec.contractResp, spec.contractGas * GasMultiplier, spec.contractErr
|
|
}
|
|
|
|
ctx, cancel := parentCtx.CacheContext()
|
|
defer cancel()
|
|
before := ctx.GasMeter().GasConsumed()
|
|
|
|
msger, capturedMsgs := wasmtesting.NewCapturingMessageHandler()
|
|
keepers.WasmKeeper.messenger = msger
|
|
|
|
if spec.overwriteMessenger != nil {
|
|
keepers.WasmKeeper.messenger = spec.overwriteMessenger
|
|
}
|
|
|
|
// when
|
|
gotAck, err := keepers.WasmKeeper.OnRecvPacket(ctx, spec.contractAddr, myPacket)
|
|
|
|
// then
|
|
events := ctx.EventManager().Events()
|
|
if spec.expErr {
|
|
require.Error(t, err)
|
|
assert.Empty(t, capturedMsgs) // no messages captured on error
|
|
if spec.expNoEvents {
|
|
require.Len(t, events, 0)
|
|
} else {
|
|
require.Len(t, events, 1)
|
|
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
|
|
}
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
require.Equal(t, spec.contractResp.Acknowledgement, gotAck)
|
|
|
|
// verify gas consumed
|
|
const storageCosts = sdk.Gas(0xa9d)
|
|
assert.Equal(t, spec.contractGas, ctx.GasMeter().GasConsumed()-before-storageCosts)
|
|
// verify msgs dispatched
|
|
assert.Equal(t, spec.contractResp.Messages, *capturedMsgs)
|
|
require.Len(t, events, 1)
|
|
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOnAckPacket(t *testing.T) {
|
|
var m wasmtesting.MockWasmer
|
|
wasmtesting.MakeIBCInstantiable(&m)
|
|
parentCtx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil)
|
|
example := SeedNewContractInstance(t, parentCtx, keepers, &m)
|
|
|
|
specs := map[string]struct {
|
|
contractAddr sdk.AccAddress
|
|
contractGas sdk.Gas
|
|
contractResp *wasmvmtypes.IBCBasicResponse
|
|
contractErr error
|
|
overwriteMessenger messenger
|
|
expErr bool
|
|
expContractEventAttrs int
|
|
expNoEvents bool
|
|
}{
|
|
"consume contract gas": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 10,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{},
|
|
},
|
|
"consume gas on error, ignore events + messages": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 20,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}},
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
contractErr: errors.New("test, ignore"),
|
|
expErr: true,
|
|
expNoEvents: true,
|
|
},
|
|
"dispatch contract messages on success": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 30,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}, {Custom: json.RawMessage(`{"foo":"bar"}`)}},
|
|
},
|
|
},
|
|
"emit contract events on success": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 40,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
expContractEventAttrs: 1,
|
|
},
|
|
"messenger errors returned, events stored": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 50,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}, {Custom: json.RawMessage(`{"foo":"bar"}`)}},
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
overwriteMessenger: &wasmtesting.MockMessageHandler{
|
|
DispatchFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msgs ...wasmvmtypes.CosmosMsg) error {
|
|
return errors.New("test, ignore")
|
|
},
|
|
},
|
|
expErr: true,
|
|
expContractEventAttrs: 1,
|
|
},
|
|
"unknown contract address": {
|
|
contractAddr: RandomAccountAddress(t),
|
|
expErr: true,
|
|
expNoEvents: true,
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
myAck := wasmvmtypes.IBCAcknowledgement{Acknowledgement: []byte("myAck")}
|
|
m.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, ack wasmvmtypes.IBCAcknowledgement, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) {
|
|
assert.Equal(t, myAck, ack)
|
|
return spec.contractResp, spec.contractGas * GasMultiplier, spec.contractErr
|
|
}
|
|
|
|
ctx, cancel := parentCtx.CacheContext()
|
|
defer cancel()
|
|
before := ctx.GasMeter().GasConsumed()
|
|
msger, capturedMsgs := wasmtesting.NewCapturingMessageHandler()
|
|
keepers.WasmKeeper.messenger = msger
|
|
|
|
if spec.overwriteMessenger != nil {
|
|
keepers.WasmKeeper.messenger = spec.overwriteMessenger
|
|
}
|
|
|
|
// when
|
|
err := keepers.WasmKeeper.OnAckPacket(ctx, spec.contractAddr, myAck)
|
|
|
|
// then
|
|
events := ctx.EventManager().Events()
|
|
if spec.expErr {
|
|
require.Error(t, err)
|
|
assert.Empty(t, capturedMsgs) // no messages captured on error
|
|
if spec.expNoEvents {
|
|
require.Len(t, events, 0)
|
|
} else {
|
|
require.Len(t, events, 1)
|
|
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
|
|
}
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
// verify gas consumed
|
|
const storageCosts = sdk.Gas(0xa9d)
|
|
assert.Equal(t, spec.contractGas, ctx.GasMeter().GasConsumed()-before-storageCosts)
|
|
// verify msgs dispatched
|
|
assert.Equal(t, spec.contractResp.Messages, *capturedMsgs)
|
|
require.Len(t, events, 1)
|
|
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOnTimeoutPacket(t *testing.T) {
|
|
var m wasmtesting.MockWasmer
|
|
wasmtesting.MakeIBCInstantiable(&m)
|
|
parentCtx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil)
|
|
example := SeedNewContractInstance(t, parentCtx, keepers, &m)
|
|
|
|
specs := map[string]struct {
|
|
contractAddr sdk.AccAddress
|
|
contractGas sdk.Gas
|
|
contractResp *wasmvmtypes.IBCBasicResponse
|
|
contractErr error
|
|
overwriteMessenger messenger
|
|
expErr bool
|
|
expContractEventAttrs int
|
|
expNoEvents bool
|
|
}{
|
|
"consume contract gas": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 10,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{},
|
|
},
|
|
"consume gas on error, ignore events + messages": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 20,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}},
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
contractErr: errors.New("test, ignore"),
|
|
expErr: true,
|
|
expNoEvents: true,
|
|
},
|
|
"dispatch contract messages on success": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 30,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}, {Custom: json.RawMessage(`{"foo":"bar"}`)}},
|
|
},
|
|
},
|
|
"emit contract events on success": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 40,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
expContractEventAttrs: 1,
|
|
},
|
|
"messenger errors returned, events stored": {
|
|
contractAddr: example.Contract,
|
|
contractGas: 50,
|
|
contractResp: &wasmvmtypes.IBCBasicResponse{
|
|
Messages: []wasmvmtypes.CosmosMsg{{Bank: &wasmvmtypes.BankMsg{}}, {Custom: json.RawMessage(`{"foo":"bar"}`)}},
|
|
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
|
|
},
|
|
overwriteMessenger: &wasmtesting.MockMessageHandler{
|
|
DispatchFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msgs ...wasmvmtypes.CosmosMsg) error {
|
|
return errors.New("test, ignore")
|
|
},
|
|
},
|
|
expErr: true,
|
|
expContractEventAttrs: 1,
|
|
},
|
|
"unknown contract address": {
|
|
contractAddr: RandomAccountAddress(t),
|
|
expErr: true,
|
|
expNoEvents: true,
|
|
},
|
|
}
|
|
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, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) {
|
|
assert.Equal(t, myPacket, packet)
|
|
return spec.contractResp, spec.contractGas * GasMultiplier, spec.contractErr
|
|
}
|
|
|
|
ctx, cancel := parentCtx.CacheContext()
|
|
defer cancel()
|
|
before := ctx.GasMeter().GasConsumed()
|
|
msger, capturedMsgs := wasmtesting.NewCapturingMessageHandler()
|
|
keepers.WasmKeeper.messenger = msger
|
|
|
|
if spec.overwriteMessenger != nil {
|
|
keepers.WasmKeeper.messenger = spec.overwriteMessenger
|
|
}
|
|
|
|
// when
|
|
err := keepers.WasmKeeper.OnTimeoutPacket(ctx, spec.contractAddr, myPacket)
|
|
|
|
// then
|
|
events := ctx.EventManager().Events()
|
|
if spec.expErr {
|
|
require.Error(t, err)
|
|
assert.Empty(t, capturedMsgs) // no messages captured on error
|
|
if spec.expNoEvents {
|
|
require.Len(t, events, 0)
|
|
} else {
|
|
require.Len(t, events, 1)
|
|
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
|
|
}
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
// verify gas consumed
|
|
const storageCosts = sdk.Gas(0xa9d)
|
|
assert.Equal(t, spec.contractGas, ctx.GasMeter().GasConsumed()-before-storageCosts)
|
|
// verify msgs dispatched
|
|
assert.Equal(t, spec.contractResp.Messages, *capturedMsgs)
|
|
require.Len(t, events, 1)
|
|
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
|
|
})
|
|
}
|
|
}
|