diff --git a/app/ante.go b/app/ante.go index 937f87fb9a..e5dd75a938 100644 --- a/app/ante.go +++ b/app/ante.go @@ -4,8 +4,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" - ibcante "github.com/cosmos/ibc-go/v3/modules/core/ante" - "github.com/cosmos/ibc-go/v3/modules/core/keeper" + ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante" + "github.com/cosmos/ibc-go/v4/modules/core/keeper" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" diff --git a/app/app.go b/app/app.go index 048c33f651..aa4d5742cf 100644 --- a/app/app.go +++ b/app/app.go @@ -74,24 +74,27 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - ica "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts" - icacontroller "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller" - icacontrollerkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/keeper" - icacontrollertypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/controller/types" - icahost "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host" - icahostkeeper "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/keeper" - icahosttypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v3/modules/apps/27-interchain-accounts/types" - transfer "github.com/cosmos/ibc-go/v3/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v3/modules/core" - ibcclient "github.com/cosmos/ibc-go/v3/modules/core/02-client" - ibcclientclient "github.com/cosmos/ibc-go/v3/modules/core/02-client/client" - ibcclienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" + ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" + icacontroller "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller" + icacontrollerkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/keeper" + icacontrollertypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/controller/types" + icahost "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host" + icahostkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/keeper" + icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + ibcfee "github.com/cosmos/ibc-go/v4/modules/apps/29-fee" + ibcfeekeeper "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/keeper" + ibcfeetypes "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + transfer "github.com/cosmos/ibc-go/v4/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v4/modules/core" + ibcclient "github.com/cosmos/ibc-go/v4/modules/core/02-client" + ibcclientclient "github.com/cosmos/ibc-go/v4/modules/core/02-client/client" + ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" // Note: please do your research before using this in production app, this is a demo and not an officially // supported IBC team implementation. It has no known issues, but do your own research before using it. @@ -207,6 +210,7 @@ var ( wasm.AppModuleBasic{}, ica.AppModuleBasic{}, intertx.AppModuleBasic{}, + ibcfee.AppModuleBasic{}, ) // module account permissions @@ -218,6 +222,7 @@ var ( stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, govtypes.ModuleName: {authtypes.Burner}, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + ibcfeetypes.ModuleName: nil, icatypes.ModuleName: nil, wasm.ModuleName: {authtypes.Burner}, } @@ -256,6 +261,7 @@ type WasmApp struct { ParamsKeeper paramskeeper.Keeper EvidenceKeeper evidencekeeper.Keeper IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + IBCFeeKeeper ibcfeekeeper.Keeper ICAControllerKeeper icacontrollerkeeper.Keeper ICAHostKeeper icahostkeeper.Keeper InterTxKeeper intertxkeeper.Keeper @@ -269,6 +275,7 @@ type WasmApp struct { ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper ScopedInterTxKeeper capabilitykeeper.ScopedKeeper ScopedTransferKeeper capabilitykeeper.ScopedKeeper + ScopedIBCFeeKeeper capabilitykeeper.ScopedKeeper ScopedWasmKeeper capabilitykeeper.ScopedKeeper // the module manager @@ -308,7 +315,8 @@ func NewWasmApp( minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, - feegrant.StoreKey, authzkeeper.StoreKey, wasm.StoreKey, icahosttypes.StoreKey, icacontrollertypes.StoreKey, intertxtypes.StoreKey, + feegrant.StoreKey, authzkeeper.StoreKey, wasm.StoreKey, icahosttypes.StoreKey, + icacontrollertypes.StoreKey, intertxtypes.StoreKey, ibcfeetypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -444,20 +452,26 @@ func NewWasmApp( AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)). AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)) + // IBC Fee Module keeper + app.IBCFeeKeeper = ibcfeekeeper.NewKeeper( + appCodec, keys[ibcfeetypes.StoreKey], app.getSubspace(ibcfeetypes.ModuleName), + app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, + ) + // Create Transfer Keepers app.TransferKeeper = ibctransferkeeper.NewKeeper( appCodec, keys[ibctransfertypes.StoreKey], app.getSubspace(ibctransfertypes.ModuleName), - app.IBCKeeper.ChannelKeeper, + app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, ) - transferModule := transfer.NewAppModule(app.TransferKeeper) - transferIBCModule := transfer.NewIBCModule(app.TransferKeeper) app.ICAHostKeeper = icahostkeeper.NewKeeper( appCodec, @@ -473,23 +487,15 @@ func NewWasmApp( appCodec, keys[icacontrollertypes.StoreKey], app.getSubspace(icacontrollertypes.SubModuleName), - app.IBCKeeper.ChannelKeeper, // may be replaced with middleware such as ics29 fee + app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, scopedICAControllerKeeper, app.MsgServiceRouter(), ) - icaModule := ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper) - icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) // For wasmd we use the demo controller from https://github.com/cosmos/interchain-accounts but see notes below app.InterTxKeeper = intertxkeeper.NewKeeper(appCodec, keys[intertxtypes.StoreKey], app.ICAControllerKeeper, scopedInterTxKeeper) - // Note: please do your research before using this in production app, this is a demo and not an officially - // supported IBC team implementation. Do your own research before using it. - interTxModule := intertx.NewAppModule(appCodec, app.InterTxKeeper) - interTxIBCModule := intertx.NewIBCModule(app.InterTxKeeper) - // You will likely want to swap out the second argument with your own reviewed and maintained ica auth module - icaControllerIBCModule := icacontroller.NewIBCModule(app.ICAControllerKeeper, interTxIBCModule) // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( @@ -529,19 +535,46 @@ func NewWasmApp( wasmOpts..., ) - // Create static IBC router, add app routes, then set and seal it - ibcRouter := porttypes.NewRouter() - // The gov proposal types can be individually enabled if len(enabledProposals) != 0 { govRouter.AddRoute(wasm.RouterKey, wasm.NewWasmProposalHandler(app.WasmKeeper, enabledProposals)) } - ibcRouter. - AddRoute(wasm.ModuleName, wasm.NewIBCHandler(app.WasmKeeper, app.IBCKeeper.ChannelKeeper)). - AddRoute(ibctransfertypes.ModuleName, transferIBCModule). - AddRoute(icacontrollertypes.SubModuleName, icaControllerIBCModule). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). - AddRoute(intertxtypes.ModuleName, icaControllerIBCModule) + + // Create Transfer Stack + var transferStack porttypes.IBCModule + transferStack = transfer.NewIBCModule(app.TransferKeeper) + transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) + + // Create Interchain Accounts Stack + // SendPacket, since it is originating from the application to core IBC: + // icaAuthModuleKeeper.SendTx -> icaController.SendPacket -> fee.SendPacket -> channel.SendPacket + + // Note: please do your research before using this in production app, this is a demo and not an officially + // supported IBC team implementation. Do your own research before using it. + var icaControllerStack porttypes.IBCModule + // You will likely want to use your own reviewed and maintained ica auth module + icaControllerStack = intertx.NewIBCModule(app.InterTxKeeper) + icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) + icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) + + // RecvPacket, message that originates from core IBC and goes down to app, the flow is: + // channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket + var icaHostStack porttypes.IBCModule + icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) + icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) + + // Create fee enabled wasm ibc Stack + var wasmStack porttypes.IBCModule + wasmStack = wasm.NewIBCHandler(app.WasmKeeper, app.IBCKeeper.ChannelKeeper, app.IBCFeeKeeper) + wasmStack = ibcfee.NewIBCMiddleware(wasmStack, app.IBCFeeKeeper) + + // Create static IBC router, add app routes, then set and seal it + ibcRouter := porttypes.NewRouter(). + AddRoute(ibctransfertypes.ModuleName, transferStack). + AddRoute(wasm.ModuleName, wasmStack). + AddRoute(intertxtypes.ModuleName, icaControllerStack). + AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). + AddRoute(icahosttypes.SubModuleName, icaHostStack) app.IBCKeeper.SetRouter(ibcRouter) app.GovKeeper = govkeeper.NewKeeper( @@ -584,9 +617,10 @@ func NewWasmApp( authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry), ibc.NewAppModule(app.IBCKeeper), params.NewAppModule(app.ParamsKeeper), - transferModule, - icaModule, - interTxModule, + transfer.NewAppModule(app.TransferKeeper), + ibcfee.NewAppModule(app.IBCFeeKeeper), + ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper), + intertx.NewAppModule(appCodec, app.InterTxKeeper), crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), // always be last to make sure that it checks for all invariants and not only part of them ) @@ -615,6 +649,7 @@ func NewWasmApp( ibctransfertypes.ModuleName, ibchost.ModuleName, icatypes.ModuleName, + ibcfeetypes.ModuleName, intertxtypes.ModuleName, wasm.ModuleName, ) @@ -640,6 +675,7 @@ func NewWasmApp( ibctransfertypes.ModuleName, ibchost.ModuleName, icatypes.ModuleName, + ibcfeetypes.ModuleName, intertxtypes.ModuleName, wasm.ModuleName, ) @@ -672,6 +708,7 @@ func NewWasmApp( ibctransfertypes.ModuleName, ibchost.ModuleName, icatypes.ModuleName, + ibcfeetypes.ModuleName, intertxtypes.ModuleName, // wasm after ibc transfer wasm.ModuleName, @@ -705,7 +742,7 @@ func NewWasmApp( evidence.NewAppModule(app.EvidenceKeeper), wasm.NewAppModule(appCodec, &app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), ibc.NewAppModule(app.IBCKeeper), - transferModule, + transfer.NewAppModule(app.TransferKeeper), ) app.sm.RegisterStoreDecoders() diff --git a/app/sim_test.go b/app/sim_test.go index e80c6fcae7..5e206064e6 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -28,8 +28,8 @@ import ( "github.com/cosmos/cosmos-sdk/x/simulation" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" diff --git a/app/test_access.go b/app/test_access.go index d992a89602..51b8bb9939 100644 --- a/app/test_access.go +++ b/app/test_access.go @@ -12,8 +12,8 @@ import ( bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" - ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" - ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" + ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" "github.com/CosmWasm/wasmd/x/wasm" ) diff --git a/app/test_helpers.go b/app/test_helpers.go index d15e155560..8c3e8c11e5 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -97,7 +97,7 @@ func Setup(isCheckTx bool, opts ...wasm.Option) *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, opts []wasm.Option, balances ...banktypes.Balance) *WasmApp { +func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, chainID string, opts []wasm.Option, balances ...banktypes.Balance) *WasmApp { app, genesisState := setup(t, true, 5, opts...) // set genesis accounts authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) @@ -106,7 +106,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) - bondAmt := sdk.NewInt(1000000) + bondAmt := sdk.TokensFromConsensusPower(1, sdk.DefaultPowerReduction) for _, val := range valSet.Validators { pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) @@ -126,30 +126,30 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), MinSelfDelegation: sdk.ZeroInt(), } + validators = append(validators, validator) delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec())) - } // set validators and delegations - stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations) - genesisState[stakingtypes.ModuleName] = app.appCodec.MustMarshalJSON(stakingGenesis) + var stakingGenesis stakingtypes.GenesisState + app.AppCodec().MustUnmarshalJSON(genesisState[stakingtypes.ModuleName], &stakingGenesis) - totalSupply := sdk.NewCoins() - for _, b := range balances { - // add genesis acc tokens and delegated tokens to total supply - totalSupply = totalSupply.Add(b.Coins.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))...) - } + bondDenom := stakingGenesis.Params.BondDenom // add bonded amount to bonded pool module account balances = append(balances, banktypes.Balance{ Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), - Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)}, + Coins: sdk.Coins{sdk.NewCoin(bondDenom, bondAmt.Mul(sdk.NewInt(int64(len(valSet.Validators)))))}, }) + // set validators and delegations + stakingGenesis = *stakingtypes.NewGenesisState(stakingGenesis.Params, validators, delegations) + genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(&stakingGenesis) + // update total supply - bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{}) - genesisState[banktypes.ModuleName] = app.appCodec.MustMarshalJSON(bankGenesis) + bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(), []banktypes.Metadata{}) + genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) stateBytes, err := json.MarshalIndent(genesisState, "", " ") require.NoError(t, err) @@ -157,6 +157,7 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs // init chain will set the validator set and initialize the genesis accounts app.InitChain( abci.RequestInitChain{ + ChainId: chainID, Validators: []abci.ValidatorUpdate{}, ConsensusParams: DefaultConsensusParams, AppStateBytes: stateBytes, @@ -165,12 +166,17 @@ func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs // commit genesis changes app.Commit() - app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{ - Height: app.LastBlockHeight() + 1, - AppHash: app.LastCommitID().Hash, - ValidatorsHash: valSet.Hash(), - NextValidatorsHash: valSet.Hash(), - }}) + app.BeginBlock( + abci.RequestBeginBlock{ + Header: tmproto.Header{ + ChainID: chainID, + Height: app.LastBlockHeight() + 1, + AppHash: app.LastCommitID().Hash, + ValidatorsHash: valSet.Hash(), + NextValidatorsHash: valSet.Hash(), + }, + }, + ) return app } @@ -380,10 +386,6 @@ func SignAndDeliver( // Simulate a sending a transaction and committing a block app.BeginBlock(abci.RequestBeginBlock{Header: header}) gInfo, res, err := app.Deliver(txCfg.TxEncoder(), tx) - - app.EndBlock(abci.RequestEndBlock{}) - app.Commit() - return gInfo, res, err } diff --git a/go.mod b/go.mod index 81f0ea1e6a..6eb36be99c 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/cosmos/cosmos-sdk v0.45.11 github.com/cosmos/gogoproto v1.4.3 github.com/cosmos/iavl v0.19.4 - github.com/cosmos/ibc-go/v3 v3.3.1 - github.com/cosmos/interchain-accounts v0.1.0 + github.com/cosmos/ibc-go/v4 v4.2.0 + github.com/cosmos/interchain-accounts v0.2.4 github.com/dvsekhvalnov/jose2go v1.5.0 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 diff --git a/go.sum b/go.sum index ae438b7c41..a2fe53b4a0 100644 --- a/go.sum +++ b/go.sum @@ -175,10 +175,10 @@ github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4 github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cosmos/iavl v0.19.4 h1:t82sN+Y0WeqxDLJRSpNd8YFX5URIrT+p8n6oJbJ2Dok= github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= -github.com/cosmos/ibc-go/v3 v3.3.1 h1:i8o3iPSPN8fr7AjCPQnHEKz/VfeMrxc8mjvgAw6txWk= -github.com/cosmos/ibc-go/v3 v3.3.1/go.mod h1:V1nliDk/5q5KWr0mup7M76oN4SY0IOU371SKbCV2wN0= -github.com/cosmos/interchain-accounts v0.1.0 h1:QmuwNsf1Hxl3P5GSGt7Z+JeuHPiZw4Z34R/038P5T6s= -github.com/cosmos/interchain-accounts v0.1.0/go.mod h1:Fv6LXDs+0ng4mIDVWwEJMXbAIMxY4kiq+A7Bw1Fb9AY= +github.com/cosmos/ibc-go/v4 v4.2.0 h1:Fx/kKq/uvawrAxk6ZrQ6sEIgffLRU5Cs/AUnvpPBrHI= +github.com/cosmos/ibc-go/v4 v4.2.0/go.mod h1:57qWScDtfCx3FOMLYmBIKPbOLE6xiVhrgxHAQmbWYXM= +github.com/cosmos/interchain-accounts v0.2.4 h1:7UrroFQsCRSp17980mk6anx4YteveIJVkU+a0wlsHQI= +github.com/cosmos/interchain-accounts v0.2.4/go.mod h1:jeiJEb0zg609G0oCrCG0r6Guhb7YbA1uFiwww/1YgZE= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= diff --git a/tests/e2e/ibc_fees_test.go b/tests/e2e/ibc_fees_test.go new file mode 100644 index 0000000000..fa315ffe60 --- /dev/null +++ b/tests/e2e/ibc_fees_test.go @@ -0,0 +1,214 @@ +package e2e + +import ( + "bytes" + "encoding/base64" + "fmt" + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + ibcfee "github.com/cosmos/ibc-go/v4/modules/apps/29-fee/types" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/CosmWasm/wasmd/app" + wasmibctesting "github.com/CosmWasm/wasmd/x/wasm/ibctesting" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" +) + +func TestIBCFeesTransfer(t *testing.T) { + // scenario: + // given 2 chains + // with an ics-20 channel established + // when an ics-29 fee is attached to an ibc package + // then the relayer's payee is receiving the fee(s) on success + marshaler := app.MakeEncodingConfig().Marshaler + coord := wasmibctesting.NewCoordinator(t, 2) + chainA := coord.GetChain(ibctesting.GetChainID(0)) + chainB := coord.GetChain(ibctesting.GetChainID(1)) + + actorChainA := sdk.AccAddress(chainA.SenderPrivKey.PubKey().Address()) + actorChainB := sdk.AccAddress(chainB.SenderPrivKey.PubKey().Address()) + receiver := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len)) + payee := sdk.AccAddress(bytes.Repeat([]byte{2}, address.Len)) + oneToken := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))) + + path := wasmibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: ibctransfertypes.PortID, + Version: string(marshaler.MustMarshalJSON(&ibcfee.Metadata{FeeVersion: ibcfee.Version, AppVersion: ibctransfertypes.Version})), + Order: channeltypes.UNORDERED, + } + path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: ibctransfertypes.PortID, + Version: string(marshaler.MustMarshalJSON(&ibcfee.Metadata{FeeVersion: ibcfee.Version, AppVersion: ibctransfertypes.Version})), + Order: channeltypes.UNORDERED, + } + // with an ics-20 transfer channel setup between both chains + coord.Setup(path) + require.True(t, chainA.App.IBCFeeKeeper.IsFeeEnabled(chainA.GetContext(), ibctransfertypes.PortID, path.EndpointA.ChannelID)) + // and with a payee registered on both chains + _, err := chainA.SendMsgs(ibcfee.NewMsgRegisterPayee(ibctransfertypes.PortID, path.EndpointA.ChannelID, actorChainA.String(), payee.String())) + require.NoError(t, err) + _, err = chainB.SendMsgs(ibcfee.NewMsgRegisterCounterpartyPayee(ibctransfertypes.PortID, path.EndpointB.ChannelID, actorChainB.String(), payee.String())) + require.NoError(t, err) + + // when a transfer package is sent + transferCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1)) + ibcPayloadMsg := ibctransfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, transferCoin, actorChainA.String(), receiver.String(), clienttypes.Height{}, uint64(time.Now().Add(time.Minute).UnixNano())) + ibcPackageFee := ibcfee.NewFee(oneToken, oneToken, sdk.Coins{}) + feeMsg := ibcfee.NewMsgPayPacketFee(ibcPackageFee, ibctransfertypes.PortID, path.EndpointA.ChannelID, actorChainA.String(), nil) + _, err = chainA.SendMsgs(feeMsg, ibcPayloadMsg) + require.NoError(t, err) + pendingIncentivisedPackages := chainA.App.IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(chainA.GetContext(), ibctransfertypes.PortID, path.EndpointA.ChannelID) + assert.Len(t, pendingIncentivisedPackages, 1) + + // and packages relayed + require.NoError(t, coord.RelayAndAckPendingPackets(path)) + + // then + expBalance := ibctransfertypes.GetTransferCoin(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, transferCoin.Denom, transferCoin.Amount) + gotBalance := chainB.Balance(receiver, expBalance.Denom) + assert.Equal(t, expBalance.String(), gotBalance.String()) + payeeBalance := chainA.AllBalances(payee) + assert.Equal(t, oneToken.Add(oneToken...).String(), payeeBalance.String()) + + // and with a payee registered for chain B to A + _, err = chainA.SendMsgs(ibcfee.NewMsgRegisterCounterpartyPayee(ibctransfertypes.PortID, path.EndpointA.ChannelID, actorChainA.String(), payee.String())) + require.NoError(t, err) + _, err = chainB.SendMsgs(ibcfee.NewMsgRegisterPayee(ibctransfertypes.PortID, path.EndpointB.ChannelID, actorChainB.String(), payee.String())) + require.NoError(t, err) + + // and transfer from B to A + ibcPayloadMsg = ibctransfertypes.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, transferCoin, actorChainB.String(), receiver.String(), clienttypes.Height{}, uint64(time.Now().Add(time.Minute).UnixNano())) + ibcPackageFee = ibcfee.NewFee(oneToken, oneToken, sdk.Coins{}) + feeMsg = ibcfee.NewMsgPayPacketFee(ibcPackageFee, ibctransfertypes.PortID, path.EndpointB.ChannelID, actorChainB.String(), nil) + _, err = chainB.SendMsgs(feeMsg, ibcPayloadMsg) + require.NoError(t, err) + pendingIncentivisedPackages = chainB.App.IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(chainB.GetContext(), ibctransfertypes.PortID, path.EndpointB.ChannelID) + assert.Len(t, pendingIncentivisedPackages, 1) + + // when packages relayed + require.NoError(t, coord.RelayAndAckPendingPackets(path)) + + // then + expBalance = ibctransfertypes.GetTransferCoin(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, transferCoin.Denom, transferCoin.Amount) + gotBalance = chainA.Balance(receiver, expBalance.Denom) + assert.Equal(t, expBalance.String(), gotBalance.String()) + payeeBalance = chainB.AllBalances(payee) + assert.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2)).String(), payeeBalance.String()) +} + +func TestIBCFeesWasm(t *testing.T) { + // scenario: + // given 2 chains with cw20-ibc on chain A and native ics20 module on B + // and an ibc channel established + // when an ics-29 fee is attached to an ibc package + // then the relayer's payee is receiving the fee(s) on success + marshaler := app.MakeEncodingConfig().Marshaler + coord := wasmibctesting.NewCoordinator(t, 2) + chainA := coord.GetChain(ibctesting.GetChainID(0)) + chainB := coord.GetChain(ibctesting.GetChainID(1)) + actorChainA := sdk.AccAddress(chainA.SenderPrivKey.PubKey().Address()) + actorChainB := sdk.AccAddress(chainB.SenderPrivKey.PubKey().Address()) + + // setup chain A + codeID := chainA.StoreCodeFile("./testdata/cw20_base.wasm.gz").CodeID + + initMsg := []byte(fmt.Sprintf(`{"decimals": 6, "name": "test", "symbol":"ALX", "initial_balances": [{"address": %q,"amount":"100000000"}] }`, actorChainA.String())) + cw20ContractAddr := chainA.InstantiateContract(codeID, initMsg) + + initMsg = []byte(fmt.Sprintf(`{"default_timeout": 360, "gov_contract": %q, "allowlist":[{"contract":%q}]}`, actorChainA.String(), cw20ContractAddr.String())) + codeID = chainA.StoreCodeFile("./testdata/cw20_ics20.wasm.gz").CodeID + ibcContractAddr := chainA.InstantiateContract(codeID, initMsg) + ibcContractPortID := chainA.ContractInfo(ibcContractAddr).IBCPortID + + payee := sdk.AccAddress(bytes.Repeat([]byte{2}, address.Len)) + oneToken := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))) + + path := wasmibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: ibcContractPortID, + Version: string(marshaler.MustMarshalJSON(&ibcfee.Metadata{FeeVersion: ibcfee.Version, AppVersion: ibctransfertypes.Version})), + Order: channeltypes.UNORDERED, + } + path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: ibctransfertypes.PortID, + Version: string(marshaler.MustMarshalJSON(&ibcfee.Metadata{FeeVersion: ibcfee.Version, AppVersion: ibctransfertypes.Version})), + Order: channeltypes.UNORDERED, + } + // with an ics-29 fee enabled channel setup between both chains + coord.Setup(path) + require.True(t, chainA.App.IBCFeeKeeper.IsFeeEnabled(chainA.GetContext(), ibcContractPortID, path.EndpointA.ChannelID)) + require.True(t, chainB.App.IBCFeeKeeper.IsFeeEnabled(chainB.GetContext(), ibctransfertypes.PortID, path.EndpointB.ChannelID)) + // and with a payee registered for A -> B + _, err := chainA.SendMsgs(ibcfee.NewMsgRegisterPayee(ibcContractPortID, path.EndpointA.ChannelID, actorChainA.String(), payee.String())) + require.NoError(t, err) + _, err = chainB.SendMsgs(ibcfee.NewMsgRegisterCounterpartyPayee(ibctransfertypes.PortID, path.EndpointB.ChannelID, actorChainB.String(), payee.String())) + require.NoError(t, err) + + // when a transfer package is sent from ics20 contract on A to B + transfer := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`{"channel": %q, "remote_address": %q}`, path.EndpointA.ChannelID, actorChainB.String()))) + exec := []byte(fmt.Sprintf(`{"send":{"contract": %q, "amount": "100", "msg": %q}}`, ibcContractAddr.String(), transfer)) + execMsg := wasmtypes.MsgExecuteContract{ + Sender: actorChainA.String(), + Contract: cw20ContractAddr.String(), + Msg: exec, + } + ibcPackageFee := ibcfee.NewFee(oneToken, oneToken, sdk.Coins{}) + feeMsg := ibcfee.NewMsgPayPacketFee(ibcPackageFee, ibcContractPortID, path.EndpointA.ChannelID, actorChainA.String(), nil) + _, err = chainA.SendMsgs(feeMsg, &execMsg) + require.NoError(t, err) + pendingIncentivisedPackages := chainA.App.IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(chainA.GetContext(), ibcContractPortID, path.EndpointA.ChannelID) + assert.Len(t, pendingIncentivisedPackages, 1) + + // and packages relayed + require.NoError(t, coord.RelayAndAckPendingPackets(path)) + + // then + // on chain A + gotCW20Balance, err := chainA.App.WasmKeeper.QuerySmart(chainA.GetContext(), cw20ContractAddr, []byte(fmt.Sprintf(`{"balance":{"address": %q}}`, actorChainA.String()))) + require.NoError(t, err) + assert.JSONEq(t, `{"balance":"99999900"}`, string(gotCW20Balance)) + payeeBalance := chainA.AllBalances(payee) + assert.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2)).String(), payeeBalance.String()) + // and on chain B + pendingIncentivisedPackages = chainA.App.IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(chainA.GetContext(), ibcContractPortID, path.EndpointA.ChannelID) + assert.Len(t, pendingIncentivisedPackages, 0) + expBalance := ibctransfertypes.GetTransferCoin(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, "cw20:"+cw20ContractAddr.String(), sdk.NewInt(100)) + gotBalance := chainB.Balance(actorChainB, expBalance.Denom) + assert.Equal(t, expBalance.String(), gotBalance.String(), chainB.AllBalances(actorChainB)) + + // and with a payee registered for chain B to A + _, err = chainA.SendMsgs(ibcfee.NewMsgRegisterCounterpartyPayee(ibcContractPortID, path.EndpointA.ChannelID, actorChainA.String(), payee.String())) + require.NoError(t, err) + _, err = chainB.SendMsgs(ibcfee.NewMsgRegisterPayee(ibctransfertypes.PortID, path.EndpointB.ChannelID, actorChainB.String(), payee.String())) + require.NoError(t, err) + + // and when sent back from chain B to A + ibcPayloadMsg := ibctransfertypes.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, gotBalance, actorChainB.String(), actorChainA.String(), clienttypes.Height{}, uint64(time.Now().Add(time.Minute).UnixNano())) + ibcPackageFee = ibcfee.NewFee(oneToken, oneToken, sdk.Coins{}) + feeMsg = ibcfee.NewMsgPayPacketFee(ibcPackageFee, ibctransfertypes.PortID, path.EndpointB.ChannelID, actorChainB.String(), nil) + _, err = chainB.SendMsgs(feeMsg, ibcPayloadMsg) + require.NoError(t, err) + pendingIncentivisedPackages = chainB.App.IBCFeeKeeper.GetIdentifiedPacketFeesForChannel(chainB.GetContext(), ibctransfertypes.PortID, path.EndpointB.ChannelID) + assert.Len(t, pendingIncentivisedPackages, 1) + + // when packages relayed + require.NoError(t, coord.RelayAndAckPendingPackets(path)) + + // then + // on chain A + gotCW20Balance, err = chainA.App.WasmKeeper.QuerySmart(chainA.GetContext(), cw20ContractAddr, []byte(fmt.Sprintf(`{"balance":{"address": %q}}`, actorChainA.String()))) + require.NoError(t, err) + assert.JSONEq(t, `{"balance":"100000000"}`, string(gotCW20Balance)) + // and on chain B + payeeBalance = chainB.AllBalances(payee) + assert.Equal(t, sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2)).String(), payeeBalance.String()) +} diff --git a/tests/e2e/ica_test.go b/tests/e2e/ica_test.go new file mode 100644 index 0000000000..24c0623611 --- /dev/null +++ b/tests/e2e/ica_test.go @@ -0,0 +1,91 @@ +package e2e + +import ( + "bytes" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + hosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + intertxtypes "github.com/cosmos/interchain-accounts/x/inter-tx/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + wasmibctesting "github.com/CosmWasm/wasmd/x/wasm/ibctesting" +) + +func TestICA(t *testing.T) { + // scenario: + // given a host and controller chain + // when an ica is registered on the controller chain + // and the channel is established to the host chain + // then the ICA owner can submit a message via IBC + // to control their account on the host chain + coord := wasmibctesting.NewCoordinator(t, 2) + hostChain := coord.GetChain(ibctesting.GetChainID(0)) + hostParams := hosttypes.NewParams(true, []string{sdk.MsgTypeURL(&banktypes.MsgSend{})}) + hostChain.App.ICAHostKeeper.SetParams(hostChain.GetContext(), hostParams) + + controllerChain := coord.GetChain(ibctesting.GetChainID(1)) + + path := wasmibctesting.NewPath(controllerChain, hostChain) + coord.SetupConnections(path) + + ownerAddr := sdk.AccAddress(controllerChain.SenderPrivKey.PubKey().Address()) + msg := intertxtypes.NewMsgRegisterAccount(ownerAddr.String(), path.EndpointA.ConnectionID, "") + res, err := controllerChain.SendMsgs(msg) + chanID, portID, version := parseIBCChannelEvents(t, res) + + // next open channels on both sides + path.EndpointA.ChannelID = chanID + path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: portID, + Version: version, + Order: channeltypes.ORDERED, + } + path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: icatypes.PortID, + Version: icatypes.Version, + Order: channeltypes.ORDERED, + } + coord.CreateChannels(path) + + // assert ICA exists on controller + icaRsp, err := controllerChain.App.InterTxKeeper.InterchainAccount(sdk.WrapSDKContext(controllerChain.GetContext()), &intertxtypes.QueryInterchainAccountRequest{ + Owner: ownerAddr.String(), + ConnectionId: path.EndpointA.ConnectionID, + }) + require.NoError(t, err) + icaAddr := sdk.MustAccAddressFromBech32(icaRsp.InterchainAccountAddress) + hostChain.Fund(icaAddr, sdk.NewInt(1_000)) + + // submit a tx + targetAddr := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len)) + sendCoin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100)) + payloadMsg := banktypes.NewMsgSend(icaAddr, targetAddr, sdk.NewCoins(sendCoin)) + msg2, err := intertxtypes.NewMsgSubmitTx(payloadMsg, path.EndpointA.ConnectionID, ownerAddr.String()) + require.NoError(t, err) + res, err = controllerChain.SendMsgs(msg2) + require.NoError(t, err) + + assert.Equal(t, 1, len(controllerChain.PendingSendPackets)) + require.NoError(t, coord.RelayAndAckPendingPackets(path)) + + gotBalance := hostChain.Balance(targetAddr, sdk.DefaultBondDenom) + assert.Equal(t, sendCoin.String(), gotBalance.String()) +} + +func parseIBCChannelEvents(t *testing.T, res *sdk.Result) (string, string, string) { + t.Helper() + chanID, err := ibctesting.ParseChannelIDFromEvents(res.GetEvents()) + require.NoError(t, err) + portID, err := wasmibctesting.ParsePortIDFromEvents(res.GetEvents()) + require.NoError(t, err) + version, err := wasmibctesting.ParseChannelVersionFromEvents(res.GetEvents()) + require.NoError(t, err) + return chanID, portID, version +} diff --git a/tests/e2e/testdata/cw20_base.wasm.gz b/tests/e2e/testdata/cw20_base.wasm.gz new file mode 100644 index 0000000000..7745e80f6d Binary files /dev/null and b/tests/e2e/testdata/cw20_base.wasm.gz differ diff --git a/tests/e2e/testdata/cw20_ics20.wasm.gz b/tests/e2e/testdata/cw20_ics20.wasm.gz new file mode 100644 index 0000000000..07517a2fb5 Binary files /dev/null and b/tests/e2e/testdata/cw20_ics20.wasm.gz differ diff --git a/x/wasm/ibc.go b/x/wasm/ibc.go index 7e76f6e9a9..2843d13b2c 100644 --- a/x/wasm/ibc.go +++ b/x/wasm/ibc.go @@ -3,28 +3,34 @@ package wasm import ( "math" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" - wasmvmtypes "github.com/CosmWasm/wasmvm/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v3/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" - types "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/CosmWasm/wasmd/x/wasm/types" ) var _ porttypes.IBCModule = IBCHandler{} +// internal interface that is implemented by ibc middleware +type appVersionGetter interface { + // GetAppVersion returns the application level version with all middleware data stripped out + GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) +} + type IBCHandler struct { - keeper types.IBCContractKeeper - channelKeeper types.ChannelKeeper + keeper types.IBCContractKeeper + channelKeeper types.ChannelKeeper + appVersionGetter appVersionGetter } -func NewIBCHandler(k types.IBCContractKeeper, ck types.ChannelKeeper) IBCHandler { - return IBCHandler{keeper: k, channelKeeper: ck} +func NewIBCHandler(k types.IBCContractKeeper, ck types.ChannelKeeper, vg appVersionGetter) IBCHandler { + return IBCHandler{keeper: k, channelKeeper: ck, appVersionGetter: vg} } // OnChanOpenInit implements the IBCModule interface @@ -37,14 +43,14 @@ func (i IBCHandler) OnChanOpenInit( chanCap *capabilitytypes.Capability, counterParty channeltypes.Counterparty, version string, -) error { +) (string, error) { // ensure port, version, capability if err := ValidateChannelParams(channelID); err != nil { - return err + return "", err } contractAddr, err := ContractFromPortID(portID) if err != nil { - return sdkerrors.Wrapf(err, "contract port id") + return "", sdkerrors.Wrapf(err, "contract port id") } msg := wasmvmtypes.IBCChannelOpenMsg{ @@ -59,15 +65,21 @@ func (i IBCHandler) OnChanOpenInit( }, }, } - _, err = i.keeper.OnOpenChannel(ctx, contractAddr, msg) + + // Allow contracts to return a version (or default to proposed version if unset) + acceptedVersion, err := i.keeper.OnOpenChannel(ctx, contractAddr, msg) if err != nil { - return err + return "", err + } + if acceptedVersion == "" { + acceptedVersion = version } + // Claim channel capability passed back by IBC module if err := i.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return sdkerrors.Wrap(err, "claim capability") + return "", sdkerrors.Wrap(err, "claim capability") } - return nil + return acceptedVersion, nil } // OnChanOpenTry implements the IBCModule interface @@ -114,8 +126,8 @@ func (i IBCHandler) OnChanOpenTry( // Module may have already claimed capability in OnChanOpenInit in the case of crossing hellos // (ie chainA and chainB both call ChanOpenInit before one of them calls ChanOpenTry) - // If module can already authenticate the capability then module already owns it so we don't need to claim - // Otherwise, module does not have channel capability and we must claim it from IBC + // If module can already authenticate the capability then module already owns it, so we don't need to claim + // Otherwise, module does not have channel capability, and we must claim it from IBC if !i.keeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { // Only claim channel capability passed back by IBC module if we do not already own it if err := i.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { @@ -148,9 +160,15 @@ func (i IBCHandler) OnChanOpenAck( // OnChanOpenAck entry point) // https://github.com/cosmos/ibc-go/pull/647/files#diff-54b5be375a2333c56f2ae1b5b4dc13ac9c734561e30286505f39837ee75762c7R25 i.channelKeeper.SetChannel(ctx, portID, channelID, channelInfo) + + appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID) + } + msg := wasmvmtypes.IBCChannelConnectMsg{ OpenAck: &wasmvmtypes.IBCOpenAck{ - Channel: toWasmVMChannel(portID, channelID, channelInfo), + Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion), CounterpartyVersion: counterpartyVersion, }, } @@ -167,9 +185,13 @@ func (i IBCHandler) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) if !ok { return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) } + appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID) + } msg := wasmvmtypes.IBCChannelConnectMsg{ OpenConfirm: &wasmvmtypes.IBCOpenConfirm{ - Channel: toWasmVMChannel(portID, channelID, channelInfo), + Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion), }, } return i.keeper.OnConnectChannel(ctx, contractAddr, msg) @@ -185,9 +207,13 @@ func (i IBCHandler) OnChanCloseInit(ctx sdk.Context, portID, channelID string) e if !ok { return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) } + appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID) + } msg := wasmvmtypes.IBCChannelCloseMsg{ - CloseInit: &wasmvmtypes.IBCCloseInit{Channel: toWasmVMChannel(portID, channelID, channelInfo)}, + CloseInit: &wasmvmtypes.IBCCloseInit{Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion)}, } err = i.keeper.OnCloseChannel(ctx, contractAddr, msg) if err != nil { @@ -209,9 +235,13 @@ func (i IBCHandler) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string if !ok { return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) } + appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID) + } msg := wasmvmtypes.IBCChannelCloseMsg{ - CloseConfirm: &wasmvmtypes.IBCCloseConfirm{Channel: toWasmVMChannel(portID, channelID, channelInfo)}, + CloseConfirm: &wasmvmtypes.IBCCloseConfirm{Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion)}, } err = i.keeper.OnCloseChannel(ctx, contractAddr, msg) if err != nil { @@ -222,12 +252,12 @@ func (i IBCHandler) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string return err } -func toWasmVMChannel(portID, channelID string, channelInfo channeltypes.Channel) wasmvmtypes.IBCChannel { +func toWasmVMChannel(portID, channelID string, channelInfo channeltypes.Channel, appVersion string) wasmvmtypes.IBCChannel { return wasmvmtypes.IBCChannel{ Endpoint: wasmvmtypes.IBCEndpoint{PortID: portID, ChannelID: channelID}, CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{PortID: channelInfo.Counterparty.PortId, ChannelID: channelInfo.Counterparty.ChannelId}, Order: channelInfo.Ordering.String(), - Version: channelInfo.Version, + Version: appVersion, ConnectionID: channelInfo.ConnectionHops[0], // At the moment this list must be of length 1. In the future multi-hop channels may be supported. } } @@ -240,12 +270,12 @@ func (i IBCHandler) OnRecvPacket( ) ibcexported.Acknowledgement { contractAddr, err := ContractFromPortID(packet.DestinationPort) if err != nil { - return channeltypes.NewErrorAcknowledgement(sdkerrors.Wrapf(err, "contract port id").Error()) + return channeltypes.NewErrorAcknowledgement(sdkerrors.Wrapf(err, "contract port id")) } msg := wasmvmtypes.IBCPacketReceiveMsg{Packet: newIBCPacket(packet), Relayer: relayer.String()} ack, err := i.keeper.OnRecvPacket(ctx, contractAddr, msg) if err != nil { - return channeltypes.NewErrorAcknowledgement(err.Error()) + return channeltypes.NewErrorAcknowledgement(err) } return ContractConfirmStateAck(ack) } diff --git a/x/wasm/ibc_integration_test.go b/x/wasm/ibc_integration_test.go new file mode 100644 index 0000000000..3df273b206 --- /dev/null +++ b/x/wasm/ibc_integration_test.go @@ -0,0 +1,126 @@ +package wasm_test + +import ( + "testing" + + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + wasmibctesting "github.com/CosmWasm/wasmd/x/wasm/ibctesting" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting" +) + +func TestOnChanOpenInitVersion(t *testing.T) { + const startVersion = "v1" + specs := map[string]struct { + contractRsp *wasmvmtypes.IBC3ChannelOpenResponse + expVersion string + }{ + "different version": { + contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{Version: "v2"}, + expVersion: "v2", + }, + "no response": { + expVersion: startVersion, + }, + "empty result": { + contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{}, + expVersion: startVersion, + }, + } + 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 + }, + } + var ( + chainAOpts = []wasmkeeper.Option{ + wasmkeeper.WithWasmEngine( + wasmtesting.NewIBCContractMockWasmer(myContract)), + } + coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts) + chainA = coordinator.GetChain(wasmibctesting.GetChainID(0)) + chainB = coordinator.GetChain(wasmibctesting.GetChainID(1)) + myContractAddr = chainA.SeedNewContractInstance() + contractInfo = chainA.App.WasmKeeper.GetContractInfo(chainA.GetContext(), myContractAddr) + ) + + path := wasmibctesting.NewPath(chainA, chainB) + coordinator.SetupConnections(path) + + path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: contractInfo.IBCPortID, + Version: startVersion, + Order: channeltypes.UNORDERED, + } + require.NoError(t, path.EndpointA.ChanOpenInit()) + assert.Equal(t, spec.expVersion, path.EndpointA.ChannelConfig.Version) + }) + } +} + +func TestOnChanOpenTryVersion(t *testing.T) { + const startVersion = ibctransfertypes.Version + specs := map[string]struct { + contractRsp *wasmvmtypes.IBC3ChannelOpenResponse + expVersion string + }{ + "different version": { + contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{Version: "v2"}, + expVersion: "v2", + }, + "no response": { + expVersion: startVersion, + }, + "empty result": { + contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{}, + expVersion: startVersion, + }, + } + 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 + }, + } + var ( + chainAOpts = []wasmkeeper.Option{ + wasmkeeper.WithWasmEngine( + wasmtesting.NewIBCContractMockWasmer(myContract)), + } + coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts) + chainA = coordinator.GetChain(wasmibctesting.GetChainID(0)) + chainB = coordinator.GetChain(wasmibctesting.GetChainID(1)) + myContractAddr = chainA.SeedNewContractInstance() + contractInfo = chainA.ContractInfo(myContractAddr) + ) + + path := wasmibctesting.NewPath(chainA, chainB) + coordinator.SetupConnections(path) + + path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: contractInfo.IBCPortID, + Version: startVersion, + Order: channeltypes.UNORDERED, + } + path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: ibctransfertypes.PortID, + Version: ibctransfertypes.Version, + Order: channeltypes.UNORDERED, + } + + require.NoError(t, path.EndpointB.ChanOpenInit()) + require.NoError(t, path.EndpointA.ChanOpenTry()) + assert.Equal(t, spec.expVersion, path.EndpointA.ChannelConfig.Version) + }) + } +} diff --git a/x/wasm/ibc_reflect_test.go b/x/wasm/ibc_reflect_test.go index 16a10c8b74..2103878147 100644 --- a/x/wasm/ibc_reflect_test.go +++ b/x/wasm/ibc_reflect_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/assert" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" wasmvmtypes "github.com/CosmWasm/wasmvm/types" "github.com/stretchr/testify/require" diff --git a/x/wasm/ibc_test.go b/x/wasm/ibc_test.go index 767ccbe9aa..ee63c7fb02 100644 --- a/x/wasm/ibc_test.go +++ b/x/wasm/ibc_test.go @@ -4,8 +4,8 @@ import ( "testing" wasmvmtypes "github.com/CosmWasm/wasmvm/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" "github.com/stretchr/testify/assert" ) diff --git a/x/wasm/ibctesting/chain.go b/x/wasm/ibctesting/chain.go index fb24372d8a..abb6607bfa 100644 --- a/x/wasm/ibctesting/chain.go +++ b/x/wasm/ibctesting/chain.go @@ -1,7 +1,6 @@ package ibctesting import ( - "bytes" "fmt" "testing" "time" @@ -18,14 +17,15 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/cosmos-sdk/x/staking/teststaking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - "github.com/cosmos/ibc-go/v3/modules/core/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v3/testing/mock" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/cosmos/ibc-go/v4/testing/mock" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/tmhash" @@ -36,10 +36,16 @@ import ( "github.com/CosmWasm/wasmd/app" "github.com/CosmWasm/wasmd/app/params" - "github.com/CosmWasm/wasmd/x/wasm" ) +var MaxAccounts = 10 + +type SenderAccount struct { + SenderPrivKey cryptotypes.PrivKey + SenderAccount authtypes.AccountI +} + // TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI // header and the validators of the TestChain. It also contains a field called ChainID. This // is the clientID that *other* chains use to refer to this TestChain. The SenderAccount @@ -57,14 +63,22 @@ type TestChain struct { TxConfig client.TxConfig Codec codec.BinaryCodec - Vals *tmtypes.ValidatorSet - Signers []tmtypes.PrivValidator + Vals *tmtypes.ValidatorSet + NextVals *tmtypes.ValidatorSet - SenderPrivKey cryptotypes.PrivKey - SenderAccount authtypes.AccountI + // Signers is a map from validator address to the PrivValidator + // The map is converted into an array that is the same order as the validators right before signing commit + // This ensures that signers will always be in correct order even as validator powers change. + // If a test adds a new validator after chain creation, then the signer map must be updated to include + // the new PrivValidator entry. + Signers map[string]tmtypes.PrivValidator + + // autogenerated sender private key + SenderPrivKey cryptotypes.PrivKey + SenderAccount authtypes.AccountI + SenderAccounts []SenderAccount PendingSendPackets []channeltypes.Packet - PendingAckPackets []PacketAck } type PacketAck struct { @@ -72,37 +86,77 @@ type PacketAck struct { Ack []byte } -// NewTestChain initializes a new TestChain instance with a single validator set using a -// generated private key. It also creates a sender account to be used for delivering transactions. +// NewTestChain initializes a new test chain with a default of 4 validators +// Use this function if the tests do not need custom control over the validator set +func NewTestChain(t *testing.T, coord *Coordinator, chainID string, opts ...wasm.Option) *TestChain { + // generate validators private/public key + var ( + validatorsPerChain = 4 + validators = make([]*tmtypes.Validator, 0, validatorsPerChain) + signersByAddress = make(map[string]tmtypes.PrivValidator, validatorsPerChain) + ) + + for i := 0; i < validatorsPerChain; i++ { + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + require.NoError(t, err) + validators = append(validators, tmtypes.NewValidator(pubKey, 1)) + signersByAddress[pubKey.Address().String()] = privVal + } + + // construct validator set; + // Note that the validators are sorted by voting power + // or, if equal, by address lexical order + valSet := tmtypes.NewValidatorSet(validators) + + return NewTestChainWithValSet(t, coord, chainID, valSet, signersByAddress, opts...) +} + +// NewTestChainWithValSet initializes a new TestChain instance with the given validator set +// and signer array. It also initializes 10 Sender accounts with a balance of 10000000000000000000 coins of +// bond denom to use for tests. // // The first block height is committed to state in order to allow for client creations on // counterparty chains. The TestChain will return with a block height starting at 2. // // 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, coord *Coordinator, chainID string, opts ...wasm.Option) *TestChain { - // generate validator private/public key - privVal := mock.NewPV() - pubKey, err := privVal.GetPubKey() - require.NoError(t, err) - - // create validator set with single validator - validator := tmtypes.NewValidator(pubKey, 1) - valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - signers := []tmtypes.PrivValidator{privVal} - - // generate genesis account - senderPrivKey := secp256k1.GenPrivKey() - acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) - amount, ok := sdk.NewIntFromString("10000000000000000000") - require.True(t, ok) - - balance := banktypes.Balance{ - Address: acc.GetAddress().String(), - Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), +// +// NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this +// constructor function. +// +// CONTRACT: Validator array must be provided in the order expected by Tendermint. +// i.e. sorted first by power and then lexicographically by address. +func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, valSet *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator, opts ...wasm.Option) *TestChain { + genAccs := []authtypes.GenesisAccount{} + genBals := []banktypes.Balance{} + senderAccs := []SenderAccount{} + + // generate genesis accounts + for i := 0; i < MaxAccounts; i++ { + senderPrivKey := secp256k1.GenPrivKey() + acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), uint64(i), 0) + amount, ok := sdk.NewIntFromString("10000000000000000000") + require.True(t, ok) + + // add sender account + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), + } + + genAccs = append(genAccs, acc) + genBals = append(genBals, balance) + + senderAcc := SenderAccount{ + SenderAccount: acc, + SenderPrivKey: senderPrivKey, + } + + senderAccs = append(senderAccs, senderAcc) } - wasmApp := app.SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, opts, balance) + wasmApp := app.SetupWithGenesisValSet(t, valSet, genAccs, chainID, opts, genBals...) // create current header and call begin block header := tmproto.Header{ @@ -115,18 +169,20 @@ func NewTestChain(t *testing.T, coord *Coordinator, chainID string, opts ...wasm // create an account to send transactions from chain := &TestChain{ - t: t, - Coordinator: coord, - ChainID: chainID, - App: wasmApp, - CurrentHeader: header, - QueryServer: wasmApp.IBCKeeper, - TxConfig: txConfig, - Codec: wasmApp.AppCodec(), - Vals: valSet, - Signers: signers, - SenderPrivKey: senderPrivKey, - SenderAccount: acc, + t: t, + Coordinator: coord, + ChainID: chainID, + App: wasmApp, + CurrentHeader: header, + QueryServer: wasmApp.IBCKeeper, + TxConfig: txConfig, + Codec: wasmApp.AppCodec(), + Vals: valSet, + NextVals: valSet, + Signers: signers, + SenderPrivKey: senderAccs[0].SenderPrivKey, + SenderAccount: senderAccs[0].SenderAccount, + SenderAccounts: senderAccs, } coord.CommitBlock(chain) @@ -207,13 +263,24 @@ func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clien // NextBlock sets the last header to the current header and increments the current header to be // at the next block height. It does not update the time as that is handled by the Coordinator. -// -// CONTRACT: this function must only be called after app.Commit() occurs +// It will call Endblock and Commit and apply the validator set changes to the next validators +// of the next block being created. This follows the Tendermint protocol of applying valset changes +// returned on block `n` to the validators of block `n+2`. +// It calls BeginBlock with the new block created before returning. func (chain *TestChain) NextBlock() { + res := chain.App.EndBlock(abci.RequestEndBlock{Height: chain.CurrentHeader.Height}) + + chain.App.Commit() + // set the last header to the current header // use nil trusted fields chain.LastHeader = chain.CurrentTMClientHeader() + // val set changes returned from previous block get applied to the next validators + // of this block. See tendermint spec for details. + chain.Vals = chain.NextVals + chain.NextVals = ibctesting.ApplyValSetChanges(chain.t, chain.Vals, res.ValidatorUpdates) + // increment the current header chain.CurrentHeader = tmproto.Header{ ChainID: chain.ChainID, @@ -223,7 +290,7 @@ func (chain *TestChain) NextBlock() { // chains. Time: chain.CurrentHeader.Time, ValidatorsHash: chain.Vals.Hash(), - NextValidatorsHash: chain.Vals.Hash(), + NextValidatorsHash: chain.NextVals.Hash(), } chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) @@ -254,7 +321,7 @@ func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) { chain.SenderPrivKey, ) - // SignAndDeliver calls app.Commit() + // NextBlock calls app.Commit() chain.NextBlock() if err != nil { return r, err @@ -279,11 +346,6 @@ func (chain *TestChain) captureIBCEvents(r *sdk.Result) { // Keep a queue on the chain that we can relay in tests chain.PendingSendPackets = append(chain.PendingSendPackets, toSend...) } - toAck := getAckPackets(r.Events) - if len(toAck) > 0 { - // Keep a queue on the chain that we can relay in tests - chain.PendingAckPackets = append(chain.PendingAckPackets, toAck...) - } } // GetClientState retrieves the client state for the provided clientID. The client is @@ -387,12 +449,12 @@ func (chain *TestChain) ExpireClient(amount time.Duration) { // CurrentTMClientHeader creates a TM header using the current header parameters // on the chain. The trusted fields in the header are set to nil. func (chain *TestChain) CurrentTMClientHeader() *ibctmtypes.Header { - return chain.CreateTMClientHeader(chain.ChainID, chain.CurrentHeader.Height, clienttypes.Height{}, chain.CurrentHeader.Time, chain.Vals, nil, chain.Signers) + return chain.CreateTMClientHeader(chain.ChainID, chain.CurrentHeader.Height, clienttypes.Height{}, chain.CurrentHeader.Time, chain.Vals, chain.NextVals, nil, chain.Signers) } // CreateTMClientHeader creates a TM header to update the TM client. Args are passed in to allow // caller flexibility to use params that differ from the chain. -func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, tmTrustedVals *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) *ibctmtypes.Header { +func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, nextVals, tmTrustedVals *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *ibctmtypes.Header { var ( valSet *tmproto.ValidatorSet trustedVals *tmproto.ValidatorSet @@ -400,6 +462,7 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, require.NotNil(chain.t, tmValSet) vsetHash := tmValSet.Hash() + nextValHash := nextVals.Hash() tmHeader := tmtypes.Header{ Version: tmprotoversion.Consensus{Block: tmversion.BlockProtocol, App: 2}, @@ -410,18 +473,27 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, LastCommitHash: chain.App.LastCommitID().Hash, DataHash: tmhash.Sum([]byte("data_hash")), ValidatorsHash: vsetHash, - NextValidatorsHash: vsetHash, + NextValidatorsHash: nextValHash, ConsensusHash: tmhash.Sum([]byte("consensus_hash")), AppHash: chain.CurrentHeader.AppHash, LastResultsHash: tmhash.Sum([]byte("last_results_hash")), EvidenceHash: tmhash.Sum([]byte("evidence_hash")), ProposerAddress: tmValSet.Proposer.Address, //nolint:staticcheck } + hhash := tmHeader.Hash() blockID := MakeBlockID(hhash, 3, tmhash.Sum([]byte("part_set"))) voteSet := tmtypes.NewVoteSet(chainID, blockHeight, 1, tmproto.PrecommitType, tmValSet) - commit, err := tmtypes.MakeCommit(blockID, blockHeight, 1, voteSet, signers, timestamp) + // MakeCommit expects a signer array in the same order as the validator array. + // Thus we iterate over the ordered validator set and construct a signer array + // from the signer map in the same order. + signerArr := make([]tmtypes.PrivValidator, len(tmValSet.Validators)) + for i, v := range tmValSet.Validators { + signerArr[i] = signers[v.Address.String()] + } + + commit, err := tmtypes.MakeCommit(blockID, blockHeight, 1, voteSet, signerArr, timestamp) require.NoError(chain.t, err) signedHeader := &tmproto.SignedHeader{ @@ -430,15 +502,11 @@ func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, } valSet, err = tmValSet.ToProto() - if err != nil { - panic(err) - } + require.NoError(chain.t, err) if tmTrustedVals != nil { trustedVals, err = tmTrustedVals.ToProto() - if err != nil { - panic(err) - } + require.NoError(chain.t, err) } // The trusted fields may be nil. They may be filled before relaying messages to a client. @@ -462,29 +530,9 @@ func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) tmtypes.Bl } } -// CreateSortedSignerArray takes two PrivValidators, and the corresponding Validator structs -// (including voting power). It returns a signer array of PrivValidators that matches the -// sorting of ValidatorSet. -// The sorting is first by .VotingPower (descending), with secondary index of .Address (ascending). -func CreateSortedSignerArray(altPrivVal, suitePrivVal tmtypes.PrivValidator, - altVal, suiteVal *tmtypes.Validator, -) []tmtypes.PrivValidator { - switch { - case altVal.VotingPower > suiteVal.VotingPower: - return []tmtypes.PrivValidator{altPrivVal, suitePrivVal} - case altVal.VotingPower < suiteVal.VotingPower: - return []tmtypes.PrivValidator{suitePrivVal, altPrivVal} - default: - if bytes.Compare(altVal.Address, suiteVal.Address) == -1 { - return []tmtypes.PrivValidator{altPrivVal, suitePrivVal} - } - return []tmtypes.PrivValidator{suitePrivVal, altPrivVal} - } -} - // CreatePortCapability binds and claims a capability for the given portID if it does not // already exist. This function will fail testing on any resulting error. -// NOTE: only creation of a capbility for a transfer or mock port is supported +// NOTE: only creation of a capability for a transfer or mock port is supported // Other applications must bind to the port in InitGenesis or modify this code. func (chain *TestChain) CreatePortCapability(scopedKeeper capabilitykeeper.ScopedKeeper, portID string) { // check if the portId is already binded, if not bind it @@ -499,8 +547,6 @@ func (chain *TestChain) CreatePortCapability(scopedKeeper capabilitykeeper.Scope require.NoError(chain.t, err) } - chain.App.Commit() - chain.NextBlock() } @@ -527,8 +573,6 @@ func (chain *TestChain) CreateChannelCapability(scopedKeeper capabilitykeeper.Sc require.NoError(chain.t, err) } - chain.App.Commit() - chain.NextBlock() } diff --git a/x/wasm/ibctesting/coordinator.go b/x/wasm/ibctesting/coordinator.go index ed85a4e786..9ceadc0a76 100644 --- a/x/wasm/ibctesting/coordinator.go +++ b/x/wasm/ibctesting/coordinator.go @@ -6,9 +6,9 @@ import ( "testing" "time" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v4/testing" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -191,7 +191,6 @@ func GetChainID(index int) string { // CONTRACT: the passed in list of indexes must not contain duplicates func (coord *Coordinator) CommitBlock(chains ...*TestChain) { for _, chain := range chains { - chain.App.Commit() chain.NextBlock() } coord.IncrementTime() @@ -201,7 +200,6 @@ func (coord *Coordinator) CommitBlock(chains ...*TestChain) { func (coord *Coordinator) CommitNBlocks(chain *TestChain, n uint64) { for i := uint64(0); i < n; i++ { chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) - chain.App.Commit() chain.NextBlock() coord.IncrementTime() } @@ -254,48 +252,27 @@ func (coord *Coordinator) ChanOpenInitOnBothChains(path *Path) error { return nil } -// from A to B +// RelayAndAckPendingPackets sends pending packages from path.EndpointA to the counterparty chain and acks func (coord *Coordinator) RelayAndAckPendingPackets(path *Path) error { // get all the packet to relay src->dest src := path.EndpointA - dest := path.EndpointB - toSend := src.Chain.PendingSendPackets - coord.t.Logf("Relay %d Packets A->B\n", len(toSend)) - - // send this to the other side - coord.IncrementTime() - coord.CommitBlock(src.Chain) - err := dest.UpdateClient() - if err != nil { - return err - } - for _, packet := range toSend { - err = dest.RecvPacket(packet) + coord.t.Logf("Relay: %d Packets A->B, %d Packets B->A\n", len(src.Chain.PendingSendPackets), len(path.EndpointB.Chain.PendingSendPackets)) + for i, v := range src.Chain.PendingSendPackets { + err := path.RelayPacket(v, nil) if err != nil { return err } + src.Chain.PendingSendPackets = append(src.Chain.PendingSendPackets[0:i], src.Chain.PendingSendPackets[i+1:]...) } - src.Chain.PendingSendPackets = nil - - // get all the acks to relay dest->src - toAck := dest.Chain.PendingAckPackets - // TODO: assert >= len(toSend)? - coord.t.Logf("Ack %d Packets B->A\n", len(toAck)) - // send the ack back from dest -> src - coord.IncrementTime() - coord.CommitBlock(dest.Chain) - err = src.UpdateClient() - if err != nil { - return err - } - for _, ack := range toAck { - err = src.AcknowledgePacket(ack.Packet, ack.Ack) + src = path.EndpointB + for i, v := range src.Chain.PendingSendPackets { + err := path.RelayPacket(v, nil) if err != nil { return err } + src.Chain.PendingSendPackets = append(src.Chain.PendingSendPackets[0:i], src.Chain.PendingSendPackets[i+1:]...) } - dest.Chain.PendingAckPackets = nil return nil } @@ -325,7 +302,6 @@ func (coord *Coordinator) TimeoutPendingPackets(path *Path) error { } } src.Chain.PendingSendPackets = nil - dest.Chain.PendingAckPackets = nil return nil } diff --git a/x/wasm/ibctesting/endpoint.go b/x/wasm/ibctesting/endpoint.go index 9d62ce7f62..e56c5d06ef 100644 --- a/x/wasm/ibctesting/endpoint.go +++ b/x/wasm/ibctesting/endpoint.go @@ -3,18 +3,16 @@ package ibctesting import ( "fmt" - ibctesting "github.com/cosmos/ibc-go/v3/testing" - - // sdk "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" "github.com/stretchr/testify/require" - - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v3/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" - "github.com/cosmos/ibc-go/v3/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" ) // Endpoint is a which represents a channel endpoint and its associated @@ -69,7 +67,7 @@ func (endpoint *Endpoint) QueryProof(key []byte) ([]byte, clienttypes.Height) { } // QueryProofAtHeight queries proof associated with this endpoint using the proof height -// providied +// provided func (endpoint *Endpoint) QueryProofAtHeight(key []byte, height uint64) ([]byte, clienttypes.Height) { // query proof on the counterparty using the latest height of the IBC client return endpoint.Chain.QueryProofAtHeight(key, int64(height)) @@ -184,8 +182,7 @@ func (endpoint *Endpoint) ConnOpenTry() error { counterpartyClient, proofClient, proofConsensus, consensusHeight, proofInit, proofHeight := endpoint.QueryConnectionHandshakeProof() msg := connectiontypes.NewMsgConnectionOpenTry( - "", endpoint.ClientID, // does not support handshake continuation - endpoint.Counterparty.ConnectionID, endpoint.Counterparty.ClientID, + endpoint.ClientID, endpoint.Counterparty.ConnectionID, endpoint.Counterparty.ClientID, counterpartyClient, endpoint.Counterparty.Chain.GetPrefix(), []*connectiontypes.Version{ibctesting.ConnectionVersion}, endpoint.ConnectionConfig.DelayPeriod, proofInit, proofClient, proofConsensus, proofHeight, consensusHeight, @@ -284,6 +281,10 @@ func (endpoint *Endpoint) ChanOpenInit() error { endpoint.ChannelID, err = ibctesting.ParseChannelIDFromEvents(res.GetEvents()) require.NoError(endpoint.Chain.t, err) + // update version to selected app version + // NOTE: this update must be performed after SendMsgs() + endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + return nil } @@ -297,7 +298,7 @@ func (endpoint *Endpoint) ChanOpenTry() error { proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) msg := channeltypes.NewMsgChannelOpenTry( - endpoint.ChannelConfig.PortID, "", // does not support handshake continuation + endpoint.ChannelConfig.PortID, endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order, []string{endpoint.ConnectionID}, endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID, endpoint.Counterparty.ChannelConfig.Version, proof, height, @@ -313,6 +314,10 @@ func (endpoint *Endpoint) ChanOpenTry() error { require.NoError(endpoint.Chain.t, err) } + // update version to selected app version + // NOTE: this update must be performed after the endpoint channelID is set + endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + return nil } @@ -331,7 +336,12 @@ func (endpoint *Endpoint) ChanOpenAck() error { proof, height, endpoint.Chain.SenderAccount.GetAddress().String(), ) - return endpoint.Chain.sendMsgs(msg) + if err := endpoint.Chain.sendMsgs(msg); err != nil { + return err + } + + endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + return nil } // ChanOpenConfirm will construct and execute a MsgChannelOpenConfirm on the associated endpoint. @@ -395,6 +405,17 @@ func (endpoint *Endpoint) SendPacket(packet exported.PacketI) error { // RecvPacket receives a packet on the associated endpoint. // The counterparty client is updated. func (endpoint *Endpoint) RecvPacket(packet channeltypes.Packet) error { + _, err := endpoint.RecvPacketWithResult(packet) + if err != nil { + return err + } + + return nil +} + +// RecvPacketWithResult receives a packet on the associated endpoint and the result +// of the transaction is returned. The counterparty client is updated. +func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*sdk.Result, error) { // get proof of packet commitment on source packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) proof, proofHeight := endpoint.Counterparty.Chain.QueryProof(packetKey) @@ -402,11 +423,16 @@ func (endpoint *Endpoint) RecvPacket(packet channeltypes.Packet) error { recvMsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) // receive on counterparty and update source client - if err := endpoint.Chain.sendMsgs(recvMsg); err != nil { - return err + res, err := endpoint.Chain.SendMsgs(recvMsg) + if err != nil { + return nil, err } - return endpoint.Counterparty.UpdateClient() + if err := endpoint.Counterparty.UpdateClient(); err != nil { + return nil, err + } + + return res, nil } // WriteAcknowledgement writes an acknowledgement on the channel associated with the endpoint. @@ -463,6 +489,36 @@ func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { return endpoint.Chain.sendMsgs(timeoutMsg) } +// TimeoutOnClose sends a MsgTimeoutOnClose to the channel associated with the endpoint. +func (endpoint *Endpoint) TimeoutOnClose(packet channeltypes.Packet) error { + // get proof for timeout based on channel order + var packetKey []byte + + switch endpoint.ChannelConfig.Order { + case channeltypes.ORDERED: + packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) + case channeltypes.UNORDERED: + packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + default: + return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order) + } + + proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) + + channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel()) + proofClosed, _ := endpoint.Counterparty.QueryProof(channelKey) + + nextSeqRecv, found := endpoint.Counterparty.Chain.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + require.True(endpoint.Chain.t, found) + + timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnClose( + packet, nextSeqRecv, + proof, proofClosed, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(timeoutOnCloseMsg) +} + // SetChannelClosed sets a channel state to CLOSED. func (endpoint *Endpoint) SetChannelClosed() error { channel := endpoint.GetChannel() diff --git a/x/wasm/ibctesting/event_utils.go b/x/wasm/ibctesting/event_utils.go index 6463515ffa..0933dadd3f 100644 --- a/x/wasm/ibctesting/event_utils.go +++ b/x/wasm/ibctesting/event_utils.go @@ -1,18 +1,22 @@ package ibctesting import ( + "encoding/hex" + "fmt" "strconv" "strings" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" abci "github.com/tendermint/tendermint/abci/types" ) func getSendPackets(evts []abci.Event) []channeltypes.Packet { var res []channeltypes.Packet for _, evt := range evts { - if evt.Type == "send_packet" { + if evt.Type == channeltypes.EventTypeSendPacket { packet := parsePacketFromEvent(evt) res = append(res, packet) } @@ -20,21 +24,6 @@ func getSendPackets(evts []abci.Event) []channeltypes.Packet { return res } -func getAckPackets(evts []abci.Event) []PacketAck { - var res []PacketAck - for _, evt := range evts { - if evt.Type == "write_acknowledgement" { - packet := parsePacketFromEvent(evt) - ack := PacketAck{ - Packet: packet, - Ack: []byte(getField(evt, "packet_ack")), - } - res = append(res, ack) - } - } - return res -} - // Used for various debug statements above when needed... do not remove // func showEvent(evt abci.Event) { // fmt.Printf("evt.Type: %s\n", evt.Type) @@ -45,17 +34,29 @@ func getAckPackets(evts []abci.Event) []PacketAck { func parsePacketFromEvent(evt abci.Event) channeltypes.Packet { return channeltypes.Packet{ - Sequence: getUintField(evt, "packet_sequence"), - SourcePort: getField(evt, "packet_src_port"), - SourceChannel: getField(evt, "packet_src_channel"), - DestinationPort: getField(evt, "packet_dst_port"), - DestinationChannel: getField(evt, "packet_dst_channel"), - Data: []byte(getField(evt, "packet_data")), - TimeoutHeight: parseTimeoutHeight(getField(evt, "packet_timeout_height")), - TimeoutTimestamp: getUintField(evt, "packet_timeout_timestamp"), + Sequence: getUintField(evt, channeltypes.AttributeKeySequence), + SourcePort: getField(evt, channeltypes.AttributeKeySrcPort), + SourceChannel: getField(evt, channeltypes.AttributeKeySrcChannel), + DestinationPort: getField(evt, channeltypes.AttributeKeyDstPort), + DestinationChannel: getField(evt, channeltypes.AttributeKeyDstChannel), + Data: getHexField(evt, channeltypes.AttributeKeyDataHex), + TimeoutHeight: parseTimeoutHeight(getField(evt, channeltypes.AttributeKeyTimeoutHeight)), + TimeoutTimestamp: getUintField(evt, channeltypes.AttributeKeyTimeoutTimestamp), } } +func getHexField(evt abci.Event, key string) []byte { + got := getField(evt, key) + if got == "" { + return nil + } + bz, err := hex.DecodeString(got) + if err != nil { + panic(err) + } + return bz +} + // return the value for the attribute with the given name func getField(evt abci.Event, key string) string { for _, attr := range evt.Attributes { @@ -89,3 +90,29 @@ func parseTimeoutHeight(raw string) clienttypes.Height { RevisionHeight: toUint64(chunks[1]), } } + +func ParsePortIDFromEvents(events sdk.Events) (string, error) { + for _, ev := range events { + if ev.Type == channeltypes.EventTypeChannelOpenInit || ev.Type == channeltypes.EventTypeChannelOpenTry { + for _, attr := range ev.Attributes { + if string(attr.Key) == channeltypes.AttributeKeyPortID { + return string(attr.Value), nil + } + } + } + } + return "", fmt.Errorf("port id event attribute not found") +} + +func ParseChannelVersionFromEvents(events sdk.Events) (string, error) { + for _, ev := range events { + if ev.Type == channeltypes.EventTypeChannelOpenInit || ev.Type == channeltypes.EventTypeChannelOpenTry { + for _, attr := range ev.Attributes { + if string(attr.Key) == channeltypes.AttributeVersion { + return string(attr.Value), nil + } + } + } + } + return "", fmt.Errorf("version event attribute not found") +} diff --git a/x/wasm/ibctesting/path.go b/x/wasm/ibctesting/path.go index 15912bd400..5e861325f0 100644 --- a/x/wasm/ibctesting/path.go +++ b/x/wasm/ibctesting/path.go @@ -5,7 +5,8 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" ) // Path contains two endpoints representing two chains connected over IBC @@ -48,15 +49,21 @@ func (path *Path) RelayPacket(packet channeltypes.Packet, ack []byte) error { return err } - if err := path.EndpointB.RecvPacket(packet); err != nil { + res, err := path.EndpointB.RecvPacketWithResult(packet) + if err != nil { + return err + } + + ack, err := ibctesting.ParseAckFromEvents(res.GetEvents()) + if err != nil { return err } if err := path.EndpointA.AcknowledgePacket(packet, ack); err != nil { return err } - return nil + return nil } pc = path.EndpointB.Chain.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(path.EndpointB.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) @@ -67,9 +74,16 @@ func (path *Path) RelayPacket(packet channeltypes.Packet, ack []byte) error { return err } - if err := path.EndpointA.RecvPacket(packet); err != nil { + res, err := path.EndpointA.RecvPacketWithResult(packet) + if err != nil { return err } + + ack, err := ibctesting.ParseAckFromEvents(res.GetEvents()) + if err != nil { + return err + } + if err := path.EndpointB.AcknowledgePacket(packet, ack); err != nil { return err } diff --git a/x/wasm/ibctesting/wasm.go b/x/wasm/ibctesting/wasm.go index 293a9f6926..0546f477eb 100644 --- a/x/wasm/ibctesting/wasm.go +++ b/x/wasm/ibctesting/wasm.go @@ -8,7 +8,7 @@ import ( "os" "strings" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + ibctesting "github.com/cosmos/ibc-go/v4/testing" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/golang/protobuf/proto" //nolint diff --git a/x/wasm/keeper/handler_plugin.go b/x/wasm/keeper/handler_plugin.go index c138e5ed00..c23a09b020 100644 --- a/x/wasm/keeper/handler_plugin.go +++ b/x/wasm/keeper/handler_plugin.go @@ -9,8 +9,8 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" "github.com/CosmWasm/wasmd/x/wasm/types" ) diff --git a/x/wasm/keeper/handler_plugin_encoders.go b/x/wasm/keeper/handler_plugin_encoders.go index 90734c1dc2..3c4712d99b 100644 --- a/x/wasm/keeper/handler_plugin_encoders.go +++ b/x/wasm/keeper/handler_plugin_encoders.go @@ -12,9 +12,9 @@ import ( distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibcclienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" "github.com/CosmWasm/wasmd/x/wasm/types" ) diff --git a/x/wasm/keeper/handler_plugin_encoders_test.go b/x/wasm/keeper/handler_plugin_encoders_test.go index e1c49c591c..7f56776e48 100644 --- a/x/wasm/keeper/handler_plugin_encoders_test.go +++ b/x/wasm/keeper/handler_plugin_encoders_test.go @@ -5,9 +5,9 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" "github.com/golang/protobuf/proto" "github.com/stretchr/testify/assert" diff --git a/x/wasm/keeper/handler_plugin_test.go b/x/wasm/keeper/handler_plugin_test.go index 557478fb44..2a41d8a997 100644 --- a/x/wasm/keeper/handler_plugin_test.go +++ b/x/wasm/keeper/handler_plugin_test.go @@ -11,9 +11,9 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/ibc.go b/x/wasm/keeper/ibc.go index f6f928df62..3857b5f272 100644 --- a/x/wasm/keeper/ibc.go +++ b/x/wasm/keeper/ibc.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - host "github.com/cosmos/ibc-go/v3/modules/core/24-host" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" "github.com/CosmWasm/wasmd/x/wasm/types" ) diff --git a/x/wasm/keeper/query_plugins.go b/x/wasm/keeper/query_plugins.go index 7196860d90..c98afda693 100644 --- a/x/wasm/keeper/query_plugins.go +++ b/x/wasm/keeper/query_plugins.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" abci "github.com/tendermint/tendermint/abci/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" "github.com/CosmWasm/wasmd/x/wasm/types" diff --git a/x/wasm/keeper/query_plugins_test.go b/x/wasm/keeper/query_plugins_test.go index 1c0fa231c9..0572cd28c3 100644 --- a/x/wasm/keeper/query_plugins_test.go +++ b/x/wasm/keeper/query_plugins_test.go @@ -18,7 +18,7 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/keeper/relay.go b/x/wasm/keeper/relay.go index 5a74ebe2ca..7c3f0b902c 100644 --- a/x/wasm/keeper/relay.go +++ b/x/wasm/keeper/relay.go @@ -24,8 +24,6 @@ func (k Keeper) OnOpenChannel( msg wasmvmtypes.IBCChannelOpenMsg, ) (string, error) { defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-open-channel") - version := "" - _, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) if err != nil { return "", err @@ -40,12 +38,10 @@ func (k Keeper) OnOpenChannel( if execErr != nil { return "", sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) } - if res != nil { - version = res.Version + return res.Version, nil } - - return version, nil + return "", nil } // OnConnectChannel calls the contract to let it know the IBC channel was established. diff --git a/x/wasm/keeper/snapshotter_integration_test.go b/x/wasm/keeper/snapshotter_integration_test.go index f100a1698c..432d56c79d 100644 --- a/x/wasm/keeper/snapshotter_integration_test.go +++ b/x/wasm/keeper/snapshotter_integration_test.go @@ -118,7 +118,7 @@ func newWasmExampleApp(t *testing.T) (*app.WasmApp, sdk.AccAddress) { } validator := tmtypes.NewValidator(pubKey, 1) valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - wasmApp := app.SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, nil, balance) + wasmApp := app.SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, "testing", nil, balance) return wasmApp, senderAddr } diff --git a/x/wasm/keeper/test_common.go b/x/wasm/keeper/test_common.go index 01cc244bf8..cf390352ab 100644 --- a/x/wasm/keeper/test_common.go +++ b/x/wasm/keeper/test_common.go @@ -56,11 +56,11 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/cosmos/ibc-go/v3/modules/apps/transfer" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v3/modules/core" - ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v4/modules/core" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" @@ -170,18 +170,19 @@ func (f *TestFaucet) NewFundedRandomAccount(ctx sdk.Context, amounts ...sdk.Coin } type TestKeepers struct { - AccountKeeper authkeeper.AccountKeeper - StakingKeeper stakingkeeper.Keeper - DistKeeper distributionkeeper.Keeper - BankKeeper bankkeeper.Keeper - GovKeeper govkeeper.Keeper - ContractKeeper types.ContractOpsKeeper - WasmKeeper *Keeper - IBCKeeper *ibckeeper.Keeper - Router *baseapp.Router - EncodingConfig wasmappparams.EncodingConfig - Faucet *TestFaucet - MultiStore sdk.CommitMultiStore + AccountKeeper authkeeper.AccountKeeper + StakingKeeper stakingkeeper.Keeper + DistKeeper distributionkeeper.Keeper + BankKeeper bankkeeper.Keeper + GovKeeper govkeeper.Keeper + ContractKeeper types.ContractOpsKeeper + WasmKeeper *Keeper + IBCKeeper *ibckeeper.Keeper + Router *baseapp.Router + EncodingConfig wasmappparams.EncodingConfig + Faucet *TestFaucet + MultiStore sdk.CommitMultiStore + ScopedWasmKeeper capabilitykeeper.ScopedKeeper } // CreateDefaultTestInput common settings for CreateTestInput @@ -428,18 +429,19 @@ func createTestInput( govKeeper.SetTallyParams(ctx, govtypes.DefaultTallyParams()) keepers := TestKeepers{ - AccountKeeper: accountKeeper, - StakingKeeper: stakingKeeper, - DistKeeper: distKeeper, - ContractKeeper: contractKeeper, - WasmKeeper: &keeper, - BankKeeper: bankKeeper, - GovKeeper: govKeeper, - IBCKeeper: ibcKeeper, - Router: router, - EncodingConfig: encodingConfig, - Faucet: faucet, - MultiStore: ms, + AccountKeeper: accountKeeper, + StakingKeeper: stakingKeeper, + DistKeeper: distKeeper, + ContractKeeper: contractKeeper, + WasmKeeper: &keeper, + BankKeeper: bankKeeper, + GovKeeper: govKeeper, + IBCKeeper: ibcKeeper, + Router: router, + EncodingConfig: encodingConfig, + Faucet: faucet, + MultiStore: ms, + ScopedWasmKeeper: scopedWasmKeeper, } return ctx, keepers } diff --git a/x/wasm/keeper/wasmtesting/mock_engine.go b/x/wasm/keeper/wasmtesting/mock_engine.go index ebf7dbcf19..10c7fdfed2 100644 --- a/x/wasm/keeper/wasmtesting/mock_engine.go +++ b/x/wasm/keeper/wasmtesting/mock_engine.go @@ -346,3 +346,56 @@ func HasIBCAnalyzeFn(wasmvm.Checksum) (*wasmvmtypes.AnalysisReport, error) { func WithoutIBCAnalyzeFn(wasmvm.Checksum) (*wasmvmtypes.AnalysisReport, error) { return &wasmvmtypes.AnalysisReport{}, nil } + +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) + 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) +} + +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) { + 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) { + 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) { + if m.IBCChannelCloseFn == nil { + panic("not expected to be called") + } + return m.IBCChannelCloseFn(codeID, env, channel, store, goapi, querier, gasMeter, gasLimit, deserCost) +} + +func (m MockIBCContractCallbacks) IBCPacketReceive(codeID wasmvm.Checksum, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacketReceiveMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) { + if m.IBCPacketReceiveFn == nil { + panic("not expected to be called") + } + 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) { + 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) { + if m.IBCPacketTimeoutFn == nil { + panic("not expected to be called") + } + return m.IBCPacketTimeoutFn(codeID, env, packet, store, goapi, querier, gasMeter, gasLimit, deserCost) +} diff --git a/x/wasm/keeper/wasmtesting/mock_keepers.go b/x/wasm/keeper/wasmtesting/mock_keepers.go index 4295b24ef0..5977db1c80 100644 --- a/x/wasm/keeper/wasmtesting/mock_keepers.go +++ b/x/wasm/keeper/wasmtesting/mock_keepers.go @@ -3,8 +3,8 @@ package wasmtesting import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" "github.com/CosmWasm/wasmd/x/wasm/types" ) diff --git a/x/wasm/relay_pingpong_test.go b/x/wasm/relay_pingpong_test.go index 8dfa403e82..a36cdce6ab 100644 --- a/x/wasm/relay_pingpong_test.go +++ b/x/wasm/relay_pingpong_test.go @@ -5,15 +5,15 @@ import ( "fmt" "testing" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" 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" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -108,11 +108,6 @@ func TestPinPong(t *testing.T) { require.Len(t, chainA.PendingSendPackets, 1) err := coordinator.RelayAndAckPendingPackets(path) require.NoError(t, err) - - // switch side - require.Len(t, chainB.PendingSendPackets, 1) - err = coordinator.RelayAndAckPendingPackets(path.Invert()) - require.NoError(t, err) } // then receive/response state is as expected diff --git a/x/wasm/relay_test.go b/x/wasm/relay_test.go index 4e72bd84f6..df34534fbc 100644 --- a/x/wasm/relay_test.go +++ b/x/wasm/relay_test.go @@ -10,10 +10,10 @@ import ( wasmvmtypes "github.com/CosmWasm/wasmvm/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v3/testing" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/x/wasm/types/expected_keepers.go b/x/wasm/types/expected_keepers.go index da00047aa4..57cc4073f5 100644 --- a/x/wasm/types/expected_keepers.go +++ b/x/wasm/types/expected_keepers.go @@ -8,9 +8,9 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - ibcexported "github.com/cosmos/ibc-go/v3/modules/core/exported" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" ) // BankViewKeeper defines a subset of methods implemented by the cosmos-sdk bank keeper