diff --git a/modules/apps/27-interchain-accounts/keeper/relay.go b/modules/apps/27-interchain-accounts/keeper/relay.go index 15ddfdf7bd3..6884a026dba 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/keeper/relay.go @@ -44,18 +44,7 @@ func (k Keeper) createOutgoingPacket( return []byte{}, types.ErrInvalidOutgoingData } - var msgs []sdk.Msg - - switch data := data.(type) { - case []sdk.Msg: - msgs = data - case sdk.Msg: - msgs = []sdk.Msg{data} - default: - return []byte{}, types.ErrInvalidOutgoingData - } - - txBytes, err := k.SerializeCosmosTx(k.cdc, msgs) + txBytes, err := k.SerializeCosmosTx(k.cdc, data) if err != nil { return []byte{}, sdkerrors.Wrap(err, "invalid packet data or codec") } diff --git a/modules/apps/27-interchain-accounts/keeper/relay_test.go b/modules/apps/27-interchain-accounts/keeper/relay_test.go index ea836fb8c05..6fd53d7b888 100644 --- a/modules/apps/27-interchain-accounts/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/keeper/relay_test.go @@ -1,9 +1,15 @@ package keeper_test import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/testing" ) @@ -74,13 +80,15 @@ func (suite *KeeperTestSuite) TestTrySendTx() { suite.Run(tc.name, func() { suite.SetupTest() // reset path = NewICAPath(suite.chainA, suite.chainB) - owner := TestOwnerAddress suite.coordinator.SetupConnections(path) - err := suite.SetupICAPath(path, owner) + err := suite.SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) + portID = path.EndpointA.ChannelConfig.PortID + tc.malleate() + _, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), portID, msg) if tc.expPass { @@ -91,3 +99,129 @@ func (suite *KeeperTestSuite) TestTrySendTx() { }) } } + +func (suite *KeeperTestSuite) TestOnRecvPacket() { + var ( + path *ibctesting.Path + msg sdk.Msg + txBytes []byte + packetData []byte + sourcePort string + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "Interchain account successfully executes banktypes.MsgSend", func() { + // build MsgSend + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + msg = &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + // build packet data + txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, msg) + suite.Require().NoError(err) + + data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + Data: txBytes} + packetData = data.GetBytes() + }, true, + }, + { + "Cannot deserialize txBytes", func() { + txBytes = []byte("invalid tx bytes") + data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + Data: txBytes} + packetData = data.GetBytes() + }, false, + }, + { + "Cannot deserialize txBytes: invalid IBCTxRaw", func() { + txBody := []byte("invalid tx body") + txRaw := &types.IBCTxRaw{ + BodyBytes: txBody, + } + + txBytes = suite.chainB.Codec.MustMarshal(txRaw) + data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + Data: txBytes} + packetData = data.GetBytes() + }, false, + }, + { + "Invalid packet type", func() { + txBytes = []byte{} + // Type here is an ENUM + // Valid type is types.EXECUTE_TX + data := types.IBCAccountPacketData{Type: 100, + Data: txBytes} + packetData = data.GetBytes() + }, false, + }, + { + "Cannot unmarshal interchain account packet data into types.IBCAccountPacketData", func() { + packetData = []byte{} + }, false, + }, + { + "Unauthorised: Interchain account not found for given source portID", func() { + sourcePort = "invalid-port-id" + }, false, + }, + { + "Unauthorised: Signer of message is not the interchain account associated with sourcePortID", func() { + // build MsgSend + amount, _ := sdk.ParseCoinsNormalized("100stake") + // Incorrect FromAddress + msg = &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount} + // build packet data + txBytes, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, msg) + suite.Require().NoError(err) + data := types.IBCAccountPacketData{Type: types.EXECUTE_TX, + Data: txBytes} + packetData = data.GetBytes() + }, false, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + path = NewICAPath(suite.chainA, suite.chainB) + suite.coordinator.SetupConnections(path) + err := suite.SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) + + // send 100stake to interchain account wallet + amount, _ := sdk.ParseCoinsNormalized("100stake") + interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID) + bankMsg := &banktypes.MsgSend{FromAddress: suite.chainB.SenderAccount.GetAddress().String(), ToAddress: interchainAccountAddr, Amount: amount} + + _, err = suite.chainB.SendMsgs(bankMsg) + suite.Require().NoError(err) + + // valid source port + sourcePort = path.EndpointA.ChannelConfig.PortID + + // malleate packetData for test cases + tc.malleate() + + seq := uint64(1) + packet := channeltypes.NewPacket(packetData, seq, sourcePort, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(0, 100), 0) + + // Pass it in here + err = suite.chainB.GetSimApp().ICAKeeper.OnRecvPacket(suite.chainB.GetContext(), packet) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +}