Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICA: Rename TxBody, Remove serialization logic from controller, introduce CosmosTx type #474

Merged
merged 8 commits into from
Oct 12, 2021
10 changes: 5 additions & 5 deletions docs/ibc/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
- [Query](#ibc.applications.interchain_accounts.v1.Query)

- [ibc/applications/interchain_accounts/v1/types.proto](#ibc/applications/interchain_accounts/v1/types.proto)
- [IBCTxBody](#ibc.applications.interchain_accounts.v1.IBCTxBody)
- [CosmosTx](#ibc.applications.interchain_accounts.v1.CosmosTx)
- [InterchainAccountPacketData](#ibc.applications.interchain_accounts.v1.InterchainAccountPacketData)

- [Type](#ibc.applications.interchain_accounts.v1.Type)
Expand Down Expand Up @@ -398,10 +398,10 @@ Query defines the gRPC querier service.



<a name="ibc.applications.interchain_accounts.v1.IBCTxBody"></a>
<a name="ibc.applications.interchain_accounts.v1.CosmosTx"></a>

### IBCTxBody
Body of a tx for an ics27 IBC packet
### CosmosTx
CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain.


| Field | Type | Label | Description |
Expand All @@ -416,7 +416,7 @@ Body of a tx for an ics27 IBC packet
<a name="ibc.applications.interchain_accounts.v1.InterchainAccountPacketData"></a>

### InterchainAccountPacketData
InterchainAccountPacketData is comprised of araw transaction,type of transaction and optional memo field.
InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field.


| Field | Type | Label | Description |
Expand Down
11 changes: 6 additions & 5 deletions modules/apps/27-interchain-accounts/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,24 @@ func NewKeeper(
}
}

// SerializeCosmosTx marshals data to bytes using the provided codec
func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, msgs []sdk.Msg) ([]byte, error) {
// SerializeCosmosTx serializes a slice of sdk.Msg's using the CosmosTx type. The sdk.Msg's are
// packed into Any's and inserted into the Messages field of a CosmosTx. The proto marshaled CosmosTx
// bytes are returned.
func (k Keeper) SerializeCosmosTx(cdc codec.BinaryCodec, msgs []sdk.Msg) (bz []byte, err error) {
msgAnys := make([]*codectypes.Any, len(msgs))

for i, msg := range msgs {
var err error
msgAnys[i], err = codectypes.NewAnyWithValue(msg)
if err != nil {
return nil, err
}
}

txBody := &types.IBCTxBody{
cosmosTx := &types.CosmosTx{
Messages: msgAnys,
}

bz, err := cdc.Marshal(txBody)
bz, err = cdc.Marshal(cosmosTx)
if err != nil {
return nil, err
}
Expand Down
73 changes: 16 additions & 57 deletions modules/apps/27-interchain-accounts/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// TODO: implement middleware functionality, this will allow us to use capabilities to
// manage helper module access to owner addresses they do not have capabilities for
func (k Keeper) TrySendTx(ctx sdk.Context, portID string, data interface{}, memo string) (uint64, error) {
func (k Keeper) TrySendTx(ctx sdk.Context, portID string, packetData types.InterchainAccountPacketData) (uint64, error) {
// Check for the active channel
activeChannelId, found := k.GetActiveChannel(ctx, portID)
if !found {
Expand All @@ -27,7 +27,7 @@ func (k Keeper) TrySendTx(ctx sdk.Context, portID string, data interface{}, memo
destinationPort := sourceChannelEnd.GetCounterparty().GetPortID()
destinationChannel := sourceChannelEnd.GetCounterparty().GetChannelID()

return k.createOutgoingPacket(ctx, portID, activeChannelId, destinationPort, destinationChannel, data, memo)
return k.createOutgoingPacket(ctx, portID, activeChannelId, destinationPort, destinationChannel, packetData)
}

func (k Keeper) createOutgoingPacket(
Expand All @@ -36,27 +36,10 @@ func (k Keeper) createOutgoingPacket(
sourceChannel,
destinationPort,
destinationChannel string,
data interface{},
memo string,
packetData types.InterchainAccountPacketData,
) (uint64, error) {
if data == nil {
return 0, types.ErrInvalidOutgoingData
}

var (
txBytes []byte
err error
)

switch data := data.(type) {
case []sdk.Msg:
txBytes, err = k.SerializeCosmosTx(k.cdc, data)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ica-auth now need to call this function and format the ica packet data properly

default:
return 0, sdkerrors.Wrapf(types.ErrInvalidOutgoingData, "message type %T is not supported", data)
}

if err != nil {
return 0, sdkerrors.Wrap(err, "serialization of transaction data failed")
if err := packetData.ValidateBasic(); err != nil {
return 0, sdkerrors.Wrap(err, "invalid interchain account packet data")
}

channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(sourcePort, sourceChannel))
Expand All @@ -70,12 +53,6 @@ func (k Keeper) createOutgoingPacket(
return 0, channeltypes.ErrSequenceSendNotFound
}

packetData := types.InterchainAccountPacketData{
Type: types.EXECUTE_TX,
Data: txBytes,
Memo: memo,
}

// timeoutTimestamp is set to be a max number here so that we never recieve a timeout
// ics-27-1 uses ordered channels which can close upon recieving a timeout, which is an undesired effect
const timeoutTimestamp = ^uint64(0) >> 1 // Shift the unsigned bit to satisfy hermes relayer timestamp conversion
Expand All @@ -100,25 +77,26 @@ func (k Keeper) createOutgoingPacket(

// DeserializeCosmosTx unmarshals and unpacks a slice of transaction bytes
// into a slice of sdk.Msg's.
func (k Keeper) DeserializeCosmosTx(_ sdk.Context, txBytes []byte) ([]sdk.Msg, error) {
var txBody types.IBCTxBody

if err := k.cdc.Unmarshal(txBytes, &txBody); err != nil {
func (k Keeper) DeserializeCosmosTx(_ sdk.Context, data []byte) ([]sdk.Msg, error) {
var cosmosTx types.CosmosTx
if err := k.cdc.Unmarshal(data, &cosmosTx); err != nil {
return nil, err
}

anys := txBody.Messages
res := make([]sdk.Msg, len(anys))
for i, any := range anys {
msgs := make([]sdk.Msg, len(cosmosTx.Messages))

for i, any := range cosmosTx.Messages {
var msg sdk.Msg

err := k.cdc.UnpackAny(any, &msg)
if err != nil {
return nil, err
}
res[i] = msg

msgs[i] = msg
}

return res, nil
return msgs, nil
}

func (k Keeper) AuthenticateTx(ctx sdk.Context, msgs []sdk.Msg, portId string) error {
Expand Down Expand Up @@ -215,28 +193,9 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet) error
}

func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.InterchainAccountPacketData, ack channeltypes.Acknowledgement) error {
switch ack.Response.(type) {
case *channeltypes.Acknowledgement_Error:
if k.hook != nil {
k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, packet.Data, data.Data)
}
return nil
case *channeltypes.Acknowledgement_Result:
if k.hook != nil {
k.hook.OnTxSucceeded(ctx, packet.SourcePort, packet.SourceChannel, packet.Data, data.Data)
}
return nil
default:
// the acknowledgement succeeded on the receiving chain so nothing
// needs to be executed and no error needs to be returned
return nil
}
return nil
}

func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.InterchainAccountPacketData) error {
if k.hook != nil {
k.hook.OnTxFailed(ctx, packet.SourcePort, packet.SourceChannel, packet.Data, data.Data)
}

return nil
}
103 changes: 54 additions & 49 deletions modules/apps/27-interchain-accounts/keeper/relay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import (

func (suite *KeeperTestSuite) TestTrySendTx() {
var (
path *ibctesting.Path
msg interface{}
portID string
path *ibctesting.Path
icaPacketData types.InterchainAccountPacketData
portID string
)

testCases := []struct {
Expand All @@ -27,9 +27,6 @@ func (suite *KeeperTestSuite) TestTrySendTx() {
}{
{
"success", func() {
amount, _ := sdk.ParseCoinsNormalized("100stake")
interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
msg = []sdk.Msg{&banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount}}
}, true,
},
{
Expand All @@ -38,45 +35,30 @@ func (suite *KeeperTestSuite) TestTrySendTx() {
interchainAccountAddr, _ := suite.chainB.GetSimApp().ICAKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), path.EndpointA.ChannelConfig.PortID)
msg1 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount}
msg2 := &banktypes.MsgSend{FromAddress: interchainAccountAddr, ToAddress: suite.chainB.SenderAccount.GetAddress().String(), Amount: amount}
msg = []sdk.Msg{msg1, msg2}
data, err := suite.chainB.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg1, msg2})
suite.Require().NoError(err)
icaPacketData.Data = data
}, true,
},
{
"incorrect outgoing data", func() {
msg = []byte{}
}, false,
},
{
"incorrect outgoing data - []sdk.Msg is not used", func() {
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}
"data is nil", func() {
icaPacketData.Data = nil
}, false,
},
{
"active channel not found", func() {
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}
portID = "incorrect portID"
}, false,
},
{
"channel does not exist", func() {
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}
suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), portID, "channel-100")
}, false,
},
{
"data is nil", func() {
msg = nil
}, false,
},
{
"data is not an SDK message", func() {
msg = "not an sdk message"
"SendPacket fails - channel closed", func() {
err := path.EndpointA.SetChannelClosed()
suite.Require().NoError(err)
}, false,
},
}
Expand All @@ -88,16 +70,28 @@ func (suite *KeeperTestSuite) TestTrySendTx() {
suite.SetupTest() // reset
path = NewICAPath(suite.chainA, suite.chainB)
suite.coordinator.SetupConnections(path)
memo := "memo"

err := suite.SetupICAPath(path, TestOwnerAddress)
suite.Require().NoError(err)

portID = path.EndpointA.ChannelConfig.PortID

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}
data, err := suite.chainB.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []sdk.Msg{msg})
suite.Require().NoError(err)

// default packet data, must be modified in malleate for test cases expected to fail
icaPacketData = types.InterchainAccountPacketData{
Type: types.EXECUTE_TX,
Data: data,
Memo: "memo",
}

tc.malleate()

_, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), portID, msg, memo)
_, err = suite.chainA.GetSimApp().ICAKeeper.TrySendTx(suite.chainA.GetContext(), portID, icaPacketData)

if tc.expPass {
suite.Require().NoError(err)
Expand All @@ -112,7 +106,6 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
var (
path *ibctesting.Path
msg sdk.Msg
txBytes []byte
packetData []byte
sourcePort string
)
Expand All @@ -129,30 +122,40 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
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, []sdk.Msg{msg})
data, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg})
suite.Require().NoError(err)

data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX,
Data: txBytes}
packetData = data.GetBytes()
icaPacketData := types.InterchainAccountPacketData{
Type: types.EXECUTE_TX,
Data: data,
}
packetData = icaPacketData.GetBytes()
}, true,
},
{
"Cannot deserialize txBytes", func() {
txBytes = []byte("invalid tx bytes")
data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX,
Data: txBytes}
packetData = data.GetBytes()
"Cannot deserialize packet data messages", func() {
data := []byte("invalid packet data")

icaPacketData := types.InterchainAccountPacketData{
Type: types.EXECUTE_TX,
Data: data,
}
packetData = icaPacketData.GetBytes()
}, false,
},
{
"Invalid packet type", func() {
txBytes = []byte{}
// build packet data
data, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{&banktypes.MsgSend{}})
suite.Require().NoError(err)

// Type here is an ENUM
// Valid type is types.EXECUTE_TX
data := types.InterchainAccountPacketData{Type: 100,
Data: txBytes}
packetData = data.GetBytes()
icaPacketData := types.InterchainAccountPacketData{
Type: 100,
Data: data,
}
packetData = icaPacketData.GetBytes()
}, false,
},
{
Expand All @@ -172,11 +175,13 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() {
// 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, []sdk.Msg{msg})
data, err := suite.chainA.GetSimApp().ICAKeeper.SerializeCosmosTx(suite.chainA.Codec, []sdk.Msg{msg})
suite.Require().NoError(err)
data := types.InterchainAccountPacketData{Type: types.EXECUTE_TX,
Data: txBytes}
packetData = data.GetBytes()
icaPacketData := types.InterchainAccountPacketData{
Type: types.EXECUTE_TX,
Data: data,
}
packetData = icaPacketData.GetBytes()
}, false,
},
}
Expand Down
Loading