From 4a63c7ad47450229b08ff26f44b4ca976d083a01 Mon Sep 17 00:00:00 2001 From: Alexander Peters Date: Wed, 20 Jan 2021 12:09:34 +0100 Subject: [PATCH] Enable some IBC calls and better test framework (#8) * Enable IBC calls and better test framework * Review feedback --- app/app.go | 3 +- app/app_test.go | 8 +- app/test_helpers.go | 14 +- cmd/wasmd/root.go | 8 +- x/wasm/alias.go | 2 + x/wasm/ibctesting/chain.go | 5 +- x/wasm/ibctesting/coordinator.go | 13 +- x/wasm/ibctesting/wasm.go | 11 +- x/wasm/internal/keeper/ibc.go | 103 ------- x/wasm/internal/keeper/keeper.go | 40 +-- x/wasm/internal/keeper/keeper_test.go | 3 +- x/wasm/internal/keeper/options.go | 15 + x/wasm/internal/keeper/querier_test.go | 12 +- x/wasm/internal/keeper/relay.go | 30 +- x/wasm/internal/keeper/test_common.go | 138 --------- .../keeper/wasmtesting/mock_engine.go | 265 ++++++++++++++++++ x/wasm/relay_pingpong_test.go | 43 +-- x/wasm/relay_test.go | 69 ++--- 18 files changed, 416 insertions(+), 366 deletions(-) create mode 100644 x/wasm/internal/keeper/options.go create mode 100644 x/wasm/internal/keeper/wasmtesting/mock_engine.go diff --git a/app/app.go b/app/app.go index a2a726f747..4395687625 100644 --- a/app/app.go +++ b/app/app.go @@ -241,7 +241,7 @@ type WasmApp struct { // NewWasmApp returns a reference to an initialized WasmApp. func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, skipUpgradeHeights map[int64]bool, homePath string, invCheckPeriod uint, enabledProposals []wasm.ProposalType, - appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp)) *WasmApp { + appOpts servertypes.AppOptions, wasmOpts []wasm.Option, baseAppOptions ...func(*baseapp.BaseApp)) *WasmApp { encodingConfig := MakeEncodingConfig() appCodec, legacyAmino := encodingConfig.Marshaler, encodingConfig.Amino @@ -375,6 +375,7 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b supportedFeatures, nil, nil, + wasmOpts..., ) // The gov proposal types can be individually enabled diff --git a/app/app_test.go b/app/app_test.go index ed33131dd9..a36dd79c48 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -14,9 +14,11 @@ import ( abci "github.com/tendermint/tendermint/abci/types" ) +var emptyWasmOpts []wasm.Option = nil + func TestWasmdExport(t *testing.T) { db := db.NewMemDB() - gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyAppOptions{}) + gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyBaseAppOptions{}, emptyWasmOpts) genesisState := NewDefaultGenesisState() stateBytes, err := json.MarshalIndent(genesisState, "", " ") @@ -32,7 +34,7 @@ func TestWasmdExport(t *testing.T) { gapp.Commit() // Making a new app object with the db, so that initchain hasn't been called - newGapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyAppOptions{}) + newGapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyBaseAppOptions{}, emptyWasmOpts) _, err = newGapp.ExportAppStateAndValidators(false, []string{}) require.NoError(t, err, "ExportAppStateAndValidators should not have an error") } @@ -40,7 +42,7 @@ func TestWasmdExport(t *testing.T) { // ensure that blocked addresses are properly set in bank keeper func TestBlockedAddrs(t *testing.T) { db := db.NewMemDB() - gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyAppOptions{}) + gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyBaseAppOptions{}, emptyWasmOpts) for acc := range maccPerms { require.Equal(t, !allowedReceivingModAcc[acc], gapp.bankKeeper.BlockedAddr(gapp.accountKeeper.GetModuleAddress(acc))) diff --git a/app/test_helpers.go b/app/test_helpers.go index 7d9f002aaf..ace8a7bd2d 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -50,9 +50,9 @@ var DefaultConsensusParams = &abci.ConsensusParams{ }, } -func setup(withGenesis bool, invCheckPeriod uint) (*WasmApp, GenesisState) { +func setup(withGenesis bool, invCheckPeriod uint, opts ...wasm.Option) (*WasmApp, GenesisState) { db := dbm.NewMemDB() - app := NewWasmApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, invCheckPeriod, wasm.EnableAllProposals, EmptyAppOptions{}) + app := NewWasmApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, invCheckPeriod, wasm.EnableAllProposals, EmptyBaseAppOptions{}, opts) if withGenesis { return app, NewDefaultGenesisState() } @@ -86,8 +86,8 @@ func Setup(isCheckTx bool) *WasmApp { // that also act as delegators. For simplicity, each validator is bonded with a delegation // of one consensus engine unit (10^6) in the default token of the WasmApp from first genesis // account. A Nop logger is set in WasmApp. -func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *WasmApp { - app, genesisState := setup(true, 5) +func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, opts []wasm.Option, balances ...banktypes.Balance) *WasmApp { + app, genesisState := setup(true, 5, opts...) // set genesis accounts authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) genesisState[authtypes.ModuleName] = app.appCodec.MustMarshalJSON(authGenesis) @@ -435,10 +435,10 @@ func NewPubKeyFromHex(pk string) (res cryptotypes.PubKey) { return &ed25519.PubKey{Key: pkBytes} } -// EmptyAppOptions is a stub implementing AppOptions -type EmptyAppOptions struct{} +// EmptyBaseAppOptions is a stub implementing AppOptions +type EmptyBaseAppOptions struct{} // Get implements AppOptions -func (ao EmptyAppOptions) Get(o string) interface{} { +func (ao EmptyBaseAppOptions) Get(o string) interface{} { return nil } diff --git a/cmd/wasmd/root.go b/cmd/wasmd/root.go index fa0c932e2b..6b010c1c38 100644 --- a/cmd/wasmd/root.go +++ b/cmd/wasmd/root.go @@ -198,12 +198,13 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts serverty if err != nil { panic(err) } - + var emptyWasmOpts []wasm.Option return app.NewWasmApp(logger, db, traceStore, true, skipUpgradeHeights, cast.ToString(appOpts.Get(flags.FlagHome)), cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), app.GetEnabledProposals(), appOpts, + emptyWasmOpts, baseapp.SetPruning(pruningOpts), baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), @@ -227,14 +228,15 @@ func createWasmAppAndExport( if !ok || homePath == "" { return servertypes.ExportedApp{}, errors.New("application home not set") } + var emptyWasmOpts []wasm.Option if height != -1 { - wasmApp = app.NewWasmApp(logger, db, traceStore, false, map[int64]bool{}, homePath, uint(1), app.GetEnabledProposals(), appOpts) + wasmApp = app.NewWasmApp(logger, db, traceStore, false, map[int64]bool{}, homePath, uint(1), app.GetEnabledProposals(), appOpts, emptyWasmOpts) if err := wasmApp.LoadHeight(height); err != nil { return servertypes.ExportedApp{}, err } } else { - wasmApp = app.NewWasmApp(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), app.GetEnabledProposals(), appOpts) + wasmApp = app.NewWasmApp(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), app.GetEnabledProposals(), appOpts, emptyWasmOpts) } return wasmApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) diff --git a/x/wasm/alias.go b/x/wasm/alias.go index 1833770533..1d52705e13 100644 --- a/x/wasm/alias.go +++ b/x/wasm/alias.go @@ -78,6 +78,7 @@ var ( NewWasmProposalHandler = keeper.NewWasmProposalHandler NewQuerier = keeper.NewQuerier ContractFromPortID = keeper.ContractFromPortID + WithWasmEngine = keeper.WithWasmEngine // variable aliases ModuleCdc = types.ModuleCdc @@ -136,4 +137,5 @@ type ( QueryHandler = keeper.QueryHandler CustomQuerier = keeper.CustomQuerier QueryPlugins = keeper.QueryPlugins + Option = keeper.Option ) diff --git a/x/wasm/ibctesting/chain.go b/x/wasm/ibctesting/chain.go index 6e03d0d09e..0a228a7462 100644 --- a/x/wasm/ibctesting/chain.go +++ b/x/wasm/ibctesting/chain.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" wasmd "github.com/CosmWasm/wasmd/app" + "github.com/CosmWasm/wasmd/x/wasm/internal/keeper" ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" "io/ioutil" "os" @@ -114,7 +115,7 @@ type TestChain struct { // // Time management is handled by the Coordinator in order to ensure synchrony between chains. // Each update of any chain increments the block header time for all chains by 5 seconds. -func NewTestChain(t *testing.T, chainID string) *TestChain { +func NewTestChain(t *testing.T, chainID string, opt ...keeper.Option) *TestChain { // generate validator private/public key privVal := mock.NewPV() pubKey, err := privVal.GetPubKey() @@ -140,7 +141,7 @@ func NewTestChain(t *testing.T, chainID string) *TestChain { } t.Cleanup(func() { os.RemoveAll(tempDir) }) - app := wasmd.SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, balance) + app := wasmd.SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, opt, balance) // create current header and call begin block header := tmproto.Header{ diff --git a/x/wasm/ibctesting/coordinator.go b/x/wasm/ibctesting/coordinator.go index 7cffb5cfa7..0e372f012a 100644 --- a/x/wasm/ibctesting/coordinator.go +++ b/x/wasm/ibctesting/coordinator.go @@ -3,6 +3,7 @@ package ibctesting import ( "fmt" "github.com/CosmWasm/wasmd/app" + "github.com/CosmWasm/wasmd/x/wasm/internal/keeper" ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" "strconv" "testing" @@ -32,12 +33,18 @@ type Coordinator struct { } // NewCoordinator initializes Coordinator with N TestChain's -func NewCoordinator(t *testing.T, n int) *Coordinator { +func NewCoordinator(t *testing.T, n int, opts ...[]keeper.Option) *Coordinator { chains := make(map[string]*TestChain) - + if len(opts) != 0 && len(opts) != n { + t.Fatalf("opts not matching number of instances: %d", len(opts)) + } for i := 0; i < n; i++ { chainID := GetChainID(i) - chains[chainID] = NewTestChain(t, chainID) + var iOpts []keeper.Option + if len(opts) != 0 { + iOpts = opts[i] + } + chains[chainID] = NewTestChain(t, chainID, iOpts...) } return &Coordinator{ t: t, diff --git a/x/wasm/ibctesting/wasm.go b/x/wasm/ibctesting/wasm.go index f046e39173..c74b7c39ac 100644 --- a/x/wasm/ibctesting/wasm.go +++ b/x/wasm/ibctesting/wasm.go @@ -10,13 +10,17 @@ import ( "io/ioutil" ) -func (c *TestChain) NewRandomContractInstance() sdk.AccAddress { - wasmCode, err := ioutil.ReadFile("./internal/keeper/testdata/hackatom.wasm.gzip") +// SeedNewContractInstance stores some wasm code and instantiates a new contract on this chain. +// This method can be called to prepare the store with some valid CodeInfo and ContractInfo. The returned +// Address is the contract address for this instance. Test should make use of this data and/or use NewIBCContractMockWasmer +// for using a contract mock in Go. +func (c *TestChain) SeedNewContractInstance() sdk.AccAddress { + anyWasmCode, err := ioutil.ReadFile("./internal/keeper/testdata/hackatom.wasm.gzip") require.NoError(c.t, err) storeMsg := &types.MsgStoreCode{ Sender: c.SenderAccount.GetAddress().String(), - WASMByteCode: wasmCode, + WASMByteCode: anyWasmCode, } r, err := c.SendMsgs(storeMsg) require.NoError(c.t, err) @@ -56,6 +60,7 @@ func (c *TestChain) parseSDKResultData(r *sdk.Result) sdk.TxMsgData { return protoResult } +// ContractInfo is a helper function to returns the ContractInfo for the given contract address func (c *TestChain) ContractInfo(contractAddr sdk.AccAddress) *types.ContractInfo { return wasmd.NewTestSupport(c.t, c.App).WasmKeeper().GetContractInfo(c.GetContext(), contractAddr) } diff --git a/x/wasm/internal/keeper/ibc.go b/x/wasm/internal/keeper/ibc.go index 31d59fcfb1..8f3c50e951 100644 --- a/x/wasm/internal/keeper/ibc.go +++ b/x/wasm/internal/keeper/ibc.go @@ -4,9 +4,6 @@ import ( "strings" "github.com/CosmWasm/wasmd/x/wasm/internal/types" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" @@ -66,103 +63,3 @@ func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Cap func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { return k.capabilityKeeper.ClaimCapability(ctx, cap, name) } - -// IBCContractCallbacks defines the methods for go-cosmwasm to interact with the wasm contract. -// A mock contract would implement the interface to fully simulate a wasm contract's behaviour. -type IBCContractCallbacks interface { - // Package livecycle - - // IBCChannelOpen is available on IBC-enabled contracts and is a hook to call into - // during the handshake pahse - IBCChannelOpen( - codeID wasmvm.CodeID, - env wasmvmtypes.Env, - channel wasmvmtypes.IBCChannel, - store wasmvm.KVStore, - goapi wasmvm.GoAPI, - querier wasmvm.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - ) (uint64, error) - - // IBCChannelConnect is available on IBC-enabled contracts and is a hook to call into - // during the handshake pahse - IBCChannelConnect( - codeID wasmvm.CodeID, - env wasmvmtypes.Env, - channel wasmvmtypes.IBCChannel, - store wasmvm.KVStore, - goapi wasmvm.GoAPI, - querier wasmvm.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) - - // IBCChannelClose is available on IBC-enabled contracts and is a hook to call into - // at the end of the channel lifetime - IBCChannelClose( - codeID wasmvm.CodeID, - env wasmvmtypes.Env, - channel wasmvmtypes.IBCChannel, - store wasmvm.KVStore, - goapi wasmvm.GoAPI, - querier wasmvm.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - ) (*wasmvmtypes.IBCBasicResponse, 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 - IBCPacketReceive( - codeID wasmvm.CodeID, - env wasmvmtypes.Env, - packet wasmvmtypes.IBCPacket, - store wasmvm.KVStore, - goapi wasmvm.GoAPI, - querier wasmvm.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - ) (*wasmvmtypes.IBCReceiveResponse, uint64, error) - - // IBCPacketAck is available on IBC-enabled contracts and is called when an - // the response for an outgoing packet (previously sent by this contract) - // is received - IBCPacketAck( - codeID wasmvm.CodeID, - env wasmvmtypes.Env, - ack wasmvmtypes.IBCAcknowledgement, - store wasmvm.KVStore, - goapi wasmvm.GoAPI, - querier wasmvm.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) - - // IBCPacketTimeout is available on IBC-enabled contracts and is called when an - // outgoing packet (previously sent by this contract) will provably never be executed. - // Usually handled like ack returning an error - IBCPacketTimeout( - codeID wasmvm.CodeID, - env wasmvmtypes.Env, - packet wasmvmtypes.IBCPacket, - store wasmvm.KVStore, - goapi wasmvm.GoAPI, - querier wasmvm.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - ) (*wasmvmtypes.IBCBasicResponse, uint64, error) - - Execute( - code []byte, - env wasmvmtypes.Env, - info wasmvmtypes.MessageInfo, - executeMsg []byte, - store prefix.Store, - api wasmvm.GoAPI, - querier wasmvmtypes.Querier, - gasMeter wasmvm.GasMeter, - gasLimit uint64, - ) (*wasmvmtypes.HandleResponse, uint64, error) -} - -var MockContracts = make(map[string]IBCContractCallbacks, 0) diff --git a/x/wasm/internal/keeper/keeper.go b/x/wasm/internal/keeper/keeper.go index 24fd9f67b3..59af53e1e9 100644 --- a/x/wasm/internal/keeper/keeper.go +++ b/x/wasm/internal/keeper/keeper.go @@ -46,6 +46,11 @@ const CompileCost uint64 = 2 // constant value so all nodes run with the same limit. const contractMemoryLimit = 32 +// Option is an extension point to instantiate keeper with non default values +type Option interface { + apply(*Keeper) +} + // Keeper will have a reference to Wasmer with it's own data directory. type Keeper struct { storeKey sdk.StoreKey @@ -84,6 +89,7 @@ func NewKeeper( supportedFeatures string, customEncoders *MessageEncoders, customPlugins *QueryPlugins, + opts ...Option, ) Keeper { wasmer, err := wasmvm.NewVM(filepath.Join(homeDir, "wasm"), supportedFeatures, contractMemoryLimit, wasmConfig.ContractDebugMode, wasmConfig.MemoryCacheSize) if err != nil { @@ -112,6 +118,9 @@ func NewKeeper( paramSpace: paramSpace, } keeper.queryPlugins = DefaultQueryPlugins(bankKeeper, stakingKeeper, distKeeper, &keeper).Merge(customPlugins) + for _, o := range opts { + o.apply(&keeper) + } return keeper } @@ -164,17 +173,20 @@ func (k Keeper) create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, // return 0, sdkerrors.Wrap(err, "cosmwasm create") return 0, sdkerrors.Wrap(types.ErrCreateFailed, err.Error()) } - store := ctx.KVStore(k.storeKey) codeID = k.autoIncrementID(ctx, types.KeyLastCodeID) if instantiateAccess == nil { defaultAccessConfig := k.getInstantiateAccessConfig(ctx).With(creator) instantiateAccess = &defaultAccessConfig } codeInfo := types.NewCodeInfo(codeHash, creator, source, builder, *instantiateAccess) + k.storeCodeInfo(ctx, codeID, codeInfo) + return codeID, nil +} + +func (k Keeper) storeCodeInfo(ctx sdk.Context, codeID uint64, codeInfo types.CodeInfo) { + store := ctx.KVStore(k.storeKey) // 0x01 | codeID (uint64) -> ContractInfo store.Set(types.GetCodeKey(codeID), k.cdc.MustMarshalBinaryBare(&codeInfo)) - - return codeID, nil } func (k Keeper) importCode(ctx sdk.Context, codeID uint64, codeInfo types.CodeInfo, wasmCode []byte) error { @@ -325,28 +337,6 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller Plugins: k.queryPlugins, } gas := gasForContract(ctx) - // todo: stort of testing mock integration - mock, ok := MockContracts[contractAddress.String()] - if ok { - res, gasUsed, execErr := mock.Execute(codeInfo.CodeHash, env, info, msg, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gas) - consumeGas(ctx, gasUsed) - if execErr != nil { - return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) - } - - // emit all events from this contract itself - events := types.ParseEvents(res.Attributes, contractAddress) - ctx.EventManager().EmitEvents(events) - - if err := k.messenger.Dispatch(ctx, contractAddress, contractInfo.IBCPortID, res.Messages...); err != nil { - return nil, err - } - return &sdk.Result{ - Data: res.Data, - }, nil - } - // todo: end of testing mock integration - res, gasUsed, execErr := k.wasmer.Execute(codeInfo.CodeHash, env, info, msg, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gas) consumeGas(ctx, gasUsed) if execErr != nil { diff --git a/x/wasm/internal/keeper/keeper_test.go b/x/wasm/internal/keeper/keeper_test.go index 776eb29a4f..6e95a73fd1 100644 --- a/x/wasm/internal/keeper/keeper_test.go +++ b/x/wasm/internal/keeper/keeper_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "errors" + "github.com/CosmWasm/wasmd/x/wasm/internal/keeper/wasmtesting" "io/ioutil" "testing" "time" @@ -440,7 +441,7 @@ func TestInstantiateWithCallbackToContract(t *testing.T) { executeCalled bool err error ) - wasmerMock := selfCallingInstMockWasmer(&executeCalled) + wasmerMock := wasmtesting.SelfCallingInstMockWasmer(&executeCalled) keepers.WasmKeeper.wasmer = wasmerMock example := StoreHackatomExampleContract(t, ctx, keepers) diff --git a/x/wasm/internal/keeper/options.go b/x/wasm/internal/keeper/options.go new file mode 100644 index 0000000000..d7fb6b3acc --- /dev/null +++ b/x/wasm/internal/keeper/options.go @@ -0,0 +1,15 @@ +package keeper + +import "github.com/CosmWasm/wasmd/x/wasm/internal/types" + +type optsFn func(*Keeper) + +func (f optsFn) apply(keeper *Keeper) { + f(keeper) +} + +func WithWasmEngine(x types.WasmerEngine) Option { + return optsFn(func(k *Keeper) { + k.wasmer = x + }) +} diff --git a/x/wasm/internal/keeper/querier_test.go b/x/wasm/internal/keeper/querier_test.go index 3df85c2170..3fc00e8a5a 100644 --- a/x/wasm/internal/keeper/querier_test.go +++ b/x/wasm/internal/keeper/querier_test.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "github.com/CosmWasm/wasmd/x/wasm/internal/keeper/wasmtesting" "io/ioutil" "testing" @@ -150,7 +151,12 @@ func TestQuerySmartContractState(t *testing.T) { func TestQuerySmartContractPanics(t *testing.T) { ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil) - exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers) + contractAddr := contractAddress(1, 1) + keepers.WasmKeeper.storeCodeInfo(ctx, 1, types.CodeInfo{}) + keepers.WasmKeeper.storeContractInfo(ctx, contractAddr, &types.ContractInfo{ + CodeID: 1, + Created: types.NewAbsoluteTxPosition(ctx), + }) ctx = ctx.WithGasMeter(sdk.NewGasMeter(InstanceCost)).WithLogger(log.TestingLogger()) specs := map[string]struct { @@ -172,14 +178,14 @@ func TestQuerySmartContractPanics(t *testing.T) { } for msg, spec := range specs { t.Run(msg, func(t *testing.T) { - keepers.WasmKeeper.wasmer = &MockWasmer{QueryFn: func(code cosmwasm.CodeID, env wasmvmtypes.Env, queryMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) ([]byte, uint64, error) { + keepers.WasmKeeper.wasmer = &wasmtesting.MockWasmer{QueryFn: func(code cosmwasm.CodeID, env wasmvmtypes.Env, queryMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) ([]byte, uint64, error) { spec.doInContract() return nil, 0, nil }} // when q := NewQuerier(keepers.WasmKeeper) got, err := q.SmartContractState(sdk.WrapSDKContext(ctx), &types.QuerySmartContractStateRequest{ - Address: exampleContract.Contract.String(), + Address: contractAddr.String(), }) require.True(t, spec.expErr.Is(err), "got error: %+v", err) assert.Nil(t, got) diff --git a/x/wasm/internal/keeper/relay.go b/x/wasm/internal/keeper/relay.go index 816f6a0cc2..7d9989e96b 100644 --- a/x/wasm/internal/keeper/relay.go +++ b/x/wasm/internal/keeper/relay.go @@ -29,11 +29,7 @@ func (k Keeper) OnOpenChannel( } gas := gasForContract(ctx) - mock, ok := MockContracts[contractAddr.String()] - if !ok { // hack for testing without wasmer - panic("not supported") - } - gasUsed, execErr := mock.IBCChannelOpen(codeInfo.CodeHash, params, channel, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas) + gasUsed, execErr := k.wasmer.IBCChannelOpen(codeInfo.CodeHash, params, channel, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas) consumeGas(ctx, gasUsed) if execErr != nil { return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) @@ -65,11 +61,7 @@ func (k Keeper) OnConnectChannel( } gas := gasForContract(ctx) - mock, ok := MockContracts[contractAddr.String()] - if !ok { // hack for testing without wasmer - panic("not supported") - } - res, gasUsed, execErr := mock.IBCChannelConnect(codeInfo.CodeHash, params, channel, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas) + res, gasUsed, execErr := k.wasmer.IBCChannelConnect(codeInfo.CodeHash, params, channel, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas) consumeGas(ctx, gasUsed) if execErr != nil { return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) @@ -108,11 +100,7 @@ func (k Keeper) OnRecvPacket( } gas := gasForContract(ctx) - mock, ok := MockContracts[contractAddr.String()] - if !ok { // hack for testing without wasmer - panic("not supported") - } - res, gasUsed, execErr := mock.IBCPacketReceive(codeInfo.CodeHash, params, packet, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas) + res, gasUsed, execErr := k.wasmer.IBCPacketReceive(codeInfo.CodeHash, params, packet, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas) consumeGas(ctx, gasUsed) if execErr != nil { return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) @@ -152,11 +140,7 @@ func (k Keeper) OnAckPacket( } gas := gasForContract(ctx) - mock, ok := MockContracts[contractAddr.String()] // hack for testing without wasmer - if !ok { - panic("not supported") - } - res, gasUsed, execErr := mock.IBCPacketAck(codeInfo.CodeHash, params, acknowledgement, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas) + res, gasUsed, execErr := k.wasmer.IBCPacketAck(codeInfo.CodeHash, params, acknowledgement, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas) consumeGas(ctx, gasUsed) if execErr != nil { return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) @@ -191,11 +175,7 @@ func (k Keeper) OnTimeoutPacket( } gas := gasForContract(ctx) - mock, ok := MockContracts[contractAddr.String()] - if !ok { // hack for testing without wasmer - panic("not supported") - } - res, gasUsed, execErr := mock.IBCPacketTimeout(codeInfo.CodeHash, params, packet, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas) + res, gasUsed, execErr := k.wasmer.IBCPacketTimeout(codeInfo.CodeHash, params, packet, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas) consumeGas(ctx, gasUsed) if execErr != nil { return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) diff --git a/x/wasm/internal/keeper/test_common.go b/x/wasm/internal/keeper/test_common.go index 8fc0b44087..da9acf20ad 100644 --- a/x/wasm/internal/keeper/test_common.go +++ b/x/wasm/internal/keeper/test_common.go @@ -1,7 +1,6 @@ package keeper import ( - "bytes" "encoding/binary" "encoding/json" "fmt" @@ -10,8 +9,6 @@ import ( "time" "github.com/CosmWasm/wasmd/x/wasm/internal/types" - wasmvm "github.com/CosmWasm/wasmvm" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -500,138 +497,3 @@ func keyPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) { addr := sdk.AccAddress(pub.Address()) return key, pub, addr } - -var _ types.WasmerEngine = &MockWasmer{} - -// MockWasmer implements types.WasmerEngine for testing purpose. One or multiple messages can be stubbed. -// Without a stub function a panic is thrown. -type MockWasmer struct { - CreateFn func(code wasmvm.WasmCode) (wasmvm.CodeID, error) - InstantiateFn func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.InitResponse, wasmvmtypes.ContractFlags, uint64, error) - ExecuteFn func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.HandleResponse, uint64, error) - QueryFn func(code wasmvm.CodeID, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) ([]byte, uint64, error) - MigrateFn func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.MigrateResponse, uint64, error) - GetCodeFn func(code wasmvm.CodeID) (wasmvm.WasmCode, error) - CleanupFn func() - IBCChannelOpenFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (uint64, error) - IBCChannelConnectFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCChannelCloseFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCPacketReceiveFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCReceiveResponse, uint64, error) - IBCPacketAckFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, ack wasmvmtypes.IBCAcknowledgement, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) - IBCPacketTimeoutFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) -} - -func (m *MockWasmer) IBCChannelOpen(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (uint64, error) { - if m.IBCChannelOpenFn == nil { - panic("not supposed to be called!") - } - return m.IBCChannelOpenFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit) -} - -func (m *MockWasmer) IBCChannelConnect(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - if m.IBCChannelConnectFn == nil { - panic("not supposed to be called!") - } - return m.IBCChannelConnectFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit) -} - -func (m *MockWasmer) IBCChannelClose(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - if m.IBCChannelCloseFn == nil { - panic("not supposed to be called!") - } - return m.IBCChannelCloseFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit) -} - -func (m *MockWasmer) IBCPacketReceive(codeID wasmvm.CodeID, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCReceiveResponse, uint64, error) { - if m.IBCPacketReceiveFn == nil { - panic("not supposed to be called!") - } - return m.IBCPacketReceiveFn(codeID, env, packet, store, goapi, querier, gasMeter, gasLimit) -} - -func (m *MockWasmer) IBCPacketAck(codeID wasmvm.CodeID, env wasmvmtypes.Env, ack wasmvmtypes.IBCAcknowledgement, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - if m.IBCPacketAckFn == nil { - panic("not supposed to be called!") - } - return m.IBCPacketAckFn(codeID, env, ack, store, goapi, querier, gasMeter, gasLimit) -} - -func (m *MockWasmer) IBCPacketTimeout(codeID wasmvm.CodeID, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) { - if m.IBCPacketTimeoutFn == nil { - panic("not supposed to be called!") - } - return m.IBCPacketTimeoutFn(codeID, env, packet, store, goapi, querier, gasMeter, gasLimit) -} - -func (m *MockWasmer) Create(code wasmvm.WasmCode) (wasmvm.CodeID, error) { - if m.CreateFn == nil { - panic("not supposed to be called!") - } - return m.CreateFn(code) -} - -func (m *MockWasmer) Instantiate(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.InitResponse, wasmvmtypes.ContractFlags, uint64, error) { - if m.InstantiateFn == nil { - panic("not supposed to be called!") - } - return m.InstantiateFn(code, env, info, initMsg, store, goapi, querier, gasMeter, gasLimit) -} - -func (m *MockWasmer) Execute(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.HandleResponse, uint64, error) { - if m.ExecuteFn == nil { - panic("not supposed to be called!") - } - return m.ExecuteFn(code, env, info, executeMsg, store, goapi, querier, gasMeter, gasLimit) -} - -func (m *MockWasmer) Query(code wasmvm.CodeID, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) ([]byte, uint64, error) { - if m.QueryFn == nil { - panic("not supposed to be called!") - } - return m.QueryFn(code, env, queryMsg, store, goapi, querier, gasMeter, gasLimit) -} - -func (m *MockWasmer) Migrate(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.MigrateResponse, uint64, error) { - if m.MigrateFn == nil { - panic("not supposed to be called!") - } - return m.MigrateFn(code, env, info, migrateMsg, store, goapi, querier, gasMeter, gasLimit) -} - -func (m *MockWasmer) GetCode(code wasmvm.CodeID) (wasmvm.WasmCode, error) { - if m.GetCodeFn == nil { - panic("not supposed to be called!") - } - return m.GetCodeFn(code) -} - -func (m *MockWasmer) Cleanup() { - if m.CleanupFn == nil { - panic("not supposed to be called!") - } - m.CleanupFn() -} - -var alwaysPanicMockWasmer = &MockWasmer{} - -// selfCallingInstMockWasmer prepares a Wasmer mock that calls itself on instantiation. -func selfCallingInstMockWasmer(executeCalled *bool) *MockWasmer { - return &MockWasmer{ - - CreateFn: func(code wasmvm.WasmCode) (wasmvm.CodeID, error) { - anyCodeID := bytes.Repeat([]byte{0x1}, 32) - return anyCodeID, nil - }, - InstantiateFn: func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.InitResponse, wasmvmtypes.ContractFlags, uint64, error) { - return &wasmvmtypes.InitResponse{ - Messages: []wasmvmtypes.CosmosMsg{ - {Wasm: &wasmvmtypes.WasmMsg{Execute: &wasmvmtypes.ExecuteMsg{ContractAddr: env.Contract.Address, Msg: []byte(`{}`)}}}, - }, - }, wasmvmtypes.ContractFlags{}, 1, nil - }, - ExecuteFn: func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.HandleResponse, uint64, error) { - *executeCalled = true - return &wasmvmtypes.HandleResponse{}, 1, nil - }, - } -} diff --git a/x/wasm/internal/keeper/wasmtesting/mock_engine.go b/x/wasm/internal/keeper/wasmtesting/mock_engine.go new file mode 100644 index 0000000000..21424a74ac --- /dev/null +++ b/x/wasm/internal/keeper/wasmtesting/mock_engine.go @@ -0,0 +1,265 @@ +package wasmtesting + +import ( + "bytes" + "crypto/sha256" + "github.com/CosmWasm/wasmd/x/wasm/internal/types" + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +var _ types.WasmerEngine = &MockWasmer{} + +// MockWasmer implements types.WasmerEngine for testing purpose. One or multiple messages can be stubbed. +// Without a stub function a panic is thrown. +type MockWasmer struct { + CreateFn func(code wasmvm.WasmCode) (wasmvm.CodeID, error) + InstantiateFn func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.InitResponse, wasmvmtypes.ContractFlags, uint64, error) + ExecuteFn func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.HandleResponse, uint64, error) + QueryFn func(code wasmvm.CodeID, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) ([]byte, uint64, error) + MigrateFn func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.MigrateResponse, uint64, error) + GetCodeFn func(code wasmvm.CodeID) (wasmvm.WasmCode, error) + CleanupFn func() + IBCChannelOpenFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (uint64, error) + IBCChannelConnectFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCChannelCloseFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCPacketReceiveFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCReceiveResponse, uint64, error) + IBCPacketAckFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, ack wasmvmtypes.IBCAcknowledgement, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) + IBCPacketTimeoutFn func(codeID wasmvm.CodeID, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) +} + +func (m *MockWasmer) IBCChannelOpen(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (uint64, error) { + if m.IBCChannelOpenFn == nil { + panic("not supposed to be called!") + } + return m.IBCChannelOpenFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit) +} + +func (m *MockWasmer) IBCChannelConnect(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + if m.IBCChannelConnectFn == nil { + panic("not supposed to be called!") + } + return m.IBCChannelConnectFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit) +} + +func (m *MockWasmer) IBCChannelClose(codeID wasmvm.CodeID, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + if m.IBCChannelCloseFn == nil { + panic("not supposed to be called!") + } + return m.IBCChannelCloseFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit) +} + +func (m *MockWasmer) IBCPacketReceive(codeID wasmvm.CodeID, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCReceiveResponse, uint64, error) { + if m.IBCPacketReceiveFn == nil { + panic("not supposed to be called!") + } + return m.IBCPacketReceiveFn(codeID, env, packet, store, goapi, querier, gasMeter, gasLimit) +} + +func (m *MockWasmer) IBCPacketAck(codeID wasmvm.CodeID, env wasmvmtypes.Env, ack wasmvmtypes.IBCAcknowledgement, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + if m.IBCPacketAckFn == nil { + panic("not supposed to be called!") + } + return m.IBCPacketAckFn(codeID, env, ack, store, goapi, querier, gasMeter, gasLimit) +} + +func (m *MockWasmer) IBCPacketTimeout(codeID wasmvm.CodeID, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + if m.IBCPacketTimeoutFn == nil { + panic("not supposed to be called!") + } + return m.IBCPacketTimeoutFn(codeID, env, packet, store, goapi, querier, gasMeter, gasLimit) +} + +func (m *MockWasmer) Create(code wasmvm.WasmCode) (wasmvm.CodeID, error) { + if m.CreateFn == nil { + panic("not supposed to be called!") + } + return m.CreateFn(code) +} + +func (m *MockWasmer) Instantiate(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.InitResponse, wasmvmtypes.ContractFlags, uint64, error) { + if m.InstantiateFn == nil { + panic("not supposed to be called!") + } + return m.InstantiateFn(code, env, info, initMsg, store, goapi, querier, gasMeter, gasLimit) +} + +func (m *MockWasmer) Execute(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.HandleResponse, uint64, error) { + if m.ExecuteFn == nil { + panic("not supposed to be called!") + } + return m.ExecuteFn(code, env, info, executeMsg, store, goapi, querier, gasMeter, gasLimit) +} + +func (m *MockWasmer) Query(code wasmvm.CodeID, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) ([]byte, uint64, error) { + if m.QueryFn == nil { + panic("not supposed to be called!") + } + return m.QueryFn(code, env, queryMsg, store, goapi, querier, gasMeter, gasLimit) +} + +func (m *MockWasmer) Migrate(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.MigrateResponse, uint64, error) { + if m.MigrateFn == nil { + panic("not supposed to be called!") + } + return m.MigrateFn(code, env, info, migrateMsg, store, goapi, querier, gasMeter, gasLimit) +} + +func (m *MockWasmer) GetCode(code wasmvm.CodeID) (wasmvm.WasmCode, error) { + if m.GetCodeFn == nil { + panic("not supposed to be called!") + } + return m.GetCodeFn(code) +} + +func (m *MockWasmer) Cleanup() { + if m.CleanupFn == nil { + panic("not supposed to be called!") + } + m.CleanupFn() +} + +var AlwaysPanicMockWasmer = &MockWasmer{} + +// selfCallingInstMockWasmer prepares a Wasmer mock that calls itself on instantiation. +func SelfCallingInstMockWasmer(executeCalled *bool) *MockWasmer { + return &MockWasmer{ + + CreateFn: func(code wasmvm.WasmCode) (wasmvm.CodeID, error) { + anyCodeID := bytes.Repeat([]byte{0x1}, 32) + return anyCodeID, nil + }, + InstantiateFn: func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.InitResponse, wasmvmtypes.ContractFlags, uint64, error) { + return &wasmvmtypes.InitResponse{ + Messages: []wasmvmtypes.CosmosMsg{ + {Wasm: &wasmvmtypes.WasmMsg{Execute: &wasmvmtypes.ExecuteMsg{ContractAddr: env.Contract.Address, Msg: []byte(`{}`)}}}, + }, + }, wasmvmtypes.ContractFlags{}, 1, nil + }, + ExecuteFn: func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.HandleResponse, uint64, error) { + *executeCalled = true + return &wasmvmtypes.HandleResponse{}, 1, nil + }, + } +} + +// IBCContractCallbacks defines the methods from wasmvm to interact with the wasm contract. +// A mock contract would implement the interface to fully simulate a wasm contract's behaviour. +type IBCContractCallbacks interface { + IBCChannelOpen( + codeID wasmvm.CodeID, + env wasmvmtypes.Env, + channel wasmvmtypes.IBCChannel, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + ) (uint64, error) + + IBCChannelConnect( + codeID wasmvm.CodeID, + env wasmvmtypes.Env, + channel wasmvmtypes.IBCChannel, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + + IBCChannelClose( + codeID wasmvm.CodeID, + env wasmvmtypes.Env, + channel wasmvmtypes.IBCChannel, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + + IBCPacketReceive( + codeID wasmvm.CodeID, + env wasmvmtypes.Env, + packet wasmvmtypes.IBCPacket, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + ) (*wasmvmtypes.IBCReceiveResponse, uint64, error) + + IBCPacketAck( + codeID wasmvm.CodeID, + env wasmvmtypes.Env, + ack wasmvmtypes.IBCAcknowledgement, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + + IBCPacketTimeout( + codeID wasmvm.CodeID, + env wasmvmtypes.Env, + packet wasmvmtypes.IBCPacket, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + ) (*wasmvmtypes.IBCBasicResponse, uint64, error) +} + +type contractExecutable interface { + Execute( + code wasmvm.CodeID, + env wasmvmtypes.Env, + info wasmvmtypes.MessageInfo, + executeMsg []byte, + store wasmvm.KVStore, + goapi wasmvm.GoAPI, + querier wasmvm.Querier, + gasMeter wasmvm.GasMeter, + gasLimit uint64, + ) (*wasmvmtypes.HandleResponse, uint64, error) +} + +// NewIBCContractMockWasmer prepares a mocked wasm_engine for testing with an IBC contract test type. +// It is safe to use the mock with store code and instantiate functions in keeper as is also prepared +// with stubs. Execute is optional. When implemented by the Go test contract then it can be used with +// the mock. +func NewIBCContractMockWasmer(c IBCContractCallbacks) *MockWasmer { + m := &MockWasmer{ + IBCChannelOpenFn: c.IBCChannelOpen, + IBCChannelConnectFn: c.IBCChannelConnect, + IBCChannelCloseFn: c.IBCChannelClose, + IBCPacketReceiveFn: c.IBCPacketReceive, + IBCPacketAckFn: c.IBCPacketAck, + IBCPacketTimeoutFn: c.IBCPacketTimeout, + // add some noop functions to not fail when contract is used for instantiation + CreateFn: HashOnlyCreateFn, + InstantiateFn: NoOpInstantiateFn(wasmvmtypes.ContractFlags{IBCEnabled: true, Stargate: true}), + } + if e, ok := c.(contractExecutable); ok { // optional function + m.ExecuteFn = e.Execute + } + return m +} + +func HashOnlyCreateFn(code wasmvm.WasmCode) (wasmvm.CodeID, error) { + if code == nil { + return nil, sdkerrors.Wrap(types.ErrInvalid, "wasm code must not be nil") + } + hash := sha256.Sum256(code) + return hash[:], nil +} + +func NoOpInstantiateFn(flags wasmvmtypes.ContractFlags) func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.InitResponse, wasmvmtypes.ContractFlags, uint64, error) { + return func(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.InitResponse, wasmvmtypes.ContractFlags, uint64, error) { + return &wasmvmtypes.InitResponse{}, flags, 0, nil + } +} diff --git a/x/wasm/relay_pingpong_test.go b/x/wasm/relay_pingpong_test.go index 24fc42f7b8..9cad26fcd0 100644 --- a/x/wasm/relay_pingpong_test.go +++ b/x/wasm/relay_pingpong_test.go @@ -4,10 +4,10 @@ import ( "encoding/json" "fmt" wasmd "github.com/CosmWasm/wasmd/app" - wasmtesting "github.com/CosmWasm/wasmd/x/wasm/ibctesting" + wasmibctesting "github.com/CosmWasm/wasmd/x/wasm/ibctesting" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/internal/keeper" + "github.com/CosmWasm/wasmd/x/wasm/internal/keeper/wasmtesting" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/internal/types" - wasm "github.com/CosmWasm/wasmvm" wasmvm "github.com/CosmWasm/wasmvm" wasmvmtypes "github.com/CosmWasm/wasmvm/types" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -15,7 +15,6 @@ import ( clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types" channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types" ibcexported "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" - ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "testing" @@ -29,24 +28,34 @@ const ( var doNotTimeout = clienttypes.NewHeight(1, 1111111) func TestPinPong(t *testing.T) { + pingContract := &player{t: t, actor: ping} + pongContract := &player{t: t, actor: pong} + var ( - coordinator = wasmtesting.NewCoordinator(t, 2) - chainA = coordinator.GetChain(ibctesting.GetChainID(0)) - chainB = coordinator.GetChain(ibctesting.GetChainID(1)) + chainAOpts = []wasmkeeper.Option{wasmkeeper.WithWasmEngine( + wasmtesting.NewIBCContractMockWasmer(pingContract)), + } + chainBOpts = []wasmkeeper.Option{wasmkeeper.WithWasmEngine( + wasmtesting.NewIBCContractMockWasmer(pongContract), + )} + coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts, chainBOpts) + chainA = coordinator.GetChain(wasmibctesting.GetChainID(0)) + chainB = coordinator.GetChain(wasmibctesting.GetChainID(1)) ) coordinator.CommitBlock(chainA, chainB) - _ = chainB.NewRandomContractInstance() // skip 1 id + + _ = chainB.SeedNewContractInstance() // skip 1 instance so that addresses are not the same var ( - pingContractAddr = chainA.NewRandomContractInstance() - pongContractAddr = chainB.NewRandomContractInstance() + pingContractAddr = chainA.SeedNewContractInstance() + pongContractAddr = chainB.SeedNewContractInstance() ) require.NotEqual(t, pingContractAddr, pongContractAddr) - pingContract := &player{t: t, actor: ping, chain: chainA, contractAddr: pingContractAddr} - pongContract := &player{t: t, actor: pong, chain: chainB, contractAddr: pongContractAddr} + pingContract.chain = chainA + pingContract.contractAddr = pingContractAddr - wasmkeeper.MockContracts[pingContractAddr.String()] = pingContract - wasmkeeper.MockContracts[pongContractAddr.String()] = pongContract + pongContract.chain = chainB + pongContract.contractAddr = pongContractAddr var ( sourcePortID = wasmkeeper.PortIDForContract(pingContractAddr) @@ -123,12 +132,12 @@ func TestPinPong(t *testing.T) { } -var _ wasmkeeper.IBCContractCallbacks = &player{} +var _ wasmtesting.IBCContractCallbacks = &player{} // player is a (mock) contract that sends and receives ibc packages type player struct { t *testing.T - chain *wasmtesting.TestChain + chain *wasmibctesting.TestChain contractAddr sdk.AccAddress actor string // either ping or pong execCalls int // number of calls to Execute method (checkTx + deliverTx) @@ -136,14 +145,14 @@ type player struct { // Execute starts the ping pong game // Contracts finds all connected channels and broadcasts a ping message -func (p *player) Execute(hash []byte, params wasmvmtypes.Env, info wasmvmtypes.MessageInfo, data []byte, store prefix.Store, api wasmvm.GoAPI, querier wasmvmtypes.Querier, meter wasm.GasMeter, gas uint64) (*wasmvmtypes.HandleResponse, uint64, error) { +func (p *player) Execute(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.HandleResponse, uint64, error) { p.execCalls++ if p.execCalls%2 == 1 { // skip checkTx step because of no rollback with `chain.GetContext()` return &wasmvmtypes.HandleResponse{}, 0, nil } // start game var start startGame - if err := json.Unmarshal(data, &start); err != nil { + if err := json.Unmarshal(executeMsg, &start); err != nil { return nil, 0, err } diff --git a/x/wasm/relay_test.go b/x/wasm/relay_test.go index 60f8805def..4c8c7e208a 100644 --- a/x/wasm/relay_test.go +++ b/x/wasm/relay_test.go @@ -5,11 +5,10 @@ import ( wasmd "github.com/CosmWasm/wasmd/app" "github.com/CosmWasm/wasmd/x/wasm/ibctesting" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/internal/keeper" + wasmtesting "github.com/CosmWasm/wasmd/x/wasm/internal/keeper/wasmtesting" "github.com/CosmWasm/wasmd/x/wasm/internal/types" - "github.com/CosmWasm/wasmvm" wasmvm "github.com/CosmWasm/wasmvm" wasmvmtypes "github.com/CosmWasm/wasmvm/types" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ibctransfertypes "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types" @@ -23,17 +22,22 @@ import ( func TestFromIBCTransferToContract(t *testing.T) { // scenario: a contract can handle the receiving side of a ibc transfer + myContract := receiverContract{t: t} var ( - coordinator = ibctesting.NewCoordinator(t, 2) + chainAOpts = []wasmkeeper.Option{wasmkeeper.WithWasmEngine( + wasmtesting.NewIBCContractMockWasmer(&myContract), + )} + coordinator = ibctesting.NewCoordinator(t, 2, nil, chainAOpts) chainA = coordinator.GetChain(ibctesting.GetChainID(0)) chainB = coordinator.GetChain(ibctesting.GetChainID(1)) ) coordinator.CommitBlock(chainA, chainB) - myContractAddr := chainB.NewRandomContractInstance() - wasmkeeper.MockContracts[myContractAddr.String()] = &receiverContract{t: t, contractAddr: myContractAddr, chain: chainB} - + myContractAddr := chainB.SeedNewContractInstance() contractAPortID := chainB.ContractInfo(myContractAddr).IBCPortID + myContract.contractAddr = myContractAddr + myContract.chain = chainB + var ( sourcePortID = "transfer" counterpartPortID = contractAPortID @@ -72,16 +76,19 @@ func TestFromIBCTransferToContract(t *testing.T) { func TestContractCanUseIBCTransferMsg(t *testing.T) { // scenario: a contract can start an ibc transfer via ibctransfertypes.NewMsgTransfer // on an existing connection + myContract := &sendViaIBCTransferContract{t: t} + var ( - coordinator = ibctesting.NewCoordinator(t, 2) + chainAOpts = []wasmkeeper.Option{wasmkeeper.WithWasmEngine( + wasmtesting.NewIBCContractMockWasmer(myContract)), + } + coordinator = ibctesting.NewCoordinator(t, 2, chainAOpts, nil) chainA = coordinator.GetChain(ibctesting.GetChainID(0)) chainB = coordinator.GetChain(ibctesting.GetChainID(1)) ) coordinator.CommitBlock(chainA, chainB) - myContractAddr := chainA.NewRandomContractInstance() + myContractAddr := chainA.SeedNewContractInstance() coordinator.CommitBlock(chainA, chainB) - myContract := &sendViaIBCTransferContract{contractStub: contractStub{}, t: t} - wasmkeeper.MockContracts[myContractAddr.String()] = myContract var ( sourcePortID = ibctransfertypes.ModuleName @@ -126,21 +133,22 @@ func TestContractCanUseIBCTransferMsg(t *testing.T) { func TestContractCanEmulateIBCTransferMessage(t *testing.T) { // scenario: a contract can start an ibc transfer via ibctransfertypes.NewMsgTransfer // on an existing connection + myContract := &sendEmulatedIBCTransferContract{t: t} + var ( - coordinator = ibctesting.NewCoordinator(t, 2) - chainA = coordinator.GetChain(ibctesting.GetChainID(0)) - chainB = coordinator.GetChain(ibctesting.GetChainID(1)) + chainAOpts = []wasmkeeper.Option{wasmkeeper.WithWasmEngine( + wasmtesting.NewIBCContractMockWasmer(myContract)), + } + coordinator = ibctesting.NewCoordinator(t, 2, chainAOpts, nil) + + chainA = coordinator.GetChain(ibctesting.GetChainID(0)) + chainB = coordinator.GetChain(ibctesting.GetChainID(1)) ) coordinator.CommitBlock(chainA, chainB) - myContractAddr := chainA.NewRandomContractInstance() - coordinator.CommitBlock(chainA, chainB) - myContract := &sendEmulatedIBCTransferContract{contractStub: contractStub{}, t: t, contractAddr: myContractAddr.String()} - wasmkeeper.MockContracts[myContractAddr.String()] = myContract - - contractAPortID := chainA.ContractInfo(myContractAddr).IBCPortID - _ = contractAPortID + myContractAddr := chainA.SeedNewContractInstance() + myContract.contractAddr = myContractAddr.String() var ( - sourcePortID = contractAPortID + sourcePortID = chainA.ContractInfo(myContractAddr).IBCPortID counterpartPortID = ibctransfertypes.ModuleName ) @@ -161,7 +169,7 @@ func TestContractCanEmulateIBCTransferMessage(t *testing.T) { ChannelID: channelA.ID, CoinsToSend: coinToSendToB, ReceiverAddr: receiverAddress.String(), - ContractIBCPort: contractAPortID, + ContractIBCPort: chainA.ContractInfo(myContractAddr).IBCPortID, }.GetBytes(), } err := coordinator.SendMsg(chainA, chainB, clientB, startMsg) @@ -180,16 +188,16 @@ func TestContractCanEmulateIBCTransferMessage(t *testing.T) { assert.Equal(t, sdk.NewCoin(voucherDenom, coinToSendToB.Amount).String(), newBalance.String(), bankKeeperB.GetAllBalances(chainB.GetContext(), chainB.SenderAccount.GetAddress())) } -var _ wasmkeeper.IBCContractCallbacks = &sendViaIBCTransferContract{} +var _ wasmtesting.IBCContractCallbacks = &sendViaIBCTransferContract{} type sendViaIBCTransferContract struct { contractStub t *testing.T } -func (s *sendViaIBCTransferContract) Execute(hash []byte, params wasmvmtypes.Env, info wasmvmtypes.MessageInfo, data []byte, store prefix.Store, api cosmwasm.GoAPI, querier wasmvmtypes.Querier, meter wasmvm.GasMeter, gas uint64) (*wasmvmtypes.HandleResponse, uint64, error) { +func (s *sendViaIBCTransferContract) Execute(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.HandleResponse, uint64, error) { var in startTransfer - if err := json.Unmarshal(data, &in); err != nil { + if err := json.Unmarshal(executeMsg, &in); err != nil { return nil, 0, err } ibcMsg := &wasmvmtypes.IBCMsg{ @@ -207,7 +215,7 @@ func (s *sendViaIBCTransferContract) Execute(hash []byte, params wasmvmtypes.Env return &wasmvmtypes.HandleResponse{Messages: []wasmvmtypes.CosmosMsg{{IBC: ibcMsg}}}, 0, nil } -var _ wasmkeeper.IBCContractCallbacks = &sendEmulatedIBCTransferContract{} +var _ wasmtesting.IBCContractCallbacks = &sendEmulatedIBCTransferContract{} type sendEmulatedIBCTransferContract struct { contractStub @@ -215,9 +223,9 @@ type sendEmulatedIBCTransferContract struct { contractAddr string } -func (s *sendEmulatedIBCTransferContract) Execute(hash []byte, params wasmvmtypes.Env, info wasmvmtypes.MessageInfo, data []byte, store prefix.Store, api cosmwasm.GoAPI, querier wasmvmtypes.Querier, meter wasmvm.GasMeter, gas uint64) (*wasmvmtypes.HandleResponse, uint64, error) { +func (s *sendEmulatedIBCTransferContract) Execute(code wasmvm.CodeID, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.HandleResponse, uint64, error) { var in startTransfer - if err := json.Unmarshal(data, &in); err != nil { + if err := json.Unmarshal(executeMsg, &in); err != nil { return nil, 0, err } escrowAddress := ibctransfertypes.GetEscrowAddress(in.ContractIBCPort, in.ChannelID) @@ -263,7 +271,7 @@ func (g startTransfer) GetBytes() json.RawMessage { return b } -var _ wasmkeeper.IBCContractCallbacks = &receiverContract{} +var _ wasmtesting.IBCContractCallbacks = &receiverContract{} // receiverContract receives an IBC transfer type receiverContract struct { @@ -328,9 +336,6 @@ func (c *receiverContract) IBCPacketAck(codeID wasmvm.CodeID, env wasmvmtypes.En func (c *receiverContract) IBCPacketTimeout(codeID wasmvm.CodeID, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) { panic("implement me") } -func (c *receiverContract) Execute(hash []byte, params wasmvmtypes.Env, info wasmvmtypes.MessageInfo, data []byte, store prefix.Store, api cosmwasm.GoAPI, querier wasmvmtypes.Querier, meter wasmvm.GasMeter, gas uint64) (*wasmvmtypes.HandleResponse, uint64, error) { - panic("implement me") -} // simple helpber struct that implements connection setup methods. type contractStub struct{}