From 845e45f1fa99f8f0b70195b62107ae00cd384638 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 15 May 2024 11:59:27 +0200 Subject: [PATCH 01/46] feat: add intial SendPacket msgs and rpc definition to ibc core --- modules/core/04-channel/types/tx.pb.go | 888 ++++++++++++++++++++----- modules/core/keeper/msg_server.go | 29 + modules/core/keeper/msg_server_test.go | 4 + proto/ibc/core/channel/v1/tx.proto | 25 + 4 files changed, 795 insertions(+), 151 deletions(-) diff --git a/modules/core/04-channel/types/tx.pb.go b/modules/core/04-channel/types/tx.pb.go index 398a9f15b64..ddd875f7764 100644 --- a/modules/core/04-channel/types/tx.pb.go +++ b/modules/core/04-channel/types/tx.pb.go @@ -10,19 +10,23 @@ import ( _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" + github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" types "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" + _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" math_bits "math/bits" + time "time" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf +var _ = time.Kitchen // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. @@ -559,6 +563,87 @@ func (m *MsgChannelCloseConfirmResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgChannelCloseConfirmResponse proto.InternalMessageInfo +// MsgSendPacket sends an outgoing IBC packet +type MsgSendPacket struct { + PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + TimeoutHeight types.Height `protobuf:"bytes,3,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height"` + TimeoutTimestamp time.Time `protobuf:"bytes,4,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3,stdtime" json:"timeout_timestamp"` + PacketData []byte `protobuf:"bytes,5,opt,name=packet_data,json=packetData,proto3" json:"packet_data,omitempty"` + Signer string `protobuf:"bytes,6,opt,name=signer,proto3" json:"signer,omitempty"` +} + +func (m *MsgSendPacket) Reset() { *m = MsgSendPacket{} } +func (m *MsgSendPacket) String() string { return proto.CompactTextString(m) } +func (*MsgSendPacket) ProtoMessage() {} +func (*MsgSendPacket) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{12} +} +func (m *MsgSendPacket) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSendPacket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSendPacket.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSendPacket) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSendPacket.Merge(m, src) +} +func (m *MsgSendPacket) XXX_Size() int { + return m.Size() +} +func (m *MsgSendPacket) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSendPacket.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSendPacket proto.InternalMessageInfo + +// MsgSendPacketReponse defines the Msg/SendPacket response type. +type MsgSendPacketResponse struct { + Sequence uint64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"` +} + +func (m *MsgSendPacketResponse) Reset() { *m = MsgSendPacketResponse{} } +func (m *MsgSendPacketResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSendPacketResponse) ProtoMessage() {} +func (*MsgSendPacketResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_bc4637e0ac3fc7b7, []int{13} +} +func (m *MsgSendPacketResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSendPacketResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSendPacketResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSendPacketResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSendPacketResponse.Merge(m, src) +} +func (m *MsgSendPacketResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSendPacketResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSendPacketResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSendPacketResponse proto.InternalMessageInfo + // MsgRecvPacket receives incoming IBC packet type MsgRecvPacket struct { Packet Packet `protobuf:"bytes,1,opt,name=packet,proto3" json:"packet"` @@ -571,7 +656,7 @@ func (m *MsgRecvPacket) Reset() { *m = MsgRecvPacket{} } func (m *MsgRecvPacket) String() string { return proto.CompactTextString(m) } func (*MsgRecvPacket) ProtoMessage() {} func (*MsgRecvPacket) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{12} + return fileDescriptor_bc4637e0ac3fc7b7, []int{14} } func (m *MsgRecvPacket) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -609,7 +694,7 @@ func (m *MsgRecvPacketResponse) Reset() { *m = MsgRecvPacketResponse{} } func (m *MsgRecvPacketResponse) String() string { return proto.CompactTextString(m) } func (*MsgRecvPacketResponse) ProtoMessage() {} func (*MsgRecvPacketResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{13} + return fileDescriptor_bc4637e0ac3fc7b7, []int{15} } func (m *MsgRecvPacketResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -651,7 +736,7 @@ func (m *MsgTimeout) Reset() { *m = MsgTimeout{} } func (m *MsgTimeout) String() string { return proto.CompactTextString(m) } func (*MsgTimeout) ProtoMessage() {} func (*MsgTimeout) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{14} + return fileDescriptor_bc4637e0ac3fc7b7, []int{16} } func (m *MsgTimeout) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -689,7 +774,7 @@ func (m *MsgTimeoutResponse) Reset() { *m = MsgTimeoutResponse{} } func (m *MsgTimeoutResponse) String() string { return proto.CompactTextString(m) } func (*MsgTimeoutResponse) ProtoMessage() {} func (*MsgTimeoutResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{15} + return fileDescriptor_bc4637e0ac3fc7b7, []int{17} } func (m *MsgTimeoutResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -733,7 +818,7 @@ func (m *MsgTimeoutOnClose) Reset() { *m = MsgTimeoutOnClose{} } func (m *MsgTimeoutOnClose) String() string { return proto.CompactTextString(m) } func (*MsgTimeoutOnClose) ProtoMessage() {} func (*MsgTimeoutOnClose) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{16} + return fileDescriptor_bc4637e0ac3fc7b7, []int{18} } func (m *MsgTimeoutOnClose) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -771,7 +856,7 @@ func (m *MsgTimeoutOnCloseResponse) Reset() { *m = MsgTimeoutOnCloseResp func (m *MsgTimeoutOnCloseResponse) String() string { return proto.CompactTextString(m) } func (*MsgTimeoutOnCloseResponse) ProtoMessage() {} func (*MsgTimeoutOnCloseResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{17} + return fileDescriptor_bc4637e0ac3fc7b7, []int{19} } func (m *MsgTimeoutOnCloseResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -813,7 +898,7 @@ func (m *MsgAcknowledgement) Reset() { *m = MsgAcknowledgement{} } func (m *MsgAcknowledgement) String() string { return proto.CompactTextString(m) } func (*MsgAcknowledgement) ProtoMessage() {} func (*MsgAcknowledgement) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{18} + return fileDescriptor_bc4637e0ac3fc7b7, []int{20} } func (m *MsgAcknowledgement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -851,7 +936,7 @@ func (m *MsgAcknowledgementResponse) Reset() { *m = MsgAcknowledgementRe func (m *MsgAcknowledgementResponse) String() string { return proto.CompactTextString(m) } func (*MsgAcknowledgementResponse) ProtoMessage() {} func (*MsgAcknowledgementResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{19} + return fileDescriptor_bc4637e0ac3fc7b7, []int{21} } func (m *MsgAcknowledgementResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -894,7 +979,7 @@ func (m *MsgChannelUpgradeInit) Reset() { *m = MsgChannelUpgradeInit{} } func (m *MsgChannelUpgradeInit) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeInit) ProtoMessage() {} func (*MsgChannelUpgradeInit) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{20} + return fileDescriptor_bc4637e0ac3fc7b7, []int{22} } func (m *MsgChannelUpgradeInit) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -933,7 +1018,7 @@ func (m *MsgChannelUpgradeInitResponse) Reset() { *m = MsgChannelUpgrade func (m *MsgChannelUpgradeInitResponse) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeInitResponse) ProtoMessage() {} func (*MsgChannelUpgradeInitResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{21} + return fileDescriptor_bc4637e0ac3fc7b7, []int{23} } func (m *MsgChannelUpgradeInitResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -979,7 +1064,7 @@ func (m *MsgChannelUpgradeTry) Reset() { *m = MsgChannelUpgradeTry{} } func (m *MsgChannelUpgradeTry) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeTry) ProtoMessage() {} func (*MsgChannelUpgradeTry) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{22} + return fileDescriptor_bc4637e0ac3fc7b7, []int{24} } func (m *MsgChannelUpgradeTry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1019,7 +1104,7 @@ func (m *MsgChannelUpgradeTryResponse) Reset() { *m = MsgChannelUpgradeT func (m *MsgChannelUpgradeTryResponse) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeTryResponse) ProtoMessage() {} func (*MsgChannelUpgradeTryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{23} + return fileDescriptor_bc4637e0ac3fc7b7, []int{25} } func (m *MsgChannelUpgradeTryResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1063,7 +1148,7 @@ func (m *MsgChannelUpgradeAck) Reset() { *m = MsgChannelUpgradeAck{} } func (m *MsgChannelUpgradeAck) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeAck) ProtoMessage() {} func (*MsgChannelUpgradeAck) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{24} + return fileDescriptor_bc4637e0ac3fc7b7, []int{26} } func (m *MsgChannelUpgradeAck) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1101,7 +1186,7 @@ func (m *MsgChannelUpgradeAckResponse) Reset() { *m = MsgChannelUpgradeA func (m *MsgChannelUpgradeAckResponse) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeAckResponse) ProtoMessage() {} func (*MsgChannelUpgradeAckResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{25} + return fileDescriptor_bc4637e0ac3fc7b7, []int{27} } func (m *MsgChannelUpgradeAckResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1146,7 +1231,7 @@ func (m *MsgChannelUpgradeConfirm) Reset() { *m = MsgChannelUpgradeConfi func (m *MsgChannelUpgradeConfirm) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeConfirm) ProtoMessage() {} func (*MsgChannelUpgradeConfirm) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{26} + return fileDescriptor_bc4637e0ac3fc7b7, []int{28} } func (m *MsgChannelUpgradeConfirm) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1184,7 +1269,7 @@ func (m *MsgChannelUpgradeConfirmResponse) Reset() { *m = MsgChannelUpgr func (m *MsgChannelUpgradeConfirmResponse) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeConfirmResponse) ProtoMessage() {} func (*MsgChannelUpgradeConfirmResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{27} + return fileDescriptor_bc4637e0ac3fc7b7, []int{29} } func (m *MsgChannelUpgradeConfirmResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1228,7 +1313,7 @@ func (m *MsgChannelUpgradeOpen) Reset() { *m = MsgChannelUpgradeOpen{} } func (m *MsgChannelUpgradeOpen) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeOpen) ProtoMessage() {} func (*MsgChannelUpgradeOpen) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{28} + return fileDescriptor_bc4637e0ac3fc7b7, []int{30} } func (m *MsgChannelUpgradeOpen) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1265,7 +1350,7 @@ func (m *MsgChannelUpgradeOpenResponse) Reset() { *m = MsgChannelUpgrade func (m *MsgChannelUpgradeOpenResponse) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeOpenResponse) ProtoMessage() {} func (*MsgChannelUpgradeOpenResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{29} + return fileDescriptor_bc4637e0ac3fc7b7, []int{31} } func (m *MsgChannelUpgradeOpenResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1308,7 +1393,7 @@ func (m *MsgChannelUpgradeTimeout) Reset() { *m = MsgChannelUpgradeTimeo func (m *MsgChannelUpgradeTimeout) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeTimeout) ProtoMessage() {} func (*MsgChannelUpgradeTimeout) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{30} + return fileDescriptor_bc4637e0ac3fc7b7, []int{32} } func (m *MsgChannelUpgradeTimeout) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1345,7 +1430,7 @@ func (m *MsgChannelUpgradeTimeoutResponse) Reset() { *m = MsgChannelUpgr func (m *MsgChannelUpgradeTimeoutResponse) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeTimeoutResponse) ProtoMessage() {} func (*MsgChannelUpgradeTimeoutResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{31} + return fileDescriptor_bc4637e0ac3fc7b7, []int{33} } func (m *MsgChannelUpgradeTimeoutResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1388,7 +1473,7 @@ func (m *MsgChannelUpgradeCancel) Reset() { *m = MsgChannelUpgradeCancel func (m *MsgChannelUpgradeCancel) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeCancel) ProtoMessage() {} func (*MsgChannelUpgradeCancel) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{32} + return fileDescriptor_bc4637e0ac3fc7b7, []int{34} } func (m *MsgChannelUpgradeCancel) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1425,7 +1510,7 @@ func (m *MsgChannelUpgradeCancelResponse) Reset() { *m = MsgChannelUpgra func (m *MsgChannelUpgradeCancelResponse) String() string { return proto.CompactTextString(m) } func (*MsgChannelUpgradeCancelResponse) ProtoMessage() {} func (*MsgChannelUpgradeCancelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{33} + return fileDescriptor_bc4637e0ac3fc7b7, []int{35} } func (m *MsgChannelUpgradeCancelResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1468,7 +1553,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{34} + return fileDescriptor_bc4637e0ac3fc7b7, []int{36} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1505,7 +1590,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{35} + return fileDescriptor_bc4637e0ac3fc7b7, []int{37} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1546,7 +1631,7 @@ func (m *MsgPruneAcknowledgements) Reset() { *m = MsgPruneAcknowledgemen func (m *MsgPruneAcknowledgements) String() string { return proto.CompactTextString(m) } func (*MsgPruneAcknowledgements) ProtoMessage() {} func (*MsgPruneAcknowledgements) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{36} + return fileDescriptor_bc4637e0ac3fc7b7, []int{38} } func (m *MsgPruneAcknowledgements) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1587,7 +1672,7 @@ func (m *MsgPruneAcknowledgementsResponse) Reset() { *m = MsgPruneAcknow func (m *MsgPruneAcknowledgementsResponse) String() string { return proto.CompactTextString(m) } func (*MsgPruneAcknowledgementsResponse) ProtoMessage() {} func (*MsgPruneAcknowledgementsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_bc4637e0ac3fc7b7, []int{37} + return fileDescriptor_bc4637e0ac3fc7b7, []int{39} } func (m *MsgPruneAcknowledgementsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1644,6 +1729,8 @@ func init() { proto.RegisterType((*MsgChannelCloseInitResponse)(nil), "ibc.core.channel.v1.MsgChannelCloseInitResponse") proto.RegisterType((*MsgChannelCloseConfirm)(nil), "ibc.core.channel.v1.MsgChannelCloseConfirm") proto.RegisterType((*MsgChannelCloseConfirmResponse)(nil), "ibc.core.channel.v1.MsgChannelCloseConfirmResponse") + proto.RegisterType((*MsgSendPacket)(nil), "ibc.core.channel.v1.MsgSendPacket") + proto.RegisterType((*MsgSendPacketResponse)(nil), "ibc.core.channel.v1.MsgSendPacketResponse") proto.RegisterType((*MsgRecvPacket)(nil), "ibc.core.channel.v1.MsgRecvPacket") proto.RegisterType((*MsgRecvPacketResponse)(nil), "ibc.core.channel.v1.MsgRecvPacketResponse") proto.RegisterType((*MsgTimeout)(nil), "ibc.core.channel.v1.MsgTimeout") @@ -1675,131 +1762,139 @@ func init() { func init() { proto.RegisterFile("ibc/core/channel/v1/tx.proto", fileDescriptor_bc4637e0ac3fc7b7) } var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ - // 1975 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0xcf, 0x6f, 0xdb, 0xc8, - 0x15, 0x36, 0xf5, 0x33, 0x7e, 0x4e, 0xd6, 0x0a, 0xe5, 0xc4, 0x32, 0x6d, 0x4b, 0x8a, 0x5a, 0x6c, - 0xbc, 0x6e, 0x22, 0xad, 0xbd, 0x49, 0xd1, 0x0d, 0x16, 0x68, 0x1d, 0x55, 0xe9, 0x1a, 0x88, 0x63, - 0x83, 0xb2, 0x8a, 0x76, 0xb7, 0xa8, 0x20, 0x53, 0x13, 0x8a, 0x90, 0x44, 0x72, 0x49, 0x4a, 0xbb, - 0x2e, 0xd0, 0x62, 0xd1, 0x53, 0x90, 0xc3, 0xa2, 0x05, 0xf6, 0x1a, 0xa0, 0x45, 0xff, 0x81, 0x3d, - 0xf7, 0xc7, 0xa1, 0xb7, 0x3d, 0x15, 0x7b, 0x5c, 0x14, 0xe8, 0xa2, 0x48, 0x0e, 0xb9, 0xf4, 0x2f, - 0x28, 0x50, 0xa0, 0xe0, 0xcc, 0x90, 0xa2, 0xc8, 0xa1, 0x44, 0x59, 0xaa, 0xd1, 0x9b, 0x38, 0xf3, - 0xcd, 0x7b, 0x6f, 0xbe, 0xef, 0xcd, 0xe3, 0xcc, 0x50, 0xb0, 0xa5, 0x9c, 0x49, 0x15, 0x49, 0x33, - 0x50, 0x45, 0xea, 0xb4, 0x54, 0x15, 0xf5, 0x2a, 0xc3, 0xbd, 0x8a, 0xf5, 0x49, 0x59, 0x37, 0x34, - 0x4b, 0xe3, 0xb3, 0xca, 0x99, 0x54, 0xb6, 0x7b, 0xcb, 0xb4, 0xb7, 0x3c, 0xdc, 0x13, 0xd6, 0x64, - 0x4d, 0xd6, 0x70, 0x7f, 0xc5, 0xfe, 0x45, 0xa0, 0xc2, 0xba, 0xa4, 0x99, 0x7d, 0xcd, 0xac, 0xf4, - 0x4d, 0xd9, 0x36, 0xd1, 0x37, 0x65, 0xda, 0x51, 0x18, 0x79, 0xe8, 0x29, 0x48, 0xb5, 0xec, 0x5e, - 0xf2, 0x8b, 0x02, 0x6e, 0xb1, 0x42, 0x70, 0xfc, 0x4d, 0x80, 0x0c, 0x74, 0xd9, 0x68, 0xb5, 0x11, - 0x81, 0x94, 0x3e, 0xe7, 0x80, 0x3f, 0x32, 0xe5, 0x2a, 0xe9, 0x3f, 0xd6, 0x91, 0x7a, 0xa8, 0x2a, - 0x16, 0xbf, 0x0e, 0x69, 0x5d, 0x33, 0xac, 0xa6, 0xd2, 0xce, 0x71, 0x45, 0x6e, 0x67, 0x59, 0x4c, - 0xd9, 0x8f, 0x87, 0x6d, 0xfe, 0x3d, 0x48, 0x53, 0x5b, 0xb9, 0x58, 0x91, 0xdb, 0x59, 0xd9, 0xdf, - 0x2a, 0x33, 0x26, 0x5b, 0xa6, 0xf6, 0x1e, 0x26, 0xbe, 0xfc, 0xa6, 0xb0, 0x24, 0x3a, 0x43, 0xf8, - 0x9b, 0x90, 0x32, 0x15, 0x59, 0x45, 0x46, 0x2e, 0x4e, 0xac, 0x92, 0xa7, 0x07, 0xab, 0xcf, 0x7e, - 0x57, 0x58, 0xfa, 0xf5, 0xeb, 0x2f, 0x76, 0x69, 0x43, 0xe9, 0x43, 0x10, 0x82, 0x51, 0x89, 0xc8, - 0xd4, 0x35, 0xd5, 0x44, 0xfc, 0x36, 0x00, 0xb5, 0x38, 0x0a, 0x70, 0x99, 0xb6, 0x1c, 0xb6, 0xf9, - 0x1c, 0xa4, 0x87, 0xc8, 0x30, 0x15, 0x4d, 0xc5, 0x31, 0x2e, 0x8b, 0xce, 0xe3, 0x83, 0x84, 0xed, - 0xa7, 0xf4, 0x4d, 0x0c, 0xae, 0x8f, 0x5b, 0x3f, 0x35, 0xce, 0xc3, 0xa7, 0xbc, 0x0f, 0x59, 0xdd, - 0x40, 0x43, 0x45, 0x1b, 0x98, 0x4d, 0x8f, 0x5b, 0x6c, 0xfa, 0x61, 0x2c, 0xc7, 0x89, 0xd7, 0x9d, - 0xee, 0xaa, 0x1b, 0x82, 0x87, 0xa6, 0xf8, 0xec, 0x34, 0xed, 0xc1, 0x9a, 0xa4, 0x0d, 0x54, 0x0b, - 0x19, 0x7a, 0xcb, 0xb0, 0xce, 0x9b, 0xce, 0x6c, 0x12, 0x38, 0xae, 0xac, 0xb7, 0xef, 0xc7, 0xa4, - 0xcb, 0xa6, 0x44, 0x37, 0x34, 0xed, 0x69, 0x53, 0x51, 0x15, 0x2b, 0x97, 0x2c, 0x72, 0x3b, 0x57, - 0xc5, 0x65, 0xdc, 0x82, 0xf5, 0xac, 0xc2, 0x55, 0xd2, 0xdd, 0x41, 0x8a, 0xdc, 0xb1, 0x72, 0x29, - 0x1c, 0x94, 0xe0, 0x09, 0x8a, 0xa4, 0xd6, 0x70, 0xaf, 0xfc, 0x3e, 0x46, 0xd0, 0x90, 0x56, 0xf0, - 0x28, 0xd2, 0xe4, 0x51, 0x2f, 0x3d, 0x59, 0xbd, 0x0f, 0x60, 0x23, 0xc0, 0xaf, 0x2b, 0x9e, 0x47, - 0x1d, 0x6e, 0x4c, 0x1d, 0x9f, 0xac, 0x31, 0x9f, 0xac, 0x54, 0xbc, 0xbf, 0x06, 0xc4, 0x3b, 0x90, - 0xba, 0xe1, 0xe2, 0x4d, 0xb6, 0xc9, 0x7f, 0x17, 0xd6, 0xc7, 0x98, 0xf6, 0x60, 0x49, 0x86, 0xde, - 0xf0, 0x76, 0x8f, 0xf4, 0xbd, 0x80, 0x42, 0x9b, 0x40, 0xf4, 0x68, 0x5a, 0xc6, 0x39, 0x15, 0xe8, - 0x0a, 0x6e, 0xb0, 0x93, 0xef, 0x72, 0xf5, 0xd9, 0xf4, 0xeb, 0x73, 0x20, 0x75, 0x1d, 0x7d, 0x4a, - 0x7f, 0xe7, 0xe0, 0xc6, 0x78, 0x6f, 0x55, 0x53, 0x9f, 0x2a, 0x46, 0xff, 0xc2, 0x24, 0xbb, 0x33, - 0x6f, 0x49, 0x5d, 0x4c, 0xab, 0x33, 0x73, 0x5b, 0x39, 0xff, 0xcc, 0x13, 0xf3, 0xcd, 0x3c, 0x39, - 0x79, 0xe6, 0x05, 0xd8, 0x66, 0xce, 0xcd, 0x9d, 0xfd, 0x10, 0xb2, 0x23, 0x40, 0xb5, 0xa7, 0x99, - 0x68, 0x72, 0x3d, 0x9c, 0x32, 0xf5, 0xc8, 0x05, 0x6f, 0x1b, 0x36, 0x19, 0x7e, 0xdd, 0xb0, 0x7e, - 0x1f, 0x83, 0x9b, 0xbe, 0xfe, 0x79, 0x55, 0x19, 0xaf, 0x18, 0xf1, 0x69, 0x15, 0x63, 0x91, 0xba, - 0xf0, 0x0f, 0x61, 0x7b, 0x6c, 0xf9, 0xd0, 0x77, 0x52, 0xd3, 0x44, 0x1f, 0x0d, 0x90, 0x2a, 0x21, - 0x9c, 0xff, 0x09, 0x71, 0xd3, 0x0b, 0x6a, 0x10, 0x4c, 0x9d, 0x42, 0x82, 0x14, 0x16, 0x21, 0xcf, - 0xa6, 0xc8, 0x65, 0xf1, 0x15, 0x07, 0xd7, 0x8e, 0x4c, 0x59, 0x44, 0xd2, 0xf0, 0xa4, 0x25, 0x75, - 0x91, 0xc5, 0xbf, 0x0b, 0x29, 0x1d, 0xff, 0xc2, 0xdc, 0xad, 0xec, 0x6f, 0x32, 0xcb, 0x34, 0x01, - 0xd3, 0x09, 0xd2, 0x01, 0xfc, 0x5b, 0x90, 0x21, 0x04, 0x49, 0x5a, 0xbf, 0xaf, 0x58, 0x7d, 0xa4, - 0x5a, 0x98, 0xe4, 0xab, 0xe2, 0x2a, 0x6e, 0xaf, 0xba, 0xcd, 0x01, 0x2e, 0xe3, 0xf3, 0x71, 0x99, - 0x98, 0x9c, 0x4a, 0x3f, 0xc7, 0xeb, 0x77, 0x34, 0x49, 0xb7, 0xf2, 0x7e, 0x1f, 0x52, 0x06, 0x32, - 0x07, 0x3d, 0x32, 0xd9, 0x37, 0xf6, 0x6f, 0x33, 0x27, 0xeb, 0xc0, 0x45, 0x0c, 0x3d, 0x3d, 0xd7, - 0x91, 0x48, 0x87, 0xd1, 0x0a, 0xfc, 0x59, 0x0c, 0xe0, 0xc8, 0x94, 0x4f, 0x95, 0x3e, 0xd2, 0x06, - 0x8b, 0xa1, 0x70, 0xa0, 0x1a, 0x48, 0x42, 0xca, 0x10, 0xb5, 0xc7, 0x28, 0x6c, 0xb8, 0xcd, 0x8b, - 0xa1, 0xf0, 0x0e, 0xf0, 0x2a, 0xfa, 0xc4, 0x72, 0xd3, 0xac, 0x69, 0x20, 0x69, 0x88, 0xe9, 0x4c, - 0x88, 0x19, 0xbb, 0xc7, 0x49, 0x2e, 0x9b, 0xbc, 0xe8, 0x45, 0xe5, 0x43, 0xbc, 0x85, 0xa2, 0x7c, - 0x2c, 0x9a, 0xed, 0x7f, 0x93, 0xf7, 0x1d, 0xb5, 0x7e, 0xac, 0xe2, 0xc4, 0xbe, 0x24, 0xd2, 0x0b, - 0xb0, 0x42, 0x53, 0xdc, 0x76, 0x4a, 0x6b, 0x04, 0xa9, 0x1a, 0x24, 0x8c, 0x85, 0x14, 0x09, 0xb6, - 0x2a, 0xc9, 0xa9, 0xaa, 0xa4, 0x66, 0x2b, 0x29, 0xe9, 0x0b, 0x94, 0x94, 0x33, 0xfc, 0xa2, 0x1c, - 0xe7, 0x7e, 0xd1, 0x02, 0x3f, 0x8b, 0xe1, 0xf4, 0x39, 0x90, 0xba, 0xaa, 0xf6, 0x71, 0x0f, 0xb5, - 0x65, 0x84, 0x6b, 0xc6, 0x1c, 0x0a, 0xef, 0xc0, 0x6a, 0x6b, 0xdc, 0x9a, 0x23, 0xb0, 0xaf, 0x79, - 0x24, 0xb0, 0x3d, 0xb0, 0x3d, 0x26, 0xf0, 0x81, 0xdd, 0x72, 0xc9, 0x6f, 0x67, 0x09, 0xef, 0xfa, - 0x7d, 0x4c, 0x2c, 0x9a, 0xef, 0x3f, 0x8e, 0xed, 0x6f, 0x68, 0x0a, 0xcc, 0xf5, 0x92, 0xff, 0x01, - 0xa4, 0x9e, 0x2a, 0xa8, 0xd7, 0x36, 0x69, 0x55, 0x2a, 0x31, 0x03, 0xa3, 0x9e, 0x1e, 0x61, 0xa4, - 0xa3, 0x18, 0x19, 0x17, 0xbd, 0xb6, 0x7f, 0xc6, 0x79, 0x37, 0x30, 0x9e, 0xe0, 0x5d, 0x96, 0xde, - 0x83, 0x34, 0x4d, 0x7d, 0x9a, 0x38, 0x5b, 0x93, 0xa2, 0x71, 0x4e, 0x1e, 0x74, 0x88, 0x5d, 0x1c, - 0x02, 0x0b, 0x27, 0x86, 0x17, 0xce, 0xea, 0xc0, 0xb7, 0x58, 0x08, 0x9b, 0xff, 0x89, 0xc3, 0x5a, - 0x20, 0xa0, 0x89, 0xc7, 0xa9, 0x29, 0x64, 0xfe, 0x08, 0x8a, 0xba, 0xa1, 0xe9, 0x9a, 0x89, 0xda, - 0xee, 0x1a, 0x96, 0x34, 0x55, 0x45, 0x92, 0xa5, 0x68, 0x6a, 0xb3, 0xa3, 0xe9, 0x36, 0xcd, 0xf1, - 0x9d, 0x65, 0x71, 0xdb, 0xc1, 0x51, 0xaf, 0x55, 0x17, 0xf5, 0xbe, 0xa6, 0x9b, 0x7c, 0x07, 0x36, - 0x99, 0x05, 0x81, 0x4a, 0x95, 0x98, 0x51, 0xaa, 0x0d, 0x46, 0xe1, 0x20, 0x80, 0xe9, 0xa5, 0x27, - 0x39, 0xb5, 0xf4, 0xf0, 0xdf, 0x82, 0x6b, 0xb4, 0xd4, 0xd2, 0x63, 0x63, 0x0a, 0xaf, 0x45, 0xb2, - 0xfa, 0x28, 0xbb, 0x23, 0x90, 0xa3, 0x70, 0xda, 0x03, 0xa2, 0x16, 0x03, 0x4b, 0xf6, 0xca, 0x7c, - 0x4b, 0x76, 0x79, 0x72, 0x42, 0xfe, 0x8d, 0x83, 0x2d, 0x96, 0xfe, 0x97, 0x9e, 0x8f, 0x9e, 0xf2, - 0x10, 0x9f, 0xa7, 0x3c, 0xfc, 0x23, 0xc6, 0x48, 0xe8, 0x79, 0x8e, 0x98, 0x0d, 0xdf, 0x51, 0xd1, - 0x61, 0x23, 0x1e, 0x99, 0x8d, 0x2c, 0x23, 0x71, 0x82, 0x09, 0x93, 0x88, 0x92, 0x30, 0xc9, 0x08, - 0x09, 0xf3, 0xbf, 0x3d, 0x7b, 0x22, 0x46, 0xbe, 0x78, 0x8e, 0x9f, 0x8b, 0xaa, 0xf2, 0x7f, 0x8a, - 0x43, 0x2e, 0xe0, 0x67, 0xde, 0x23, 0xd3, 0x4f, 0x40, 0x60, 0xde, 0x16, 0x98, 0x56, 0xcb, 0x42, - 0x34, 0xed, 0x04, 0x66, 0xbc, 0x75, 0x1b, 0x21, 0xe6, 0x18, 0x97, 0x09, 0xb8, 0x27, 0x34, 0x49, - 0x12, 0x0b, 0x4e, 0x92, 0x64, 0x94, 0x24, 0x49, 0x45, 0x48, 0x92, 0xf4, 0x7c, 0x49, 0x72, 0x65, - 0x72, 0x92, 0x28, 0x50, 0x0c, 0x13, 0x6f, 0xd1, 0x89, 0xf2, 0x69, 0x9c, 0xb1, 0x1d, 0x38, 0xd6, - 0x91, 0xfa, 0x7f, 0x98, 0x25, 0x53, 0x5f, 0x34, 0x89, 0x0b, 0xbc, 0x68, 0x58, 0x29, 0x71, 0xb9, - 0x25, 0xa1, 0xc0, 0xd8, 0xd3, 0xd8, 0x0a, 0xb8, 0xe7, 0xf6, 0x3f, 0xc7, 0x18, 0x8b, 0xd9, 0x39, - 0x7f, 0x2e, 0xaa, 0x2e, 0xcf, 0x7e, 0x5f, 0x9b, 0x65, 0x08, 0x15, 0xad, 0x2e, 0xfb, 0xf9, 0x4d, - 0xce, 0xc7, 0x6f, 0x6a, 0x32, 0xbf, 0x25, 0xc6, 0x6a, 0xf2, 0x9d, 0x56, 0x4b, 0x7f, 0x89, 0xc1, - 0x7a, 0x70, 0xc9, 0xb5, 0x54, 0x09, 0xf5, 0x2e, 0xcc, 0xf0, 0x63, 0xb8, 0x86, 0x0c, 0x43, 0x33, - 0x9a, 0xf8, 0x40, 0xa9, 0x3b, 0x87, 0xf6, 0x5b, 0x4c, 0x6a, 0x6b, 0x36, 0x52, 0x24, 0x40, 0x3a, - 0xdb, 0xab, 0xc8, 0xd3, 0xc6, 0x97, 0x21, 0x4b, 0x38, 0x1b, 0xb7, 0x49, 0xe8, 0xbd, 0x8e, 0xbb, - 0xbc, 0x36, 0x2e, 0x99, 0xe3, 0x5b, 0x50, 0x08, 0xa1, 0xcf, 0xa5, 0xf8, 0x57, 0xb0, 0x7a, 0x64, - 0xca, 0x0d, 0xbd, 0xdd, 0xb2, 0xd0, 0x49, 0xcb, 0x68, 0xf5, 0x4d, 0x7e, 0x0b, 0x96, 0x5b, 0x03, - 0xab, 0xa3, 0x19, 0x8a, 0x75, 0xee, 0x7c, 0xc7, 0x70, 0x1b, 0xc8, 0x11, 0xd0, 0xc6, 0xd1, 0x4f, - 0x2d, 0x61, 0x47, 0x40, 0x1b, 0x32, 0x3a, 0x02, 0xda, 0x4f, 0x0f, 0x78, 0x27, 0xbe, 0x91, 0xb9, - 0xd2, 0x06, 0x56, 0xd8, 0xeb, 0xdf, 0x0d, 0xed, 0xb7, 0x1c, 0x5e, 0x60, 0x27, 0xc6, 0x40, 0x45, - 0xbe, 0xe3, 0x97, 0x79, 0x61, 0xf9, 0xd7, 0x20, 0xd9, 0x53, 0xfa, 0xf4, 0x6e, 0x31, 0x21, 0x92, - 0x87, 0xe8, 0x47, 0x9d, 0xcf, 0x39, 0x9c, 0xb6, 0xcc, 0x98, 0xdc, 0x97, 0xc0, 0x3d, 0xb8, 0x69, - 0x69, 0x56, 0xab, 0xd7, 0xd4, 0x6d, 0x58, 0xdb, 0xad, 0x84, 0x26, 0x0e, 0x35, 0x21, 0xae, 0xe1, - 0x5e, 0x6c, 0xa3, 0xed, 0x94, 0x40, 0x93, 0x7f, 0x00, 0x1b, 0x64, 0x94, 0x81, 0xfa, 0x2d, 0x45, - 0x55, 0x54, 0xd9, 0x33, 0x90, 0x6c, 0x2f, 0xd7, 0x31, 0x40, 0x74, 0xfa, 0xdd, 0xb1, 0xbb, 0x5f, - 0x73, 0xc0, 0x07, 0x5f, 0x2a, 0xfc, 0x7d, 0x28, 0x8a, 0xb5, 0xfa, 0xc9, 0xf1, 0x93, 0x7a, 0xad, - 0x29, 0xd6, 0xea, 0x8d, 0xc7, 0xa7, 0xcd, 0xd3, 0x9f, 0x9e, 0xd4, 0x9a, 0x8d, 0x27, 0xf5, 0x93, - 0x5a, 0xf5, 0xf0, 0xd1, 0x61, 0xed, 0x87, 0x99, 0x25, 0x61, 0xf5, 0xf9, 0x8b, 0xe2, 0x8a, 0xa7, - 0x89, 0xbf, 0x0d, 0x1b, 0xcc, 0x61, 0x4f, 0x8e, 0x8f, 0x4f, 0x32, 0x9c, 0x70, 0xe5, 0xf9, 0x8b, - 0x62, 0xc2, 0xfe, 0xcd, 0xdf, 0x85, 0x2d, 0x26, 0xb0, 0xde, 0xa8, 0x56, 0x6b, 0xf5, 0x7a, 0x26, - 0x26, 0xac, 0x3c, 0x7f, 0x51, 0x4c, 0xd3, 0xc7, 0x50, 0xf8, 0xa3, 0x83, 0xc3, 0xc7, 0x0d, 0xb1, - 0x96, 0x89, 0x13, 0x38, 0x7d, 0x14, 0x12, 0xcf, 0xfe, 0x90, 0x5f, 0xda, 0xff, 0x57, 0x06, 0xe2, - 0x47, 0xa6, 0xcc, 0x77, 0x61, 0xd5, 0xff, 0x3d, 0x90, 0xfd, 0x72, 0x0d, 0x7e, 0xa2, 0x13, 0x2a, - 0x11, 0x81, 0xae, 0x82, 0x1d, 0x78, 0xc3, 0xf7, 0x21, 0xee, 0xcd, 0x08, 0x26, 0x4e, 0x8d, 0x73, - 0xa1, 0x1c, 0x0d, 0x17, 0xe2, 0xc9, 0xde, 0xd2, 0x47, 0xf1, 0x74, 0x20, 0x75, 0x23, 0x79, 0xf2, - 0xee, 0x61, 0x2d, 0xe0, 0x19, 0x9f, 0x4f, 0x76, 0x23, 0x58, 0xa1, 0x58, 0x61, 0x3f, 0x3a, 0xd6, - 0xf5, 0xaa, 0x42, 0x26, 0xf0, 0xdd, 0x62, 0x67, 0x8a, 0x1d, 0x17, 0x29, 0xbc, 0x1d, 0x15, 0xe9, - 0xfa, 0xfb, 0x18, 0xb2, 0xac, 0xef, 0x11, 0xdf, 0x89, 0x62, 0xc8, 0x99, 0xe7, 0x3b, 0x33, 0x80, - 0x5d, 0xc7, 0x3f, 0x03, 0xf0, 0x5c, 0xe1, 0x97, 0xc2, 0x4c, 0x8c, 0x30, 0xc2, 0xee, 0x74, 0x8c, - 0x6b, 0xbd, 0x0e, 0x69, 0x67, 0x6b, 0x51, 0x08, 0x1b, 0x46, 0x01, 0xc2, 0xed, 0x29, 0x00, 0x6f, - 0xee, 0xf9, 0x6e, 0x70, 0xdf, 0x9c, 0x32, 0x94, 0xe2, 0xc2, 0x73, 0x2f, 0xe4, 0x56, 0xb2, 0x0b, - 0xab, 0xfe, 0xab, 0xc4, 0xd0, 0x28, 0x7d, 0xc0, 0xf0, 0xc5, 0x1b, 0x76, 0x25, 0x37, 0x4a, 0x74, - 0xef, 0x3d, 0xda, 0xb4, 0x44, 0xf7, 0x60, 0xa7, 0x26, 0x3a, 0xeb, 0x8a, 0xeb, 0x23, 0xb8, 0x1e, - 0xbc, 0x6f, 0x7a, 0x2b, 0x9a, 0x21, 0xbb, 0x70, 0xec, 0x45, 0x86, 0x86, 0xbb, 0xb4, 0xcb, 0x47, - 0x44, 0x97, 0x76, 0x05, 0xd9, 0x8b, 0x0c, 0x75, 0x5d, 0xfe, 0x12, 0x6e, 0xb0, 0x4f, 0xaf, 0x77, - 0xa3, 0xd9, 0x72, 0x96, 0xd8, 0xfd, 0x99, 0xe0, 0xe1, 0xd2, 0xe2, 0x33, 0x51, 0x44, 0x69, 0x6d, - 0x6c, 0x54, 0x69, 0xbd, 0x3b, 0xfd, 0xe0, 0xa4, 0x9d, 0xa5, 0x18, 0x71, 0xd2, 0xce, 0xc2, 0xbc, - 0x3f, 0x13, 0xdc, 0x75, 0xff, 0x0b, 0x58, 0x63, 0xee, 0x80, 0xef, 0x44, 0xe4, 0x10, 0xa3, 0x85, - 0x7b, 0xb3, 0xa0, 0x5d, 0xdf, 0x0a, 0x64, 0xc9, 0xde, 0x8c, 0xa2, 0xe8, 0x16, 0xf1, 0xdb, 0x61, - 0xc6, 0xbc, 0x1b, 0x39, 0xe1, 0x4e, 0x14, 0x94, 0x97, 0x65, 0xf6, 0x56, 0x2f, 0x94, 0x65, 0x26, - 0x3c, 0x9c, 0xe5, 0x89, 0x9b, 0x36, 0x21, 0xf9, 0xe9, 0xeb, 0x2f, 0x76, 0xb9, 0x87, 0xf5, 0x2f, - 0x5f, 0xe6, 0xb9, 0xaf, 0x5e, 0xe6, 0xb9, 0x7f, 0xbe, 0xcc, 0x73, 0xbf, 0x79, 0x95, 0x5f, 0xfa, - 0xea, 0x55, 0x7e, 0xe9, 0xeb, 0x57, 0xf9, 0xa5, 0x0f, 0xde, 0x95, 0x15, 0xab, 0x33, 0x38, 0x2b, - 0x4b, 0x5a, 0xbf, 0x42, 0xff, 0x1f, 0xa5, 0x9c, 0x49, 0x77, 0x65, 0xad, 0x32, 0xfc, 0x5e, 0xa5, - 0xaf, 0xb5, 0x07, 0x3d, 0x64, 0x92, 0xff, 0x35, 0xbd, 0x7d, 0xef, 0xae, 0xf3, 0xd7, 0x26, 0xeb, - 0x5c, 0x47, 0xe6, 0x59, 0x0a, 0xff, 0xad, 0xe9, 0x9d, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xf2, - 0x6f, 0x97, 0x8a, 0xa1, 0x25, 0x00, 0x00, + // 2106 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0xcd, 0x6f, 0x1b, 0xc7, + 0x15, 0xd7, 0xf2, 0x53, 0x7a, 0xb2, 0x2d, 0x69, 0x29, 0xdb, 0xd4, 0xea, 0x83, 0x34, 0x5b, 0xc4, + 0x8a, 0x6a, 0x93, 0x91, 0x62, 0x17, 0xb5, 0x11, 0xa0, 0x95, 0x18, 0xba, 0x11, 0x60, 0x59, 0xea, + 0x52, 0x2a, 0xda, 0xa4, 0x28, 0xb1, 0x5a, 0x8e, 0x57, 0x0b, 0x91, 0xbb, 0x9b, 0xdd, 0x25, 0x13, + 0x15, 0x68, 0x11, 0xf4, 0x64, 0xf8, 0x10, 0xa4, 0x40, 0xae, 0x06, 0x5a, 0xf4, 0x5c, 0x20, 0xe7, + 0x7e, 0x1c, 0x7a, 0x0b, 0x7a, 0x28, 0x72, 0x0c, 0x0a, 0x34, 0x2d, 0xec, 0x43, 0xfe, 0x87, 0x02, + 0x05, 0x8a, 0x9d, 0x99, 0x1d, 0x2e, 0x97, 0xb3, 0xe4, 0x4a, 0x64, 0x85, 0xdc, 0xb8, 0x33, 0xbf, + 0x79, 0xf3, 0xe6, 0xf7, 0x7b, 0xf3, 0xf6, 0xcd, 0x2c, 0x61, 0x45, 0x3f, 0x56, 0x2b, 0xaa, 0x69, + 0xa3, 0x8a, 0x7a, 0xa2, 0x18, 0x06, 0x6a, 0x55, 0xba, 0x9b, 0x15, 0xf7, 0xc3, 0xb2, 0x65, 0x9b, + 0xae, 0x29, 0xe6, 0xf4, 0x63, 0xb5, 0xec, 0xf5, 0x96, 0x69, 0x6f, 0xb9, 0xbb, 0x29, 0x15, 0x34, + 0xd3, 0xd4, 0x5a, 0xa8, 0x82, 0x21, 0xc7, 0x9d, 0xa7, 0x15, 0x57, 0x6f, 0x23, 0xc7, 0x55, 0xda, + 0x16, 0x19, 0x25, 0x2d, 0x6a, 0xa6, 0x66, 0xe2, 0x9f, 0x15, 0xef, 0x17, 0x6d, 0xbd, 0xa9, 0x9a, + 0x4e, 0xdb, 0x74, 0x2a, 0x6d, 0x47, 0xf3, 0xe6, 0x68, 0x3b, 0x1a, 0xed, 0x28, 0xf4, 0x5c, 0x68, + 0xe9, 0xc8, 0x70, 0xbd, 0x5e, 0xf2, 0x8b, 0x02, 0x6e, 0xf1, 0x7c, 0xf4, 0x1d, 0x1a, 0x02, 0xe9, + 0x58, 0x9a, 0xad, 0x34, 0x11, 0x81, 0x94, 0x3e, 0x15, 0x40, 0xdc, 0x73, 0xb4, 0x2a, 0xe9, 0xdf, + 0xb7, 0x90, 0xb1, 0x6b, 0xe8, 0xae, 0x78, 0x13, 0xb2, 0x96, 0x69, 0xbb, 0x0d, 0xbd, 0x99, 0x17, + 0x8a, 0xc2, 0xfa, 0x8c, 0x9c, 0xf1, 0x1e, 0x77, 0x9b, 0xe2, 0x5b, 0x90, 0xa5, 0xb6, 0xf2, 0x89, + 0xa2, 0xb0, 0x3e, 0xbb, 0xb5, 0x52, 0xe6, 0xb0, 0x51, 0xa6, 0xf6, 0x76, 0x52, 0x9f, 0x7f, 0x55, + 0x98, 0x92, 0xfd, 0x21, 0xe2, 0x0d, 0xc8, 0x38, 0xba, 0x66, 0x20, 0x3b, 0x9f, 0x24, 0x56, 0xc9, + 0xd3, 0xc3, 0xb9, 0x67, 0xbf, 0x2d, 0x4c, 0xfd, 0xfa, 0xeb, 0xcf, 0x36, 0x68, 0x43, 0xe9, 0x3d, + 0x90, 0x06, 0xbd, 0x92, 0x91, 0x63, 0x99, 0x86, 0x83, 0xc4, 0x55, 0x00, 0x6a, 0xb1, 0xe7, 0xe0, + 0x0c, 0x6d, 0xd9, 0x6d, 0x8a, 0x79, 0xc8, 0x76, 0x91, 0xed, 0xe8, 0xa6, 0x81, 0x7d, 0x9c, 0x91, + 0xfd, 0xc7, 0x87, 0x29, 0x6f, 0x9e, 0xd2, 0x57, 0x09, 0x58, 0xe8, 0xb7, 0x7e, 0x68, 0x9f, 0x45, + 0x2f, 0x79, 0x0b, 0x72, 0x96, 0x8d, 0xba, 0xba, 0xd9, 0x71, 0x1a, 0x81, 0x69, 0xb1, 0xe9, 0x9d, + 0x44, 0x5e, 0x90, 0x17, 0xfc, 0xee, 0x2a, 0x73, 0x21, 0x40, 0x53, 0xf2, 0xfc, 0x34, 0x6d, 0xc2, + 0xa2, 0x6a, 0x76, 0x0c, 0x17, 0xd9, 0x96, 0x62, 0xbb, 0x67, 0x0d, 0x7f, 0x35, 0x29, 0xec, 0x57, + 0x2e, 0xd8, 0xf7, 0x63, 0xd2, 0xe5, 0x51, 0x62, 0xd9, 0xa6, 0xf9, 0xb4, 0xa1, 0x1b, 0xba, 0x9b, + 0x4f, 0x17, 0x85, 0xf5, 0x2b, 0xf2, 0x0c, 0x6e, 0xc1, 0x7a, 0x56, 0xe1, 0x0a, 0xe9, 0x3e, 0x41, + 0xba, 0x76, 0xe2, 0xe6, 0x33, 0xd8, 0x29, 0x29, 0xe0, 0x14, 0x09, 0xad, 0xee, 0x66, 0xf9, 0x1d, + 0x8c, 0xa0, 0x2e, 0xcd, 0xe2, 0x51, 0xa4, 0x29, 0xa0, 0x5e, 0x76, 0xb8, 0x7a, 0xef, 0xc2, 0xd2, + 0x00, 0xbf, 0x4c, 0xbc, 0x80, 0x3a, 0x42, 0x9f, 0x3a, 0x21, 0x59, 0x13, 0x21, 0x59, 0xa9, 0x78, + 0x7f, 0x1d, 0x10, 0x6f, 0x5b, 0x3d, 0x8d, 0x16, 0x6f, 0xb8, 0x4d, 0xf1, 0xbb, 0x70, 0xb3, 0x8f, + 0xe9, 0x00, 0x96, 0x44, 0xe8, 0xf5, 0x60, 0x77, 0x4f, 0xdf, 0x0b, 0x28, 0xb4, 0x0c, 0x44, 0x8f, + 0x86, 0x6b, 0x9f, 0x51, 0x81, 0xa6, 0x71, 0x83, 0x17, 0x7c, 0x97, 0xab, 0xcf, 0x72, 0x58, 0x9f, + 0x6d, 0xf5, 0xd4, 0xd7, 0xa7, 0xf4, 0x0f, 0x01, 0xae, 0xf7, 0xf7, 0x56, 0x4d, 0xe3, 0xa9, 0x6e, + 0xb7, 0x2f, 0x4c, 0x32, 0x5b, 0xb9, 0xa2, 0x9e, 0x62, 0x5a, 0xfd, 0x95, 0x7b, 0xca, 0x85, 0x57, + 0x9e, 0x1a, 0x6f, 0xe5, 0xe9, 0xe1, 0x2b, 0x2f, 0xc0, 0x2a, 0x77, 0x6d, 0x6c, 0xf5, 0x5d, 0xc8, + 0xf5, 0x00, 0xd5, 0x96, 0xe9, 0xa0, 0xe1, 0xf9, 0x70, 0xc4, 0xd2, 0x63, 0x27, 0xbc, 0x55, 0x58, + 0xe6, 0xcc, 0xcb, 0xdc, 0xfa, 0x5d, 0x02, 0x6e, 0x84, 0xfa, 0xc7, 0x55, 0xa5, 0x3f, 0x63, 0x24, + 0x47, 0x65, 0x8c, 0x49, 0xea, 0x22, 0xee, 0xc0, 0x6a, 0xdf, 0xf6, 0xa1, 0xef, 0xa4, 0x86, 0x83, + 0xde, 0xef, 0x20, 0x43, 0x45, 0x38, 0xfe, 0x53, 0xf2, 0x72, 0x10, 0x74, 0x44, 0x30, 0x75, 0x0a, + 0x19, 0xa4, 0xb0, 0x08, 0x6b, 0x7c, 0x8a, 0x18, 0x8b, 0x7f, 0x48, 0xc0, 0xd5, 0x3d, 0x47, 0xab, + 0x23, 0xa3, 0x79, 0xa0, 0xa8, 0xa7, 0xe8, 0xe2, 0xba, 0xfe, 0x10, 0xae, 0x79, 0xef, 0x77, 0xb3, + 0xe3, 0xfa, 0xfc, 0x24, 0x63, 0xf2, 0x73, 0x95, 0x8e, 0xa3, 0x0c, 0xfd, 0x08, 0x16, 0x7c, 0x43, + 0xac, 0x60, 0x60, 0x5c, 0x93, 0x92, 0xa2, 0xec, 0x97, 0x14, 0xe5, 0x43, 0x1f, 0xb1, 0x33, 0xed, + 0xd9, 0xfa, 0xe4, 0x5f, 0x05, 0x41, 0x9e, 0xa7, 0xc3, 0x59, 0x9f, 0x58, 0x80, 0x59, 0x0b, 0xaf, + 0xae, 0xd1, 0x54, 0x5c, 0x85, 0xa6, 0x1a, 0x20, 0x4d, 0x6f, 0x2b, 0xae, 0x12, 0x50, 0x25, 0x33, + 0x3c, 0x28, 0x1f, 0xe0, 0x4c, 0xd0, 0xa3, 0x8b, 0xe5, 0x70, 0x09, 0xa6, 0x99, 0x54, 0x02, 0x96, + 0x8a, 0x3d, 0xd3, 0x34, 0xfd, 0x4a, 0xc0, 0x54, 0xcb, 0x48, 0xed, 0x52, 0xaa, 0x1f, 0x40, 0x86, + 0xf8, 0x80, 0x47, 0xcc, 0x6e, 0x2d, 0x73, 0xdf, 0x88, 0x04, 0x4c, 0xb9, 0xa2, 0x03, 0xc4, 0xd7, + 0x61, 0x9e, 0xc4, 0xa2, 0x6a, 0xb6, 0xdb, 0xba, 0xdb, 0x46, 0x86, 0x8b, 0x25, 0xb9, 0x22, 0xcf, + 0xe1, 0xf6, 0x2a, 0x6b, 0x1e, 0x08, 0xdb, 0xe4, 0x78, 0x61, 0x9b, 0x1a, 0x4e, 0xd0, 0xcf, 0x31, + 0x41, 0xbd, 0x45, 0x32, 0x82, 0xbe, 0x0f, 0x19, 0x1b, 0x39, 0x9d, 0x16, 0x59, 0xec, 0xb5, 0xad, + 0xdb, 0xdc, 0xc5, 0xfa, 0x70, 0x19, 0x43, 0x0f, 0xcf, 0x2c, 0x24, 0xd3, 0x61, 0x94, 0xc5, 0x8f, + 0x13, 0x00, 0x7b, 0x8e, 0x76, 0x48, 0x24, 0x9e, 0x08, 0x85, 0x1d, 0xc3, 0x46, 0x2a, 0xd2, 0xbb, + 0xa8, 0xd9, 0x47, 0xe1, 0x11, 0x6b, 0x9e, 0x0c, 0x85, 0x77, 0x40, 0x34, 0xd0, 0x87, 0x2e, 0xdb, + 0xd1, 0x0d, 0x1b, 0xa9, 0x5d, 0x4c, 0x67, 0x4a, 0x9e, 0xf7, 0x7a, 0xfc, 0x7d, 0xec, 0x91, 0x17, + 0x3f, 0x7f, 0xbf, 0x87, 0xab, 0x55, 0xca, 0xc7, 0xa4, 0xd9, 0xfe, 0x0f, 0x29, 0x2d, 0xa8, 0xf5, + 0x7d, 0x03, 0xe7, 0x90, 0x4b, 0x22, 0xdd, 0xdb, 0xb4, 0x24, 0xc4, 0xbd, 0x49, 0x69, 0x3a, 0x26, + 0x09, 0x9a, 0xb8, 0x31, 0x91, 0x7c, 0xcc, 0x57, 0x25, 0x3d, 0x52, 0x95, 0xcc, 0xf9, 0xb2, 0x77, + 0xf6, 0x02, 0xd9, 0xfb, 0x18, 0xd7, 0x24, 0xfd, 0xdc, 0x4f, 0x5a, 0xe0, 0x67, 0x09, 0x1c, 0x3e, + 0xdb, 0xea, 0xa9, 0x61, 0x7e, 0xd0, 0x42, 0x4d, 0x0d, 0xe1, 0x9c, 0x31, 0x86, 0xc2, 0xeb, 0x30, + 0xa7, 0xf4, 0x5b, 0xf3, 0x05, 0x0e, 0x35, 0xf7, 0x04, 0xf6, 0x06, 0x36, 0xfb, 0x04, 0xde, 0xf6, + 0x5a, 0x2e, 0xb9, 0x10, 0x52, 0xf1, 0x01, 0x2b, 0xc4, 0xc4, 0xa4, 0xf9, 0xfe, 0x63, 0x5f, 0x29, + 0x49, 0x43, 0x60, 0xac, 0x7a, 0xea, 0x07, 0x90, 0x79, 0xaa, 0xa3, 0x56, 0xd3, 0xa1, 0x59, 0xa9, + 0xc4, 0x75, 0x8c, 0xce, 0xf4, 0x08, 0x23, 0x7d, 0xc5, 0xc8, 0xb8, 0xf8, 0xb9, 0xfd, 0x63, 0x21, + 0x58, 0x2b, 0x06, 0x9c, 0x67, 0x2c, 0xbd, 0x05, 0x59, 0x1a, 0xfa, 0x34, 0x70, 0x56, 0x86, 0x79, + 0xe3, 0x1f, 0xf2, 0xe8, 0x10, 0x2f, 0x39, 0x0c, 0x6c, 0x9c, 0x04, 0xde, 0x38, 0x73, 0x9d, 0xd0, + 0x66, 0x21, 0x6c, 0xfe, 0x37, 0x09, 0x8b, 0x03, 0x0e, 0x0d, 0x3d, 0xb9, 0x8e, 0x2c, 0x62, 0x8a, + 0x96, 0x6d, 0x5a, 0xa6, 0x83, 0x9a, 0x6c, 0x0f, 0xab, 0xa6, 0x61, 0x20, 0xd5, 0xd5, 0x4d, 0xa3, + 0x71, 0x62, 0x5a, 0x1e, 0xcd, 0xc9, 0xf5, 0x19, 0x79, 0xd5, 0xc7, 0xd1, 0x59, 0xab, 0x0c, 0xf5, + 0x8e, 0x69, 0x39, 0xe2, 0x09, 0x2c, 0x73, 0x13, 0x02, 0x95, 0x2a, 0x75, 0x4e, 0xa9, 0x96, 0x38, + 0x89, 0x83, 0x00, 0x46, 0xa7, 0x9e, 0xf4, 0xc8, 0xd4, 0x23, 0x7e, 0x0b, 0xae, 0xd2, 0x54, 0x4b, + 0x4f, 0xe8, 0x19, 0xbc, 0x17, 0xc9, 0xee, 0xa3, 0xec, 0xf6, 0x40, 0xbe, 0xc2, 0xd9, 0x00, 0x88, + 0x5a, 0x1c, 0xd8, 0xb2, 0xd3, 0xe3, 0x6d, 0xd9, 0x99, 0xe1, 0x01, 0xf9, 0x77, 0x01, 0x56, 0x78, + 0xfa, 0x5f, 0x7a, 0x3c, 0x06, 0xd2, 0x43, 0x72, 0x9c, 0xf4, 0xf0, 0xcf, 0x04, 0x27, 0xa0, 0xc7, + 0x39, 0xcd, 0x1f, 0x85, 0x4e, 0xe5, 0x3e, 0x1b, 0xc9, 0xd8, 0x6c, 0xe4, 0x38, 0x81, 0x33, 0x18, + 0x30, 0xa9, 0x38, 0x01, 0x93, 0x8e, 0x11, 0x30, 0xff, 0xdf, 0x63, 0x3e, 0xe2, 0xc4, 0x4b, 0xe0, + 0xa4, 0x3f, 0xa9, 0x2c, 0xff, 0xa7, 0x24, 0xe4, 0x07, 0xe6, 0x19, 0xf7, 0x74, 0xfa, 0x13, 0x90, + 0xb8, 0x17, 0x33, 0x8e, 0xab, 0xb8, 0x88, 0x86, 0x9d, 0xc4, 0xf5, 0xb7, 0xee, 0x21, 0xe4, 0x3c, + 0xe7, 0xde, 0x06, 0xf7, 0x44, 0x06, 0x49, 0x6a, 0xc2, 0x41, 0x92, 0x8e, 0x13, 0x24, 0x99, 0x18, + 0x41, 0x92, 0x1d, 0x2f, 0x48, 0xa6, 0x87, 0x07, 0x89, 0x0e, 0xc5, 0x28, 0xf1, 0x26, 0x1d, 0x28, + 0x1f, 0x25, 0x39, 0xe5, 0xc0, 0xbe, 0x85, 0x8c, 0x6f, 0x60, 0x94, 0x8c, 0x7c, 0xd1, 0xa4, 0x2e, + 0xf0, 0xa2, 0xe1, 0x85, 0xc4, 0xe5, 0xa6, 0x84, 0x02, 0xa7, 0xa6, 0xf1, 0x14, 0x60, 0x57, 0x24, + 0x7f, 0x4e, 0x70, 0x36, 0xb3, 0x7f, 0xfe, 0x9c, 0x54, 0x5e, 0x3e, 0xff, 0xd5, 0x78, 0x8e, 0x23, + 0x54, 0xbc, 0xbc, 0x1c, 0xe6, 0x37, 0x3d, 0x1e, 0xbf, 0x23, 0x6e, 0x4c, 0x4a, 0x9c, 0xdd, 0x14, + 0x3a, 0xad, 0x96, 0xfe, 0x92, 0x80, 0x9b, 0x83, 0x5b, 0x4e, 0x31, 0x54, 0xd4, 0xba, 0x30, 0xc3, + 0x8f, 0xe1, 0x2a, 0xb2, 0x6d, 0xd3, 0x6e, 0xe0, 0x03, 0xa5, 0xe5, 0x1f, 0xda, 0x6f, 0x71, 0xa9, + 0xad, 0x79, 0x48, 0x99, 0x00, 0xe9, 0x6a, 0xaf, 0xa0, 0x40, 0x9b, 0x58, 0x86, 0x1c, 0xe1, 0xac, + 0xdf, 0x26, 0xa1, 0x77, 0x01, 0x77, 0x05, 0x6d, 0x5c, 0x32, 0xc7, 0xb7, 0xa0, 0x10, 0x41, 0x1f, + 0xa3, 0xf8, 0x57, 0x30, 0xb7, 0xe7, 0x68, 0x47, 0x56, 0x53, 0x71, 0xd1, 0x81, 0x62, 0x2b, 0x6d, + 0x47, 0x5c, 0x81, 0x19, 0xa5, 0xe3, 0x9e, 0x98, 0xb6, 0xee, 0x9e, 0xf9, 0x9f, 0x8c, 0x58, 0x03, + 0x39, 0x02, 0x7a, 0x38, 0xfa, 0x55, 0x2b, 0xea, 0x08, 0xe8, 0x41, 0x7a, 0x47, 0x40, 0xef, 0xe9, + 0xa1, 0xe8, 0xfb, 0xd7, 0x33, 0x57, 0x5a, 0xc2, 0x0a, 0x07, 0xe7, 0x67, 0xae, 0xfd, 0x46, 0xc0, + 0x1b, 0xec, 0xc0, 0xee, 0x18, 0x28, 0x74, 0xfc, 0x72, 0x2e, 0x2c, 0xff, 0x22, 0xa4, 0x5b, 0x7a, + 0x9b, 0x5e, 0xe3, 0xa6, 0x64, 0xf2, 0x10, 0xff, 0xa8, 0xf3, 0xa9, 0x80, 0xc3, 0x96, 0xeb, 0x13, + 0x7b, 0x09, 0xdc, 0x83, 0x1b, 0xae, 0xe9, 0x2a, 0xad, 0x86, 0xe5, 0xc1, 0x9a, 0x2c, 0x13, 0x3a, + 0xf4, 0x06, 0x70, 0x11, 0xf7, 0x62, 0x1b, 0x4d, 0x3f, 0x05, 0x3a, 0xe2, 0x43, 0x58, 0x22, 0xa3, + 0x6c, 0xd4, 0x56, 0x74, 0x43, 0x37, 0xb4, 0xc0, 0x40, 0x52, 0x5e, 0xde, 0xc4, 0x00, 0xd9, 0xef, + 0x67, 0x63, 0x37, 0xbe, 0x14, 0x40, 0x1c, 0x7c, 0xa9, 0x88, 0xf7, 0xa1, 0x28, 0xd7, 0xea, 0x07, + 0xfb, 0x4f, 0xea, 0xb5, 0x86, 0x5c, 0xab, 0x1f, 0x3d, 0x3e, 0x6c, 0x1c, 0xfe, 0xf4, 0xa0, 0xd6, + 0x38, 0x7a, 0x52, 0x3f, 0xa8, 0x55, 0x77, 0x1f, 0xed, 0xd6, 0xde, 0x9e, 0x9f, 0x92, 0xe6, 0x9e, + 0xbf, 0x28, 0xce, 0x06, 0x9a, 0xc4, 0xdb, 0xb0, 0xc4, 0x1d, 0xf6, 0x64, 0x7f, 0xff, 0x60, 0x5e, + 0x90, 0xa6, 0x9f, 0xbf, 0x28, 0xa6, 0xbc, 0xdf, 0xe2, 0x5d, 0x58, 0xe1, 0x02, 0xeb, 0x47, 0xd5, + 0x6a, 0xad, 0x5e, 0x9f, 0x4f, 0x48, 0xb3, 0xcf, 0x5f, 0x14, 0xb3, 0xf4, 0x31, 0x12, 0xfe, 0x68, + 0x7b, 0xf7, 0xf1, 0x91, 0x5c, 0x9b, 0x4f, 0x12, 0x38, 0x7d, 0x94, 0x52, 0xcf, 0x7e, 0xbf, 0x36, + 0xb5, 0xf5, 0xb7, 0x05, 0x48, 0xee, 0x39, 0x9a, 0x78, 0x0a, 0x73, 0xe1, 0x4f, 0xaf, 0xfc, 0x97, + 0xeb, 0xe0, 0xd7, 0x50, 0xa9, 0x12, 0x13, 0xc8, 0x14, 0x3c, 0x81, 0x6b, 0xa1, 0x6f, 0x9e, 0xaf, + 0xc5, 0x30, 0x71, 0x68, 0x9f, 0x49, 0xe5, 0x78, 0xb8, 0x88, 0x99, 0xbc, 0x92, 0x3e, 0xce, 0x4c, + 0xdb, 0xea, 0x69, 0xac, 0x99, 0x82, 0x35, 0xac, 0x0b, 0x22, 0xe7, 0x4b, 0xd5, 0x46, 0x0c, 0x2b, + 0x14, 0x2b, 0x6d, 0xc5, 0xc7, 0xb2, 0x59, 0x0d, 0x98, 0x1f, 0xf8, 0x44, 0xb4, 0x3e, 0xc2, 0x0e, + 0x43, 0x4a, 0x6f, 0xc4, 0x45, 0xb2, 0xf9, 0x3e, 0x80, 0x1c, 0xef, 0xd3, 0xcf, 0x77, 0xe2, 0x18, + 0xf2, 0xd7, 0xf9, 0xe6, 0x39, 0xc0, 0x6c, 0xe2, 0x9f, 0x01, 0x04, 0xbe, 0x96, 0x94, 0xa2, 0x4c, + 0xf4, 0x30, 0xd2, 0xc6, 0x68, 0x4c, 0xd0, 0x7a, 0xe0, 0x03, 0x41, 0xa4, 0xf5, 0x1e, 0x26, 0xda, + 0x3a, 0xe7, 0x0e, 0xbe, 0x0e, 0x59, 0xbf, 0x70, 0x29, 0x44, 0x0d, 0xa3, 0x00, 0xe9, 0xf6, 0x08, + 0x40, 0x30, 0xb2, 0x43, 0xf7, 0xc3, 0xaf, 0x8d, 0x18, 0x4a, 0x71, 0xd1, 0x91, 0x1d, 0x71, 0xe7, + 0x79, 0x0a, 0x73, 0xe1, 0x8b, 0xca, 0x48, 0x2f, 0x43, 0xc0, 0xe8, 0xd4, 0x10, 0x75, 0xe1, 0xd7, + 0xdb, 0x46, 0xc1, 0x5b, 0xba, 0x51, 0xdb, 0x28, 0x80, 0x1d, 0xb9, 0x8d, 0x78, 0x17, 0x68, 0xef, + 0xc3, 0xc2, 0xe0, 0x6d, 0xd6, 0xeb, 0xf1, 0x0c, 0x79, 0x69, 0x69, 0x33, 0x36, 0x34, 0x7a, 0x4a, + 0x2f, 0x39, 0xc5, 0x9c, 0xd2, 0xcb, 0x4f, 0x9b, 0xb1, 0xa1, 0x6c, 0xca, 0x5f, 0xc2, 0x75, 0xfe, + 0xd9, 0xf8, 0x6e, 0x3c, 0x5b, 0xfe, 0x06, 0xbe, 0x7f, 0x2e, 0x78, 0xb4, 0xb4, 0xf8, 0xc4, 0x15, + 0x53, 0x5a, 0x0f, 0x1b, 0x57, 0xda, 0xe0, 0x39, 0x62, 0x70, 0xd1, 0xfe, 0x56, 0x8c, 0xb9, 0x68, + 0x7f, 0x63, 0xde, 0x3f, 0x17, 0x9c, 0x4d, 0xff, 0x0b, 0x58, 0xe4, 0xd6, 0xd7, 0x77, 0x62, 0x72, + 0x88, 0xd1, 0xd2, 0xbd, 0xf3, 0xa0, 0xd9, 0xdc, 0x3a, 0xe4, 0x48, 0xe5, 0x47, 0x51, 0xb4, 0x00, + 0xfd, 0x76, 0x94, 0xb1, 0x60, 0x99, 0x28, 0xdd, 0x89, 0x83, 0x0a, 0xb2, 0xcc, 0x2f, 0x24, 0x23, + 0x59, 0xe6, 0xc2, 0xa3, 0x59, 0x1e, 0x5a, 0x12, 0x4a, 0xe9, 0x8f, 0xbe, 0xfe, 0x6c, 0x43, 0xd8, + 0xa9, 0x7f, 0xfe, 0x72, 0x4d, 0xf8, 0xe2, 0xe5, 0x9a, 0xf0, 0xef, 0x97, 0x6b, 0xc2, 0x27, 0xaf, + 0xd6, 0xa6, 0xbe, 0x78, 0xb5, 0x36, 0xf5, 0xe5, 0xab, 0xb5, 0xa9, 0x77, 0x1f, 0x68, 0xba, 0x7b, + 0xd2, 0x39, 0x2e, 0xab, 0x66, 0xbb, 0x42, 0xff, 0xe8, 0xa6, 0x1f, 0xab, 0x77, 0x35, 0xb3, 0xd2, + 0xfd, 0x5e, 0xa5, 0x6d, 0x36, 0x3b, 0x2d, 0xe4, 0x90, 0x3f, 0xa8, 0xbd, 0x71, 0xef, 0xae, 0xff, + 0x1f, 0x35, 0xf7, 0xcc, 0x42, 0xce, 0x71, 0x06, 0x7f, 0xf5, 0x7e, 0xf3, 0x7f, 0x01, 0x00, 0x00, + 0xff, 0xff, 0xfb, 0x3b, 0xc3, 0x28, 0x8b, 0x27, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1827,6 +1922,8 @@ type MsgClient interface { // ChannelCloseConfirm defines a rpc handler method for // MsgChannelCloseConfirm. ChannelCloseConfirm(ctx context.Context, in *MsgChannelCloseConfirm, opts ...grpc.CallOption) (*MsgChannelCloseConfirmResponse, error) + // SendPacket defines a rpc handler method for MsgSendPacket. + SendPacket(ctx context.Context, in *MsgSendPacket, opts ...grpc.CallOption) (*MsgSendPacketResponse, error) // RecvPacket defines a rpc handler method for MsgRecvPacket. RecvPacket(ctx context.Context, in *MsgRecvPacket, opts ...grpc.CallOption) (*MsgRecvPacketResponse, error) // Timeout defines a rpc handler method for MsgTimeout. @@ -1917,6 +2014,15 @@ func (c *msgClient) ChannelCloseConfirm(ctx context.Context, in *MsgChannelClose return out, nil } +func (c *msgClient) SendPacket(ctx context.Context, in *MsgSendPacket, opts ...grpc.CallOption) (*MsgSendPacketResponse, error) { + out := new(MsgSendPacketResponse) + err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/SendPacket", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) RecvPacket(ctx context.Context, in *MsgRecvPacket, opts ...grpc.CallOption) (*MsgRecvPacketResponse, error) { out := new(MsgRecvPacketResponse) err := c.cc.Invoke(ctx, "/ibc.core.channel.v1.Msg/RecvPacket", in, out, opts...) @@ -2049,6 +2155,8 @@ type MsgServer interface { // ChannelCloseConfirm defines a rpc handler method for // MsgChannelCloseConfirm. ChannelCloseConfirm(context.Context, *MsgChannelCloseConfirm) (*MsgChannelCloseConfirmResponse, error) + // SendPacket defines a rpc handler method for MsgSendPacket. + SendPacket(context.Context, *MsgSendPacket) (*MsgSendPacketResponse, error) // RecvPacket defines a rpc handler method for MsgRecvPacket. RecvPacket(context.Context, *MsgRecvPacket) (*MsgRecvPacketResponse, error) // Timeout defines a rpc handler method for MsgTimeout. @@ -2099,6 +2207,9 @@ func (*UnimplementedMsgServer) ChannelCloseInit(ctx context.Context, req *MsgCha func (*UnimplementedMsgServer) ChannelCloseConfirm(ctx context.Context, req *MsgChannelCloseConfirm) (*MsgChannelCloseConfirmResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ChannelCloseConfirm not implemented") } +func (*UnimplementedMsgServer) SendPacket(ctx context.Context, req *MsgSendPacket) (*MsgSendPacketResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendPacket not implemented") +} func (*UnimplementedMsgServer) RecvPacket(ctx context.Context, req *MsgRecvPacket) (*MsgRecvPacketResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RecvPacket not implemented") } @@ -2251,6 +2362,24 @@ func _Msg_ChannelCloseConfirm_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Msg_SendPacket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSendPacket) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SendPacket(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ibc.core.channel.v1.Msg/SendPacket", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SendPacket(ctx, req.(*MsgSendPacket)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_RecvPacket_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgRecvPacket) if err := dec(in); err != nil { @@ -2513,6 +2642,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "ChannelCloseConfirm", Handler: _Msg_ChannelCloseConfirm_Handler, }, + { + MethodName: "SendPacket", + Handler: _Msg_SendPacket_Handler, + }, { MethodName: "RecvPacket", Handler: _Msg_RecvPacket_Handler, @@ -3107,6 +3240,103 @@ func (m *MsgChannelCloseConfirmResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *MsgSendPacket) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSendPacket) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSendPacket) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0x32 + } + if len(m.PacketData) > 0 { + i -= len(m.PacketData) + copy(dAtA[i:], m.PacketData) + i = encodeVarintTx(dAtA, i, uint64(len(m.PacketData))) + i-- + dAtA[i] = 0x2a + } + n7, err7 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.TimeoutTimestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.TimeoutTimestamp):]) + if err7 != nil { + return 0, err7 + } + i -= n7 + i = encodeVarintTx(dAtA, i, uint64(n7)) + i-- + dAtA[i] = 0x22 + { + size, err := m.TimeoutHeight.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChannelId))) + i-- + dAtA[i] = 0x12 + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTx(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSendPacketResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSendPacketResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSendPacketResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Sequence != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *MsgRecvPacket) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4593,6 +4823,47 @@ func (m *MsgChannelCloseConfirmResponse) Size() (n int) { return n } +func (m *MsgSendPacket) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.TimeoutHeight.Size() + n += 1 + l + sovTx(uint64(l)) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.TimeoutTimestamp) + n += 1 + l + sovTx(uint64(l)) + l = len(m.PacketData) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgSendPacketResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sequence != 0 { + n += 1 + sovTx(uint64(m.Sequence)) + } + return n +} + func (m *MsgRecvPacket) Size() (n int) { if m == nil { return 0 @@ -6839,6 +7110,321 @@ func (m *MsgChannelCloseConfirmResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgSendPacket) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSendPacket: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSendPacket: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeoutHeight", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TimeoutHeight.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeoutTimestamp", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.TimeoutTimestamp, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PacketData", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PacketData = append(m.PacketData[:0], dAtA[iNdEx:postIndex]...) + if m.PacketData == nil { + m.PacketData = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Signer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSendPacketResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSendPacketResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSendPacketResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) + } + m.Sequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgRecvPacket) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index a30e96d1ed6..3f3979feb8b 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -445,6 +445,35 @@ func (k *Keeper) ChannelCloseConfirm(goCtx context.Context, msg *channeltypes.Ms return &channeltypes.MsgChannelCloseConfirmResponse{}, nil } +// SendPacket defines a rpc handler method for MsgSendPacket. +func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPacket) (*channeltypes.MsgSendPacketResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) + if err != nil { + ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) + return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") + } + + // Retrieve callbacks from router + cbs, ok := k.PortKeeper.Route(module) + if !ok { + ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + } + + sequence, err := k.ChannelKeeper.SendPacket(ctx, capability, msg.PortId, msg.ChannelId, msg.TimeoutHeight, uint64(msg.TimeoutTimestamp.UnixNano()), msg.PacketData) + if err != nil { + ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet failed")) + return nil, errorsmod.Wrapf(err, "send packet failed for module: %s", module) + } + + // cbs.OnSendPacket(...) + _ = cbs + + return &channeltypes.MsgSendPacketResponse{Sequence: sequence}, nil +} + // RecvPacket defines a rpc handler method for MsgRecvPacket. func (k *Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPacket) (*channeltypes.MsgRecvPacketResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 4ff6133b631..5d8998f2a47 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -31,6 +31,10 @@ var ( maxSequence = uint64(10) ) +func (suite *KeeperTestSuite) TestHandleSendPacket() { + suite.T().Skip("todo: handle test send packet rpc") +} + // tests the IBC handler receiving a packet on ordered and unordered channels. // It verifies that the storing of an acknowledgement on success occurs. It // tests high level properties like ordering and basic sanity checks. More diff --git a/proto/ibc/core/channel/v1/tx.proto b/proto/ibc/core/channel/v1/tx.proto index 3f30e8b8c97..842c44db897 100644 --- a/proto/ibc/core/channel/v1/tx.proto +++ b/proto/ibc/core/channel/v1/tx.proto @@ -4,6 +4,7 @@ package ibc.core.channel.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; +import "google/protobuf/timestamp.proto"; import "gogoproto/gogo.proto"; import "cosmos/msg/v1/msg.proto"; import "ibc/core/client/v1/client.proto"; @@ -33,6 +34,9 @@ service Msg { // MsgChannelCloseConfirm. rpc ChannelCloseConfirm(MsgChannelCloseConfirm) returns (MsgChannelCloseConfirmResponse); + // SendPacket defines a rpc handler method for MsgSendPacket. + rpc SendPacket(MsgSendPacket) returns (MsgSendPacketResponse); + // RecvPacket defines a rpc handler method for MsgRecvPacket. rpc RecvPacket(MsgRecvPacket) returns (MsgRecvPacketResponse); @@ -208,6 +212,27 @@ message MsgChannelCloseConfirm { // type. message MsgChannelCloseConfirmResponse {} +// MsgSendPacket sends an outgoing IBC packet +message MsgSendPacket { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + ibc.core.client.v1.Height timeout_height = 3 [(gogoproto.nullable) = false]; + google.protobuf.Timestamp timeout_timestamp = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + bytes packet_data = 5; + string signer = 6; +} + +// MsgSendPacketReponse defines the Msg/SendPacket response type. +message MsgSendPacketResponse { + option (gogoproto.goproto_getters) = false; + + uint64 sequence = 1; +} + // MsgRecvPacket receives incoming IBC packet message MsgRecvPacket { option (cosmos.msg.v1.signer) = "signer"; From db5cddf34b734bca54619e5688c3790b4f34be49 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 15 May 2024 12:15:23 +0200 Subject: [PATCH 02/46] feat: add OnSendPacket callback to IBCModule interface --- .../controller/ibc_middleware.go | 12 ++++++++++++ .../apps/27-interchain-accounts/host/ibc_module.go | 12 ++++++++++++ modules/apps/29-fee/ibc_middleware.go | 12 ++++++++++++ modules/apps/transfer/ibc_module.go | 12 ++++++++++++ modules/core/05-port/types/module.go | 10 ++++++++++ testing/mock/ibc_app.go | 9 +++++++++ testing/mock/ibc_module.go | 9 +++++++++ testing/mock/middleware.go | 9 +++++++++ 8 files changed, 85 insertions(+) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index fe9ef65a026..1356018a5c4 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -170,6 +170,18 @@ func (im IBCMiddleware) OnChanCloseConfirm( return nil } +// OnSendPacket implements the IBCModule interface. +func (IBCMiddleware) OnSendPacket( + ctx sdk.Context, + portID string, + channelID string, + sequence uint64, + data []byte, + signer string, +) error { + return nil +} + // OnRecvPacket implements the IBCMiddleware interface func (IBCMiddleware) OnRecvPacket( ctx sdk.Context, diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 3829a4c9acd..b74f3a9f58a 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -110,6 +110,18 @@ func (im IBCModule) OnChanCloseConfirm( return im.keeper.OnChanCloseConfirm(ctx, portID, channelID) } +// OnSendPacket implements the IBCModule interface. +func (IBCModule) OnSendPacket( + ctx sdk.Context, + portID string, + channelID string, + sequence uint64, + data []byte, + signer string, +) error { + return errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "cannot send packet on icahost") +} + // OnRecvPacket implements the IBCModule interface func (im IBCModule) OnRecvPacket( ctx sdk.Context, diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 218efb08882..c3f0f8894ca 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -212,6 +212,18 @@ func (im IBCMiddleware) OnChanCloseConfirm( return im.keeper.RefundFeesOnChannelClosure(ctx, portID, channelID) } +// OnSendPacket implements the IBCModule interface. +func (IBCMiddleware) OnSendPacket( + ctx sdk.Context, + portID string, + channelID string, + sequence uint64, + data []byte, + signer string, +) error { + return nil +} + // OnRecvPacket implements the IBCMiddleware interface. // If fees are not enabled, this callback will default to the ibc-core packet callback func (im IBCMiddleware) OnRecvPacket( diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 7e312b7b869..6a82d654bcd 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -172,6 +172,18 @@ func (IBCModule) OnChanCloseConfirm( return nil } +// OnSendPacket implements the IBCModule interface. +func (IBCModule) OnSendPacket( + ctx sdk.Context, + portID string, + channelID string, + sequence uint64, + data []byte, + signer string, +) error { + return nil +} + // OnRecvPacket implements the IBCModule interface. A successful acknowledgement // is returned if the packet data is successfully decoded and the receive application // logic returns without error. diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 23fc5705233..a8e9089e2f3 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -81,6 +81,15 @@ type IBCModule interface { channelID string, ) error + OnSendPacket( + ctx sdk.Context, + portID string, + channelID string, + sequence uint64, + data []byte, + signer string, + ) error + // OnRecvPacket must return an acknowledgement that implements the Acknowledgement interface. // In the case of an asynchronous acknowledgement, nil should be returned. // If the acknowledgement returned is successful, the state changes on callback are written, @@ -159,6 +168,7 @@ type UpgradableModule interface { // ICS4Wrapper implements the ICS4 interfaces that IBC applications use to send packets and acknowledgements. type ICS4Wrapper interface { + // TODO: Leave in place to avoid compiler errors and incrementally work to remove. We can then delete these methods SendPacket( ctx sdk.Context, chanCap *capabilitytypes.Capability, diff --git a/testing/mock/ibc_app.go b/testing/mock/ibc_app.go index 026a5d0873d..52880396cd8 100644 --- a/testing/mock/ibc_app.go +++ b/testing/mock/ibc_app.go @@ -62,6 +62,15 @@ type IBCApp struct { channelID string, ) error + OnSendPacket func( + ctx sdk.Context, + portID string, + channelID string, + sequence uint64, + data []byte, + signer string, + ) error + // OnRecvPacket must return an acknowledgement that implements the Acknowledgement interface. // In the case of an asynchronous acknowledgement, nil should be returned. // If the acknowledgement returned is successful, the state changes on callback are written, diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index b3bd2432de3..c1dd38fa0ca 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -122,6 +122,15 @@ func (im IBCModule) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string return nil } +// OnSendPacket implements the IBCModule interface. +func (im IBCModule) OnSendPacket(ctx sdk.Context, portID string, channelID string, sequence uint64, data []byte, signer string) error { + if im.IBCApp.OnSendPacket != nil { + return im.IBCApp.OnSendPacket(ctx, portID, channelID, sequence, data, signer) + } + + return nil +} + // OnRecvPacket implements the IBCModule interface. func (im IBCModule) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) exported.Acknowledgement { if im.IBCApp.OnRecvPacket != nil { diff --git a/testing/mock/middleware.go b/testing/mock/middleware.go index 954132d0cff..e952d9dce16 100644 --- a/testing/mock/middleware.go +++ b/testing/mock/middleware.go @@ -113,6 +113,15 @@ func (im BlockUpgradeMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, cha return nil } +// OnSendPacket implements the IBCModule interface. +func (im BlockUpgradeMiddleware) OnSendPacket(ctx sdk.Context, portID string, channelID string, sequence uint64, data []byte, signer string) error { + if im.IBCApp.OnSendPacket != nil { + return im.IBCApp.OnSendPacket(ctx, portID, channelID, sequence, data, signer) + } + + return nil +} + // OnRecvPacket implements the IBCModule interface. func (im BlockUpgradeMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) exported.Acknowledgement { if im.IBCApp.OnRecvPacket != nil { From 385674ac38ce69f81689b3bc4cf4764b5fcc8dcc Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 15 May 2024 12:18:02 +0200 Subject: [PATCH 03/46] chore: invoke OnSendPacket callback from msg server rpc --- modules/core/keeper/msg_server.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 3f3979feb8b..eb35397cec3 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -468,8 +468,10 @@ func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPack return nil, errorsmod.Wrapf(err, "send packet failed for module: %s", module) } - // cbs.OnSendPacket(...) - _ = cbs + if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.PacketData, msg.Signer); err != nil { + ctx.Logger().Error("send packet callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet callback failed")) + return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", module) + } return &channeltypes.MsgSendPacketResponse{Sequence: sequence}, nil } From 5c861f4fb4cae59039f8266206257cab205016a4 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 15 May 2024 12:29:47 +0200 Subject: [PATCH 04/46] chore: add comment --- modules/core/keeper/msg_server.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index eb35397cec3..a500594be92 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -468,6 +468,9 @@ func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPack return nil, errorsmod.Wrapf(err, "send packet failed for module: %s", module) } + // TODO: Make port router have list of ordered callbacks + // Loop over cbs in-order calling OnSendPacket on each IBCModule. To be done for RecvPacket handler as well in opposite order. + // Adjust app logic to account for what should be done before MsgSendPacket and what should be done in OnSendPacket. if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.PacketData, msg.Signer); err != nil { ctx.Logger().Error("send packet callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet callback failed")) return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", module) From 9d4d2eafa240dbc0fa759a2fe5e29b820c4d7072 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 15 May 2024 14:11:41 +0200 Subject: [PATCH 05/46] chore: rename proto fields --- modules/core/04-channel/types/tx.pb.go | 325 ++++++++++++------------- modules/core/keeper/msg_server.go | 4 +- proto/ibc/core/channel/v1/tx.proto | 5 +- 3 files changed, 155 insertions(+), 179 deletions(-) diff --git a/modules/core/04-channel/types/tx.pb.go b/modules/core/04-channel/types/tx.pb.go index ddd875f7764..f8e76a6a130 100644 --- a/modules/core/04-channel/types/tx.pb.go +++ b/modules/core/04-channel/types/tx.pb.go @@ -10,23 +10,19 @@ import ( _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" - github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" types "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" - _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" math_bits "math/bits" - time "time" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf -var _ = time.Kitchen // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. @@ -568,8 +564,8 @@ type MsgSendPacket struct { PortId string `protobuf:"bytes,1,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` ChannelId string `protobuf:"bytes,2,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` TimeoutHeight types.Height `protobuf:"bytes,3,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height"` - TimeoutTimestamp time.Time `protobuf:"bytes,4,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3,stdtime" json:"timeout_timestamp"` - PacketData []byte `protobuf:"bytes,5,opt,name=packet_data,json=packetData,proto3" json:"packet_data,omitempty"` + TimeoutTimestamp uint64 `protobuf:"varint,4,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3" json:"timeout_timestamp,omitempty"` + Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` Signer string `protobuf:"bytes,6,opt,name=signer,proto3" json:"signer,omitempty"` } @@ -1762,139 +1758,136 @@ func init() { func init() { proto.RegisterFile("ibc/core/channel/v1/tx.proto", fileDescriptor_bc4637e0ac3fc7b7) } var fileDescriptor_bc4637e0ac3fc7b7 = []byte{ - // 2106 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0xcd, 0x6f, 0x1b, 0xc7, - 0x15, 0xd7, 0xf2, 0x53, 0x7a, 0xb2, 0x2d, 0x69, 0x29, 0xdb, 0xd4, 0xea, 0x83, 0x34, 0x5b, 0xc4, - 0x8a, 0x6a, 0x93, 0x91, 0x62, 0x17, 0xb5, 0x11, 0xa0, 0x95, 0x18, 0xba, 0x11, 0x60, 0x59, 0xea, - 0x52, 0x2a, 0xda, 0xa4, 0x28, 0xb1, 0x5a, 0x8e, 0x57, 0x0b, 0x91, 0xbb, 0x9b, 0xdd, 0x25, 0x13, - 0x15, 0x68, 0x11, 0xf4, 0x64, 0xf8, 0x10, 0xa4, 0x40, 0xae, 0x06, 0x5a, 0xf4, 0x5c, 0x20, 0xe7, - 0x7e, 0x1c, 0x7a, 0x0b, 0x7a, 0x28, 0x72, 0x0c, 0x0a, 0x34, 0x2d, 0xec, 0x43, 0xfe, 0x87, 0x02, - 0x05, 0x8a, 0x9d, 0x99, 0x1d, 0x2e, 0x97, 0xb3, 0xe4, 0x4a, 0x64, 0x85, 0xdc, 0xb8, 0x33, 0xbf, - 0x79, 0xf3, 0xe6, 0xf7, 0x7b, 0xf3, 0xf6, 0xcd, 0x2c, 0x61, 0x45, 0x3f, 0x56, 0x2b, 0xaa, 0x69, - 0xa3, 0x8a, 0x7a, 0xa2, 0x18, 0x06, 0x6a, 0x55, 0xba, 0x9b, 0x15, 0xf7, 0xc3, 0xb2, 0x65, 0x9b, - 0xae, 0x29, 0xe6, 0xf4, 0x63, 0xb5, 0xec, 0xf5, 0x96, 0x69, 0x6f, 0xb9, 0xbb, 0x29, 0x15, 0x34, - 0xd3, 0xd4, 0x5a, 0xa8, 0x82, 0x21, 0xc7, 0x9d, 0xa7, 0x15, 0x57, 0x6f, 0x23, 0xc7, 0x55, 0xda, - 0x16, 0x19, 0x25, 0x2d, 0x6a, 0xa6, 0x66, 0xe2, 0x9f, 0x15, 0xef, 0x17, 0x6d, 0xbd, 0xa9, 0x9a, - 0x4e, 0xdb, 0x74, 0x2a, 0x6d, 0x47, 0xf3, 0xe6, 0x68, 0x3b, 0x1a, 0xed, 0x28, 0xf4, 0x5c, 0x68, - 0xe9, 0xc8, 0x70, 0xbd, 0x5e, 0xf2, 0x8b, 0x02, 0x6e, 0xf1, 0x7c, 0xf4, 0x1d, 0x1a, 0x02, 0xe9, - 0x58, 0x9a, 0xad, 0x34, 0x11, 0x81, 0x94, 0x3e, 0x15, 0x40, 0xdc, 0x73, 0xb4, 0x2a, 0xe9, 0xdf, - 0xb7, 0x90, 0xb1, 0x6b, 0xe8, 0xae, 0x78, 0x13, 0xb2, 0x96, 0x69, 0xbb, 0x0d, 0xbd, 0x99, 0x17, - 0x8a, 0xc2, 0xfa, 0x8c, 0x9c, 0xf1, 0x1e, 0x77, 0x9b, 0xe2, 0x5b, 0x90, 0xa5, 0xb6, 0xf2, 0x89, - 0xa2, 0xb0, 0x3e, 0xbb, 0xb5, 0x52, 0xe6, 0xb0, 0x51, 0xa6, 0xf6, 0x76, 0x52, 0x9f, 0x7f, 0x55, - 0x98, 0x92, 0xfd, 0x21, 0xe2, 0x0d, 0xc8, 0x38, 0xba, 0x66, 0x20, 0x3b, 0x9f, 0x24, 0x56, 0xc9, - 0xd3, 0xc3, 0xb9, 0x67, 0xbf, 0x2d, 0x4c, 0xfd, 0xfa, 0xeb, 0xcf, 0x36, 0x68, 0x43, 0xe9, 0x3d, - 0x90, 0x06, 0xbd, 0x92, 0x91, 0x63, 0x99, 0x86, 0x83, 0xc4, 0x55, 0x00, 0x6a, 0xb1, 0xe7, 0xe0, - 0x0c, 0x6d, 0xd9, 0x6d, 0x8a, 0x79, 0xc8, 0x76, 0x91, 0xed, 0xe8, 0xa6, 0x81, 0x7d, 0x9c, 0x91, - 0xfd, 0xc7, 0x87, 0x29, 0x6f, 0x9e, 0xd2, 0x57, 0x09, 0x58, 0xe8, 0xb7, 0x7e, 0x68, 0x9f, 0x45, - 0x2f, 0x79, 0x0b, 0x72, 0x96, 0x8d, 0xba, 0xba, 0xd9, 0x71, 0x1a, 0x81, 0x69, 0xb1, 0xe9, 0x9d, - 0x44, 0x5e, 0x90, 0x17, 0xfc, 0xee, 0x2a, 0x73, 0x21, 0x40, 0x53, 0xf2, 0xfc, 0x34, 0x6d, 0xc2, - 0xa2, 0x6a, 0x76, 0x0c, 0x17, 0xd9, 0x96, 0x62, 0xbb, 0x67, 0x0d, 0x7f, 0x35, 0x29, 0xec, 0x57, - 0x2e, 0xd8, 0xf7, 0x63, 0xd2, 0xe5, 0x51, 0x62, 0xd9, 0xa6, 0xf9, 0xb4, 0xa1, 0x1b, 0xba, 0x9b, - 0x4f, 0x17, 0x85, 0xf5, 0x2b, 0xf2, 0x0c, 0x6e, 0xc1, 0x7a, 0x56, 0xe1, 0x0a, 0xe9, 0x3e, 0x41, - 0xba, 0x76, 0xe2, 0xe6, 0x33, 0xd8, 0x29, 0x29, 0xe0, 0x14, 0x09, 0xad, 0xee, 0x66, 0xf9, 0x1d, - 0x8c, 0xa0, 0x2e, 0xcd, 0xe2, 0x51, 0xa4, 0x29, 0xa0, 0x5e, 0x76, 0xb8, 0x7a, 0xef, 0xc2, 0xd2, - 0x00, 0xbf, 0x4c, 0xbc, 0x80, 0x3a, 0x42, 0x9f, 0x3a, 0x21, 0x59, 0x13, 0x21, 0x59, 0xa9, 0x78, - 0x7f, 0x1d, 0x10, 0x6f, 0x5b, 0x3d, 0x8d, 0x16, 0x6f, 0xb8, 0x4d, 0xf1, 0xbb, 0x70, 0xb3, 0x8f, - 0xe9, 0x00, 0x96, 0x44, 0xe8, 0xf5, 0x60, 0x77, 0x4f, 0xdf, 0x0b, 0x28, 0xb4, 0x0c, 0x44, 0x8f, - 0x86, 0x6b, 0x9f, 0x51, 0x81, 0xa6, 0x71, 0x83, 0x17, 0x7c, 0x97, 0xab, 0xcf, 0x72, 0x58, 0x9f, - 0x6d, 0xf5, 0xd4, 0xd7, 0xa7, 0xf4, 0x0f, 0x01, 0xae, 0xf7, 0xf7, 0x56, 0x4d, 0xe3, 0xa9, 0x6e, - 0xb7, 0x2f, 0x4c, 0x32, 0x5b, 0xb9, 0xa2, 0x9e, 0x62, 0x5a, 0xfd, 0x95, 0x7b, 0xca, 0x85, 0x57, - 0x9e, 0x1a, 0x6f, 0xe5, 0xe9, 0xe1, 0x2b, 0x2f, 0xc0, 0x2a, 0x77, 0x6d, 0x6c, 0xf5, 0x5d, 0xc8, - 0xf5, 0x00, 0xd5, 0x96, 0xe9, 0xa0, 0xe1, 0xf9, 0x70, 0xc4, 0xd2, 0x63, 0x27, 0xbc, 0x55, 0x58, - 0xe6, 0xcc, 0xcb, 0xdc, 0xfa, 0x5d, 0x02, 0x6e, 0x84, 0xfa, 0xc7, 0x55, 0xa5, 0x3f, 0x63, 0x24, - 0x47, 0x65, 0x8c, 0x49, 0xea, 0x22, 0xee, 0xc0, 0x6a, 0xdf, 0xf6, 0xa1, 0xef, 0xa4, 0x86, 0x83, - 0xde, 0xef, 0x20, 0x43, 0x45, 0x38, 0xfe, 0x53, 0xf2, 0x72, 0x10, 0x74, 0x44, 0x30, 0x75, 0x0a, - 0x19, 0xa4, 0xb0, 0x08, 0x6b, 0x7c, 0x8a, 0x18, 0x8b, 0x7f, 0x48, 0xc0, 0xd5, 0x3d, 0x47, 0xab, - 0x23, 0xa3, 0x79, 0xa0, 0xa8, 0xa7, 0xe8, 0xe2, 0xba, 0xfe, 0x10, 0xae, 0x79, 0xef, 0x77, 0xb3, - 0xe3, 0xfa, 0xfc, 0x24, 0x63, 0xf2, 0x73, 0x95, 0x8e, 0xa3, 0x0c, 0xfd, 0x08, 0x16, 0x7c, 0x43, - 0xac, 0x60, 0x60, 0x5c, 0x93, 0x92, 0xa2, 0xec, 0x97, 0x14, 0xe5, 0x43, 0x1f, 0xb1, 0x33, 0xed, - 0xd9, 0xfa, 0xe4, 0x5f, 0x05, 0x41, 0x9e, 0xa7, 0xc3, 0x59, 0x9f, 0x58, 0x80, 0x59, 0x0b, 0xaf, - 0xae, 0xd1, 0x54, 0x5c, 0x85, 0xa6, 0x1a, 0x20, 0x4d, 0x6f, 0x2b, 0xae, 0x12, 0x50, 0x25, 0x33, - 0x3c, 0x28, 0x1f, 0xe0, 0x4c, 0xd0, 0xa3, 0x8b, 0xe5, 0x70, 0x09, 0xa6, 0x99, 0x54, 0x02, 0x96, - 0x8a, 0x3d, 0xd3, 0x34, 0xfd, 0x4a, 0xc0, 0x54, 0xcb, 0x48, 0xed, 0x52, 0xaa, 0x1f, 0x40, 0x86, - 0xf8, 0x80, 0x47, 0xcc, 0x6e, 0x2d, 0x73, 0xdf, 0x88, 0x04, 0x4c, 0xb9, 0xa2, 0x03, 0xc4, 0xd7, - 0x61, 0x9e, 0xc4, 0xa2, 0x6a, 0xb6, 0xdb, 0xba, 0xdb, 0x46, 0x86, 0x8b, 0x25, 0xb9, 0x22, 0xcf, - 0xe1, 0xf6, 0x2a, 0x6b, 0x1e, 0x08, 0xdb, 0xe4, 0x78, 0x61, 0x9b, 0x1a, 0x4e, 0xd0, 0xcf, 0x31, - 0x41, 0xbd, 0x45, 0x32, 0x82, 0xbe, 0x0f, 0x19, 0x1b, 0x39, 0x9d, 0x16, 0x59, 0xec, 0xb5, 0xad, - 0xdb, 0xdc, 0xc5, 0xfa, 0x70, 0x19, 0x43, 0x0f, 0xcf, 0x2c, 0x24, 0xd3, 0x61, 0x94, 0xc5, 0x8f, - 0x13, 0x00, 0x7b, 0x8e, 0x76, 0x48, 0x24, 0x9e, 0x08, 0x85, 0x1d, 0xc3, 0x46, 0x2a, 0xd2, 0xbb, - 0xa8, 0xd9, 0x47, 0xe1, 0x11, 0x6b, 0x9e, 0x0c, 0x85, 0x77, 0x40, 0x34, 0xd0, 0x87, 0x2e, 0xdb, - 0xd1, 0x0d, 0x1b, 0xa9, 0x5d, 0x4c, 0x67, 0x4a, 0x9e, 0xf7, 0x7a, 0xfc, 0x7d, 0xec, 0x91, 0x17, - 0x3f, 0x7f, 0xbf, 0x87, 0xab, 0x55, 0xca, 0xc7, 0xa4, 0xd9, 0xfe, 0x0f, 0x29, 0x2d, 0xa8, 0xf5, - 0x7d, 0x03, 0xe7, 0x90, 0x4b, 0x22, 0xdd, 0xdb, 0xb4, 0x24, 0xc4, 0xbd, 0x49, 0x69, 0x3a, 0x26, - 0x09, 0x9a, 0xb8, 0x31, 0x91, 0x7c, 0xcc, 0x57, 0x25, 0x3d, 0x52, 0x95, 0xcc, 0xf9, 0xb2, 0x77, - 0xf6, 0x02, 0xd9, 0xfb, 0x18, 0xd7, 0x24, 0xfd, 0xdc, 0x4f, 0x5a, 0xe0, 0x67, 0x09, 0x1c, 0x3e, - 0xdb, 0xea, 0xa9, 0x61, 0x7e, 0xd0, 0x42, 0x4d, 0x0d, 0xe1, 0x9c, 0x31, 0x86, 0xc2, 0xeb, 0x30, - 0xa7, 0xf4, 0x5b, 0xf3, 0x05, 0x0e, 0x35, 0xf7, 0x04, 0xf6, 0x06, 0x36, 0xfb, 0x04, 0xde, 0xf6, - 0x5a, 0x2e, 0xb9, 0x10, 0x52, 0xf1, 0x01, 0x2b, 0xc4, 0xc4, 0xa4, 0xf9, 0xfe, 0x63, 0x5f, 0x29, - 0x49, 0x43, 0x60, 0xac, 0x7a, 0xea, 0x07, 0x90, 0x79, 0xaa, 0xa3, 0x56, 0xd3, 0xa1, 0x59, 0xa9, - 0xc4, 0x75, 0x8c, 0xce, 0xf4, 0x08, 0x23, 0x7d, 0xc5, 0xc8, 0xb8, 0xf8, 0xb9, 0xfd, 0x63, 0x21, - 0x58, 0x2b, 0x06, 0x9c, 0x67, 0x2c, 0xbd, 0x05, 0x59, 0x1a, 0xfa, 0x34, 0x70, 0x56, 0x86, 0x79, - 0xe3, 0x1f, 0xf2, 0xe8, 0x10, 0x2f, 0x39, 0x0c, 0x6c, 0x9c, 0x04, 0xde, 0x38, 0x73, 0x9d, 0xd0, - 0x66, 0x21, 0x6c, 0xfe, 0x37, 0x09, 0x8b, 0x03, 0x0e, 0x0d, 0x3d, 0xb9, 0x8e, 0x2c, 0x62, 0x8a, - 0x96, 0x6d, 0x5a, 0xa6, 0x83, 0x9a, 0x6c, 0x0f, 0xab, 0xa6, 0x61, 0x20, 0xd5, 0xd5, 0x4d, 0xa3, - 0x71, 0x62, 0x5a, 0x1e, 0xcd, 0xc9, 0xf5, 0x19, 0x79, 0xd5, 0xc7, 0xd1, 0x59, 0xab, 0x0c, 0xf5, - 0x8e, 0x69, 0x39, 0xe2, 0x09, 0x2c, 0x73, 0x13, 0x02, 0x95, 0x2a, 0x75, 0x4e, 0xa9, 0x96, 0x38, - 0x89, 0x83, 0x00, 0x46, 0xa7, 0x9e, 0xf4, 0xc8, 0xd4, 0x23, 0x7e, 0x0b, 0xae, 0xd2, 0x54, 0x4b, - 0x4f, 0xe8, 0x19, 0xbc, 0x17, 0xc9, 0xee, 0xa3, 0xec, 0xf6, 0x40, 0xbe, 0xc2, 0xd9, 0x00, 0x88, - 0x5a, 0x1c, 0xd8, 0xb2, 0xd3, 0xe3, 0x6d, 0xd9, 0x99, 0xe1, 0x01, 0xf9, 0x77, 0x01, 0x56, 0x78, - 0xfa, 0x5f, 0x7a, 0x3c, 0x06, 0xd2, 0x43, 0x72, 0x9c, 0xf4, 0xf0, 0xcf, 0x04, 0x27, 0xa0, 0xc7, - 0x39, 0xcd, 0x1f, 0x85, 0x4e, 0xe5, 0x3e, 0x1b, 0xc9, 0xd8, 0x6c, 0xe4, 0x38, 0x81, 0x33, 0x18, - 0x30, 0xa9, 0x38, 0x01, 0x93, 0x8e, 0x11, 0x30, 0xff, 0xdf, 0x63, 0x3e, 0xe2, 0xc4, 0x4b, 0xe0, - 0xa4, 0x3f, 0xa9, 0x2c, 0xff, 0xa7, 0x24, 0xe4, 0x07, 0xe6, 0x19, 0xf7, 0x74, 0xfa, 0x13, 0x90, - 0xb8, 0x17, 0x33, 0x8e, 0xab, 0xb8, 0x88, 0x86, 0x9d, 0xc4, 0xf5, 0xb7, 0xee, 0x21, 0xe4, 0x3c, - 0xe7, 0xde, 0x06, 0xf7, 0x44, 0x06, 0x49, 0x6a, 0xc2, 0x41, 0x92, 0x8e, 0x13, 0x24, 0x99, 0x18, - 0x41, 0x92, 0x1d, 0x2f, 0x48, 0xa6, 0x87, 0x07, 0x89, 0x0e, 0xc5, 0x28, 0xf1, 0x26, 0x1d, 0x28, - 0x1f, 0x25, 0x39, 0xe5, 0xc0, 0xbe, 0x85, 0x8c, 0x6f, 0x60, 0x94, 0x8c, 0x7c, 0xd1, 0xa4, 0x2e, - 0xf0, 0xa2, 0xe1, 0x85, 0xc4, 0xe5, 0xa6, 0x84, 0x02, 0xa7, 0xa6, 0xf1, 0x14, 0x60, 0x57, 0x24, - 0x7f, 0x4e, 0x70, 0x36, 0xb3, 0x7f, 0xfe, 0x9c, 0x54, 0x5e, 0x3e, 0xff, 0xd5, 0x78, 0x8e, 0x23, - 0x54, 0xbc, 0xbc, 0x1c, 0xe6, 0x37, 0x3d, 0x1e, 0xbf, 0x23, 0x6e, 0x4c, 0x4a, 0x9c, 0xdd, 0x14, - 0x3a, 0xad, 0x96, 0xfe, 0x92, 0x80, 0x9b, 0x83, 0x5b, 0x4e, 0x31, 0x54, 0xd4, 0xba, 0x30, 0xc3, - 0x8f, 0xe1, 0x2a, 0xb2, 0x6d, 0xd3, 0x6e, 0xe0, 0x03, 0xa5, 0xe5, 0x1f, 0xda, 0x6f, 0x71, 0xa9, - 0xad, 0x79, 0x48, 0x99, 0x00, 0xe9, 0x6a, 0xaf, 0xa0, 0x40, 0x9b, 0x58, 0x86, 0x1c, 0xe1, 0xac, - 0xdf, 0x26, 0xa1, 0x77, 0x01, 0x77, 0x05, 0x6d, 0x5c, 0x32, 0xc7, 0xb7, 0xa0, 0x10, 0x41, 0x1f, - 0xa3, 0xf8, 0x57, 0x30, 0xb7, 0xe7, 0x68, 0x47, 0x56, 0x53, 0x71, 0xd1, 0x81, 0x62, 0x2b, 0x6d, - 0x47, 0x5c, 0x81, 0x19, 0xa5, 0xe3, 0x9e, 0x98, 0xb6, 0xee, 0x9e, 0xf9, 0x9f, 0x8c, 0x58, 0x03, - 0x39, 0x02, 0x7a, 0x38, 0xfa, 0x55, 0x2b, 0xea, 0x08, 0xe8, 0x41, 0x7a, 0x47, 0x40, 0xef, 0xe9, - 0xa1, 0xe8, 0xfb, 0xd7, 0x33, 0x57, 0x5a, 0xc2, 0x0a, 0x07, 0xe7, 0x67, 0xae, 0xfd, 0x46, 0xc0, - 0x1b, 0xec, 0xc0, 0xee, 0x18, 0x28, 0x74, 0xfc, 0x72, 0x2e, 0x2c, 0xff, 0x22, 0xa4, 0x5b, 0x7a, - 0x9b, 0x5e, 0xe3, 0xa6, 0x64, 0xf2, 0x10, 0xff, 0xa8, 0xf3, 0xa9, 0x80, 0xc3, 0x96, 0xeb, 0x13, - 0x7b, 0x09, 0xdc, 0x83, 0x1b, 0xae, 0xe9, 0x2a, 0xad, 0x86, 0xe5, 0xc1, 0x9a, 0x2c, 0x13, 0x3a, - 0xf4, 0x06, 0x70, 0x11, 0xf7, 0x62, 0x1b, 0x4d, 0x3f, 0x05, 0x3a, 0xe2, 0x43, 0x58, 0x22, 0xa3, - 0x6c, 0xd4, 0x56, 0x74, 0x43, 0x37, 0xb4, 0xc0, 0x40, 0x52, 0x5e, 0xde, 0xc4, 0x00, 0xd9, 0xef, - 0x67, 0x63, 0x37, 0xbe, 0x14, 0x40, 0x1c, 0x7c, 0xa9, 0x88, 0xf7, 0xa1, 0x28, 0xd7, 0xea, 0x07, - 0xfb, 0x4f, 0xea, 0xb5, 0x86, 0x5c, 0xab, 0x1f, 0x3d, 0x3e, 0x6c, 0x1c, 0xfe, 0xf4, 0xa0, 0xd6, - 0x38, 0x7a, 0x52, 0x3f, 0xa8, 0x55, 0x77, 0x1f, 0xed, 0xd6, 0xde, 0x9e, 0x9f, 0x92, 0xe6, 0x9e, - 0xbf, 0x28, 0xce, 0x06, 0x9a, 0xc4, 0xdb, 0xb0, 0xc4, 0x1d, 0xf6, 0x64, 0x7f, 0xff, 0x60, 0x5e, - 0x90, 0xa6, 0x9f, 0xbf, 0x28, 0xa6, 0xbc, 0xdf, 0xe2, 0x5d, 0x58, 0xe1, 0x02, 0xeb, 0x47, 0xd5, - 0x6a, 0xad, 0x5e, 0x9f, 0x4f, 0x48, 0xb3, 0xcf, 0x5f, 0x14, 0xb3, 0xf4, 0x31, 0x12, 0xfe, 0x68, - 0x7b, 0xf7, 0xf1, 0x91, 0x5c, 0x9b, 0x4f, 0x12, 0x38, 0x7d, 0x94, 0x52, 0xcf, 0x7e, 0xbf, 0x36, - 0xb5, 0xf5, 0xb7, 0x05, 0x48, 0xee, 0x39, 0x9a, 0x78, 0x0a, 0x73, 0xe1, 0x4f, 0xaf, 0xfc, 0x97, - 0xeb, 0xe0, 0xd7, 0x50, 0xa9, 0x12, 0x13, 0xc8, 0x14, 0x3c, 0x81, 0x6b, 0xa1, 0x6f, 0x9e, 0xaf, - 0xc5, 0x30, 0x71, 0x68, 0x9f, 0x49, 0xe5, 0x78, 0xb8, 0x88, 0x99, 0xbc, 0x92, 0x3e, 0xce, 0x4c, - 0xdb, 0xea, 0x69, 0xac, 0x99, 0x82, 0x35, 0xac, 0x0b, 0x22, 0xe7, 0x4b, 0xd5, 0x46, 0x0c, 0x2b, - 0x14, 0x2b, 0x6d, 0xc5, 0xc7, 0xb2, 0x59, 0x0d, 0x98, 0x1f, 0xf8, 0x44, 0xb4, 0x3e, 0xc2, 0x0e, - 0x43, 0x4a, 0x6f, 0xc4, 0x45, 0xb2, 0xf9, 0x3e, 0x80, 0x1c, 0xef, 0xd3, 0xcf, 0x77, 0xe2, 0x18, - 0xf2, 0xd7, 0xf9, 0xe6, 0x39, 0xc0, 0x6c, 0xe2, 0x9f, 0x01, 0x04, 0xbe, 0x96, 0x94, 0xa2, 0x4c, - 0xf4, 0x30, 0xd2, 0xc6, 0x68, 0x4c, 0xd0, 0x7a, 0xe0, 0x03, 0x41, 0xa4, 0xf5, 0x1e, 0x26, 0xda, - 0x3a, 0xe7, 0x0e, 0xbe, 0x0e, 0x59, 0xbf, 0x70, 0x29, 0x44, 0x0d, 0xa3, 0x00, 0xe9, 0xf6, 0x08, - 0x40, 0x30, 0xb2, 0x43, 0xf7, 0xc3, 0xaf, 0x8d, 0x18, 0x4a, 0x71, 0xd1, 0x91, 0x1d, 0x71, 0xe7, - 0x79, 0x0a, 0x73, 0xe1, 0x8b, 0xca, 0x48, 0x2f, 0x43, 0xc0, 0xe8, 0xd4, 0x10, 0x75, 0xe1, 0xd7, - 0xdb, 0x46, 0xc1, 0x5b, 0xba, 0x51, 0xdb, 0x28, 0x80, 0x1d, 0xb9, 0x8d, 0x78, 0x17, 0x68, 0xef, - 0xc3, 0xc2, 0xe0, 0x6d, 0xd6, 0xeb, 0xf1, 0x0c, 0x79, 0x69, 0x69, 0x33, 0x36, 0x34, 0x7a, 0x4a, - 0x2f, 0x39, 0xc5, 0x9c, 0xd2, 0xcb, 0x4f, 0x9b, 0xb1, 0xa1, 0x6c, 0xca, 0x5f, 0xc2, 0x75, 0xfe, - 0xd9, 0xf8, 0x6e, 0x3c, 0x5b, 0xfe, 0x06, 0xbe, 0x7f, 0x2e, 0x78, 0xb4, 0xb4, 0xf8, 0xc4, 0x15, - 0x53, 0x5a, 0x0f, 0x1b, 0x57, 0xda, 0xe0, 0x39, 0x62, 0x70, 0xd1, 0xfe, 0x56, 0x8c, 0xb9, 0x68, - 0x7f, 0x63, 0xde, 0x3f, 0x17, 0x9c, 0x4d, 0xff, 0x0b, 0x58, 0xe4, 0xd6, 0xd7, 0x77, 0x62, 0x72, - 0x88, 0xd1, 0xd2, 0xbd, 0xf3, 0xa0, 0xd9, 0xdc, 0x3a, 0xe4, 0x48, 0xe5, 0x47, 0x51, 0xb4, 0x00, - 0xfd, 0x76, 0x94, 0xb1, 0x60, 0x99, 0x28, 0xdd, 0x89, 0x83, 0x0a, 0xb2, 0xcc, 0x2f, 0x24, 0x23, - 0x59, 0xe6, 0xc2, 0xa3, 0x59, 0x1e, 0x5a, 0x12, 0x4a, 0xe9, 0x8f, 0xbe, 0xfe, 0x6c, 0x43, 0xd8, - 0xa9, 0x7f, 0xfe, 0x72, 0x4d, 0xf8, 0xe2, 0xe5, 0x9a, 0xf0, 0xef, 0x97, 0x6b, 0xc2, 0x27, 0xaf, - 0xd6, 0xa6, 0xbe, 0x78, 0xb5, 0x36, 0xf5, 0xe5, 0xab, 0xb5, 0xa9, 0x77, 0x1f, 0x68, 0xba, 0x7b, - 0xd2, 0x39, 0x2e, 0xab, 0x66, 0xbb, 0x42, 0xff, 0xe8, 0xa6, 0x1f, 0xab, 0x77, 0x35, 0xb3, 0xd2, - 0xfd, 0x5e, 0xa5, 0x6d, 0x36, 0x3b, 0x2d, 0xe4, 0x90, 0x3f, 0xa8, 0xbd, 0x71, 0xef, 0xae, 0xff, - 0x1f, 0x35, 0xf7, 0xcc, 0x42, 0xce, 0x71, 0x06, 0x7f, 0xf5, 0x7e, 0xf3, 0x7f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xfb, 0x3b, 0xc3, 0x28, 0x8b, 0x27, 0x00, 0x00, + // 2062 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0xcd, 0x6f, 0xe3, 0xc6, + 0x15, 0x37, 0xf5, 0x69, 0x3f, 0xef, 0xae, 0x6d, 0xca, 0xbb, 0x96, 0xe9, 0x2f, 0xad, 0x5a, 0x64, + 0x1d, 0x67, 0x57, 0x8a, 0x9d, 0xdd, 0xa2, 0xbb, 0x08, 0xd0, 0x7a, 0x55, 0x6d, 0x63, 0x60, 0xbd, + 0x36, 0x28, 0xbb, 0x68, 0x93, 0xa2, 0x02, 0x4d, 0xcd, 0x52, 0x84, 0x24, 0x92, 0x21, 0x29, 0x25, + 0x2e, 0xd0, 0x22, 0xe8, 0x69, 0xb1, 0x87, 0xa0, 0x05, 0x72, 0x5d, 0xa0, 0x45, 0xff, 0x81, 0x9c, + 0xfb, 0x71, 0xe8, 0x2d, 0xe8, 0xa1, 0xc8, 0x31, 0x28, 0xd0, 0xa0, 0x58, 0x1f, 0xf2, 0x3f, 0x04, + 0x28, 0x50, 0x70, 0x66, 0x48, 0x51, 0xe4, 0x50, 0xa2, 0x2c, 0xd5, 0xe8, 0xc9, 0xe2, 0xcc, 0x6f, + 0xde, 0x9b, 0xf9, 0xfd, 0xde, 0x7b, 0x9c, 0x19, 0x1a, 0xd6, 0xd5, 0x33, 0xb9, 0x2c, 0xeb, 0x26, + 0x2a, 0xcb, 0x4d, 0x49, 0xd3, 0x50, 0xbb, 0xdc, 0xdb, 0x2d, 0xdb, 0x1f, 0x97, 0x0c, 0x53, 0xb7, + 0x75, 0x3e, 0xa7, 0x9e, 0xc9, 0x25, 0xa7, 0xb7, 0x44, 0x7b, 0x4b, 0xbd, 0x5d, 0x61, 0x59, 0xd1, + 0x15, 0x1d, 0xf7, 0x97, 0x9d, 0x5f, 0x04, 0x2a, 0xac, 0xc8, 0xba, 0xd5, 0xd1, 0xad, 0x72, 0xc7, + 0x52, 0x1c, 0x13, 0x1d, 0x4b, 0xa1, 0x1d, 0x5b, 0x7d, 0x0f, 0x6d, 0x15, 0x69, 0xb6, 0xd3, 0x4b, + 0x7e, 0x51, 0xc0, 0x6d, 0xd6, 0x14, 0x5c, 0x7f, 0x43, 0x20, 0x5d, 0x43, 0x31, 0xa5, 0x06, 0x22, + 0x90, 0xe2, 0x67, 0x1c, 0xf0, 0x87, 0x96, 0x52, 0x21, 0xfd, 0x47, 0x06, 0xd2, 0x0e, 0x34, 0xd5, + 0xe6, 0x57, 0x20, 0x6b, 0xe8, 0xa6, 0x5d, 0x57, 0x1b, 0x79, 0xae, 0xc0, 0x6d, 0xcf, 0x89, 0x19, + 0xe7, 0xf1, 0xa0, 0xc1, 0xbf, 0x0b, 0x59, 0x6a, 0x2b, 0x9f, 0x28, 0x70, 0xdb, 0xf3, 0x7b, 0xeb, + 0x25, 0xc6, 0x62, 0x4b, 0xd4, 0xde, 0xe3, 0xd4, 0x17, 0x5f, 0x6f, 0xcd, 0x88, 0xee, 0x10, 0xfe, + 0x16, 0x64, 0x2c, 0x55, 0xd1, 0x90, 0x99, 0x4f, 0x12, 0xab, 0xe4, 0xe9, 0xd1, 0xc2, 0x8b, 0xdf, + 0x6f, 0xcd, 0xfc, 0xe6, 0x9b, 0xcf, 0x77, 0x68, 0x43, 0xf1, 0x03, 0x10, 0xc2, 0xb3, 0x12, 0x91, + 0x65, 0xe8, 0x9a, 0x85, 0xf8, 0x0d, 0x00, 0x6a, 0xb1, 0x3f, 0xc1, 0x39, 0xda, 0x72, 0xd0, 0xe0, + 0xf3, 0x90, 0xed, 0x21, 0xd3, 0x52, 0x75, 0x0d, 0xcf, 0x71, 0x4e, 0x74, 0x1f, 0x1f, 0xa5, 0x1c, + 0x3f, 0xc5, 0xaf, 0x13, 0xb0, 0x34, 0x68, 0xfd, 0xc4, 0x3c, 0x8f, 0x5e, 0xf2, 0x1e, 0xe4, 0x0c, + 0x13, 0xf5, 0x54, 0xbd, 0x6b, 0xd5, 0x7d, 0x6e, 0xb1, 0xe9, 0xc7, 0x89, 0x3c, 0x27, 0x2e, 0xb9, + 0xdd, 0x15, 0x6f, 0x0a, 0x3e, 0x9a, 0x92, 0xe3, 0xd3, 0xb4, 0x0b, 0xcb, 0xb2, 0xde, 0xd5, 0x6c, + 0x64, 0x1a, 0x92, 0x69, 0x9f, 0xd7, 0xdd, 0xd5, 0xa4, 0xf0, 0xbc, 0x72, 0xfe, 0xbe, 0x9f, 0x90, + 0x2e, 0x87, 0x12, 0xc3, 0xd4, 0xf5, 0xe7, 0x75, 0x55, 0x53, 0xed, 0x7c, 0xba, 0xc0, 0x6d, 0x5f, + 0x13, 0xe7, 0x70, 0x0b, 0xd6, 0xb3, 0x02, 0xd7, 0x48, 0x77, 0x13, 0xa9, 0x4a, 0xd3, 0xce, 0x67, + 0xf0, 0xa4, 0x04, 0xdf, 0xa4, 0x48, 0x68, 0xf5, 0x76, 0x4b, 0xef, 0x61, 0x04, 0x9d, 0xd2, 0x3c, + 0x1e, 0x45, 0x9a, 0x7c, 0xea, 0x65, 0x87, 0xab, 0xf7, 0x3e, 0xac, 0x86, 0xf8, 0xf5, 0xc4, 0xf3, + 0xa9, 0xc3, 0x0d, 0xa8, 0x13, 0x90, 0x35, 0x11, 0x90, 0x95, 0x8a, 0xf7, 0xb7, 0x90, 0x78, 0xfb, + 0x72, 0x2b, 0x5a, 0xbc, 0xe1, 0x36, 0xf9, 0xef, 0xc1, 0xca, 0x00, 0xd3, 0x3e, 0x2c, 0x89, 0xd0, + 0x9b, 0xfe, 0xee, 0xbe, 0xbe, 0x97, 0x50, 0x68, 0x0d, 0x88, 0x1e, 0x75, 0xdb, 0x3c, 0xa7, 0x02, + 0xcd, 0xe2, 0x06, 0x27, 0xf8, 0xae, 0x56, 0x9f, 0xb5, 0xa0, 0x3e, 0xfb, 0x72, 0xcb, 0xd5, 0xa7, + 0xf8, 0x4f, 0x0e, 0x6e, 0x0e, 0xf6, 0x56, 0x74, 0xed, 0xb9, 0x6a, 0x76, 0x2e, 0x4d, 0xb2, 0xb7, + 0x72, 0x49, 0x6e, 0x61, 0x5a, 0xdd, 0x95, 0x3b, 0xca, 0x05, 0x57, 0x9e, 0x9a, 0x6c, 0xe5, 0xe9, + 0xe1, 0x2b, 0xdf, 0x82, 0x0d, 0xe6, 0xda, 0xbc, 0xd5, 0xf7, 0x20, 0xd7, 0x07, 0x54, 0xda, 0xba, + 0x85, 0x86, 0xd7, 0xc3, 0x11, 0x4b, 0x8f, 0x5d, 0xf0, 0x36, 0x60, 0x8d, 0xe1, 0xd7, 0x9b, 0xd6, + 0x1f, 0x12, 0x70, 0x2b, 0xd0, 0x3f, 0xa9, 0x2a, 0x83, 0x15, 0x23, 0x39, 0xaa, 0x62, 0x4c, 0x53, + 0x17, 0xfe, 0x31, 0x6c, 0x0c, 0xa4, 0x0f, 0x7d, 0x27, 0xd5, 0x2d, 0xf4, 0x61, 0x17, 0x69, 0x32, + 0xc2, 0xf1, 0x9f, 0x12, 0xd7, 0xfc, 0xa0, 0x53, 0x82, 0xa9, 0x51, 0x48, 0x98, 0xc2, 0x02, 0x6c, + 0xb2, 0x29, 0xf2, 0x58, 0xfc, 0x96, 0x83, 0xeb, 0x87, 0x96, 0x52, 0x43, 0x5a, 0xe3, 0x58, 0x92, + 0x5b, 0xe8, 0xf2, 0xba, 0xfe, 0x18, 0x6e, 0xd8, 0x6a, 0x07, 0xe9, 0x5d, 0xdb, 0xe5, 0x27, 0x19, + 0x93, 0x9f, 0xeb, 0x74, 0x1c, 0x65, 0xe8, 0x2d, 0x58, 0x72, 0x0d, 0x39, 0x7f, 0x2d, 0x5b, 0xea, + 0x18, 0x98, 0xeb, 0x94, 0xb8, 0x48, 0x3b, 0x4e, 0xdc, 0x76, 0x9e, 0x87, 0x54, 0x43, 0xb2, 0x25, + 0x5a, 0x3d, 0xf0, 0x6f, 0x1f, 0xc5, 0x99, 0xe1, 0x11, 0xf6, 0x10, 0xa7, 0x75, 0x7f, 0xed, 0x5e, + 0x41, 0x16, 0x60, 0xd6, 0xe3, 0x9d, 0xc3, 0x9e, 0xbd, 0x67, 0x5a, 0x73, 0x2f, 0x08, 0x6f, 0x22, + 0x92, 0x7b, 0x94, 0xb7, 0x87, 0x90, 0x31, 0xf0, 0x2f, 0x3c, 0x62, 0x7e, 0x6f, 0x8d, 0xf9, 0x7a, + 0x23, 0x60, 0xba, 0x70, 0x3a, 0x80, 0x7f, 0x13, 0x16, 0x49, 0x60, 0xc9, 0x7a, 0xa7, 0xa3, 0xda, + 0x1d, 0xa4, 0xd9, 0x98, 0xdf, 0x6b, 0xe2, 0x02, 0x6e, 0xaf, 0x78, 0xcd, 0xa1, 0x18, 0x4c, 0x4e, + 0x16, 0x83, 0xa9, 0xe1, 0x04, 0xfd, 0x02, 0x13, 0xd4, 0x5f, 0xa4, 0x47, 0xd0, 0x0f, 0x20, 0x63, + 0x22, 0xab, 0xdb, 0x26, 0x8b, 0xbd, 0xb1, 0x77, 0x87, 0xb9, 0x58, 0x17, 0x2e, 0x62, 0xe8, 0xc9, + 0xb9, 0x81, 0x44, 0x3a, 0x8c, 0xb2, 0xf8, 0x69, 0x02, 0xe0, 0xd0, 0x52, 0x4e, 0x88, 0xaa, 0x53, + 0xa1, 0xb0, 0xab, 0x99, 0x48, 0x46, 0x6a, 0x0f, 0x35, 0x06, 0x28, 0x3c, 0xf5, 0x9a, 0xa7, 0x43, + 0xe1, 0x5d, 0xe0, 0x35, 0xf4, 0xb1, 0xed, 0xa5, 0x67, 0xdd, 0x44, 0x72, 0xcf, 0x8d, 0x52, 0xa7, + 0xc7, 0x4d, 0x4a, 0x87, 0xbc, 0xf8, 0xc5, 0xf8, 0x03, 0xbc, 0xf5, 0xa4, 0x7c, 0x4c, 0x9b, 0xed, + 0x6f, 0xc9, 0x3e, 0x81, 0x5a, 0x3f, 0xd2, 0x70, 0x41, 0xb8, 0x22, 0xd2, 0xb7, 0x60, 0x9e, 0x86, + 0xb8, 0xe3, 0x94, 0xd6, 0x56, 0x52, 0x6d, 0xc9, 0x34, 0xa6, 0x52, 0x5c, 0xd9, 0xaa, 0xa4, 0x47, + 0xaa, 0x92, 0x19, 0xaf, 0x14, 0x67, 0x2f, 0x51, 0x8a, 0xcf, 0xf0, 0x06, 0x63, 0x90, 0xfb, 0x69, + 0x0b, 0xfc, 0x22, 0x81, 0xc3, 0x67, 0x5f, 0x6e, 0x69, 0xfa, 0x47, 0x6d, 0xd4, 0x50, 0x10, 0xae, + 0x19, 0x13, 0x28, 0xbc, 0x0d, 0x0b, 0xd2, 0xa0, 0x35, 0x57, 0xe0, 0x40, 0x73, 0x5f, 0x60, 0x67, + 0x60, 0x63, 0x40, 0xe0, 0x7d, 0xa7, 0xe5, 0x8a, 0x77, 0x35, 0x32, 0x3e, 0x2d, 0x05, 0x98, 0x98, + 0x36, 0xdf, 0x7f, 0x1a, 0xd8, 0x17, 0xd2, 0x10, 0x98, 0x68, 0x73, 0xf4, 0x43, 0xc8, 0x3c, 0x57, + 0x51, 0xbb, 0x61, 0xd1, 0xaa, 0x54, 0x64, 0x4e, 0x8c, 0x7a, 0x7a, 0x82, 0x91, 0xae, 0x62, 0x64, + 0x5c, 0xfc, 0xda, 0xfe, 0x29, 0xe7, 0xdf, 0xf8, 0xf9, 0x26, 0xef, 0xb1, 0xf4, 0x2e, 0x64, 0x69, + 0xe8, 0xd3, 0xc0, 0x59, 0x1f, 0x36, 0x1b, 0xf7, 0xc4, 0x46, 0x87, 0x38, 0xc5, 0x21, 0x94, 0x38, + 0x09, 0x9c, 0x38, 0x0b, 0xdd, 0x40, 0xb2, 0x10, 0x36, 0xff, 0x93, 0x84, 0xe5, 0xd0, 0x84, 0x86, + 0x1e, 0x43, 0x47, 0xee, 0x48, 0x0a, 0x86, 0xa9, 0x1b, 0xba, 0x85, 0x1a, 0x5e, 0x0e, 0xcb, 0xba, + 0xa6, 0x21, 0xd9, 0x56, 0x75, 0xad, 0xde, 0xd4, 0x0d, 0x87, 0xe6, 0xe4, 0xf6, 0x9c, 0xb8, 0xe1, + 0xe2, 0xa8, 0xd7, 0x8a, 0x87, 0x7a, 0x4f, 0x37, 0x2c, 0xbe, 0x09, 0x6b, 0xcc, 0x82, 0x40, 0xa5, + 0x4a, 0x8d, 0x29, 0xd5, 0x2a, 0xa3, 0x70, 0x10, 0xc0, 0xe8, 0xd2, 0x93, 0x1e, 0x59, 0x7a, 0xf8, + 0xef, 0xc0, 0x75, 0x5a, 0x6a, 0xe9, 0x71, 0x3b, 0x83, 0x73, 0x91, 0x64, 0x1f, 0x65, 0xb7, 0x0f, + 0x72, 0x15, 0xce, 0xfa, 0x40, 0xd4, 0x62, 0x28, 0x65, 0x67, 0x27, 0x4b, 0xd9, 0xb9, 0xe1, 0x01, + 0xf9, 0x0f, 0x0e, 0xd6, 0x59, 0xfa, 0x5f, 0x79, 0x3c, 0xfa, 0xca, 0x43, 0x72, 0x92, 0xf2, 0xf0, + 0xaf, 0x04, 0x23, 0xa0, 0x27, 0x39, 0x9a, 0x9f, 0x06, 0x8e, 0xd8, 0x2e, 0x1b, 0xc9, 0xd8, 0x6c, + 0xe4, 0x18, 0x81, 0x13, 0x0e, 0x98, 0x54, 0x9c, 0x80, 0x49, 0xc7, 0x08, 0x98, 0xff, 0xed, 0x99, + 0x1d, 0x31, 0xe2, 0xc5, 0x77, 0x6c, 0x9f, 0x56, 0x95, 0xff, 0x73, 0x12, 0xf2, 0x21, 0x3f, 0x93, + 0x1e, 0x35, 0x7f, 0x0a, 0x02, 0xf3, 0x96, 0xc5, 0xb2, 0x25, 0x1b, 0xd1, 0xb0, 0x13, 0x98, 0xf3, + 0xad, 0x39, 0x08, 0x31, 0xcf, 0xb8, 0x84, 0xc1, 0x3d, 0x91, 0x41, 0x92, 0x9a, 0x72, 0x90, 0xa4, + 0xe3, 0x04, 0x49, 0x26, 0x46, 0x90, 0x64, 0x27, 0x0b, 0x92, 0xd9, 0xe1, 0x41, 0xa2, 0x42, 0x21, + 0x4a, 0xbc, 0x69, 0x07, 0xca, 0x27, 0x49, 0xc6, 0x76, 0xe0, 0xc8, 0x40, 0xda, 0xff, 0x61, 0x94, + 0x8c, 0x7c, 0xd1, 0xa4, 0x2e, 0xf1, 0xa2, 0x61, 0x85, 0xc4, 0xd5, 0x96, 0x84, 0x2d, 0xc6, 0x9e, + 0xc6, 0x51, 0xc0, 0xbb, 0xef, 0xf8, 0x4b, 0x82, 0x91, 0xcc, 0xee, 0xf9, 0x73, 0x5a, 0x75, 0x79, + 0xfc, 0x7b, 0xee, 0x1c, 0x43, 0xa8, 0x78, 0x75, 0x39, 0xc8, 0x6f, 0x7a, 0x32, 0x7e, 0x47, 0xdc, + 0x98, 0x14, 0x19, 0xd9, 0x14, 0x38, 0xad, 0x16, 0xff, 0x9a, 0x80, 0x95, 0x70, 0xca, 0x49, 0x9a, + 0x8c, 0xda, 0x97, 0x66, 0xf8, 0x29, 0x5c, 0x47, 0xa6, 0xa9, 0x9b, 0x75, 0x7c, 0xa0, 0x34, 0xdc, + 0x43, 0xfb, 0x6d, 0x26, 0xb5, 0x55, 0x07, 0x29, 0x12, 0x20, 0x5d, 0xed, 0x35, 0xe4, 0x6b, 0xe3, + 0x4b, 0x90, 0x23, 0x9c, 0x0d, 0xda, 0x24, 0xf4, 0x2e, 0xe1, 0x2e, 0xbf, 0x8d, 0x2b, 0xe6, 0xf8, + 0x36, 0x6c, 0x45, 0xd0, 0xe7, 0x51, 0xfc, 0x6b, 0x58, 0x38, 0xb4, 0x94, 0x53, 0xa3, 0x21, 0xd9, + 0xe8, 0x58, 0x32, 0xa5, 0x8e, 0xc5, 0xaf, 0xc3, 0x9c, 0xd4, 0xb5, 0x9b, 0xba, 0xa9, 0xda, 0xe7, + 0xee, 0xf7, 0x1f, 0xaf, 0x81, 0x1c, 0x01, 0x1d, 0x1c, 0xfd, 0x44, 0x15, 0x75, 0x04, 0x74, 0x20, + 0xfd, 0x23, 0xa0, 0xf3, 0xf4, 0x88, 0x77, 0xe7, 0xd7, 0x37, 0x57, 0x5c, 0xc5, 0x0a, 0xfb, 0xfd, + 0x7b, 0x53, 0xfb, 0x1d, 0x87, 0x13, 0xec, 0xd8, 0xec, 0x6a, 0x28, 0x70, 0xfc, 0xb2, 0x2e, 0x2d, + 0xff, 0x32, 0xa4, 0xdb, 0x6a, 0x87, 0xde, 0xc9, 0xa6, 0x44, 0xf2, 0x10, 0xff, 0xa8, 0xf3, 0x19, + 0x87, 0xc3, 0x96, 0x39, 0x27, 0xef, 0x25, 0x70, 0x1f, 0x6e, 0xd9, 0xba, 0x2d, 0xb5, 0xeb, 0x86, + 0x03, 0x6b, 0x78, 0x95, 0xd0, 0xa2, 0x37, 0x80, 0xcb, 0xb8, 0x17, 0xdb, 0x68, 0xb8, 0x25, 0xd0, + 0xe2, 0x1f, 0xc1, 0x2a, 0x19, 0x65, 0xa2, 0x8e, 0xa4, 0x6a, 0xaa, 0xa6, 0xf8, 0x06, 0x92, 0xed, + 0xe5, 0x0a, 0x06, 0x88, 0x6e, 0xbf, 0x37, 0x76, 0xe7, 0x2b, 0x0e, 0xf8, 0xf0, 0x4b, 0x85, 0x7f, + 0x00, 0x05, 0xb1, 0x5a, 0x3b, 0x3e, 0x7a, 0x56, 0xab, 0xd6, 0xc5, 0x6a, 0xed, 0xf4, 0xe9, 0x49, + 0xfd, 0xe4, 0x67, 0xc7, 0xd5, 0xfa, 0xe9, 0xb3, 0xda, 0x71, 0xb5, 0x72, 0xf0, 0xe4, 0xa0, 0xfa, + 0xa3, 0xc5, 0x19, 0x61, 0xe1, 0xe5, 0xab, 0xc2, 0xbc, 0xaf, 0x89, 0xbf, 0x03, 0xab, 0xcc, 0x61, + 0xcf, 0x8e, 0x8e, 0x8e, 0x17, 0x39, 0x61, 0xf6, 0xe5, 0xab, 0x42, 0xca, 0xf9, 0xcd, 0xdf, 0x83, + 0x75, 0x26, 0xb0, 0x76, 0x5a, 0xa9, 0x54, 0x6b, 0xb5, 0xc5, 0x84, 0x30, 0xff, 0xf2, 0x55, 0x21, + 0x4b, 0x1f, 0x23, 0xe1, 0x4f, 0xf6, 0x0f, 0x9e, 0x9e, 0x8a, 0xd5, 0xc5, 0x24, 0x81, 0xd3, 0x47, + 0x21, 0xf5, 0xe2, 0x8f, 0x9b, 0x33, 0x7b, 0x7f, 0x5f, 0x82, 0xe4, 0xa1, 0xa5, 0xf0, 0x2d, 0x58, + 0x08, 0x7e, 0x47, 0x65, 0xbf, 0x5c, 0xc3, 0x9f, 0x36, 0x85, 0x72, 0x4c, 0xa0, 0xa7, 0x60, 0x13, + 0x6e, 0x04, 0x3e, 0x60, 0xbe, 0x11, 0xc3, 0xc4, 0x89, 0x79, 0x2e, 0x94, 0xe2, 0xe1, 0x22, 0x3c, + 0x39, 0x5b, 0xfa, 0x38, 0x9e, 0xf6, 0xe5, 0x56, 0x2c, 0x4f, 0xfe, 0x3d, 0xac, 0x0d, 0x3c, 0xe3, + 0xb3, 0xd3, 0x4e, 0x0c, 0x2b, 0x14, 0x2b, 0xec, 0xc5, 0xc7, 0x7a, 0x5e, 0x35, 0x58, 0x0c, 0x7d, + 0xef, 0xd9, 0x1e, 0x61, 0xc7, 0x43, 0x0a, 0x6f, 0xc7, 0x45, 0x7a, 0xfe, 0x3e, 0x82, 0x1c, 0xeb, + 0x3b, 0xce, 0x5b, 0x71, 0x0c, 0xb9, 0xeb, 0x7c, 0x67, 0x0c, 0xb0, 0xe7, 0xf8, 0xe7, 0x00, 0xbe, + 0x4f, 0x1f, 0xc5, 0x28, 0x13, 0x7d, 0x8c, 0xb0, 0x33, 0x1a, 0xe3, 0xb7, 0xee, 0xfb, 0x40, 0x10, + 0x69, 0xbd, 0x8f, 0x89, 0xb6, 0xce, 0xb8, 0x83, 0xaf, 0x41, 0xd6, 0xdd, 0xb8, 0x6c, 0x45, 0x0d, + 0xa3, 0x00, 0xe1, 0xce, 0x08, 0x80, 0x3f, 0xb2, 0x03, 0xf7, 0xc3, 0x6f, 0x8c, 0x18, 0x4a, 0x71, + 0xd1, 0x91, 0x1d, 0x71, 0xe7, 0xd9, 0x82, 0x85, 0xe0, 0x45, 0x65, 0xe4, 0x2c, 0x03, 0xc0, 0xe8, + 0xd2, 0x10, 0x75, 0xe1, 0xd7, 0x4f, 0x23, 0xff, 0x2d, 0xdd, 0xa8, 0x34, 0xf2, 0x61, 0x47, 0xa6, + 0x11, 0xeb, 0x02, 0xed, 0x43, 0x58, 0x0a, 0xdf, 0x66, 0xbd, 0x19, 0xcf, 0x90, 0x53, 0x96, 0x76, + 0x63, 0x43, 0xa3, 0x5d, 0x3a, 0xc5, 0x29, 0xa6, 0x4b, 0xa7, 0x3e, 0xed, 0xc6, 0x86, 0x7a, 0x2e, + 0x7f, 0x05, 0x37, 0xd9, 0x67, 0xe3, 0x7b, 0xf1, 0x6c, 0xb9, 0x09, 0xfc, 0x60, 0x2c, 0x78, 0xb4, + 0xb4, 0xf8, 0xc4, 0x15, 0x53, 0x5a, 0x07, 0x1b, 0x57, 0x5a, 0xff, 0x39, 0x22, 0xbc, 0x68, 0x37, + 0x15, 0x63, 0x2e, 0xda, 0x4d, 0xcc, 0x07, 0x63, 0xc1, 0x3d, 0xf7, 0xbf, 0x84, 0x65, 0xe6, 0xfe, + 0xfa, 0x6e, 0x4c, 0x0e, 0x31, 0x5a, 0xb8, 0x3f, 0x0e, 0xda, 0xf3, 0xad, 0x42, 0x8e, 0xec, 0xfc, + 0x28, 0x8a, 0x6e, 0x40, 0xbf, 0x1b, 0x65, 0xcc, 0xbf, 0x4d, 0x14, 0xee, 0xc6, 0x41, 0xf9, 0x59, + 0x66, 0x6f, 0x24, 0x23, 0x59, 0x66, 0xc2, 0xa3, 0x59, 0x1e, 0xba, 0x25, 0x14, 0xd2, 0x9f, 0x7c, + 0xf3, 0xf9, 0x0e, 0xf7, 0xb8, 0xf6, 0xc5, 0xeb, 0x4d, 0xee, 0xcb, 0xd7, 0x9b, 0xdc, 0xbf, 0x5f, + 0x6f, 0x72, 0xbf, 0xbd, 0xd8, 0x9c, 0xf9, 0xf2, 0x62, 0x73, 0xe6, 0xab, 0x8b, 0xcd, 0x99, 0xf7, + 0x1f, 0x2a, 0xaa, 0xdd, 0xec, 0x9e, 0x95, 0x64, 0xbd, 0x53, 0xa6, 0xff, 0xb5, 0xa6, 0x9e, 0xc9, + 0xf7, 0x14, 0xbd, 0xdc, 0xfb, 0x7e, 0xb9, 0xa3, 0x37, 0xba, 0x6d, 0x64, 0x91, 0xff, 0x36, 0x7b, + 0xfb, 0xfe, 0x3d, 0xf7, 0x1f, 0xce, 0xec, 0x73, 0x03, 0x59, 0x67, 0x19, 0xfc, 0xcf, 0x66, 0xef, + 0xfc, 0x37, 0x00, 0x00, 0xff, 0xff, 0x8c, 0xcd, 0xc5, 0x26, 0x37, 0x27, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3267,21 +3260,18 @@ func (m *MsgSendPacket) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x32 } - if len(m.PacketData) > 0 { - i -= len(m.PacketData) - copy(dAtA[i:], m.PacketData) - i = encodeVarintTx(dAtA, i, uint64(len(m.PacketData))) + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) i-- dAtA[i] = 0x2a } - n7, err7 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.TimeoutTimestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.TimeoutTimestamp):]) - if err7 != nil { - return 0, err7 + if m.TimeoutTimestamp != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.TimeoutTimestamp)) + i-- + dAtA[i] = 0x20 } - i -= n7 - i = encodeVarintTx(dAtA, i, uint64(n7)) - i-- - dAtA[i] = 0x22 { size, err := m.TimeoutHeight.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -4839,9 +4829,10 @@ func (m *MsgSendPacket) Size() (n int) { } l = m.TimeoutHeight.Size() n += 1 + l + sovTx(uint64(l)) - l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.TimeoutTimestamp) - n += 1 + l + sovTx(uint64(l)) - l = len(m.PacketData) + if m.TimeoutTimestamp != 0 { + n += 1 + sovTx(uint64(m.TimeoutTimestamp)) + } + l = len(m.Data) if l > 0 { n += 1 + l + sovTx(uint64(l)) } @@ -7237,10 +7228,10 @@ func (m *MsgSendPacket) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 4: - if wireType != 2 { + if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field TimeoutTimestamp", wireType) } - var msglen int + m.TimeoutTimestamp = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -7250,28 +7241,14 @@ func (m *MsgSendPacket) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + m.TimeoutTimestamp |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.TimeoutTimestamp, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PacketData", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -7298,9 +7275,9 @@ func (m *MsgSendPacket) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.PacketData = append(m.PacketData[:0], dAtA[iNdEx:postIndex]...) - if m.PacketData == nil { - m.PacketData = []byte{} + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} } iNdEx = postIndex case 6: diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index a500594be92..bc06ce68368 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -462,7 +462,7 @@ func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPack return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) } - sequence, err := k.ChannelKeeper.SendPacket(ctx, capability, msg.PortId, msg.ChannelId, msg.TimeoutHeight, uint64(msg.TimeoutTimestamp.UnixNano()), msg.PacketData) + sequence, err := k.ChannelKeeper.SendPacket(ctx, capability, msg.PortId, msg.ChannelId, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data) if err != nil { ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet failed")) return nil, errorsmod.Wrapf(err, "send packet failed for module: %s", module) @@ -471,7 +471,7 @@ func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPack // TODO: Make port router have list of ordered callbacks // Loop over cbs in-order calling OnSendPacket on each IBCModule. To be done for RecvPacket handler as well in opposite order. // Adjust app logic to account for what should be done before MsgSendPacket and what should be done in OnSendPacket. - if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.PacketData, msg.Signer); err != nil { + if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.Data, msg.Signer); err != nil { ctx.Logger().Error("send packet callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet callback failed")) return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", module) } diff --git a/proto/ibc/core/channel/v1/tx.proto b/proto/ibc/core/channel/v1/tx.proto index 842c44db897..f21637e3073 100644 --- a/proto/ibc/core/channel/v1/tx.proto +++ b/proto/ibc/core/channel/v1/tx.proto @@ -4,7 +4,6 @@ package ibc.core.channel.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; -import "google/protobuf/timestamp.proto"; import "gogoproto/gogo.proto"; import "cosmos/msg/v1/msg.proto"; import "ibc/core/client/v1/client.proto"; @@ -221,8 +220,8 @@ message MsgSendPacket { string port_id = 1; string channel_id = 2; ibc.core.client.v1.Height timeout_height = 3 [(gogoproto.nullable) = false]; - google.protobuf.Timestamp timeout_timestamp = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - bytes packet_data = 5; + uint64 timeout_timestamp = 4; + bytes data = 5; string signer = 6; } From 90fe8ae518d581feac0960e2c4b463a2fe03087b Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 15 May 2024 14:15:34 +0200 Subject: [PATCH 06/46] chore: add OnSendPacket to ibccallbacks --- modules/apps/callbacks/ibc_middleware.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 0ab1f5f9887..e2af5b804bb 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -121,6 +121,18 @@ func (im IBCMiddleware) SendPacket( return seq, nil } +// OnSendPacket implements the IBCModule interface. +func (IBCMiddleware) OnSendPacket( + ctx sdk.Context, + portID string, + channelID string, + sequence uint64, + data []byte, + signer string, +) error { + return nil +} + // OnAcknowledgementPacket implements source callbacks for acknowledgement packets. // It defers to the underlying application and then calls the contract callback. // If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are From fc309f639d30dd727d55f0fb71786de55155489a Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 15 May 2024 14:30:09 +0200 Subject: [PATCH 07/46] feat: add router_v2 while leaving current router impl in place --- modules/core/05-port/types/router_v2.go | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 modules/core/05-port/types/router_v2.go diff --git a/modules/core/05-port/types/router_v2.go b/modules/core/05-port/types/router_v2.go new file mode 100644 index 00000000000..74d64e6fd31 --- /dev/null +++ b/modules/core/05-port/types/router_v2.go @@ -0,0 +1,69 @@ +// NOTE: router_v2 is added to incrementally add functionality and switch over parts of codebase while leaving current router in place +// Eventually this will replace the v1 router. +package types + +import ( + "errors" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// AppRouter contains a map from module name to an ordered list of IBCModules +// which contains all the module-defined callbacks required by ICS-26. +type AppRouter struct { + routes map[string][]IBCModule + sealed bool +} + +// NewAppRouter creates and returns a new IBCModule application router. +func NewAppRouter() *AppRouter { + return &AppRouter{ + routes: make(map[string][]IBCModule), + } +} + +// Seal prevents the Router from any subsequent route handlers to be registered. +// Seal will panic if called more than once. +func (rtr *AppRouter) Seal() { + if rtr.sealed { + panic(errors.New("router already sealed")) + } + rtr.sealed = true +} + +// Sealed returns a boolean signifying if the Router is sealed or not. +func (rtr AppRouter) Sealed() bool { + return rtr.sealed +} + +// AddRoute adds IBCModule for a given module name. It returns the Router +// so AddRoute calls can be linked. It will panic if the Router is sealed. +func (rtr *AppRouter) AddRoute(module string, cbs IBCModule) *AppRouter { + if rtr.sealed { + panic(fmt.Errorf("router sealed; cannot register %s route callbacks", module)) + } + if !sdk.IsAlphaNumeric(module) { + panic(errors.New("route expressions can only contain alphanumeric characters")) + } + if rtr.HasRoute(module) { + panic(fmt.Errorf("route %s has already been registered", module)) + } + + rtr.routes[module] = append(rtr.routes[module], cbs) + return rtr +} + +// HasRoute returns true if the Router has a module registered or false otherwise. +func (rtr *AppRouter) HasRoute(module string) bool { + _, ok := rtr.routes[module] + return ok +} + +// GetRoute returns a IBCModule for a given module. +func (rtr *AppRouter) GetRoute(module string) ([]IBCModule, bool) { + if !rtr.HasRoute(module) { + return nil, false + } + return rtr.routes[module], true +} From d0f85dbc1a78716479f79f5c1be9093002733b8d Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 15 May 2024 14:41:10 +0200 Subject: [PATCH 08/46] chore: add getter and setters for AppRouter to core ibc --- modules/core/05-port/keeper/keeper.go | 13 ++++++++++--- modules/core/keeper/keeper.go | 11 +++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/modules/core/05-port/keeper/keeper.go b/modules/core/05-port/keeper/keeper.go index 51d77152a59..180f9c2ae16 100644 --- a/modules/core/05-port/keeper/keeper.go +++ b/modules/core/05-port/keeper/keeper.go @@ -15,7 +15,8 @@ import ( // Keeper defines the IBC connection keeper type Keeper struct { - Router *types.Router + AppRouter *types.AppRouter + Router *types.Router scopedKeeper exported.ScopedKeeper } @@ -84,6 +85,12 @@ func (k *Keeper) LookupModuleByPort(ctx sdk.Context, portID string) (string, *ca // Route returns a IBCModule for a given module, and a boolean indicating // whether or not the route is present. -func (k *Keeper) Route(clientID string) (types.IBCModule, bool) { - return k.Router.GetRoute(clientID) +func (k *Keeper) Route(module string) (types.IBCModule, bool) { + return k.Router.GetRoute(module) +} + +// AppRoute returns an ordered list of IBCModule callbacks for a given module name, and a boolean indicating +// whether or not the callbacks are present. +func (k *Keeper) AppRoute(module string) ([]types.IBCModule, bool) { + return k.AppRouter.GetRoute(module) } diff --git a/modules/core/keeper/keeper.go b/modules/core/keeper/keeper.go index 30726efecfc..4fedba4b0f4 100644 --- a/modules/core/keeper/keeper.go +++ b/modules/core/keeper/keeper.go @@ -89,6 +89,17 @@ func (k *Keeper) SetConsensusHost(consensusHost clienttypes.ConsensusHost) { k.ClientKeeper.SetConsensusHost(consensusHost) } +// SetAppRouter sets the Router in IBC Keeper and seals it. The method panics if +// there is an existing router that's already sealed. +func (k *Keeper) SetAppRouter(rtr *porttypes.AppRouter) { + if k.PortKeeper.AppRouter != nil && k.PortKeeper.AppRouter.Sealed() { + panic(errors.New("cannot reset a sealed router")) + } + + k.PortKeeper.AppRouter = rtr + k.PortKeeper.AppRouter.Seal() +} + // SetRouter sets the Router in IBC Keeper and seals it. The method panics if // there is an existing router that's already sealed. func (k *Keeper) SetRouter(rtr *porttypes.Router) { From 588ff66c8901bfa85c4a631aa8ef9b1be9351552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 15 May 2024 18:03:14 +0200 Subject: [PATCH 09/46] imp: implement callbacks OnSendPacket --- .../controller/ibc_middleware.go | 2 + .../27-interchain-accounts/host/ibc_module.go | 3 ++ modules/apps/29-fee/ibc_middleware.go | 2 + modules/apps/callbacks/ibc_middleware.go | 37 +++++++++++-------- modules/apps/transfer/ibc_module.go | 3 ++ modules/core/05-port/types/module.go | 3 ++ modules/core/keeper/msg_server.go | 2 +- testing/mock/ibc_module.go | 3 +- testing/mock/middleware.go | 2 +- 9 files changed, 39 insertions(+), 18 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 1356018a5c4..0213063c1b3 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -176,6 +176,8 @@ func (IBCMiddleware) OnSendPacket( portID string, channelID string, sequence uint64, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, data []byte, signer string, ) error { diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index b74f3a9f58a..3c063cde20d 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" @@ -116,6 +117,8 @@ func (IBCModule) OnSendPacket( portID string, channelID string, sequence uint64, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, data []byte, signer string, ) error { diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index c3f0f8894ca..a9c7bfda02c 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -218,6 +218,8 @@ func (IBCMiddleware) OnSendPacket( portID string, channelID string, sequence uint64, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, data []byte, signer string, ) error { diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index e2af5b804bb..e5524a2fad8 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -99,12 +99,31 @@ func (im IBCMiddleware) SendPacket( return 0, err } + if err := im.OnSendPacket(ctx, sourcePort, sourceChannel, seq, timeoutHeight, timeoutTimestamp, data, ""); err != nil { + return 0, err + } + + return seq, nil +} + +// OnSendPacket implements the IBCModule interface. +func (im IBCMiddleware) OnSendPacket( + ctx sdk.Context, + sourcePort string, + sourceChannel string, + sequence uint64, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, + signer string, +) error { callbackData, err := types.GetSourceCallbackData(im.app, data, sourcePort, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) // SendPacket is not blocked if the packet does not opt-in to callbacks if err != nil { - return seq, nil + return nil } + // TODO: the packet sender is now passed in, it is possible to remove `GetPacketSender` in favour of this arg callbackExecutor := func(cachedCtx sdk.Context) error { return im.contractKeeper.IBCSendPacketCallback( cachedCtx, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data, callbackData.CallbackAddress, callbackData.SenderAddress, @@ -114,22 +133,10 @@ func (im IBCMiddleware) SendPacket( err = im.processCallback(ctx, types.CallbackTypeSendPacket, callbackData, callbackExecutor) // contract keeper is allowed to reject the packet send. if err != nil { - return 0, err + return err } - types.EmitCallbackEvent(ctx, sourcePort, sourceChannel, seq, types.CallbackTypeSendPacket, callbackData, nil) - return seq, nil -} - -// OnSendPacket implements the IBCModule interface. -func (IBCMiddleware) OnSendPacket( - ctx sdk.Context, - portID string, - channelID string, - sequence uint64, - data []byte, - signer string, -) error { + types.EmitCallbackEvent(ctx, sourcePort, sourceChannel, sequence, types.CallbackTypeSendPacket, callbackData, nil) return nil } diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 6a82d654bcd..eacf8cfd229 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -13,6 +13,7 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" @@ -178,6 +179,8 @@ func (IBCModule) OnSendPacket( portID string, channelID string, sequence uint64, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, data []byte, signer string, ) error { diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index a8e9089e2f3..09fc494b0d4 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -81,11 +81,14 @@ type IBCModule interface { channelID string, ) error + // TODO: consider removing timeout height and timeout timestamp added back for callbacks OnSendPacket( ctx sdk.Context, portID string, channelID string, sequence uint64, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, data []byte, signer string, ) error diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index bc06ce68368..d380030e47f 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -471,7 +471,7 @@ func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPack // TODO: Make port router have list of ordered callbacks // Loop over cbs in-order calling OnSendPacket on each IBCModule. To be done for RecvPacket handler as well in opposite order. // Adjust app logic to account for what should be done before MsgSendPacket and what should be done in OnSendPacket. - if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.Data, msg.Signer); err != nil { + if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data, msg.Signer); err != nil { ctx.Logger().Error("send packet callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet callback failed")) return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", module) } diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index c1dd38fa0ca..21e0a61b40d 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -10,6 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" @@ -123,7 +124,7 @@ func (im IBCModule) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string } // OnSendPacket implements the IBCModule interface. -func (im IBCModule) OnSendPacket(ctx sdk.Context, portID string, channelID string, sequence uint64, data []byte, signer string) error { +func (im IBCModule) OnSendPacket(ctx sdk.Context, portID string, channelID string, sequence uint64, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, signer string) error { if im.IBCApp.OnSendPacket != nil { return im.IBCApp.OnSendPacket(ctx, portID, channelID, sequence, data, signer) } diff --git a/testing/mock/middleware.go b/testing/mock/middleware.go index e952d9dce16..5729b8cc276 100644 --- a/testing/mock/middleware.go +++ b/testing/mock/middleware.go @@ -114,7 +114,7 @@ func (im BlockUpgradeMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, cha } // OnSendPacket implements the IBCModule interface. -func (im BlockUpgradeMiddleware) OnSendPacket(ctx sdk.Context, portID string, channelID string, sequence uint64, data []byte, signer string) error { +func (im BlockUpgradeMiddleware) OnSendPacket(ctx sdk.Context, portID string, channelID string, sequence uint64, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, signer string) error { if im.IBCApp.OnSendPacket != nil { return im.IBCApp.OnSendPacket(ctx, portID, channelID, sequence, data, signer) } From 8bc82f6292de01e6a07454c277ee431d9c31c172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 16 May 2024 09:58:47 +0200 Subject: [PATCH 10/46] imp: implement OnSendPacket for ics27 --- .../controller/ibc_middleware.go | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 0213063c1b3..a0c80fec60d 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -171,7 +171,7 @@ func (im IBCMiddleware) OnChanCloseConfirm( } // OnSendPacket implements the IBCModule interface. -func (IBCMiddleware) OnSendPacket( +func (im IBCMiddleware) OnSendPacket( ctx sdk.Context, portID string, channelID string, @@ -181,6 +181,42 @@ func (IBCMiddleware) OnSendPacket( data []byte, signer string, ) error { + if !im.keeper.GetParams(ctx).ControllerEnabled { + return types.ErrControllerSubModuleDisabled + } + + controllerPortID, err := icatypes.NewControllerPortID(signer) + if err != nil { + return err + } + + if controllerPortID != portID { + return errorsmod.Wrap(ibcerrors.ErrUnauthorized, "signer is not owner of interchain account channel") + } + + connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) + if err != nil { + return err + } + + activeChannelID, found := im.keeper.GetOpenActiveChannel(ctx, connectionID, portID) + if !found { + return errorsmod.Wrapf(icatypes.ErrActiveChannelNotFound, "failed to retrieve active channel on connection %s for port %s", connectionID, portID) + } + + if activeChannelID != channelID { + return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "active channel ID does not match provided channelID. expected %s, got %s", activeChannelID, channelID) + } + + var icaPacketData icatypes.InterchainAccountPacketData + if err := icaPacketData.UnmarshalJSON(data); err != nil { + return err + } + + if err := icaPacketData.ValidateBasic(); err != nil { + return errorsmod.Wrap(err, "invalid interchain account packet data") + } + return nil } From f883d68ca836855b0bcfaec9a2e8a393bd01468a Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 16 May 2024 10:06:05 +0200 Subject: [PATCH 11/46] imp: implement OnSendPacket in transfer --- modules/apps/transfer/ibc_module.go | 22 ++++-- modules/apps/transfer/keeper/msg_server.go | 30 +++++++++ modules/apps/transfer/keeper/relay.go | 78 ++++++++++++++++++++++ 3 files changed, 124 insertions(+), 6 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index eacf8cfd229..f9992b7b06a 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -174,17 +174,27 @@ func (IBCModule) OnChanCloseConfirm( } // OnSendPacket implements the IBCModule interface. -func (IBCModule) OnSendPacket( +func (im IBCModule) OnSendPacket( ctx sdk.Context, portID string, channelID string, - sequence uint64, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, + _ uint64, + _ clienttypes.Height, + _ uint64, + dataBz []byte, signer string, ) error { - return nil + var data types.FungibleTokenPacketData + if err := json.Unmarshal(dataBz, &data); err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data") + } + + sender, err := sdk.AccAddressFromBech32(signer) + if err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "cannot convert signer address to sdk.AccAddress") + } + + return im.keeper.OnSendPacket(ctx, portID, channelID, data, sender) } // OnRecvPacket implements the IBCModule interface. A successful acknowledgement diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index c5171573226..443b51ed026 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -2,12 +2,14 @@ package keeper import ( "context" + "strings" errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ) @@ -34,6 +36,34 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to send funds", sender) } + // NOTE: denomination and hex hash correctness checked during msg.ValidateBasic + fullDenomPath := msg.Token.Denom + + // deconstruct the token denomination into the denomination trace info + // to determine if the sender is the source chain + if strings.HasPrefix(msg.Token.Denom, "ibc/") { + fullDenomPath, err = k.DenomPathFromHash(ctx, msg.Token.Denom) + if err != nil { + return nil, err + } + } + + packetData := types.NewFungibleTokenPacketData( + fullDenomPath, msg.Token.Amount.String(), sender.String(), msg.Receiver, msg.Memo, + ) + + msgSendPacket := channeltypes.MsgSendPacket{ + PortId: msg.SourcePort, + ChannelId: msg.SourceChannel, + TimeoutHeight: msg.TimeoutHeight, + TimeoutTimestamp: msg.TimeoutTimestamp, + Data: packetData.GetBytes(), + Signer: sender.String(), + } + + // TODO: route msgSendPacket to core which calls OnSendPacket + _ = msgSendPacket + sequence, err := k.sendTransfer( ctx, msg.SourcePort, msg.SourceChannel, msg.Token, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Memo) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 3bae0b9da03..53984afae89 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -158,6 +158,84 @@ func (k Keeper) sendTransfer( return sequence, nil } +// OnSendPacket handles transfer sending logic. +// TODO: Copy godoc from above sendTransfer function. +func (k Keeper) OnSendPacket(ctx sdk.Context, + sourcePort string, + sourceChannel string, + packetData types.FungibleTokenPacketData, + sender sdk.AccAddress, +) error { + channel, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) + if !found { + return errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", sourcePort, sourceChannel) + } + + // begin createOutgoingPacket logic + // See spec for this logic: https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#packet-relay + labels := []metrics.Label{ + telemetry.NewLabel(coretypes.LabelDestinationPort, channel.Counterparty.PortId), + telemetry.NewLabel(coretypes.LabelDestinationChannel, channel.Counterparty.ChannelId), + } + + amount, ok := sdkmath.NewIntFromString(packetData.Amount) + if !ok { + return errorsmod.Wrapf(types.ErrInvalidAmount, "cannot convert packet data amount to int: %s", packetData.Amount) + } + + token := sdk.NewCoin(packetData.Denom, amount) + + // NOTE: SendTransfer simply sends the denomination as it exists on its own + // chain inside the packet data. The receiving chain will perform denom + // prefixing as necessary. + if types.SenderChainIsSource(sourcePort, sourceChannel, packetData.Denom) { + labels = append(labels, telemetry.NewLabel(coretypes.LabelSource, "true")) + + // obtain the escrow address for the source channel end + escrowAddress := types.GetEscrowAddress(sourcePort, sourceChannel) + if err := k.escrowToken(ctx, sender, escrowAddress, token); err != nil { + return err + } + + } else { + labels = append(labels, telemetry.NewLabel(coretypes.LabelSource, "false")) + + // transfer the coins to the module account and burn them + if err := k.bankKeeper.SendCoinsFromAccountToModule( + ctx, sender, types.ModuleName, sdk.NewCoins(token), + ); err != nil { + return err + } + + if err := k.bankKeeper.BurnCoins( + ctx, types.ModuleName, sdk.NewCoins(token), + ); err != nil { + // NOTE: should not happen as the module account was + // retrieved on the step above and it has enough balance + // to burn. + panic(fmt.Errorf("cannot burn coins after a successful send to a module account: %v", err)) + } + } + + defer func() { + if token.Amount.IsInt64() { + telemetry.SetGaugeWithLabels( + []string{"tx", "msg", "ibc", "transfer"}, + float32(token.Amount.Int64()), + []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, packetData.Denom)}, + ) + } + + telemetry.IncrCounterWithLabels( + []string{"ibc", types.ModuleName, "send"}, + 1, + labels, + ) + }() + + return nil +} + // OnRecvPacket processes a cross chain fungible token transfer. If the // sender chain is the source of minted tokens then vouchers will be minted // and sent to the receiving address. Otherwise if the sender chain is sending From e626c7b7ec55f56aab82303d58e18b1b8945edd2 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 16 May 2024 10:29:18 +0200 Subject: [PATCH 12/46] chore: start wiring up router_v2 in app.go --- testing/simapp/app.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index cbb77eac3db..3fe90417aa1 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -464,6 +464,7 @@ func NewSimApp( ) // Create IBC Router + ibcAppRouter := porttypes.NewAppRouter() ibcRouter := porttypes.NewRouter() // Middleware Stacks @@ -489,10 +490,13 @@ func NewSimApp( mockIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(ibcmock.ModuleName, scopedIBCMockKeeper)) app.IBCMockModule = mockIBCModule ibcRouter.AddRoute(ibcmock.ModuleName, mockIBCModule) + ibcAppRouter.AddRoute(ibcmock.ModuleName, mockIBCModule) // Mock IBC app wrapped with a middleware which does not implement the UpgradeableModule interface. // NOTE: this is used to test integration with apps which do not yet fulfill the UpgradeableModule interface and error when // an upgrade is tried on the channel. + + // TODO: THIS CAN BE REMOVED ENTIRELY RIGHT NOW FROM MAIN. IGNORE FOR NOW mockBlockUpgradeIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(ibcmock.MockBlockUpgrade, scopedIBCMockBlockUpgradeKeeper)) mockBlockUpgradeMw := ibcmock.NewBlockUpgradeMiddleware(&mockModule, mockBlockUpgradeIBCModule.IBCApp) ibcRouter.AddRoute(ibcmock.MockBlockUpgrade, mockBlockUpgradeMw) @@ -515,6 +519,7 @@ func NewSimApp( // Add transfer stack to IBC Router ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) + ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) // Create Interchain Accounts Stack // SendPacket, since it is originating from the application to core IBC: @@ -547,6 +552,11 @@ func NewSimApp( AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) + ibcAppRouter. + AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). + AddRoute(icahosttypes.SubModuleName, icaHostStack). + AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) + // Create Mock IBC Fee module stack for testing // SendPacket, mock module cannot send packets @@ -562,8 +572,11 @@ func NewSimApp( feeWithMockModule := ibcfee.NewIBCMiddleware(feeMockModule, app.IBCFeeKeeper) ibcRouter.AddRoute(MockFeePort, feeWithMockModule) + ibcAppRouter.AddRoute(MockFeePort, feeWithMockModule) + // Seal the IBC Router app.IBCKeeper.SetRouter(ibcRouter) + app.IBCKeeper.SetAppRouter(ibcAppRouter) clientRouter := app.IBCKeeper.ClientKeeper.GetRouter() From 45896aa82062763b2ebc576986eb82d088893570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 16 May 2024 10:51:45 +0200 Subject: [PATCH 13/46] imp: add msg server handler to transfer --- modules/apps/callbacks/testing/simapp/app.go | 1 + modules/apps/transfer/keeper/keeper.go | 4 ++ modules/apps/transfer/keeper/keeper_test.go | 3 + modules/apps/transfer/keeper/msg_server.go | 16 +++++- .../apps/transfer/types/expected_keepers.go | 7 +++ modules/core/keeper/msg_server.go | 56 ++++++++++--------- .../08-wasm/testing/simapp/app.go | 1 + testing/simapp/app.go | 1 + 8 files changed, 61 insertions(+), 28 deletions(-) diff --git a/modules/apps/callbacks/testing/simapp/app.go b/modules/apps/callbacks/testing/simapp/app.go index db4eee5c2fc..a2633cb4c53 100644 --- a/modules/apps/callbacks/testing/simapp/app.go +++ b/modules/apps/callbacks/testing/simapp/app.go @@ -481,6 +481,7 @@ func NewSimApp( app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, + app.MsgServiceRouter(), authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 6ee9ee7edfe..df5397eb343 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -36,6 +36,8 @@ type Keeper struct { bankKeeper types.BankKeeper scopedKeeper exported.ScopedKeeper + msgRouter types.MessageRouter + // the address capable of executing a MsgUpdateParams message. Typically, this // should be the x/gov module account. authority string @@ -52,6 +54,7 @@ func NewKeeper( authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, scopedKeeper exported.ScopedKeeper, + msgRouter types.MessageRouter, authority string, ) Keeper { // ensure ibc transfer module account is set @@ -73,6 +76,7 @@ func NewKeeper( authKeeper: authKeeper, bankKeeper: bankKeeper, scopedKeeper: scopedKeeper, + msgRouter: msgRouter, authority: authority, } } diff --git a/modules/apps/transfer/keeper/keeper_test.go b/modules/apps/transfer/keeper/keeper_test.go index 0d0da50c002..9b11252430b 100644 --- a/modules/apps/transfer/keeper/keeper_test.go +++ b/modules/apps/transfer/keeper/keeper_test.go @@ -62,6 +62,7 @@ func (suite *KeeperTestSuite) TestNewKeeper() { suite.chainA.GetSimApp().AccountKeeper, suite.chainA.GetSimApp().BankKeeper, suite.chainA.GetSimApp().ScopedTransferKeeper, + suite.chainA.GetSimApp().MsgServiceRouter(), suite.chainA.GetSimApp().ICAControllerKeeper.GetAuthority(), ) }, true}, @@ -76,6 +77,7 @@ func (suite *KeeperTestSuite) TestNewKeeper() { authkeeper.AccountKeeper{}, // empty account keeper suite.chainA.GetSimApp().BankKeeper, suite.chainA.GetSimApp().ScopedTransferKeeper, + suite.chainA.GetSimApp().MsgServiceRouter(), suite.chainA.GetSimApp().ICAControllerKeeper.GetAuthority(), ) }, false}, @@ -90,6 +92,7 @@ func (suite *KeeperTestSuite) TestNewKeeper() { suite.chainA.GetSimApp().AccountKeeper, suite.chainA.GetSimApp().BankKeeper, suite.chainA.GetSimApp().ScopedTransferKeeper, + suite.chainA.GetSimApp().MsgServiceRouter(), "", // authority ) }, false}, diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 443b51ed026..60a223b99cc 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -52,7 +52,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. fullDenomPath, msg.Token.Amount.String(), sender.String(), msg.Receiver, msg.Memo, ) - msgSendPacket := channeltypes.MsgSendPacket{ + msgSendPacket := &channeltypes.MsgSendPacket{ PortId: msg.SourcePort, ChannelId: msg.SourceChannel, TimeoutHeight: msg.TimeoutHeight, @@ -61,8 +61,18 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. Signer: sender.String(), } - // TODO: route msgSendPacket to core which calls OnSendPacket - _ = msgSendPacket + handler := k.msgRouter.Handler(msgSendPacket) + _, err = handler(ctx, msgSendPacket) + if err != nil { + return nil, err + } + + // sendPacketResp, ok := res.MsgResponses[0].GetCachedValue().(*channeltypes.MsgSendPacketResponse) + // if !ok { + // return errorsmod.Wrap(ibcerrors.ErrInvalidType, "failed to convert %T message response to %T", res.MsgResponse[0].GetCachedValue(), &channeltypes.MsgSendPacketResponse) + // } + + // seq := sendPacketResp.Sequence sequence, err := k.sendTransfer( ctx, msg.SourcePort, msg.SourceChannel, msg.Token, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, diff --git a/modules/apps/transfer/types/expected_keepers.go b/modules/apps/transfer/types/expected_keepers.go index e639a84606f..108470dc0c4 100644 --- a/modules/apps/transfer/types/expected_keepers.go +++ b/modules/apps/transfer/types/expected_keepers.go @@ -3,6 +3,7 @@ package types import ( "context" + "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" @@ -61,3 +62,9 @@ type PortKeeper interface { type ParamSubspace interface { GetParamSet(ctx sdk.Context, ps paramtypes.ParamSet) } + +// MessageRouter ADR 031 request type routing +// https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-031-msg-service.md +type MessageRouter interface { + Handler(msg sdk.Msg) baseapp.MsgServiceHandler +} diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index d380030e47f..cd74ea523b3 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -447,36 +447,42 @@ func (k *Keeper) ChannelCloseConfirm(goCtx context.Context, msg *channeltypes.Ms // SendPacket defines a rpc handler method for MsgSendPacket. func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPacket) (*channeltypes.MsgSendPacketResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) + // ctx := sdk.UnwrapSDKContext(goCtx) - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } + return &channeltypes.MsgSendPacketResponse{Sequence: 0}, nil - // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(module) - if !ok { - ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) - } + /* - sequence, err := k.ChannelKeeper.SendPacket(ctx, capability, msg.PortId, msg.ChannelId, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data) - if err != nil { - ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet failed")) - return nil, errorsmod.Wrapf(err, "send packet failed for module: %s", module) - } + module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) + if err != nil { + ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) + return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") + } - // TODO: Make port router have list of ordered callbacks - // Loop over cbs in-order calling OnSendPacket on each IBCModule. To be done for RecvPacket handler as well in opposite order. - // Adjust app logic to account for what should be done before MsgSendPacket and what should be done in OnSendPacket. - if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data, msg.Signer); err != nil { - ctx.Logger().Error("send packet callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet callback failed")) - return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", module) - } + // Retrieve callbacks from router + cbs, ok := k.PortKeeper.Route(module) + if !ok { + ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + } + + sequence, err := k.ChannelKeeper.SendPacket(ctx, capability, msg.PortId, msg.ChannelId, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data) + if err != nil { + ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet failed")) + return nil, errorsmod.Wrapf(err, "send packet failed for module: %s", module) + } + + // TODO: Make port router have list of ordered callbacks + // Loop over cbs in-order calling OnSendPacket on each IBCModule. To be done for RecvPacket handler as well in opposite order. + // Adjust app logic to account for what should be done before MsgSendPacket and what should be done in OnSendPacket. + if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data, msg.Signer); err != nil { + ctx.Logger().Error("send packet callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet callback failed")) + return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", module) + } + + */ - return &channeltypes.MsgSendPacketResponse{Sequence: sequence}, nil + // return &channeltypes.MsgSendPacketResponse{Sequence: sequence}, nil } // RecvPacket defines a rpc handler method for MsgRecvPacket. diff --git a/modules/light-clients/08-wasm/testing/simapp/app.go b/modules/light-clients/08-wasm/testing/simapp/app.go index 8537c7f797d..e9e924bdac7 100644 --- a/modules/light-clients/08-wasm/testing/simapp/app.go +++ b/modules/light-clients/08-wasm/testing/simapp/app.go @@ -526,6 +526,7 @@ func NewSimApp( app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, + app.MsgServiceRouter(), authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index cbb77eac3db..7a381400364 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -475,6 +475,7 @@ func NewSimApp( app.IBCFeeKeeper, // ISC4 Wrapper: fee IBC middleware app.IBCKeeper.ChannelKeeper, app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, + app.MsgServiceRouter(), authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) From 3714960937b9001eacbdc87cfafa690b80a8ee9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 16 May 2024 11:35:02 +0200 Subject: [PATCH 14/46] refactor: enable core IBC SendPacket API and switch transfer to redirect to it --- modules/apps/callbacks/testing/simapp/app.go | 15 +++ modules/apps/transfer/keeper/msg_server.go | 24 ++-- modules/apps/transfer/keeper/relay.go | 114 +------------------ modules/apps/transfer/keeper/relay_test.go | 10 -- modules/core/05-port/types/router_v2.go | 4 - modules/core/keeper/msg_server.go | 49 ++++---- testing/simapp/app.go | 3 +- 7 files changed, 51 insertions(+), 168 deletions(-) diff --git a/modules/apps/callbacks/testing/simapp/app.go b/modules/apps/callbacks/testing/simapp/app.go index a2633cb4c53..9c8f238fc29 100644 --- a/modules/apps/callbacks/testing/simapp/app.go +++ b/modules/apps/callbacks/testing/simapp/app.go @@ -468,6 +468,7 @@ func NewSimApp( ) // Create IBC Router + ibcAppRouter := porttypes.NewAppRouter() ibcRouter := porttypes.NewRouter() // Middleware Stacks @@ -495,6 +496,7 @@ func NewSimApp( // The mock module is used for testing IBC mockIBCModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(ibcmock.ModuleName, scopedIBCMockKeeper)) ibcRouter.AddRoute(ibcmock.ModuleName, mockIBCModule) + ibcAppRouter.AddRoute(ibcmock.ModuleName, mockIBCModule) // Create Transfer Stack // SendPacket, since it is originating from the application to core IBC: @@ -511,7 +513,10 @@ func NewSimApp( // create IBC module from bottom to top of stack var transferStack porttypes.IBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) + ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) + ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) + var transferICS4Wrapper porttypes.ICS4Wrapper transferICS4Wrapper, ok := transferStack.(porttypes.ICS4Wrapper) if !ok { @@ -519,6 +524,8 @@ func NewSimApp( } transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) + ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) + // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the transfer keeper app.TransferKeeper.WithICS4Wrapper(transferICS4Wrapper) @@ -563,6 +570,11 @@ func NewSimApp( AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) + ibcAppRouter. + AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). + AddRoute(icahosttypes.SubModuleName, icaHostStack). + AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) + // Create Mock IBC Fee module stack for testing // SendPacket, mock module cannot send packets @@ -579,8 +591,11 @@ func NewSimApp( feeWithMockModule = ibccallbacks.NewIBCMiddleware(feeWithMockModule, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) ibcRouter.AddRoute(MockFeePort, feeWithMockModule) + ibcAppRouter.AddRoute(MockFeePort, feeWithMockModule) + // Seal the IBC Router app.IBCKeeper.SetRouter(ibcRouter) + app.IBCKeeper.SetAppRouter(ibcAppRouter) clientRouter := app.IBCKeeper.ClientKeeper.GetRouter() diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 60a223b99cc..5645bd3f919 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -58,29 +58,23 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. TimeoutHeight: msg.TimeoutHeight, TimeoutTimestamp: msg.TimeoutTimestamp, Data: packetData.GetBytes(), - Signer: sender.String(), + Signer: msg.Sender, } handler := k.msgRouter.Handler(msgSendPacket) - _, err = handler(ctx, msgSendPacket) + res, err := handler(ctx, msgSendPacket) if err != nil { return nil, err } - // sendPacketResp, ok := res.MsgResponses[0].GetCachedValue().(*channeltypes.MsgSendPacketResponse) - // if !ok { - // return errorsmod.Wrap(ibcerrors.ErrInvalidType, "failed to convert %T message response to %T", res.MsgResponse[0].GetCachedValue(), &channeltypes.MsgSendPacketResponse) - // } - - // seq := sendPacketResp.Sequence - - sequence, err := k.sendTransfer( - ctx, msg.SourcePort, msg.SourceChannel, msg.Token, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, - msg.Memo) - if err != nil { - return nil, err + sendPacketResp, ok := res.MsgResponses[0].GetCachedValue().(*channeltypes.MsgSendPacketResponse) + if !ok { + return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "failed to convert %T message response to %T", res.MsgResponses[0].GetCachedValue(), &channeltypes.MsgSendPacketResponse{}) } + // NOTE: The sdk msg handler creates a new EventManager, so events must be correctly propagated back to the current context + ctx.EventManager().EmitEvents(res.GetEvents()) + k.Logger(ctx).Info("IBC fungible token transfer", "token", msg.Token.Denom, "amount", msg.Token.Amount.String(), "sender", msg.Sender, "receiver", msg.Receiver) ctx.EventManager().EmitEvents(sdk.Events{ @@ -98,7 +92,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. ), }) - return &types.MsgTransferResponse{Sequence: sequence}, nil + return &types.MsgTransferResponse{Sequence: sendPacketResp.Sequence}, nil } // UpdateParams defines an rpc handler method for MsgUpdateParams. Updates the ibc-transfer module's parameters. diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 53984afae89..7a363f9ea74 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -2,7 +2,6 @@ package keeper import ( "fmt" - "strings" metrics "github.com/hashicorp/go-metrics" @@ -13,14 +12,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" coretypes "github.com/cosmos/ibc-go/v8/modules/core/types" ) -// sendTransfer handles transfer sending logic. There are 2 possible cases: +// OnSendPacket handles transfer sending logic. There are 2 possible cases: // // 1. Sender chain is acting as the source zone. The coins are transferred // to an escrow address (i.e locked) on the sender chain and then transferred @@ -52,113 +49,7 @@ import ( // 4. A -> C : sender chain is sink zone. Denom upon receiving: 'C/B/denom' // 5. C -> B : sender chain is sink zone. Denom upon receiving: 'B/denom' // 6. B -> A : sender chain is sink zone. Denom upon receiving: 'denom' -func (k Keeper) sendTransfer( - ctx sdk.Context, - sourcePort, - sourceChannel string, - token sdk.Coin, - sender sdk.AccAddress, - receiver string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - memo string, -) (uint64, error) { - channel, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) - if !found { - return 0, errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", sourcePort, sourceChannel) - } - - destinationPort := channel.Counterparty.PortId - destinationChannel := channel.Counterparty.ChannelId - - // begin createOutgoingPacket logic - // See spec for this logic: https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#packet-relay - channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(sourcePort, sourceChannel)) - if !ok { - return 0, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") - } - - // NOTE: denomination and hex hash correctness checked during msg.ValidateBasic - fullDenomPath := token.Denom - - var err error - - // deconstruct the token denomination into the denomination trace info - // to determine if the sender is the source chain - if strings.HasPrefix(token.Denom, "ibc/") { - fullDenomPath, err = k.DenomPathFromHash(ctx, token.Denom) - if err != nil { - return 0, err - } - } - - labels := []metrics.Label{ - telemetry.NewLabel(coretypes.LabelDestinationPort, destinationPort), - telemetry.NewLabel(coretypes.LabelDestinationChannel, destinationChannel), - } - - // NOTE: SendTransfer simply sends the denomination as it exists on its own - // chain inside the packet data. The receiving chain will perform denom - // prefixing as necessary. - - if types.SenderChainIsSource(sourcePort, sourceChannel, fullDenomPath) { - labels = append(labels, telemetry.NewLabel(coretypes.LabelSource, "true")) - - // obtain the escrow address for the source channel end - escrowAddress := types.GetEscrowAddress(sourcePort, sourceChannel) - if err := k.escrowToken(ctx, sender, escrowAddress, token); err != nil { - return 0, err - } - - } else { - labels = append(labels, telemetry.NewLabel(coretypes.LabelSource, "false")) - - // transfer the coins to the module account and burn them - if err := k.bankKeeper.SendCoinsFromAccountToModule( - ctx, sender, types.ModuleName, sdk.NewCoins(token), - ); err != nil { - return 0, err - } - - if err := k.bankKeeper.BurnCoins( - ctx, types.ModuleName, sdk.NewCoins(token), - ); err != nil { - // NOTE: should not happen as the module account was - // retrieved on the step above and it has enough balance - // to burn. - panic(fmt.Errorf("cannot burn coins after a successful send to a module account: %v", err)) - } - } - - packetData := types.NewFungibleTokenPacketData( - fullDenomPath, token.Amount.String(), sender.String(), receiver, memo, - ) - - sequence, err := k.ics4Wrapper.SendPacket(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, packetData.GetBytes()) - if err != nil { - return 0, err - } - - defer func() { - if token.Amount.IsInt64() { - telemetry.SetGaugeWithLabels( - []string{"tx", "msg", "ibc", "transfer"}, - float32(token.Amount.Int64()), - []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, fullDenomPath)}, - ) - } - - telemetry.IncrCounterWithLabels( - []string{"ibc", types.ModuleName, "send"}, - 1, - labels, - ) - }() - - return sequence, nil -} -// OnSendPacket handles transfer sending logic. // TODO: Copy godoc from above sendTransfer function. func (k Keeper) OnSendPacket(ctx sdk.Context, sourcePort string, @@ -183,7 +74,8 @@ func (k Keeper) OnSendPacket(ctx sdk.Context, return errorsmod.Wrapf(types.ErrInvalidAmount, "cannot convert packet data amount to int: %s", packetData.Amount) } - token := sdk.NewCoin(packetData.Denom, amount) + denomTrace := types.ParseDenomTrace(packetData.Denom) + token := sdk.NewCoin(denomTrace.IBCDenom(), amount) // NOTE: SendTransfer simply sends the denomination as it exists on its own // chain inside the packet data. The receiving chain will perform denom diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 1eb02bba9bd..fed93a82ff0 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -92,20 +92,10 @@ func (suite *KeeperTestSuite) TestSendTransfer() { coin = types.GetTransferCoin(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coin.Denom, coin.Amount.Add(sdkmath.NewInt(1))) }, false, }, - { - "channel capability not found", - func() { - capability := suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - - // Release channel capability - suite.chainA.GetSimApp().ScopedTransferKeeper.ReleaseCapability(suite.chainA.GetContext(), capability) //nolint:errcheck // ignore error for testing - }, false, - }, { "SendPacket fails, timeout height and timeout timestamp are zero", func() { timeoutHeight = clienttypes.ZeroHeight() - expEscrowAmount = sdkmath.NewInt(100) }, false, }, } diff --git a/modules/core/05-port/types/router_v2.go b/modules/core/05-port/types/router_v2.go index 74d64e6fd31..22c7d01d084 100644 --- a/modules/core/05-port/types/router_v2.go +++ b/modules/core/05-port/types/router_v2.go @@ -46,10 +46,6 @@ func (rtr *AppRouter) AddRoute(module string, cbs IBCModule) *AppRouter { if !sdk.IsAlphaNumeric(module) { panic(errors.New("route expressions can only contain alphanumeric characters")) } - if rtr.HasRoute(module) { - panic(fmt.Errorf("route %s has already been registered", module)) - } - rtr.routes[module] = append(rtr.routes[module], cbs) return rtr } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index cd74ea523b3..e59ddd1a270 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -447,42 +447,37 @@ func (k *Keeper) ChannelCloseConfirm(goCtx context.Context, msg *channeltypes.Ms // SendPacket defines a rpc handler method for MsgSendPacket. func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPacket) (*channeltypes.MsgSendPacketResponse, error) { - // ctx := sdk.UnwrapSDKContext(goCtx) - - return &channeltypes.MsgSendPacketResponse{Sequence: 0}, nil - - /* + ctx := sdk.UnwrapSDKContext(goCtx) - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } + module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) + if err != nil { + ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) + return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") + } - // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(module) - if !ok { - ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) - } + // Retrieve callbacks from router + cbsList, ok := k.PortKeeper.AppRoute(module) + if !ok { + ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + } - sequence, err := k.ChannelKeeper.SendPacket(ctx, capability, msg.PortId, msg.ChannelId, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data) - if err != nil { - ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet failed")) - return nil, errorsmod.Wrapf(err, "send packet failed for module: %s", module) - } + sequence, err := k.ChannelKeeper.SendPacket(ctx, capability, msg.PortId, msg.ChannelId, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data) + if err != nil { + ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet failed")) + return nil, errorsmod.Wrapf(err, "send packet failed for module: %s", module) + } - // TODO: Make port router have list of ordered callbacks - // Loop over cbs in-order calling OnSendPacket on each IBCModule. To be done for RecvPacket handler as well in opposite order. - // Adjust app logic to account for what should be done before MsgSendPacket and what should be done in OnSendPacket. + // Loop over cbs in-order calling OnSendPacket on each IBCModule. To be done for RecvPacket handler as well in opposite order. + // Adjust app logic to account for what should be done before MsgSendPacket and what should be done in OnSendPacket. + for _, cbs := range cbsList { if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data, msg.Signer); err != nil { ctx.Logger().Error("send packet callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet callback failed")) return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", module) } + } - */ - - // return &channeltypes.MsgSendPacketResponse{Sequence: sequence}, nil + return &channeltypes.MsgSendPacketResponse{Sequence: sequence}, nil } // RecvPacket defines a rpc handler method for MsgRecvPacket. diff --git a/testing/simapp/app.go b/testing/simapp/app.go index dda61375473..7a3b7f22539 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -516,11 +516,12 @@ func NewSimApp( // create IBC module from bottom to top of stack var transferStack porttypes.IBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) + ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) + ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) // Add transfer stack to IBC Router ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) - ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) // Create Interchain Accounts Stack // SendPacket, since it is originating from the application to core IBC: From b2df2f33cd7abe71a75a6d74b5ccf06ccfb84e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 16 May 2024 12:02:58 +0200 Subject: [PATCH 15/46] refactor: rewire controller to use SendPacket API --- .../controller/keeper/msg_server.go | 2 +- .../controller/keeper/relay.go | 45 +++++++++++-------- .../controller/keeper/relay_test.go | 24 ---------- testing/simapp/app.go | 3 +- 4 files changed, 29 insertions(+), 45 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go b/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go index 66ad2afd0a9..b3810818c7f 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/msg_server.go @@ -65,7 +65,7 @@ func (s msgServer) SendTx(goCtx context.Context, msg *types.MsgSendTx) (*types.M // the absolute timeout value is calculated using the controller chain block time + the relative timeout value // this assumes time synchrony to a certain degree between the controller and counterparty host chain absoluteTimeout := uint64(ctx.BlockTime().UnixNano()) + msg.RelativeTimeout - seq, err := s.sendTx(ctx, msg.ConnectionId, portID, msg.PacketData, absoluteTimeout) + seq, err := s.sendTx(ctx, msg.ConnectionId, portID, msg.PacketData, absoluteTimeout, msg.Owner) if err != nil { return nil, err } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay.go b/modules/apps/27-interchain-accounts/controller/keeper/relay.go index 9b8de929750..ebcc0c60ee4 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay.go @@ -1,16 +1,18 @@ package keeper import ( + "strings" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" + "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ) // SendTx takes pre-built packet data containing messages to be executed on the host chain from an authentication module and attempts to send the packet. @@ -24,38 +26,43 @@ import ( // by the underlying application. For a full summary of the changes in v6.x.x, please see ADR009. // This API will be removed in later releases. func (k Keeper) SendTx(ctx sdk.Context, _ *capabilitytypes.Capability, connectionID, portID string, icaPacketData icatypes.InterchainAccountPacketData, timeoutTimestamp uint64) (uint64, error) { - return k.sendTx(ctx, connectionID, portID, icaPacketData, timeoutTimestamp) + return k.sendTx(ctx, connectionID, portID, icaPacketData, timeoutTimestamp, "") } -func (k Keeper) sendTx(ctx sdk.Context, connectionID, portID string, icaPacketData icatypes.InterchainAccountPacketData, timeoutTimestamp uint64) (uint64, error) { - if !k.GetParams(ctx).ControllerEnabled { - return 0, types.ErrControllerSubModuleDisabled - } - +func (k Keeper) sendTx(ctx sdk.Context, connectionID, portID string, icaPacketData icatypes.InterchainAccountPacketData, timeoutTimestamp uint64, owner string) (uint64, error) { activeChannelID, found := k.GetOpenActiveChannel(ctx, connectionID, portID) if !found { return 0, errorsmod.Wrapf(icatypes.ErrActiveChannelNotFound, "failed to retrieve active channel on connection %s for port %s", connectionID, portID) } - chanCap, found := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(portID, activeChannelID)) - if !found { - return 0, errorsmod.Wrapf(capabilitytypes.ErrCapabilityNotFound, "failed to find capability: %s", host.ChannelCapabilityPath(portID, activeChannelID)) + if strings.TrimSpace(owner) == "" { + owner = strings.TrimPrefix(portID, types.ControllerPortPrefix) } - if uint64(ctx.BlockTime().UnixNano()) >= timeoutTimestamp { - return 0, icatypes.ErrInvalidTimeoutTimestamp + msgSendPacket := &channeltypes.MsgSendPacket{ + PortId: portID, + ChannelId: activeChannelID, + TimeoutHeight: clienttypes.ZeroHeight(), + TimeoutTimestamp: timeoutTimestamp, + Data: icaPacketData.GetBytes(), + Signer: owner, } - if err := icaPacketData.ValidateBasic(); err != nil { - return 0, errorsmod.Wrap(err, "invalid interchain account packet data") - } - - sequence, err := k.ics4Wrapper.SendPacket(ctx, chanCap, portID, activeChannelID, clienttypes.ZeroHeight(), timeoutTimestamp, icaPacketData.GetBytes()) + handler := k.msgRouter.Handler(msgSendPacket) + res, err := handler(ctx, msgSendPacket) if err != nil { return 0, err } - return sequence, nil + sendPacketResp, ok := res.MsgResponses[0].GetCachedValue().(*channeltypes.MsgSendPacketResponse) + if !ok { + return 0, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "failed to convert %T message response to %T", res.MsgResponses[0].GetCachedValue(), &channeltypes.MsgSendPacketResponse{}) + } + + // NOTE: The sdk msg handler creates a new EventManager, so events must be correctly propagated back to the current context + ctx.EventManager().EmitEvents(res.GetEvents()) + + return sendPacketResp.Sequence, nil } // OnTimeoutPacket removes the active channel associated with the provided packet, the underlying channel end is closed diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go index 3f81bb6dbf6..b40b34b3667 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay_test.go @@ -116,30 +116,6 @@ func (suite *KeeperTestSuite) TestSendTx() { }, false, }, - { - "timeout timestamp is not in the future", - func() { - interchainAccountAddr, found := suite.chainA.GetSimApp().ICAControllerKeeper.GetInterchainAccountAddress(suite.chainA.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) - suite.Require().True(found) - - msg := &banktypes.MsgSend{ - FromAddress: interchainAccountAddr, - ToAddress: suite.chainB.SenderAccount.GetAddress().String(), - Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), - } - - data, err := icatypes.SerializeCosmosTx(suite.chainB.GetSimApp().AppCodec(), []proto.Message{msg}, icatypes.EncodingProtobuf) - suite.Require().NoError(err) - - packetData = icatypes.InterchainAccountPacketData{ - Type: icatypes.EXECUTE_TX, - Data: data, - } - - timeoutTimestamp = uint64(suite.chainA.GetContext().BlockTime().UnixNano()) - }, - false, - }, } for _, tc := range testCases { diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 7a3b7f22539..1efad182a3f 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -536,7 +536,9 @@ func NewSimApp( panic(fmt.Errorf("cannot convert %T into %T", icaControllerStack, app.ICAAuthModule)) } icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) + ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) + ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) // RecvPacket, message that originates from core IBC and goes down to app, the flow is: // channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket @@ -555,7 +557,6 @@ func NewSimApp( AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) ibcAppRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) From b2959491be34ba36b1e6f470c97cf5d82df30b62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 16 May 2024 12:03:13 +0200 Subject: [PATCH 16/46] refactor: rewire 29-fee to use SendPacket API --- modules/apps/29-fee/ibc_middleware.go | 2 +- modules/apps/29-fee/keeper/relay.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index a9c7bfda02c..08dba830563 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -465,7 +465,7 @@ func (im IBCMiddleware) SendPacket( timeoutTimestamp uint64, data []byte, ) (uint64, error) { - return im.keeper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) + panic("TODO: remove") } // WriteAcknowledgement implements the ICS4 Wrapper interface diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go index d069045c919..b05ec8bf802 100644 --- a/modules/apps/29-fee/keeper/relay.go +++ b/modules/apps/29-fee/keeper/relay.go @@ -24,7 +24,7 @@ func (k Keeper) SendPacket( timeoutTimestamp uint64, data []byte, ) (uint64, error) { - return k.ics4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) + panic("TODO: remove") } // WriteAcknowledgement wraps IBC ChannelKeeper's WriteAcknowledgement function From 2f5116e6ede69dffeb567a22e8b766d015e62b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 16 May 2024 12:37:30 +0200 Subject: [PATCH 17/46] refactor: use SendPacket API for callbacks --- modules/apps/callbacks/ibc_middleware.go | 11 +------ modules/apps/callbacks/ibc_middleware_test.go | 31 ++++++------------- modules/apps/callbacks/testing/simapp/app.go | 4 ++- 3 files changed, 14 insertions(+), 32 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index e5524a2fad8..6353cf8ccf2 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -94,16 +94,7 @@ func (im IBCMiddleware) SendPacket( timeoutTimestamp uint64, data []byte, ) (uint64, error) { - seq, err := im.ics4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) - if err != nil { - return 0, err - } - - if err := im.OnSendPacket(ctx, sourcePort, sourceChannel, seq, timeoutHeight, timeoutTimestamp, data, ""); err != nil { - return 0, err - } - - return seq, nil + panic("TODO: remove") } // OnSendPacket implements the IBCModule interface. diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index d4419ffd8ec..ba23c74d21c 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -119,15 +119,6 @@ func (s *CallbacksTestSuite) TestSendPacket() { false, nil, }, - { - "failure: ics4Wrapper SendPacket call fails", - func() { - s.path.EndpointA.ChannelID = "invalid-channel" - }, - "none", // ics4wrapper failure should result in no callback execution - false, - channeltypes.ErrChannelNotFound, - }, { "failure: callback execution fails", func() { @@ -162,26 +153,26 @@ func (s *CallbacksTestSuite) TestSendPacket() { s.Run(tc.name, func() { s.SetupTransferTest() - transferICS4Wrapper := GetSimApp(s.chainA).TransferKeeper.GetICS4Wrapper() + cbs, ok := GetSimApp(s.chainA).IBCKeeper.PortKeeper.AppRoute(transfertypes.ModuleName) + s.Require().True(ok) + + callbacksModule, ok := cbs[1].(ibccallbacks.IBCMiddleware) // callbacks module is routed second + s.Require().True(ok) packetData = transfertypes.NewFungibleTokenPacketData( ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract), ) - chanCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) - tc.malleate() ctx := s.chainA.GetContext() gasLimit := ctx.GasMeter().Limit() - var ( - seq uint64 - err error - ) + var err error + sendPacket := func() { - seq, err = transferICS4Wrapper.SendPacket(ctx, chanCap, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, s.chainB.GetTimeoutHeight(), 0, packetData.GetBytes()) + err = callbacksModule.OnSendPacket(ctx, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, 1, s.chainB.GetTimeoutHeight(), 0, packetData.GetBytes(), ibctesting.TestAccAddress) } expPass := tc.expValue == nil @@ -189,11 +180,10 @@ func (s *CallbacksTestSuite) TestSendPacket() { case expPass: sendPacket() s.Require().Nil(err) - s.Require().Equal(uint64(1), seq) expEvent, exists := GetExpectedEvent( - transferICS4Wrapper.(porttypes.PacketDataUnmarshaler), gasLimit, packetData.GetBytes(), s.path.EndpointA.ChannelConfig.PortID, - s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, seq, types.CallbackTypeSendPacket, nil, + callbacksModule, gasLimit, packetData.GetBytes(), s.path.EndpointA.ChannelConfig.PortID, + s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, 1, types.CallbackTypeSendPacket, nil, ) if exists { s.Require().Contains(ctx.EventManager().Events().ToABCIEvents(), expEvent) @@ -205,7 +195,6 @@ func (s *CallbacksTestSuite) TestSendPacket() { default: sendPacket() s.Require().ErrorIs(err, tc.expValue.(error)) - s.Require().Equal(uint64(0), seq) } s.AssertHasExecutedExpectedCallback(tc.callbackType, expPass) diff --git a/modules/apps/callbacks/testing/simapp/app.go b/modules/apps/callbacks/testing/simapp/app.go index 9c8f238fc29..9070b53c2e8 100644 --- a/modules/apps/callbacks/testing/simapp/app.go +++ b/modules/apps/callbacks/testing/simapp/app.go @@ -544,13 +544,16 @@ func NewSimApp( panic(fmt.Errorf("cannot convert %T to %T", icaControllerStack, app.ICAAuthModule)) } icaControllerStack = icacontroller.NewIBCMiddleware(icaControllerStack, app.ICAControllerKeeper) + ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) + ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) var icaICS4Wrapper porttypes.ICS4Wrapper icaICS4Wrapper, ok = icaControllerStack.(porttypes.ICS4Wrapper) if !ok { panic(fmt.Errorf("cannot convert %T to %T", icaControllerStack, icaICS4Wrapper)) } icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) + ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the ica controller keeper app.ICAControllerKeeper.WithICS4Wrapper(icaICS4Wrapper) @@ -571,7 +574,6 @@ func NewSimApp( AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) ibcAppRouter. - AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) From 16a88b4d6fd14dd2b7e0cc9ccb0103b41b809605 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 16 May 2024 16:20:53 +0200 Subject: [PATCH 18/46] imp: remove capability from SendPacket and add prefix routing --- .../controller/ibc_middleware.go | 1 - .../host/keeper/keeper_test.go | 23 ------------- modules/apps/29-fee/ibc_middleware.go | 1 - modules/apps/29-fee/keeper/keeper_test.go | 22 ------------- modules/apps/29-fee/keeper/relay.go | 1 - modules/apps/callbacks/ibc_middleware.go | 1 - modules/apps/transfer/ibc_module.go | 4 +++ modules/apps/transfer/keeper/keeper_test.go | 17 ---------- modules/core/04-channel/keeper/keeper.go | 2 -- modules/core/04-channel/keeper/packet.go | 5 --- modules/core/04-channel/keeper/packet_test.go | 33 +------------------ modules/core/05-port/keeper/keeper.go | 18 +++++++++- modules/core/05-port/types/module.go | 1 - modules/core/05-port/types/router_v2.go | 5 +++ modules/core/keeper/msg_server.go | 18 ++++------ testing/endpoint.go | 4 +-- testing/mock/middleware.go | 1 - 17 files changed, 34 insertions(+), 123 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index a0c80fec60d..01f18cbfefc 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -362,7 +362,6 @@ func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID str // SendPacket implements the ICS4 Wrapper interface func (IBCMiddleware) SendPacket( ctx sdk.Context, - chanCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, diff --git a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go index acbc274ef2f..5b273843524 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/keeper_test.go @@ -12,8 +12,6 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" - ibcfeekeeper "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/keeper" - channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -402,24 +400,3 @@ func (suite *KeeperTestSuite) TestUnsetParams() { suite.chainA.GetSimApp().ICAHostKeeper.GetParams(ctx) }) } - -func (suite *KeeperTestSuite) TestWithICS4Wrapper() { - suite.SetupTest() - - // test if the ics4 wrapper is the fee keeper initially - ics4Wrapper := suite.chainA.GetSimApp().ICAHostKeeper.GetICS4Wrapper() - - _, isFeeKeeper := ics4Wrapper.(ibcfeekeeper.Keeper) - suite.Require().True(isFeeKeeper) - _, isChannelKeeper := ics4Wrapper.(*channelkeeper.Keeper) - suite.Require().False(isChannelKeeper) - - // set the ics4 wrapper to the channel keeper - suite.chainA.GetSimApp().ICAHostKeeper.WithICS4Wrapper(suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper) - ics4Wrapper = suite.chainA.GetSimApp().ICAHostKeeper.GetICS4Wrapper() - - suite.Require().IsType((*channelkeeper.Keeper)(nil), ics4Wrapper) - - _, isFeeKeeper = ics4Wrapper.(ibcfeekeeper.Keeper) - suite.Require().False(isFeeKeeper) -} diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 08dba830563..278038f5894 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -458,7 +458,6 @@ func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID str // SendPacket implements the ICS4 Wrapper interface func (im IBCMiddleware) SendPacket( ctx sdk.Context, - chanCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, diff --git a/modules/apps/29-fee/keeper/keeper_test.go b/modules/apps/29-fee/keeper/keeper_test.go index 1a29a98d5ef..93520a622c2 100644 --- a/modules/apps/29-fee/keeper/keeper_test.go +++ b/modules/apps/29-fee/keeper/keeper_test.go @@ -10,9 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" - channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -289,23 +287,3 @@ func (suite *KeeperTestSuite) TestGetAllCounterpartyPayees() { suite.Require().Len(counterpartyPayeeAddr, len(expectedCounterpartyPayee)) suite.Require().Equal(counterpartyPayeeAddr, expectedCounterpartyPayee) } - -func (suite *KeeperTestSuite) TestWithICS4Wrapper() { - suite.SetupTest() - - // test if the ics4 wrapper is the channel keeper initially - ics4Wrapper := suite.chainA.GetSimApp().IBCFeeKeeper.GetICS4Wrapper() - - suite.Require().IsType((*channelkeeper.Keeper)(nil), ics4Wrapper) - _, isFeeKeeper := ics4Wrapper.(keeper.Keeper) - suite.Require().False(isFeeKeeper) - - // set the ics4 wrapper to itself (don't do this in production) - suite.chainA.GetSimApp().IBCFeeKeeper.WithICS4Wrapper(suite.chainA.GetSimApp().IBCFeeKeeper) - ics4Wrapper = suite.chainA.GetSimApp().IBCFeeKeeper.GetICS4Wrapper() - - _, isFeeKeeper = ics4Wrapper.(keeper.Keeper) - suite.Require().True(isFeeKeeper) - _, isChannelKeeper := ics4Wrapper.(*channelkeeper.Keeper) - suite.Require().False(isChannelKeeper) -} diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go index b05ec8bf802..bde56e786de 100644 --- a/modules/apps/29-fee/keeper/relay.go +++ b/modules/apps/29-fee/keeper/relay.go @@ -17,7 +17,6 @@ import ( // SendPacket wraps the ICS4Wrapper SendPacket function func (k Keeper) SendPacket( ctx sdk.Context, - chanCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 6353cf8ccf2..78830b186bd 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -87,7 +87,6 @@ func (im *IBCMiddleware) GetICS4Wrapper() porttypes.ICS4Wrapper { // the packet send is rejected. func (im IBCMiddleware) SendPacket( ctx sdk.Context, - chanCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index f9992b7b06a..e2aa9e4c91c 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -194,6 +194,10 @@ func (im IBCModule) OnSendPacket( return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "cannot convert signer address to sdk.AccAddress") } + if data.Sender != sender.String() { + return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "invalid signer address: expected %s, got %s", data.Sender, signer) + } + return im.keeper.OnSendPacket(ctx, portID, channelID, data, sender) } diff --git a/modules/apps/transfer/keeper/keeper_test.go b/modules/apps/transfer/keeper/keeper_test.go index 9b11252430b..a07390f4467 100644 --- a/modules/apps/transfer/keeper/keeper_test.go +++ b/modules/apps/transfer/keeper/keeper_test.go @@ -16,7 +16,6 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -337,19 +336,3 @@ func (suite *KeeperTestSuite) TestUnsetParams() { suite.chainA.GetSimApp().TransferKeeper.GetParams(ctx) }) } - -func (suite *KeeperTestSuite) TestWithICS4Wrapper() { - suite.SetupTest() - - // test if the ics4 wrapper is the channel keeper initially - ics4Wrapper := suite.chainA.GetSimApp().TransferKeeper.GetICS4Wrapper() - - _, isChannelKeeper := ics4Wrapper.(*channelkeeper.Keeper) - suite.Require().False(isChannelKeeper) - - // set the ics4 wrapper to the channel keeper - suite.chainA.GetSimApp().TransferKeeper.WithICS4Wrapper(suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper) - ics4Wrapper = suite.chainA.GetSimApp().TransferKeeper.GetICS4Wrapper() - - suite.Require().IsType((*channelkeeper.Keeper)(nil), ics4Wrapper) -} diff --git a/modules/core/04-channel/keeper/keeper.go b/modules/core/04-channel/keeper/keeper.go index 463c2174bb1..7064716fad9 100644 --- a/modules/core/04-channel/keeper/keeper.go +++ b/modules/core/04-channel/keeper/keeper.go @@ -23,8 +23,6 @@ import ( "github.com/cosmos/ibc-go/v8/modules/core/exported" ) -var _ porttypes.ICS4Wrapper = (*Keeper)(nil) - // Keeper defines the IBC channel keeper type Keeper struct { // implements gRPC QueryServer interface diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index 08d1d678538..b859b1b0a56 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -22,7 +22,6 @@ import ( // is returned if one occurs. func (k *Keeper) SendPacket( ctx sdk.Context, - channelCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, @@ -38,10 +37,6 @@ func (k *Keeper) SendPacket( return 0, errorsmod.Wrapf(types.ErrInvalidChannelState, "channel is not OPEN (got %s)", channel.State) } - if !k.scopedKeeper.AuthenticateCapability(ctx, channelCap, host.ChannelCapabilityPath(sourcePort, sourceChannel)) { - return 0, errorsmod.Wrapf(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)", sourcePort, sourceChannel) - } - sequence, found := k.GetNextSequenceSend(ctx, sourcePort, sourceChannel) if !found { return 0, errorsmod.Wrapf( diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index 0a5c04eb082..1a5dccfd57c 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -40,22 +40,17 @@ func (suite *KeeperTestSuite) TestSendPacket() { packetData []byte timeoutHeight clienttypes.Height timeoutTimestamp uint64 - channelCap *capabilitytypes.Capability ) testCases := []testCase{ {"success: UNORDERED channel", func() { path.Setup() sourceChannel = path.EndpointA.ChannelID - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"success: ORDERED channel", func() { path.SetChannelOrdered() path.Setup() sourceChannel = path.EndpointA.ChannelID - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"success with solomachine: UNORDERED channel", func() { path.Setup() @@ -66,8 +61,6 @@ func (suite *KeeperTestSuite) TestSendPacket() { path.EndpointA.ClientID = clienttypes.FormatClientIdentifier(exported.Solomachine, 10) path.EndpointA.SetClientState(solomachine.ClientState()) path.EndpointA.UpdateConnection(func(c *connectiontypes.ConnectionEnd) { c.ClientId = path.EndpointA.ClientID }) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"success with solomachine: ORDERED channel", func() { path.SetChannelOrdered() @@ -80,21 +73,16 @@ func (suite *KeeperTestSuite) TestSendPacket() { path.EndpointA.SetClientState(solomachine.ClientState()) path.EndpointA.UpdateConnection(func(c *connectiontypes.ConnectionEnd) { c.ClientId = path.EndpointA.ClientID }) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"packet basic validation failed, empty packet data", func() { path.Setup() sourceChannel = path.EndpointA.ChannelID - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) packetData = []byte{} }, false}, {"channel not found", func() { // use wrong channel naming path.Setup() sourceChannel = ibctesting.InvalidID - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"channel is in CLOSED state", func() { path.Setup() @@ -120,8 +108,6 @@ func (suite *KeeperTestSuite) TestSendPacket() { sourceChannel = path.EndpointA.ChannelID path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.ConnectionHops[0] = "invalid-connection" }) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"client state not found", func() { path.Setup() @@ -129,8 +115,6 @@ func (suite *KeeperTestSuite) TestSendPacket() { // change connection client ID path.EndpointA.UpdateConnection(func(c *connectiontypes.ConnectionEnd) { c.ClientId = ibctesting.InvalidID }) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"client state is frozen", func() { path.Setup() @@ -144,8 +128,6 @@ func (suite *KeeperTestSuite) TestSendPacket() { // freeze client cs.FrozenHeight = clienttypes.NewHeight(0, 1) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), connection.ClientId, cs) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"client state zero height", func() { path.Setup() @@ -162,8 +144,6 @@ func (suite *KeeperTestSuite) TestSendPacket() { cs.LatestHeight = clienttypes.ZeroHeight() suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), connection.ClientId, cs) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"timeout height passed", func() { path.Setup() @@ -172,7 +152,6 @@ func (suite *KeeperTestSuite) TestSendPacket() { var ok bool timeoutHeight, ok = path.EndpointA.GetClientLatestHeight().(clienttypes.Height) suite.Require().True(ok) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"timeout timestamp passed", func() { path.Setup() @@ -184,7 +163,6 @@ func (suite *KeeperTestSuite) TestSendPacket() { timeoutHeight = disabledTimeoutHeight timeoutTimestamp = timestamp - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"timeout timestamp passed with solomachine", func() { path.Setup() @@ -202,8 +180,6 @@ func (suite *KeeperTestSuite) TestSendPacket() { sourceChannel = path.EndpointA.ChannelID timeoutHeight = disabledTimeoutHeight timeoutTimestamp = timestamp - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"next sequence send not found", func() { path := ibctesting.NewPath(suite.chainA, suite.chainB) @@ -217,13 +193,6 @@ func (suite *KeeperTestSuite) TestSendPacket() { types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID), []string{path.EndpointA.ConnectionID}, path.EndpointA.ChannelConfig.Version), ) suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - }, false}, - {"channel capability not found", func() { - path.Setup() - sourceChannel = path.EndpointA.ChannelID - - channelCap = capabilitytypes.NewCapability(5) }, false}, { "channel is in FLUSH_COMPLETE state", @@ -272,7 +241,7 @@ func (suite *KeeperTestSuite) TestSendPacket() { // only check if nextSequenceSend exists in no error case since it is a tested error case above. expectedSequence, ok := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceSend(suite.chainA.GetContext(), sourcePort, sourceChannel) - sequence, err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.SendPacket(suite.chainA.GetContext(), channelCap, + sequence, err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.SendPacket(suite.chainA.GetContext(), sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, packetData) if tc.expPass { diff --git a/modules/core/05-port/keeper/keeper.go b/modules/core/05-port/keeper/keeper.go index 180f9c2ae16..93ef74bc79b 100644 --- a/modules/core/05-port/keeper/keeper.go +++ b/modules/core/05-port/keeper/keeper.go @@ -2,6 +2,7 @@ package keeper import ( "fmt" + "strings" "cosmossdk.io/log" @@ -92,5 +93,20 @@ func (k *Keeper) Route(module string) (types.IBCModule, bool) { // AppRoute returns an ordered list of IBCModule callbacks for a given module name, and a boolean indicating // whether or not the callbacks are present. func (k *Keeper) AppRoute(module string) ([]types.IBCModule, bool) { - return k.AppRouter.GetRoute(module) + routes, ok := k.AppRouter.GetRoute(module) + if ok { + return routes, true + } + + for _, prefix := range k.Keys() { + if strings.Contains(module, prefix) { + return k.AppRouter.GetRoute(prefix) + } + } + + return nil, false +} + +func (k *Keeper) Keys() []string { + return k.AppRouter.Keys() } diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 09fc494b0d4..237e1a8209c 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -174,7 +174,6 @@ type ICS4Wrapper interface { // TODO: Leave in place to avoid compiler errors and incrementally work to remove. We can then delete these methods SendPacket( ctx sdk.Context, - chanCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, diff --git a/modules/core/05-port/types/router_v2.go b/modules/core/05-port/types/router_v2.go index 22c7d01d084..bb19636e71a 100644 --- a/modules/core/05-port/types/router_v2.go +++ b/modules/core/05-port/types/router_v2.go @@ -7,6 +7,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + "golang.org/x/exp/maps" ) // AppRouter contains a map from module name to an ordered list of IBCModules @@ -63,3 +64,7 @@ func (rtr *AppRouter) GetRoute(module string) ([]IBCModule, bool) { } return rtr.routes[module], true } + +func (rtr *AppRouter) Keys() []string { + return maps.Keys(rtr.routes) +} diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index e59ddd1a270..556ada41cf1 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -449,23 +449,17 @@ func (k *Keeper) ChannelCloseConfirm(goCtx context.Context, msg *channeltypes.Ms func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPacket) (*channeltypes.MsgSendPacketResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve callbacks from router - cbsList, ok := k.PortKeeper.AppRoute(module) + cbsList, ok := k.PortKeeper.AppRoute(msg.PortId) if !ok { - ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) } - sequence, err := k.ChannelKeeper.SendPacket(ctx, capability, msg.PortId, msg.ChannelId, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data) + sequence, err := k.ChannelKeeper.SendPacket(ctx, msg.PortId, msg.ChannelId, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data) if err != nil { ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet failed")) - return nil, errorsmod.Wrapf(err, "send packet failed for module: %s", module) + return nil, errorsmod.Wrapf(err, "send packet failed for module: %s", msg.PortId) } // Loop over cbs in-order calling OnSendPacket on each IBCModule. To be done for RecvPacket handler as well in opposite order. @@ -473,7 +467,7 @@ func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPack for _, cbs := range cbsList { if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data, msg.Signer); err != nil { ctx.Logger().Error("send packet callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet callback failed")) - return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", module) + return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", msg.PortId) } } diff --git a/testing/endpoint.go b/testing/endpoint.go index cf523ee8d38..c382b016d76 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -440,10 +440,8 @@ func (endpoint *Endpoint) SendPacket( timeoutTimestamp uint64, data []byte, ) (uint64, error) { - channelCap := endpoint.Chain.GetChannelCapability(endpoint.ChannelConfig.PortID, endpoint.ChannelID) - // no need to send message, acting as a module - sequence, err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SendPacket(endpoint.Chain.GetContext(), channelCap, endpoint.ChannelConfig.PortID, endpoint.ChannelID, timeoutHeight, timeoutTimestamp, data) + sequence, err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SendPacket(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, timeoutHeight, timeoutTimestamp, data) if err != nil { return 0, err } diff --git a/testing/mock/middleware.go b/testing/mock/middleware.go index 5729b8cc276..3f0cde37b78 100644 --- a/testing/mock/middleware.go +++ b/testing/mock/middleware.go @@ -180,7 +180,6 @@ func (im BlockUpgradeMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channel // SendPacket implements the ICS4 Wrapper interface func (BlockUpgradeMiddleware) SendPacket( ctx sdk.Context, - chanCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, From 67e4b5fd555c4c1bce7254fd4f545c065da1f00a Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 16 May 2024 16:33:18 +0200 Subject: [PATCH 19/46] refactor: adapt signer to sdk.AccAddress --- .../controller/ibc_middleware.go | 4 ++-- .../apps/27-interchain-accounts/host/ibc_module.go | 2 +- modules/apps/29-fee/ibc_middleware.go | 2 +- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/apps/callbacks/ibc_middleware_test.go | 2 +- modules/apps/transfer/ibc_module.go | 11 +++-------- modules/core/05-port/types/module.go | 2 +- modules/core/keeper/msg_server.go | 8 +++++++- testing/mock/ibc_app.go | 2 +- testing/mock/ibc_module.go | 2 +- testing/mock/middleware.go | 2 +- 11 files changed, 20 insertions(+), 19 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 01f18cbfefc..318618416e1 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -179,13 +179,13 @@ func (im IBCMiddleware) OnSendPacket( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, - signer string, + signer sdk.AccAddress, ) error { if !im.keeper.GetParams(ctx).ControllerEnabled { return types.ErrControllerSubModuleDisabled } - controllerPortID, err := icatypes.NewControllerPortID(signer) + controllerPortID, err := icatypes.NewControllerPortID(signer.String()) if err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 3c063cde20d..8bee2600ebe 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -120,7 +120,7 @@ func (IBCModule) OnSendPacket( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, - signer string, + signer sdk.AccAddress, ) error { return errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "cannot send packet on icahost") } diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 278038f5894..9ebf11b29cf 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -221,7 +221,7 @@ func (IBCMiddleware) OnSendPacket( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, - signer string, + signer sdk.AccAddress, ) error { return nil } diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 78830b186bd..288838cbf28 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -105,7 +105,7 @@ func (im IBCMiddleware) OnSendPacket( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, - signer string, + signer sdk.AccAddress, ) error { callbackData, err := types.GetSourceCallbackData(im.app, data, sourcePort, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) // SendPacket is not blocked if the packet does not opt-in to callbacks diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index ba23c74d21c..da27e16410a 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -172,7 +172,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { var err error sendPacket := func() { - err = callbacksModule.OnSendPacket(ctx, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, 1, s.chainB.GetTimeoutHeight(), 0, packetData.GetBytes(), ibctesting.TestAccAddress) + err = callbacksModule.OnSendPacket(ctx, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, 1, s.chainB.GetTimeoutHeight(), 0, packetData.GetBytes(), s.chainB.SenderAccount.GetAddress()) } expPass := tc.expValue == nil diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index e2aa9e4c91c..61ea4f6be69 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -182,23 +182,18 @@ func (im IBCModule) OnSendPacket( _ clienttypes.Height, _ uint64, dataBz []byte, - signer string, + signer sdk.AccAddress, ) error { var data types.FungibleTokenPacketData if err := json.Unmarshal(dataBz, &data); err != nil { return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data") } - sender, err := sdk.AccAddressFromBech32(signer) - if err != nil { - return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "cannot convert signer address to sdk.AccAddress") - } - - if data.Sender != sender.String() { + if data.Sender != signer.String() { return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "invalid signer address: expected %s, got %s", data.Sender, signer) } - return im.keeper.OnSendPacket(ctx, portID, channelID, data, sender) + return im.keeper.OnSendPacket(ctx, portID, channelID, data, signer) } // OnRecvPacket implements the IBCModule interface. A successful acknowledgement diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 237e1a8209c..2295c2224e4 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -90,7 +90,7 @@ type IBCModule interface { timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, - signer string, + signer sdk.AccAddress, ) error // OnRecvPacket must return an acknowledgement that implements the Acknowledgement interface. diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 556ada41cf1..62de0414a60 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -449,6 +449,12 @@ func (k *Keeper) ChannelCloseConfirm(goCtx context.Context, msg *channeltypes.Ms func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPacket) (*channeltypes.MsgSendPacketResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + signer, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + ctx.Logger().Error("send packet failed", "error", errorsmod.Wrap(err, "Invalid address for msg Signer")) + return nil, errorsmod.Wrap(err, "Invalid address for msg Signer") + } + // Retrieve callbacks from router cbsList, ok := k.PortKeeper.AppRoute(msg.PortId) if !ok { @@ -465,7 +471,7 @@ func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPack // Loop over cbs in-order calling OnSendPacket on each IBCModule. To be done for RecvPacket handler as well in opposite order. // Adjust app logic to account for what should be done before MsgSendPacket and what should be done in OnSendPacket. for _, cbs := range cbsList { - if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data, msg.Signer); err != nil { + if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data, signer); err != nil { ctx.Logger().Error("send packet callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet callback failed")) return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", msg.PortId) } diff --git a/testing/mock/ibc_app.go b/testing/mock/ibc_app.go index 52880396cd8..5b53f47dcc0 100644 --- a/testing/mock/ibc_app.go +++ b/testing/mock/ibc_app.go @@ -68,7 +68,7 @@ type IBCApp struct { channelID string, sequence uint64, data []byte, - signer string, + signer sdk.AccAddress, ) error // OnRecvPacket must return an acknowledgement that implements the Acknowledgement interface. diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 21e0a61b40d..0acb5e66898 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -124,7 +124,7 @@ func (im IBCModule) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string } // OnSendPacket implements the IBCModule interface. -func (im IBCModule) OnSendPacket(ctx sdk.Context, portID string, channelID string, sequence uint64, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, signer string) error { +func (im IBCModule) OnSendPacket(ctx sdk.Context, portID string, channelID string, sequence uint64, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, signer sdk.AccAddress) error { if im.IBCApp.OnSendPacket != nil { return im.IBCApp.OnSendPacket(ctx, portID, channelID, sequence, data, signer) } diff --git a/testing/mock/middleware.go b/testing/mock/middleware.go index 3f0cde37b78..1cb595ca2d4 100644 --- a/testing/mock/middleware.go +++ b/testing/mock/middleware.go @@ -114,7 +114,7 @@ func (im BlockUpgradeMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, cha } // OnSendPacket implements the IBCModule interface. -func (im BlockUpgradeMiddleware) OnSendPacket(ctx sdk.Context, portID string, channelID string, sequence uint64, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, signer string) error { +func (im BlockUpgradeMiddleware) OnSendPacket(ctx sdk.Context, portID string, channelID string, sequence uint64, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, signer sdk.AccAddress) error { if im.IBCApp.OnSendPacket != nil { return im.IBCApp.OnSendPacket(ctx, portID, channelID, sequence, data, signer) } From 3db16130399a580ebc653133a56255afe4347afb Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 16 May 2024 18:42:24 +0200 Subject: [PATCH 20/46] chore: rm capabilities from recv, ack, timeout packet handler --- .../controller/ibc_middleware.go | 1 - modules/apps/29-fee/ibc_middleware.go | 3 +- modules/apps/29-fee/keeper/relay.go | 7 +- modules/apps/29-fee/keeper/relay_test.go | 6 +- modules/apps/callbacks/ibc_middleware.go | 3 +- modules/apps/callbacks/ibc_middleware_test.go | 4 +- modules/core/04-channel/keeper/packet.go | 32 ----- modules/core/04-channel/keeper/packet_test.go | 123 ++---------------- modules/core/04-channel/keeper/timeout.go | 20 --- .../core/04-channel/keeper/timeout_test.go | 70 +--------- modules/core/05-port/types/module.go | 1 - modules/core/keeper/msg_server.go | 20 +-- testing/endpoint.go | 4 +- testing/mock/middleware.go | 1 - 14 files changed, 31 insertions(+), 264 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 318618416e1..76808694769 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -374,7 +374,6 @@ func (IBCMiddleware) SendPacket( // WriteAcknowledgement implements the ICS4 Wrapper interface func (IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, - chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, ack ibcexported.Acknowledgement, ) error { diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 9ebf11b29cf..92259b6392a 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -470,11 +470,10 @@ func (im IBCMiddleware) SendPacket( // WriteAcknowledgement implements the ICS4 Wrapper interface func (im IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, - chanCap *capabilitytypes.Capability, packet exported.PacketI, ack exported.Acknowledgement, ) error { - return im.keeper.WriteAcknowledgement(ctx, chanCap, packet, ack) + return im.keeper.WriteAcknowledgement(ctx, packet, ack) } // GetAppVersion returns the application version of the underlying application diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go index bde56e786de..dc0cca447a2 100644 --- a/modules/apps/29-fee/keeper/relay.go +++ b/modules/apps/29-fee/keeper/relay.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -28,10 +27,10 @@ func (k Keeper) SendPacket( // WriteAcknowledgement wraps IBC ChannelKeeper's WriteAcknowledgement function // ICS29 WriteAcknowledgement is used for asynchronous acknowledgements -func (k Keeper) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error { +func (k Keeper) WriteAcknowledgement(ctx sdk.Context, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error { if !k.IsFeeEnabled(ctx, packet.GetDestPort(), packet.GetDestChannel()) { // ics4Wrapper may be core IBC or higher-level middleware - return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, acknowledgement) + return k.ics4Wrapper.WriteAcknowledgement(ctx, packet, acknowledgement) } packetID := channeltypes.NewPacketID(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) @@ -51,7 +50,7 @@ func (k Keeper) WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.C k.DeleteForwardRelayerAddress(ctx, packetID) // ics4Wrapper may be core IBC or higher-level middleware - return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) + return k.ics4Wrapper.WriteAcknowledgement(ctx, packet, ack) } // GetAppVersion returns the underlying application version. diff --git a/modules/apps/29-fee/keeper/relay_test.go b/modules/apps/29-fee/keeper/relay_test.go index 8918b325f3b..20efc7e3d6b 100644 --- a/modules/apps/29-fee/keeper/relay_test.go +++ b/modules/apps/29-fee/keeper/relay_test.go @@ -54,12 +54,11 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgementAsync() { ) ack := channeltypes.NewResultAcknowledgement([]byte("success")) - chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) // malleate test case tc.malleate() - err := suite.chainB.GetSimApp().IBCFeeKeeper.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) + err := suite.chainB.GetSimApp().IBCFeeKeeper.WriteAcknowledgement(suite.chainB.GetContext(), packet, ack) if tc.expPass { suite.Require().NoError(err) @@ -95,9 +94,8 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgementAsyncFeeDisabled() { ) ack := channeltypes.NewResultAcknowledgement([]byte("success")) - chanCap := suite.chainB.GetChannelCapability(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) - err := suite.chainB.GetSimApp().IBCFeeKeeper.WriteAcknowledgement(suite.chainB.GetContext(), chanCap, packet, ack) + err := suite.chainB.GetSimApp().IBCFeeKeeper.WriteAcknowledgement(suite.chainB.GetContext(), packet, ack) suite.Require().NoError(err) packetAck, _ := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 288838cbf28..dcedf70132e 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -245,11 +245,10 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet // reverted via a panic. func (im IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, - chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, ack ibcexported.Acknowledgement, ) error { - err := im.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) + err := im.ics4Wrapper.WriteAcknowledgement(ctx, packet, ack) if err != nil { return err } diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index da27e16410a..498520c5b25 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -755,14 +755,12 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { ctx = s.chainB.GetContext() gasLimit := ctx.GasMeter().Limit() - chanCap := s.chainB.GetChannelCapability(s.path.EndpointB.ChannelConfig.PortID, s.path.EndpointB.ChannelID) - tc.malleate() // callbacks module is routed as top level middleware transferICS4Wrapper := GetSimApp(s.chainB).TransferKeeper.GetICS4Wrapper() - err := transferICS4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, ack) + err := transferICS4Wrapper.WriteAcknowledgement(ctx, packet, ack) expPass := tc.expError == nil s.AssertHasExecutedExpectedCallback(tc.callbackType, expPass) diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index b859b1b0a56..6255c67dfb7 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -9,11 +9,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -102,7 +100,6 @@ func (k *Keeper) SendPacket( // sent on the corresponding channel end on the counterparty chain. func (k *Keeper) RecvPacket( ctx sdk.Context, - chanCap *capabilitytypes.Capability, packet types.Packet, proof []byte, proofHeight exported.Height, @@ -129,15 +126,6 @@ func (k *Keeper) RecvPacket( } } - // Authenticate capability to ensure caller has authority to receive packet on this channel - capName := host.ChannelCapabilityPath(packet.GetDestPort(), packet.GetDestChannel()) - if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, capName) { - return errorsmod.Wrapf( - types.ErrInvalidChannelCapability, - "channel capability failed authentication for capability name %s", capName, - ) - } - // packet must come from the channel's counterparty if packet.GetSourcePort() != channel.Counterparty.PortId { return errorsmod.Wrapf( @@ -277,7 +265,6 @@ func (k *Keeper) RecvPacket( // previously by RecvPacket. func (k *Keeper) WriteAcknowledgement( ctx sdk.Context, - chanCap *capabilitytypes.Capability, packet exported.PacketI, acknowledgement exported.Acknowledgement, ) error { @@ -290,15 +277,6 @@ func (k *Keeper) WriteAcknowledgement( return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s, %s], got %s", types.OPEN, types.FLUSHING, types.FLUSHCOMPLETE, channel.State) } - // Authenticate capability to ensure caller has authority to receive packet on this channel - capName := host.ChannelCapabilityPath(packet.GetDestPort(), packet.GetDestChannel()) - if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, capName) { - return errorsmod.Wrapf( - types.ErrInvalidChannelCapability, - "channel capability failed authentication for capability name %s", capName, - ) - } - // REPLAY PROTECTION: The recvStartSequence will prevent historical proofs from allowing replay // attacks on packets processed in previous lifecycles of a channel. After a successful channel // upgrade all packets under the recvStartSequence will have been processed and thus should be @@ -354,7 +332,6 @@ func (k *Keeper) WriteAcknowledgement( // It will also increment NextSequenceAck in case of ORDERED channels. func (k *Keeper) AcknowledgePacket( ctx sdk.Context, - chanCap *capabilitytypes.Capability, packet types.Packet, acknowledgement []byte, proof []byte, @@ -372,15 +349,6 @@ func (k *Keeper) AcknowledgePacket( return errorsmod.Wrapf(types.ErrInvalidChannelState, "packets cannot be acknowledged on channel with state (%s)", channel.State) } - // Authenticate capability to ensure caller has authority to receive packet on this channel - capName := host.ChannelCapabilityPath(packet.GetSourcePort(), packet.GetSourceChannel()) - if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, capName) { - return errorsmod.Wrapf( - types.ErrInvalidChannelCapability, - "channel capability failed authentication for capability name %s", capName, - ) - } - // packet must have been sent to the channel's counterparty if packet.GetDestPort() != channel.Counterparty.PortId { return errorsmod.Wrapf( diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index 1a5dccfd57c..de26955aa32 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -9,7 +9,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -261,9 +260,8 @@ func (suite *KeeperTestSuite) TestSendPacket() { // verification tests need to simulate sending a packet from chainA to chainB. func (suite *KeeperTestSuite) TestRecvPacket() { var ( - path *ibctesting.Path - packet types.Packet - channelCap *capabilitytypes.Capability + path *ibctesting.Path + packet types.Packet ) testCases := []struct { @@ -280,7 +278,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, nil, }, @@ -292,7 +289,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, nil, }, @@ -306,7 +302,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, nil, }, @@ -320,7 +315,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, nil, }, @@ -336,7 +330,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) // attempts to receive packet 2 without receiving packet 1 - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, nil, }, @@ -347,7 +340,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) @@ -364,7 +356,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) }, @@ -380,7 +371,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) @@ -398,7 +388,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) err = path.EndpointB.RecvPacket(packet) @@ -413,7 +402,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { path.Setup() sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) err = path.EndpointB.RecvPacket(packet) @@ -435,7 +423,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) // attempts to receive packet 2 without receiving packet 1 - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, types.ErrPacketSequenceOutOfOrder, }, @@ -445,7 +432,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { // use wrong channel naming path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ibctesting.InvalidID, ibctesting.InvalidID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, types.ErrChannelNotFound, }, @@ -456,23 +442,9 @@ func (suite *KeeperTestSuite) TestRecvPacket() { packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, types.ErrInvalidChannelState, }, - { - "capability cannot authenticate ORDERED", - func() { - path.SetChannelOrdered() - path.Setup() - - sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) - suite.Require().NoError(err) - packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = capabilitytypes.NewCapability(3) - }, - types.ErrInvalidChannelCapability, - }, { "packet source port ≠ channel counterparty port", func() { @@ -480,7 +452,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { // use wrong port for dest packet = types.NewPacket(ibctesting.MockPacketData, 1, ibctesting.InvalidID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, types.ErrInvalidPacket, }, @@ -491,7 +462,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { // use wrong port for dest packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, ibctesting.InvalidID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, types.ErrInvalidPacket, }, @@ -508,7 +478,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { ) packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) suite.chainB.CreateChannelCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, connectiontypes.ErrConnectionNotFound, }, @@ -529,7 +498,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { ) packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) suite.chainB.CreateChannelCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, connectiontypes.ErrInvalidConnectionState, }, @@ -539,7 +507,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.GetSelfHeight(suite.chainB.GetContext()), disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, types.ErrTimeoutElapsed, }, @@ -549,7 +516,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, disabledTimeoutHeight, uint64(suite.chainB.GetContext().BlockTime().UnixNano())) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, types.ErrTimeoutElapsed, }, @@ -574,8 +540,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { suite.chainA.App.GetIBCKeeper().ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, packet.GetSequence(), types.CommitPacket(suite.chainA.App.AppCodec(), packet)) suite.chainB.CreateChannelCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - err := path.EndpointA.UpdateClient() suite.Require().NoError(err) err = path.EndpointB.UpdateClient() @@ -591,7 +555,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) // set recv seq start to indicate packet was processed in previous upgrade suite.chainB.App.GetIBCKeeper().ChannelKeeper.SetRecvStartSequence(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sequence+1) @@ -607,7 +570,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { suite.Require().NoError(err) suite.chainB.App.GetIBCKeeper().ChannelKeeper.SetPacketReceipt(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sequence) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, types.ErrNoOpMsg, }, @@ -617,7 +579,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { // packet commitment not set resulting in invalid proof path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, commitmenttypes.ErrInvalidProof, }, @@ -635,7 +596,7 @@ func (suite *KeeperTestSuite) TestRecvPacket() { packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) proof, proofHeight := path.EndpointA.QueryProof(packetKey) - err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.RecvPacket(suite.chainB.GetContext(), channelCap, packet, proof, proofHeight) + err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.RecvPacket(suite.chainB.GetContext(), packet, proof, proofHeight) expPass := tc.expError == nil if expPass { @@ -664,10 +625,9 @@ func (suite *KeeperTestSuite) TestRecvPacket() { func (suite *KeeperTestSuite) TestWriteAcknowledgement() { var ( - path *ibctesting.Path - ack exported.Acknowledgement - packet exported.PacketI - channelCap *capabilitytypes.Capability + path *ibctesting.Path + ack exported.Acknowledgement + packet exported.PacketI ) testCases := []testCase{ @@ -677,7 +637,6 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) ack = ibcmock.MockAcknowledgement - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, true, }, @@ -689,7 +648,6 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { ack = ibcmock.MockAcknowledgement path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, true, }, @@ -701,7 +659,6 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { ack = ibcmock.MockAcknowledgement path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHCOMPLETE }) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, true, }, @@ -710,7 +667,6 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ibctesting.InvalidID, ibctesting.InvalidID, defaultTimeoutHeight, disabledTimeoutTimestamp) ack = ibcmock.MockAcknowledgement - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, false}, {"channel not open", func() { path.Setup() @@ -718,18 +674,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { ack = ibcmock.MockAcknowledgement path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, false}, - { - "capability authentication failed", - func() { - path.Setup() - packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - ack = ibcmock.MockAcknowledgement - channelCap = capabilitytypes.NewCapability(3) - }, - false, - }, { "no-op, already acked", func() { @@ -737,7 +682,6 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) ack = ibcmock.MockAcknowledgement suite.chainB.App.GetIBCKeeper().ChannelKeeper.SetPacketAcknowledgement(suite.chainB.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ack.Acknowledgement()) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, false, }, @@ -747,7 +691,6 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) ack = ibcmock.NewEmptyAcknowledgement() - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, false, }, @@ -757,7 +700,6 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) ack = nil - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, false, }, @@ -769,7 +711,6 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) ack = ibcmock.MockAcknowledgement // set recv seq start to indicate packet was processed in previous upgrade @@ -786,7 +727,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { tc.malleate() - err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(suite.chainB.GetContext(), channelCap, packet, ack) + err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(suite.chainB.GetContext(), packet, ack) if tc.expPass { suite.Require().NoError(err) @@ -803,8 +744,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { path *ibctesting.Path packet types.Packet ack = ibcmock.MockAcknowledgement - - channelCap *capabilitytypes.Capability ) assertErr := func(errType *errors.Error) func(commitment []byte, err error) { @@ -853,8 +792,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertSuccess(func() uint64 { return packet.GetSequence() + 1 }, "sequence not incremented in ordered channel"), }, @@ -872,8 +809,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertSuccess(func() uint64 { return uint64(1) }, "sequence incremented for UNORDERED channel"), }, @@ -892,8 +827,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) }, expResult: func(commitment []byte, err error) { @@ -923,8 +856,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) counterpartyUpgrade := types.Upgrade{ @@ -976,8 +907,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) upgrade := types.Upgrade{ @@ -1024,8 +953,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - err = path.EndpointA.AcknowledgePacket(packet, ack.Acknowledgement()) suite.Require().NoError(err) }, @@ -1046,8 +973,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - err = path.EndpointA.AcknowledgePacket(packet, ack.Acknowledgement()) suite.Require().NoError(err) }, @@ -1079,7 +1004,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertErr(types.ErrInvalidChannelState), }, @@ -1088,7 +1012,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { malleate: func() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHCOMPLETE }) }, @@ -1098,25 +1021,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { suite.Require().Nil(commitment) }, }, - { - name: "capability authentication failed ORDERED", - malleate: func() { - path.SetChannelOrdered() - path.Setup() - - // create packet commitment - sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) - suite.Require().NoError(err) - - // create packet receipt and acknowledgement - packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - err = path.EndpointB.RecvPacket(packet) - suite.Require().NoError(err) - - channelCap = capabilitytypes.NewCapability(3) - }, - expResult: assertErr(types.ErrInvalidChannelCapability), - }, { name: "packet destination port ≠ channel counterparty port", malleate: func() { @@ -1128,7 +1032,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { // use wrong port for dest packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ibctesting.InvalidID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertErr(types.ErrInvalidPacket), }, @@ -1143,7 +1046,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { // use wrong channel for dest packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, ibctesting.InvalidID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertErr(types.ErrInvalidPacket), }, @@ -1166,7 +1068,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { ) suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertErr(connectiontypes.ErrConnectionNotFound), }, @@ -1192,7 +1093,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID), []string{path.EndpointA.ConnectionID}, path.EndpointA.ChannelConfig.Version), ) suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertErr(connectiontypes.ErrInvalidConnectionState), }, @@ -1202,7 +1102,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { // packet commitment never written path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertNoOp, // NOTE: ibc core does not distinguish between unsent and already relayed packets. }, @@ -1218,7 +1117,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertErr(commitmenttypes.ErrInvalidProof), }, @@ -1237,8 +1135,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { err = path.EndpointB.RecvPacket(packet) suite.Require().NoError(err) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - packet.Data = []byte("invalid packet commitment") }, expResult: assertErr(types.ErrInvalidPacket), @@ -1262,8 +1158,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { ibcStore := suite.chainA.GetContext().KVStore(storeKey) ibcStore.Delete(host.NextSequenceAckKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertErr(types.ErrSequenceAckNotFound), }, @@ -1284,7 +1178,6 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { // set next sequence ack wrong suite.chainA.App.GetIBCKeeper().ChannelKeeper.SetNextSequenceAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, 10) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, expResult: assertErr(types.ErrPacketSequenceOutOfOrder), }, @@ -1303,7 +1196,7 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) proof, proofHeight := path.EndpointB.QueryProof(packetKey) - err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.AcknowledgePacket(ctx, channelCap, packet, ack.Acknowledgement(), proof, proofHeight) + err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.AcknowledgePacket(ctx, packet, ack.Acknowledgement(), proof, proofHeight) commitment := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(ctx, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, packet.GetSequence()) tc.expResult(commitment, err) diff --git a/modules/core/04-channel/keeper/timeout.go b/modules/core/04-channel/keeper/timeout.go index 8d7fdf892ff..4350409e2bd 100644 --- a/modules/core/04-channel/keeper/timeout.go +++ b/modules/core/04-channel/keeper/timeout.go @@ -8,11 +8,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -132,7 +130,6 @@ func (k *Keeper) TimeoutPacket( // CONTRACT: this function must be called in the IBC handler func (k *Keeper) TimeoutExecuted( ctx sdk.Context, - chanCap *capabilitytypes.Capability, packet types.Packet, ) error { channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) @@ -140,14 +137,6 @@ func (k *Keeper) TimeoutExecuted( return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", packet.GetSourcePort(), packet.GetSourceChannel()) } - capName := host.ChannelCapabilityPath(packet.GetSourcePort(), packet.GetSourceChannel()) - if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, capName) { - return errorsmod.Wrapf( - types.ErrChannelCapabilityNotFound, - "caller does not own capability for channel with capability name %s", capName, - ) - } - k.deletePacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) // if an upgrade is in progress, handling packet flushing and update channel state appropriately @@ -210,7 +199,6 @@ func (k *Keeper) TimeoutExecuted( // never be received (even if the timeoutHeight has not yet been reached). func (k *Keeper) TimeoutOnClose( ctx sdk.Context, - chanCap *capabilitytypes.Capability, packet types.Packet, proof, closedProof []byte, @@ -223,14 +211,6 @@ func (k *Keeper) TimeoutOnClose( return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", packet.GetSourcePort(), packet.GetSourceChannel()) } - capName := host.ChannelCapabilityPath(packet.GetSourcePort(), packet.GetSourceChannel()) - if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, capName) { - return errorsmod.Wrapf( - types.ErrInvalidChannelCapability, - "channel capability failed authentication with capability name %s", capName, - ) - } - if packet.GetDestPort() != channel.Counterparty.PortId { return errorsmod.Wrapf( types.ErrInvalidPacket, diff --git a/modules/core/04-channel/keeper/timeout_test.go b/modules/core/04-channel/keeper/timeout_test.go index 44aca2f33ce..11d1dc4ed15 100644 --- a/modules/core/04-channel/keeper/timeout_test.go +++ b/modules/core/04-channel/keeper/timeout_test.go @@ -10,7 +10,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -240,9 +239,8 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { // after a timeout is updated accordingly. func (suite *KeeperTestSuite) TestTimeoutExecuted() { var ( - path *ibctesting.Path - packet types.Packet - chanCap *capabilitytypes.Capability + path *ibctesting.Path + packet types.Packet ) testCases := []struct { @@ -264,7 +262,6 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, func(packetCommitment []byte, err error) { suite.Require().NoError(err) @@ -292,36 +289,12 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { }, nil, }, - { - "incorrect capability ORDERED", - func() { - path.SetChannelOrdered() - path.Setup() - - timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) - timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) - - sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) - suite.Require().NoError(err) - - packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = capabilitytypes.NewCapability(100) - }, - func(packetCommitment []byte, err error) { - suite.Require().Error(err) - suite.Require().ErrorIs(err, types.ErrChannelCapabilityNotFound) - - // packet sent, never deleted. - suite.Require().NotNil(packetCommitment) - }, - nil, - }, { "set to flush complete with no inflight packets", func() { path.Setup() - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) @@ -364,7 +337,6 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) }, @@ -388,7 +360,6 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) @@ -437,7 +408,6 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) @@ -479,7 +449,6 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) @@ -518,7 +487,7 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { tc.malleate() - err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.TimeoutExecuted(ctx, chanCap, packet) + err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.TimeoutExecuted(ctx, packet) pc := suite.chainA.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) tc.expResult(pc, err) @@ -539,7 +508,6 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { var ( path *ibctesting.Path packet types.Packet - chanCap *capabilitytypes.Capability nextSeqRecv uint64 counterpartyUpgradeSequence uint64 ordered bool @@ -562,7 +530,6 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"success: UNORDERED", func() { ordered = false @@ -578,7 +545,6 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"channel not found", func() { // use wrong channel naming @@ -589,13 +555,11 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { path.Setup() // use wrong port for dest packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ibctesting.InvalidID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"packet dest channel ID ≠ channel counterparty channel ID", func() { path.Setup() // use wrong channel for dest packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, ibctesting.InvalidID, defaultTimeoutHeight, disabledTimeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"connection not found", func() { // pass channel check @@ -608,14 +572,12 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { // create chancap suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"packet hasn't been sent ORDERED", func() { path.SetChannelOrdered() path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.GetSelfHeight(suite.chainB.GetContext()), uint64(suite.chainB.GetContext().BlockTime().UnixNano())) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"packet already received ORDERED", func() { path.SetChannelOrdered() @@ -634,7 +596,6 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"channel verification failed ORDERED", func() { ordered = true @@ -647,7 +608,6 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"next seq receive verification failed ORDERED", func() { // set ordered to false providing the wrong proof for ORDERED case @@ -665,7 +625,6 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.GetSelfHeight(suite.chainB.GetContext()), uint64(suite.chainB.GetContext().BlockTime().UnixNano())) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"packet ack verification failed", func() { // set ordered to true providing the wrong proof for UNORDERED case @@ -681,25 +640,6 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - }, false}, - {"channel capability not found ORDERED", func() { - ordered = true - path.SetChannelOrdered() - path.Setup() - - timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext()) - timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano()) - - sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData) - suite.Require().NoError(err) - path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) - // need to update chainA's client representing chainB to prove missing ack - err = path.EndpointA.UpdateClient() - suite.Require().NoError(err) - - packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.GetSelfHeight(suite.chainB.GetContext()), uint64(suite.chainB.GetContext().BlockTime().UnixNano())) - chanCap = capabilitytypes.NewCapability(100) }, false}, { "failure: invalid counterparty upgrade sequence", @@ -724,7 +664,6 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp) - chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false, }, @@ -756,7 +695,6 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.TimeoutOnClose( suite.chainA.GetContext(), - chanCap, packet, proof, closedProof, diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 2295c2224e4..ef320122a56 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -183,7 +183,6 @@ type ICS4Wrapper interface { WriteAcknowledgement( ctx sdk.Context, - chanCap *capabilitytypes.Capability, packet exported.PacketI, ack exported.Acknowledgement, ) error diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 62de0414a60..5274b2d1b5c 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -491,7 +491,7 @@ func (k *Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPack } // Lookup module by channel capability - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel) + module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel) if err != nil { ctx.Logger().Error("receive packet failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") @@ -509,7 +509,7 @@ func (k *Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPack // If the packet was already received, perform a no-op // Use a cached context to prevent accidental state changes cacheCtx, writeFn := ctx.CacheContext() - err = k.ChannelKeeper.RecvPacket(cacheCtx, capability, msg.Packet, msg.ProofCommitment, msg.ProofHeight) + err = k.ChannelKeeper.RecvPacket(cacheCtx, msg.Packet, msg.ProofCommitment, msg.ProofHeight) switch err { case nil: @@ -540,7 +540,7 @@ func (k *Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPack // NOTE: IBC applications modules may call the WriteAcknowledgement asynchronously if the // acknowledgement is nil. if ack != nil { - if err := k.ChannelKeeper.WriteAcknowledgement(ctx, capability, msg.Packet, ack); err != nil { + if err := k.ChannelKeeper.WriteAcknowledgement(ctx, msg.Packet, ack); err != nil { return nil, err } } @@ -572,7 +572,7 @@ func (k *Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (* } // Lookup module by channel capability - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.SourcePort, msg.Packet.SourceChannel) + module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.SourcePort, msg.Packet.SourceChannel) if err != nil { ctx.Logger().Error("timeout failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") @@ -605,7 +605,7 @@ func (k *Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (* } // Delete packet commitment - if err = k.ChannelKeeper.TimeoutExecuted(ctx, capability, msg.Packet); err != nil { + if err = k.ChannelKeeper.TimeoutExecuted(ctx, msg.Packet); err != nil { return nil, err } @@ -644,7 +644,7 @@ func (k *Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTime } // Lookup module by channel capability - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.SourcePort, msg.Packet.SourceChannel) + module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.SourcePort, msg.Packet.SourceChannel) if err != nil { ctx.Logger().Error("timeout on close failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") @@ -662,7 +662,7 @@ func (k *Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTime // If the timeout was already received, perform a no-op // Use a cached context to prevent accidental state changes cacheCtx, writeFn := ctx.CacheContext() - err = k.ChannelKeeper.TimeoutOnClose(cacheCtx, capability, msg.Packet, msg.ProofUnreceived, msg.ProofClose, msg.ProofHeight, msg.NextSequenceRecv, msg.CounterpartyUpgradeSequence) + err = k.ChannelKeeper.TimeoutOnClose(cacheCtx, msg.Packet, msg.ProofUnreceived, msg.ProofClose, msg.ProofHeight, msg.NextSequenceRecv, msg.CounterpartyUpgradeSequence) switch err { case nil: @@ -677,7 +677,7 @@ func (k *Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTime } // Delete packet commitment - if err = k.ChannelKeeper.TimeoutExecuted(ctx, capability, msg.Packet); err != nil { + if err = k.ChannelKeeper.TimeoutExecuted(ctx, msg.Packet); err != nil { return nil, err } @@ -719,7 +719,7 @@ func (k *Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAck } // Lookup module by channel capability - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.SourcePort, msg.Packet.SourceChannel) + module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.SourcePort, msg.Packet.SourceChannel) if err != nil { ctx.Logger().Error("acknowledgement failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") @@ -737,7 +737,7 @@ func (k *Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAck // If the acknowledgement was already received, perform a no-op // Use a cached context to prevent accidental state changes cacheCtx, writeFn := ctx.CacheContext() - err = k.ChannelKeeper.AcknowledgePacket(cacheCtx, capability, msg.Packet, msg.Acknowledgement, msg.ProofAcked, msg.ProofHeight) + err = k.ChannelKeeper.AcknowledgePacket(cacheCtx, msg.Packet, msg.Acknowledgement, msg.ProofAcked, msg.ProofHeight) switch err { case nil: diff --git a/testing/endpoint.go b/testing/endpoint.go index c382b016d76..7f3c8648c24 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -493,10 +493,8 @@ func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*abc // WriteAcknowledgement writes an acknowledgement on the channel associated with the endpoint. // The counterparty client is updated. func (endpoint *Endpoint) WriteAcknowledgement(ack exported.Acknowledgement, packet exported.PacketI) error { - channelCap := endpoint.Chain.GetChannelCapability(packet.GetDestPort(), packet.GetDestChannel()) - // no need to send message, acting as a handler - err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), channelCap, packet, ack) + err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), packet, ack) if err != nil { return err } diff --git a/testing/mock/middleware.go b/testing/mock/middleware.go index 1cb595ca2d4..2a8a5e47108 100644 --- a/testing/mock/middleware.go +++ b/testing/mock/middleware.go @@ -192,7 +192,6 @@ func (BlockUpgradeMiddleware) SendPacket( // WriteAcknowledgement implements the ICS4 Wrapper interface func (BlockUpgradeMiddleware) WriteAcknowledgement( ctx sdk.Context, - chanCap *capabilitytypes.Capability, packet exported.PacketI, ack exported.Acknowledgement, ) error { From 07e8b1ced177c85da1bc4b9c996f64769306916e Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 16 May 2024 18:46:16 +0200 Subject: [PATCH 21/46] lint: make lint-fix and address --- modules/apps/27-interchain-accounts/controller/keeper/relay.go | 3 +-- modules/apps/29-fee/ibc_middleware.go | 2 +- modules/apps/29-fee/keeper/relay.go | 2 +- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/core/05-port/types/router_v2.go | 3 ++- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/relay.go b/modules/apps/27-interchain-accounts/controller/keeper/relay.go index ebcc0c60ee4..0f52d16de96 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/relay.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/relay.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -36,7 +35,7 @@ func (k Keeper) sendTx(ctx sdk.Context, connectionID, portID string, icaPacketDa } if strings.TrimSpace(owner) == "" { - owner = strings.TrimPrefix(portID, types.ControllerPortPrefix) + owner = strings.TrimPrefix(portID, icatypes.ControllerPortPrefix) } msgSendPacket := &channeltypes.MsgSendPacket{ diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 92259b6392a..ed429faa8aa 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -456,7 +456,7 @@ func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID str } // SendPacket implements the ICS4 Wrapper interface -func (im IBCMiddleware) SendPacket( +func (IBCMiddleware) SendPacket( ctx sdk.Context, sourcePort string, sourceChannel string, diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go index dc0cca447a2..6d153067529 100644 --- a/modules/apps/29-fee/keeper/relay.go +++ b/modules/apps/29-fee/keeper/relay.go @@ -14,7 +14,7 @@ import ( ) // SendPacket wraps the ICS4Wrapper SendPacket function -func (k Keeper) SendPacket( +func (Keeper) SendPacket( ctx sdk.Context, sourcePort string, sourceChannel string, diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index dcedf70132e..858e3956bf2 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -85,7 +85,7 @@ func (im *IBCMiddleware) GetICS4Wrapper() porttypes.ICS4Wrapper { // It defers to the underlying application and then calls the contract callback. // If the contract callback returns an error, panics, or runs out of gas, then // the packet send is rejected. -func (im IBCMiddleware) SendPacket( +func (IBCMiddleware) SendPacket( ctx sdk.Context, sourcePort string, sourceChannel string, diff --git a/modules/core/05-port/types/router_v2.go b/modules/core/05-port/types/router_v2.go index bb19636e71a..e165ae257e0 100644 --- a/modules/core/05-port/types/router_v2.go +++ b/modules/core/05-port/types/router_v2.go @@ -6,8 +6,9 @@ import ( "errors" "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" "golang.org/x/exp/maps" + + sdk "github.com/cosmos/cosmos-sdk/types" ) // AppRouter contains a map from module name to an ordered list of IBCModules From 421420173868acba3902626cd3ac4d7b4f6ac963 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 16 May 2024 19:04:20 +0200 Subject: [PATCH 22/46] refactor: rm SendPacket from ics4wrapper --- .../controller/ibc_middleware.go | 12 ------------ modules/apps/29-fee/ibc_middleware.go | 12 ------------ modules/apps/29-fee/keeper/relay.go | 13 ------------- modules/apps/callbacks/ibc_middleware.go | 15 --------------- modules/core/05-port/types/module.go | 9 --------- testing/mock/middleware.go | 12 ------------ 6 files changed, 73 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 76808694769..67f616b3b4e 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -359,18 +359,6 @@ func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID str } } -// SendPacket implements the ICS4 Wrapper interface -func (IBCMiddleware) SendPacket( - ctx sdk.Context, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (uint64, error) { - panic(errors.New("SendPacket not supported for ICA controller module. Please use SendTx")) -} - // WriteAcknowledgement implements the ICS4 Wrapper interface func (IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index ed429faa8aa..461d33fa07f 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -455,18 +455,6 @@ func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID str cbs.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, versionMetadata.AppVersion) } -// SendPacket implements the ICS4 Wrapper interface -func (IBCMiddleware) SendPacket( - ctx sdk.Context, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (uint64, error) { - panic("TODO: remove") -} - // WriteAcknowledgement implements the ICS4 Wrapper interface func (im IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go index 6d153067529..b9d9cfdcd4c 100644 --- a/modules/apps/29-fee/keeper/relay.go +++ b/modules/apps/29-fee/keeper/relay.go @@ -8,23 +8,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" ) -// SendPacket wraps the ICS4Wrapper SendPacket function -func (Keeper) SendPacket( - ctx sdk.Context, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (uint64, error) { - panic("TODO: remove") -} - // WriteAcknowledgement wraps IBC ChannelKeeper's WriteAcknowledgement function // ICS29 WriteAcknowledgement is used for asynchronous acknowledgements func (k Keeper) WriteAcknowledgement(ctx sdk.Context, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error { diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 858e3956bf2..30af03d66ce 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -81,21 +81,6 @@ func (im *IBCMiddleware) GetICS4Wrapper() porttypes.ICS4Wrapper { return im.ics4Wrapper } -// SendPacket implements source callbacks for sending packets. -// It defers to the underlying application and then calls the contract callback. -// If the contract callback returns an error, panics, or runs out of gas, then -// the packet send is rejected. -func (IBCMiddleware) SendPacket( - ctx sdk.Context, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (uint64, error) { - panic("TODO: remove") -} - // OnSendPacket implements the IBCModule interface. func (im IBCMiddleware) OnSendPacket( ctx sdk.Context, diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index ef320122a56..ee2c1b87d61 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -172,15 +172,6 @@ type UpgradableModule interface { // ICS4Wrapper implements the ICS4 interfaces that IBC applications use to send packets and acknowledgements. type ICS4Wrapper interface { // TODO: Leave in place to avoid compiler errors and incrementally work to remove. We can then delete these methods - SendPacket( - ctx sdk.Context, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, - ) (sequence uint64, err error) - WriteAcknowledgement( ctx sdk.Context, packet exported.PacketI, diff --git a/testing/mock/middleware.go b/testing/mock/middleware.go index 2a8a5e47108..df69faea296 100644 --- a/testing/mock/middleware.go +++ b/testing/mock/middleware.go @@ -177,18 +177,6 @@ func (im BlockUpgradeMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channel return nil } -// SendPacket implements the ICS4 Wrapper interface -func (BlockUpgradeMiddleware) SendPacket( - ctx sdk.Context, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (uint64, error) { - return 0, nil -} - // WriteAcknowledgement implements the ICS4 Wrapper interface func (BlockUpgradeMiddleware) WriteAcknowledgement( ctx sdk.Context, From 9610871145211a2ae6f09e0bb17aa8be84044d0f Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 16 May 2024 19:06:22 +0200 Subject: [PATCH 23/46] chore: rm callbacks var in SendPacket handler --- modules/core/keeper/msg_server.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 5274b2d1b5c..e697036c1b5 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -456,7 +456,7 @@ func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPack } // Retrieve callbacks from router - cbsList, ok := k.PortKeeper.AppRoute(msg.PortId) + cbs, ok := k.PortKeeper.AppRoute(msg.PortId) if !ok { ctx.Logger().Error("send packet failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) @@ -470,8 +470,8 @@ func (k *Keeper) SendPacket(goCtx context.Context, msg *channeltypes.MsgSendPack // Loop over cbs in-order calling OnSendPacket on each IBCModule. To be done for RecvPacket handler as well in opposite order. // Adjust app logic to account for what should be done before MsgSendPacket and what should be done in OnSendPacket. - for _, cbs := range cbsList { - if err := cbs.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data, signer); err != nil { + for _, cb := range cbs { + if err := cb.OnSendPacket(ctx, msg.PortId, msg.ChannelId, sequence, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Data, signer); err != nil { ctx.Logger().Error("send packet callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "send packet callback failed")) return nil, errorsmod.Wrapf(err, "send packet callback failed for module: %s", msg.PortId) } From cf339f2c601be70a5f55a29368d3962f40849ab6 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 22 May 2024 16:44:11 +0200 Subject: [PATCH 24/46] fix: rm capability arg in ibc ante handler --- modules/core/ante/ante.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/core/ante/ante.go b/modules/core/ante/ante.go index c456ed45a6f..0e483f6ee64 100644 --- a/modules/core/ante/ante.go +++ b/modules/core/ante/ante.go @@ -109,7 +109,7 @@ func (rrd RedundantRelayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula // It only performs core IBC receiving logic and skips any application logic. func (rrd RedundantRelayDecorator) recvPacketCheckTx(ctx sdk.Context, msg *channeltypes.MsgRecvPacket) (*channeltypes.MsgRecvPacketResponse, error) { // grab channel capability - _, capability, err := rrd.k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel) + _, _, err := rrd.k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel) if err != nil { return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") } @@ -117,7 +117,7 @@ func (rrd RedundantRelayDecorator) recvPacketCheckTx(ctx sdk.Context, msg *chann // If the packet was already received, perform a no-op // Use a cached context to prevent accidental state changes cacheCtx, writeFn := ctx.CacheContext() - err = rrd.k.ChannelKeeper.RecvPacket(cacheCtx, capability, msg.Packet, msg.ProofCommitment, msg.ProofHeight) + err = rrd.k.ChannelKeeper.RecvPacket(cacheCtx, msg.Packet, msg.ProofCommitment, msg.ProofHeight) switch err { case nil: From a4a7bdd5d01c96d5aa265ce018a31cc9cc3cd9af Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Mon, 5 Aug 2024 16:02:54 +0100 Subject: [PATCH 25/46] (chore): remove capabilities from channel handsake (#7009) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * not working yet * More tests fixed. * added message error * commented out tests * Wire approuter to e2e testing simapp * Delete obsolete tests * remove possibly unneeded call * Removed tests no longer needed * test: fix commented/removed tests --------- Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> --- .../controller/ibc_middleware.go | 12 +- .../controller/ibc_middleware_test.go | 22 +- .../controller/keeper/handshake.go | 2 - .../controller/keeper/handshake_test.go | 7 +- .../controller/keeper/migrations_test.go | 72 ------ .../migrations/v6/migrations_test.go | 72 ------ .../27-interchain-accounts/host/ibc_module.go | 5 +- .../host/ibc_module_test.go | 8 +- .../host/keeper/handshake.go | 9 - .../host/keeper/handshake_test.go | 25 +- modules/apps/29-fee/ibc_middleware.go | 11 +- modules/apps/29-fee/ibc_middleware_test.go | 21 +- modules/apps/callbacks/ibc_middleware.go | 7 +- modules/apps/transfer/ibc_module.go | 14 -- modules/apps/transfer/ibc_module_test.go | 25 +- modules/core/04-channel/keeper/handshake.go | 76 ++---- .../core/04-channel/keeper/handshake_test.go | 158 +----------- modules/core/05-port/keeper/keeper.go | 14 +- modules/core/05-port/types/module.go | 3 - modules/core/ante/ante.go | 8 +- modules/core/ante/ante_test.go | 10 - modules/core/keeper/msg_server.go | 234 +++++------------- modules/core/keeper/msg_server_test.go | 57 ----- simapp/app.go | 10 + testing/mock/ibc_app.go | 3 - testing/mock/ibc_module.go | 24 +- testing/mock/middleware.go | 24 +- 27 files changed, 152 insertions(+), 781 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 1b612ff93d7..b6999af4c4a 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -7,14 +7,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -62,7 +60,6 @@ func (im IBCMiddleware) OnChanOpenInit( connectionHops []string, portID string, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, ) (string, error) { @@ -70,20 +67,16 @@ func (im IBCMiddleware) OnChanOpenInit( return "", types.ErrControllerSubModuleDisabled } - version, err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) + version, err := im.keeper.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, version) if err != nil { return "", err } - if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } - // call underlying app's OnChanOpenInit callback with the passed in version // the version returned is discarded as the ica-auth module does not have permission to edit the version string. // ics27 will always return the version string containing the Metadata struct which is created during the `RegisterInterchainAccount` call. if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionHops[0]) { - if _, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, nil, counterparty, version); err != nil { + if _, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, version); err != nil { return "", err } } @@ -98,7 +91,6 @@ func (IBCMiddleware) OnChanOpenTry( connectionHops []string, portID, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index f5ba5299ef0..ecfd30decb1 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -11,7 +11,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller" controllerkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" @@ -129,13 +128,9 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { { "ICA auth module does not claim channel capability", func() { suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, + portID, channelID string, counterparty channeltypes.Counterparty, version string, ) (string, error) { - if chanCap != nil { - return "", fmt.Errorf("channel capability should be nil") - } - return version, nil } }, true, @@ -145,7 +140,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { // NOTE: explicitly modify the channel version via the auth module callback, // ensuring the expected JSON encoded metadata is not modified upon return suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, + portID, channelID string, counterparty channeltypes.Counterparty, version string, ) (string, error) { return "invalid-version", nil @@ -160,7 +155,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { { "ICA auth module callback fails", func() { suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, + portID, channelID string, counterparty channeltypes.Counterparty, version string, ) (string, error) { return "", fmt.Errorf("mock ica auth fails") @@ -177,7 +172,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, + portID, channelID string, counterparty channeltypes.Counterparty, version string, ) (string, error) { return "", fmt.Errorf("error should be unreachable") @@ -227,9 +222,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) suite.Require().NoError(err) - chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) suite.Require().True(ok) @@ -238,7 +230,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { } version, err := cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.Version, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel.Counterparty, channel.Version, ) if tc.expPass { @@ -292,12 +284,10 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenTry() { suite.Require().True(ok) counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - chanCap, found := suite.chainA.App.GetScopedIBCKeeper().GetCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().True(found) version, err := cbs.OnChanOpenTry( suite.chainA.GetContext(), path.EndpointA.ChannelConfig.Order, []string{path.EndpointA.ConnectionID}, - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterparty, path.EndpointB.ChannelConfig.Version, ) suite.Require().Error(err) diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go index aa54053221a..729e8d68883 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -26,7 +25,6 @@ func (k Keeper) OnChanOpenInit( connectionHops []string, portID string, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, ) (string, error) { diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go index 7e6f0add2f8..b6d9a7df187 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -19,7 +18,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { var ( channel *channeltypes.Channel path *ibctesting.Path - chanCap *capabilitytypes.Capability metadata icatypes.Metadata expectedVersion string ) @@ -294,13 +292,10 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { Version: string(versionBytes), } - chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().NoError(err) - tc.malleate() // malleate mutates test data version, err := suite.chainA.GetSimApp().ICAControllerKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.Version, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel.Counterparty, channel.Version, ) expPass := tc.expError == nil diff --git a/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go b/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go index ec48a442860..dd7493dec35 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/migrations_test.go @@ -5,80 +5,8 @@ import ( icacontrollerkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/keeper" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" - icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v8/testing" ) -func (suite *KeeperTestSuite) TestAssertChannelCapabilityMigrations() { - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success", - func() {}, - true, - }, - { - "channel with different port is filtered out", - func() { - portIDWithOutPrefix := ibctesting.MockPort - suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), portIDWithOutPrefix, ibctesting.FirstChannelID, channeltypes.Channel{ - ConnectionHops: []string{ibctesting.FirstConnectionID}, - }) - }, - true, - }, - { - "capability not found", - func() { - portIDWithPrefix := fmt.Sprintf("%s%s", icatypes.ControllerPortPrefix, "port-without-capability") - suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), portIDWithPrefix, ibctesting.FirstChannelID, channeltypes.Channel{ - ConnectionHops: []string{ibctesting.FirstConnectionID}, - }) - }, - false, - }, - } - - for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - - path := NewICAPath(suite.chainA, suite.chainB, ordering) - path.SetupConnections() - - err := SetupICAPath(path, ibctesting.TestAccAddress) - suite.Require().NoError(err) - - tc.malleate() - - migrator := icacontrollerkeeper.NewMigrator(&suite.chainA.GetSimApp().ICAControllerKeeper) - err = migrator.AssertChannelCapabilityMigrations(suite.chainA.GetContext()) - - if tc.expPass { - suite.Require().NoError(err) - - isMiddlewareEnabled := suite.chainA.GetSimApp().ICAControllerKeeper.IsMiddlewareEnabled( - suite.chainA.GetContext(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ConnectionID, - ) - - suite.Require().True(isMiddlewareEnabled) - } else { - suite.Require().Error(err) - } - }) - } - } -} - func (suite *KeeperTestSuite) TestMigratorMigrateParams() { testCases := []struct { msg string diff --git a/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go b/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go index d63b69ec110..6d60c76e0b0 100644 --- a/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go +++ b/modules/apps/27-interchain-accounts/controller/migrations/v6/migrations_test.go @@ -8,13 +8,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/migrations/v6" - "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v8/testing" - ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) type MigrationsTestSuite struct { @@ -86,74 +82,6 @@ func TestKeeperTestSuite(t *testing.T) { testifysuite.Run(t, new(MigrationsTestSuite)) } -func (suite *MigrationsTestSuite) TestMigrateICS27ChannelCapability() { - suite.SetupTest() - suite.path.SetupConnections() - - err := suite.SetupPath() - suite.Require().NoError(err) - - // create additional capabilities to cover edge cases - suite.CreateMockCapabilities() - - // create and claim a new capability with ibc/mock for "channel-1" - // note: suite.SetupPath() now claims the channel capability using icacontroller for "channel-0" - capName := host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, channeltypes.FormatChannelIdentifier(1)) - - capability, err := suite.chainA.GetSimApp().ScopedIBCKeeper.NewCapability(suite.chainA.GetContext(), capName) - suite.Require().NoError(err) - - err = suite.chainA.GetSimApp().ScopedICAMockKeeper.ClaimCapability(suite.chainA.GetContext(), capability, capName) - suite.Require().NoError(err) - - // assert the capability is owned by the mock module - capability, found := suite.chainA.GetSimApp().ScopedICAMockKeeper.GetCapability(suite.chainA.GetContext(), capName) - suite.Require().NotNil(capability) - suite.Require().True(found) - - isAuthenticated := suite.chainA.GetSimApp().ScopedICAMockKeeper.AuthenticateCapability(suite.chainA.GetContext(), capability, capName) - suite.Require().True(isAuthenticated) - - capability, found = suite.chainA.GetSimApp().ScopedICAControllerKeeper.GetCapability(suite.chainA.GetContext(), capName) - suite.Require().Nil(capability) - suite.Require().False(found) - - suite.ResetMemStore() // empty the x/capability in-memory store - - err = v6.MigrateICS27ChannelCapability( - suite.chainA.GetContext(), - suite.chainA.Codec, - suite.chainA.GetSimApp().GetKey(capabilitytypes.StoreKey), - suite.chainA.GetSimApp().CapabilityKeeper, - ibcmock.ModuleName+types.SubModuleName, - ) - - suite.Require().NoError(err) - - // assert the capability is now owned by the ICS27 controller submodule - capability, found = suite.chainA.GetSimApp().ScopedICAControllerKeeper.GetCapability(suite.chainA.GetContext(), capName) - suite.Require().NotNil(capability) - suite.Require().True(found) - - isAuthenticated = suite.chainA.GetSimApp().ScopedICAControllerKeeper.AuthenticateCapability(suite.chainA.GetContext(), capability, capName) - suite.Require().True(isAuthenticated) - - capability, found = suite.chainA.GetSimApp().ScopedICAMockKeeper.GetCapability(suite.chainA.GetContext(), capName) - suite.Require().Nil(capability) - suite.Require().False(found) - - // ensure channel capability for "channel-0" is still owned by the controller - capName = host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) - capability, found = suite.chainA.GetSimApp().ScopedICAControllerKeeper.GetCapability(suite.chainA.GetContext(), capName) - suite.Require().NotNil(capability) - suite.Require().True(found) - - isAuthenticated = suite.chainA.GetSimApp().ScopedICAControllerKeeper.AuthenticateCapability(suite.chainA.GetContext(), capability, capName) - suite.Require().True(isAuthenticated) - - suite.AssertMockCapabiltiesUnchanged() -} - // CreateMockCapabilities creates an additional two capabilities used for testing purposes: // 1. A capability with a single owner // 2. A capability with two owners, neither of which is "ibc" diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index eb830423b04..8b5abdaf1c7 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" @@ -43,7 +42,6 @@ func (IBCModule) OnChanOpenInit( connectionHops []string, portID string, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, ) (string, error) { @@ -57,7 +55,6 @@ func (im IBCModule) OnChanOpenTry( connectionHops []string, portID, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { @@ -65,7 +62,7 @@ func (im IBCModule) OnChanOpenTry( return "", types.ErrHostSubModuleDisabled } - return im.keeper.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, counterpartyVersion) + return im.keeper.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, counterpartyVersion) } // OnChanOpenAck implements the IBCModule interface diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 1fee5dd0c75..79c06c34006 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -14,7 +14,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" icahost "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host" "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" @@ -166,7 +165,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { "success: ICA auth module callback returns error", func() { // mock module callback should not be called on host side suite.chainB.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenTry = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, + portID, channelID string, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { return "", fmt.Errorf("mock ica auth fails") @@ -207,14 +206,11 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) suite.Require().NoError(err) - chanCap, err := suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) - suite.Require().NoError(err) - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) suite.Require().True(ok) version, err := cbs.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, path.EndpointA.ChannelConfig.Version, + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel.Counterparty, path.EndpointA.ChannelConfig.Version, ) if tc.expPass { diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake.go b/modules/apps/27-interchain-accounts/host/keeper/handshake.go index 0613b8f32cf..2a769e33d1f 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake.go @@ -8,12 +8,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) // OnChanOpenTry performs basic validation of the ICA channel @@ -26,7 +24,6 @@ func (k Keeper) OnChanOpenTry( connectionHops []string, portID, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { @@ -69,12 +66,6 @@ func (k Keeper) OnChanOpenTry( // be overwritten with the correct one before the metadata is returned. } - // On the host chain the capability may only be claimed during the OnChanOpenTry - // The capability being claimed in OpenInit is for a controller chain (the port is different) - if err = k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", errorsmod.Wrapf(err, "failed to claim capability for channel %s on port %s", channelID, portID) - } - var accAddress sdk.AccAddress interchainAccAddr, found := k.GetInterchainAccountAddress(ctx, metadata.HostConnectionId, counterparty.PortId) diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go index 2e37ddb4418..6cfde2149d6 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go @@ -5,13 +5,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" hosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -47,7 +45,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { var ( channel *channeltypes.Channel path *ibctesting.Path - chanCap *capabilitytypes.Capability metadata icatypes.Metadata ) @@ -67,8 +64,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { // create interchain account // undo setup path.EndpointB.ChannelID = "" - err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) - suite.Require().NoError(err) suite.openAndCloseChannel(path) }, @@ -80,8 +75,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { // create interchain account // undo setup path.EndpointB.ChannelID = "" - err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) - suite.Require().NoError(err) suite.openAndCloseChannel(path) @@ -132,8 +125,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { // create interchain account // undo setup path.EndpointB.ChannelID = "" - err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) - suite.Require().NoError(err) suite.openAndCloseChannel(path) @@ -152,8 +143,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { // create interchain account // undo setup path.EndpointB.ChannelID = "" - err := suite.chainB.App.GetScopedIBCKeeper().ReleaseCapability(suite.chainB.GetContext(), chanCap) - suite.Require().NoError(err) suite.openAndCloseChannel(path) @@ -252,15 +241,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { }, false, }, - { - "capability already claimed", - func() { - path.EndpointB.SetChannel(*channel) - err := suite.chainB.GetSimApp().ScopedICAHostKeeper.ClaimCapability(suite.chainB.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) - suite.Require().NoError(err) - }, - false, - }, { "active channel already set (OPEN state)", func() { @@ -324,13 +304,10 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { Version: string(versionBytes), } - chanCap, err = suite.chainB.App.GetScopedIBCKeeper().NewCapability(suite.chainB.GetContext(), host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)) - suite.Require().NoError(err) - tc.malleate() // malleate mutates test data version, err := suite.chainB.GetSimApp().ICAHostKeeper.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, chanCap, channel.Counterparty, path.EndpointA.ChannelConfig.Version, + path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel.Counterparty, path.EndpointA.ChannelConfig.Version, ) if tc.expPass { diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index e00c28f72a9..f60ca2ee70c 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -44,7 +43,6 @@ func (im IBCMiddleware) OnChanOpenInit( connectionHops []string, portID string, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, ) (string, error) { @@ -63,7 +61,7 @@ func (im IBCMiddleware) OnChanOpenInit( // lower down in the stack. Thus, if it is not a fee version we pass the entire version string onto the underlying // application. return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, - chanCap, counterparty, version) + counterparty, version) } versionMetadata = metadata } @@ -72,7 +70,7 @@ func (im IBCMiddleware) OnChanOpenInit( return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) } - appVersion, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, versionMetadata.AppVersion) + appVersion, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, versionMetadata.AppVersion) if err != nil { return "", err } @@ -98,7 +96,6 @@ func (im IBCMiddleware) OnChanOpenTry( connectionHops []string, portID, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { @@ -107,7 +104,7 @@ func (im IBCMiddleware) OnChanOpenTry( // Since it is valid for fee version to not be specified, the above middleware version may be for a middleware // lower down in the stack. Thus, if it is not a fee version we pass the entire version string onto the underlying // application. - return im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, counterpartyVersion) + return im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, counterpartyVersion) } if versionMetadata.FeeVersion != types.Version { @@ -117,7 +114,7 @@ func (im IBCMiddleware) OnChanOpenTry( im.keeper.SetFeeEnabled(ctx, portID, channelID) // call underlying app's OnChanOpenTry callback with the app versions - appVersion, err := im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, versionMetadata.AppVersion) + appVersion, err := im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, versionMetadata.AppVersion) if err != nil { return "", err } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index b8bbd2eac52..3e1ac8d05e8 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -8,14 +8,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" ibcfee "github.com/cosmos/ibc-go/v8/modules/apps/29-fee" feekeeper "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v8/testing" ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" @@ -84,7 +82,7 @@ func (suite *FeeTestSuite) TestOnChanOpenInit() { // setup mock callback suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, + portID, channelID string, counterparty channeltypes.Counterparty, version string, ) (string, error) { if version != ibcmock.Version { @@ -107,14 +105,11 @@ func (suite *FeeTestSuite) TestOnChanOpenInit() { module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) suite.Require().NoError(err) - chanCap, err := suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) - suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) suite.Require().True(ok) version, err := cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, chanCap, counterparty, channel.Version) + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, counterparty, channel.Version) if tc.expPass { // check if the channel is fee enabled. If so version string should include metaData @@ -184,7 +179,7 @@ func (suite *FeeTestSuite) TestOnChanOpenTry() { // setup mock callback suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenTry = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, chanCap *capabilitytypes.Capability, + portID, channelID string, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { if counterpartyVersion != ibcmock.Version { @@ -193,13 +188,7 @@ func (suite *FeeTestSuite) TestOnChanOpenTry() { return ibcmock.Version, nil } - var ( - chanCap *capabilitytypes.Capability - ok bool - ) - - chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID)) - suite.Require().NoError(err) + var ok bool suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID @@ -219,7 +208,7 @@ func (suite *FeeTestSuite) TestOnChanOpenTry() { suite.Require().True(ok) _, err = cbs.OnChanOpenTry(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, chanCap, counterparty, tc.cpVersion) + suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, counterparty, tc.cpVersion) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 9ba056dd1dd..95b0a35e29b 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -10,7 +10,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/modules/apps/callbacks/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" @@ -313,11 +312,10 @@ func (im IBCMiddleware) OnChanOpenInit( connectionHops []string, portID, channelID string, - channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, ) (string, error) { - return im.app.OnChanOpenInit(ctx, channelOrdering, connectionHops, portID, channelID, channelCap, counterparty, version) + return im.app.OnChanOpenInit(ctx, channelOrdering, connectionHops, portID, channelID, counterparty, version) } // OnChanOpenTry defers to the underlying application @@ -326,11 +324,10 @@ func (im IBCMiddleware) OnChanOpenTry( channelOrdering channeltypes.Order, connectionHops []string, portID, channelID string, - channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { - return im.app.OnChanOpenTry(ctx, channelOrdering, connectionHops, portID, channelID, channelCap, counterparty, counterpartyVersion) + return im.app.OnChanOpenTry(ctx, channelOrdering, connectionHops, portID, channelID, counterparty, counterpartyVersion) } // OnChanOpenAck defers to the underlying application diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 6cf311ebbf7..3774020b639 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -10,7 +10,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/events" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" @@ -18,7 +17,6 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -80,7 +78,6 @@ func (im IBCModule) OnChanOpenInit( connectionHops []string, portID string, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, ) (string, error) { @@ -97,11 +94,6 @@ func (im IBCModule) OnChanOpenInit( return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected one of %s, got %s", types.SupportedVersions, version) } - // Claim channel capability passed back by IBC module - if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } - return version, nil } @@ -112,7 +104,6 @@ func (im IBCModule) OnChanOpenTry( connectionHops []string, portID, channelID string, - chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { @@ -120,11 +111,6 @@ func (im IBCModule) OnChanOpenTry( return "", err } - // OpenTry must claim the channelCapability that IBC passes into the callback - if err := im.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } - if !slices.Contains(types.SupportedVersions, counterpartyVersion) { im.keeper.Logger(ctx).Debug("invalid counterparty version, proposing latest app version", "counterpartyVersion", counterpartyVersion, "version", types.V2) return types.V2, nil diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 3e796a469cf..4da867b8687 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -10,14 +10,12 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -27,7 +25,6 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { var ( channel *channeltypes.Channel path *ibctesting.Path - chanCap *capabilitytypes.Capability counterparty channeltypes.Counterparty ) @@ -77,12 +74,6 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { channel.Version = "version" //nolint:goconst }, types.ErrInvalidVersion, "", }, - { - "capability already claimed", func() { - err := suite.chainA.GetSimApp().ScopedTransferKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().NoError(err) - }, capabilitytypes.ErrOwnerClaimed, "", - }, } for _, tc := range testCases { @@ -104,14 +95,12 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { } var err error - chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, path.EndpointA.ChannelID)) - suite.Require().NoError(err) tc.malleate() // explicitly change fields in channel and testChannel transferModule := transfer.NewIBCModule(suite.chainA.GetSimApp().TransferKeeper) version, err := transferModule.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, counterparty, channel.Version, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterparty, channel.Version, ) expPass := tc.expError == nil @@ -129,7 +118,6 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { func (suite *TransferTestSuite) TestOnChanOpenTry() { var ( channel *channeltypes.Channel - chanCap *capabilitytypes.Capability path *ibctesting.Path counterparty channeltypes.Counterparty counterpartyVersion string @@ -160,12 +148,6 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(math.MaxUint32 + 1) }, types.ErrMaxTransferChannels, "", }, - { - "failure: capability already claimed", func() { - err := suite.chainA.GetSimApp().ScopedTransferKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) - suite.Require().NoError(err) - }, capabilitytypes.ErrOwnerClaimed, "", - }, { "failure: invalid order - ORDERED", func() { channel.Ordering = channeltypes.ORDERED @@ -201,16 +183,13 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) suite.Require().NoError(err) - chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, path.EndpointA.ChannelID)) - suite.Require().NoError(err) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) suite.Require().True(ok) tc.malleate() // explicitly change fields in channel and testChannel version, err := cbs.OnChanOpenTry(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, counterpartyVersion, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel.Counterparty, counterpartyVersion, ) expPass := tc.expError == nil if expPass { diff --git a/modules/core/04-channel/keeper/handshake.go b/modules/core/04-channel/keeper/handshake.go index de6f3d09d13..e11035e1eb0 100644 --- a/modules/core/04-channel/keeper/handshake.go +++ b/modules/core/04-channel/keeper/handshake.go @@ -8,12 +8,9 @@ import ( "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -25,19 +22,18 @@ func (k *Keeper) ChanOpenInit( order types.Order, connectionHops []string, portID string, - portCap *capabilitytypes.Capability, counterparty types.Counterparty, version string, -) (string, *capabilitytypes.Capability, error) { +) (string, error) { // connection hop length checked on msg.ValidateBasic() connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { - return "", nil, errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, connectionHops[0]) + return "", errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, connectionHops[0]) } getVersions := connectionEnd.Versions if len(getVersions) != 1 { - return "", nil, errorsmod.Wrapf( + return "", errorsmod.Wrapf( connectiontypes.ErrInvalidVersion, "single version must be negotiated on connection before opening channel, got: %v", getVersions, @@ -45,7 +41,7 @@ func (k *Keeper) ChanOpenInit( } if !connectiontypes.VerifySupportedFeature(getVersions[0], order.String()) { - return "", nil, errorsmod.Wrapf( + return "", errorsmod.Wrapf( connectiontypes.ErrInvalidVersion, "connection version %s does not support channel ordering: %s", getVersions[0], order.String(), @@ -53,21 +49,12 @@ func (k *Keeper) ChanOpenInit( } if status := k.clientKeeper.GetClientStatus(ctx, connectionEnd.ClientId); status != exported.Active { - return "", nil, errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", connectionEnd.ClientId, status) - } - - if !k.portKeeper.Authenticate(ctx, portCap, portID) { - return "", nil, errorsmod.Wrapf(porttypes.ErrInvalidPort, "caller does not own port capability for port ID %s", portID) + return "", errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", connectionEnd.ClientId, status) } channelID := k.GenerateChannelIdentifier(ctx) - capKey, err := k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) - if err != nil { - return "", nil, errorsmod.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, channelID) - } - - return channelID, capKey, nil + return channelID, nil } // WriteOpenInitChannel writes a channel which has successfully passed the OpenInit handshake step. @@ -103,36 +90,31 @@ func (k *Keeper) ChanOpenTry( order types.Order, connectionHops []string, portID string, - portCap *capabilitytypes.Capability, counterparty types.Counterparty, counterpartyVersion string, initProof []byte, proofHeight exported.Height, -) (string, *capabilitytypes.Capability, error) { +) (string, error) { // connection hops only supports a single connection if len(connectionHops) != 1 { - return "", nil, errorsmod.Wrapf(types.ErrTooManyConnectionHops, "expected 1, got %d", len(connectionHops)) + return "", errorsmod.Wrapf(types.ErrTooManyConnectionHops, "expected 1, got %d", len(connectionHops)) } // generate a new channel channelID := k.GenerateChannelIdentifier(ctx) - if !k.portKeeper.Authenticate(ctx, portCap, portID) { - return "", nil, errorsmod.Wrapf(porttypes.ErrInvalidPort, "caller does not own port capability for port ID %s", portID) - } - connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0]) if !found { - return "", nil, errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, connectionHops[0]) + return "", errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, connectionHops[0]) } if connectionEnd.State != connectiontypes.OPEN { - return "", nil, errorsmod.Wrapf(connectiontypes.ErrInvalidConnectionState, "connection state is not OPEN (got %s)", connectionEnd.State) + return "", errorsmod.Wrapf(connectiontypes.ErrInvalidConnectionState, "connection state is not OPEN (got %s)", connectionEnd.State) } getVersions := connectionEnd.Versions if len(getVersions) != 1 { - return "", nil, errorsmod.Wrapf( + return "", errorsmod.Wrapf( connectiontypes.ErrInvalidVersion, "single version must be negotiated on connection before opening channel, got: %v", getVersions, @@ -140,7 +122,7 @@ func (k *Keeper) ChanOpenTry( } if !connectiontypes.VerifySupportedFeature(getVersions[0], order.String()) { - return "", nil, errorsmod.Wrapf( + return "", errorsmod.Wrapf( connectiontypes.ErrInvalidVersion, "connection version %s does not support channel ordering: %s", getVersions[0], order.String(), @@ -161,20 +143,10 @@ func (k *Keeper) ChanOpenTry( ctx, connectionEnd, proofHeight, initProof, counterparty.PortId, counterparty.ChannelId, expectedChannel, ); err != nil { - return "", nil, err - } - - var ( - capKey *capabilitytypes.Capability - err error - ) - - capKey, err = k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) - if err != nil { - return "", nil, errorsmod.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, channelID) + return "", err } - return channelID, capKey, nil + return channelID, nil } // WriteOpenTryChannel writes a channel which has successfully passed the OpenTry handshake step. @@ -210,7 +182,6 @@ func (k *Keeper) ChanOpenAck( ctx sdk.Context, portID, channelID string, - chanCap *capabilitytypes.Capability, counterpartyVersion, counterpartyChannelID string, tryProof []byte, @@ -225,10 +196,6 @@ func (k *Keeper) ChanOpenAck( return errorsmod.Wrapf(types.ErrInvalidChannelState, "channel state should be INIT (got %s)", channel.State) } - if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { - return errorsmod.Wrapf(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)", portID, channelID) - } - connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { return errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) @@ -285,7 +252,6 @@ func (k *Keeper) ChanOpenConfirm( ctx sdk.Context, portID, channelID string, - chanCap *capabilitytypes.Capability, ackProof []byte, proofHeight exported.Height, ) error { @@ -301,10 +267,6 @@ func (k *Keeper) ChanOpenConfirm( ) } - if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { - return errorsmod.Wrapf(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)", portID, channelID) - } - connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) if !found { return errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) @@ -362,12 +324,7 @@ func (k *Keeper) ChanCloseInit( ctx sdk.Context, portID, channelID string, - chanCap *capabilitytypes.Capability, ) error { - if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { - return errorsmod.Wrapf(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)", portID, channelID) - } - channel, found := k.GetChannel(ctx, portID, channelID) if !found { return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) @@ -408,15 +365,10 @@ func (k *Keeper) ChanCloseConfirm( ctx sdk.Context, portID, channelID string, - chanCap *capabilitytypes.Capability, initProof []byte, proofHeight exported.Height, counterpartyUpgradeSequence uint64, ) error { - if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { - return errorsmod.Wrapf(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)", portID, channelID) - } - channel, found := k.GetChannel(ctx, portID, channelID) if !found { return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) diff --git a/modules/core/04-channel/keeper/handshake_test.go b/modules/core/04-channel/keeper/handshake_test.go index c522f0ba31a..036be4eeb61 100644 --- a/modules/core/04-channel/keeper/handshake_test.go +++ b/modules/core/04-channel/keeper/handshake_test.go @@ -3,7 +3,6 @@ package keeper_test import ( "fmt" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -27,7 +26,6 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { var ( path *ibctesting.Path features []string - portCap *capabilitytypes.Capability expErrorMsgSubstring string ) @@ -36,21 +34,12 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { path.SetupConnections() features = []string{"ORDER_ORDERED", "ORDER_UNORDERED"} suite.chainA.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) - portCap = suite.chainA.GetPortCapability(ibctesting.MockPort) }, true}, - {"channel already exists", func() { - path.Setup() - }, false}, {"connection doesn't exist", func() { // any non-empty values path.EndpointA.ConnectionID = "connection-0" path.EndpointB.ConnectionID = "connection-0" }, false}, - {"capability is incorrect", func() { - path.SetupConnections() - features = []string{"ORDER_ORDERED", "ORDER_UNORDERED"} - portCap = capabilitytypes.NewCapability(3) - }, false}, {"connection version not negotiated", func() { path.SetupConnections() @@ -61,7 +50,6 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { features = []string{"ORDER_ORDERED", "ORDER_UNORDERED"} suite.chainA.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) - portCap = suite.chainA.GetPortCapability(ibctesting.MockPort) }, false}, {"connection does not support ORDERED channels", func() { path.SetupConnections() @@ -74,7 +62,6 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { // NOTE: Opening UNORDERED channels is still expected to pass but ORDERED channels should fail features = []string{"ORDER_UNORDERED"} suite.chainA.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) - portCap = suite.chainA.GetPortCapability(ibctesting.MockPort) }, true}, { msg: "unauthorized client", @@ -89,7 +76,6 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { suite.chainA.App.GetIBCKeeper().ClientKeeper.SetParams(suite.chainA.GetContext(), params) suite.chainA.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) - portCap = suite.chainA.GetPortCapability(ibctesting.MockPort) }, }, } @@ -109,9 +95,9 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { counterparty := types.NewCounterparty(ibctesting.MockPort, ibctesting.FirstChannelID) - channelID, capability, err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.ChanOpenInit( + channelID, err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.ChanOpenInit( suite.chainA.GetContext(), path.EndpointA.ChannelConfig.Order, []string{path.EndpointA.ConnectionID}, - path.EndpointA.ChannelConfig.PortID, portCap, counterparty, path.EndpointA.ChannelConfig.Version, + path.EndpointA.ChannelConfig.PortID, counterparty, path.EndpointA.ChannelConfig.Version, ) // check if order is supported by channel to determine expected behaviour @@ -126,19 +112,10 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { // asserting the channel handshake initiation succeeded if tc.expPass && orderSupported { suite.Require().NoError(err) - suite.Require().NotNil(capability) suite.Require().Equal(types.FormatChannelIdentifier(0), channelID) - - chanCap, ok := suite.chainA.App.GetScopedIBCKeeper().GetCapability( - suite.chainA.GetContext(), - host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, channelID), - ) - suite.Require().True(ok, "could not retrieve channel capability after successful ChanOpenInit") - suite.Require().Equal(chanCap.String(), capability.String(), "channel capability is not correct") } else { suite.Require().Error(err) suite.Require().Contains(err.Error(), expErrorMsgSubstring) - suite.Require().Nil(capability) suite.Require().Equal("", channelID) } } @@ -153,7 +130,6 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { func (suite *KeeperTestSuite) TestChanOpenTry() { var ( path *ibctesting.Path - portCap *capabilitytypes.Capability heightDiff uint64 ) @@ -165,7 +141,6 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { suite.Require().NoError(err) suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) - portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) }, true}, {"connection doesn't exist", func() { path.EndpointA.ConnectionID = ibctesting.FirstConnectionID @@ -173,13 +148,11 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { // pass capability check suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) - portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) }, false}, {"connection is not OPEN", func() { path.SetupClients() // pass capability check suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) - portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) err := path.EndpointB.ConnOpenInit() suite.Require().NoError(err) @@ -191,22 +164,12 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { suite.Require().NoError(err) suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) - portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) heightDiff = 3 // consensus state doesn't exist at this height }, false}, {"channel verification failed", func() { // not creating a channel on chainA will result in an invalid proof of existence path.SetupConnections() - portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) - }, false}, - {"port capability not found", func() { - path.SetupConnections() - path.SetChannelOrdered() - err := path.EndpointA.ChanOpenInit() - suite.Require().NoError(err) - - portCap = capabilitytypes.NewCapability(3) }, false}, {"connection version not negotiated", func() { path.SetupConnections() @@ -220,7 +183,6 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { }) suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) - portCap = suite.chainB.GetPortCapability(ibctesting.MockPort) }, false}, {"connection does not support ORDERED channels", func() { path.SetupConnections() @@ -229,12 +191,11 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { suite.Require().NoError(err) // modify connA versions to only support UNORDERED channels - path.EndpointA.UpdateConnection(func(c *connectiontypes.ConnectionEnd) { + path.EndpointB.UpdateConnection(func(c *connectiontypes.ConnectionEnd) { c.Versions = []*connectiontypes.Version{connectiontypes.NewVersion("1", []string{"ORDER_UNORDERED"})} }) - suite.chainA.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) - portCap = suite.chainA.GetPortCapability(ibctesting.MockPort) + suite.chainB.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort) }, false}, } @@ -258,22 +219,14 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { channelKey := host.ChannelKey(counterparty.PortId, counterparty.ChannelId) proof, proofHeight := suite.chainA.QueryProof(channelKey) - channelID, capability, err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.ChanOpenTry( + _, err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.ChanOpenTry( suite.chainB.GetContext(), types.ORDERED, []string{path.EndpointB.ConnectionID}, - path.EndpointB.ChannelConfig.PortID, portCap, counterparty, path.EndpointA.ChannelConfig.Version, + path.EndpointB.ChannelConfig.PortID, counterparty, path.EndpointA.ChannelConfig.Version, proof, malleateHeight(proofHeight, heightDiff), ) if tc.expPass { suite.Require().NoError(err) - suite.Require().NotNil(capability) - - chanCap, ok := suite.chainB.App.GetScopedIBCKeeper().GetCapability( - suite.chainB.GetContext(), - host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, channelID), - ) - suite.Require().True(ok, "could not retrieve channel capability after successful ChanOpenTry") - suite.Require().Equal(chanCap.String(), capability.String(), "channel capability is not correct") } else { suite.Require().Error(err) } @@ -288,7 +241,6 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { var ( path *ibctesting.Path counterpartyChannelID string - channelCap *capabilitytypes.Capability heightDiff uint64 ) @@ -301,8 +253,6 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { err = path.EndpointB.ChanOpenTry() suite.Require().NoError(err) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"success with empty stored counterparty channel ID", func() { path.SetupConnections() @@ -322,14 +272,11 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { counterpartyChannelID = path.EndpointB.ChannelID suite.chainA.App.GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"channel doesn't exist", func() {}, false}, {"channel state is not INIT", func() { // create fully open channels on both chains path.Setup() - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"connection not found", func() { path.SetupConnections() @@ -340,8 +287,6 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { err = path.EndpointB.ChanOpenTry() suite.Require().NoError(err) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - // set the channel's connection hops to wrong connection ID channel := path.EndpointA.GetChannel() channel.ConnectionHops[0] = doesnotexist @@ -360,7 +305,6 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { suite.Require().NoError(err) suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"consensus state not found", func() { path.SetupConnections() @@ -372,8 +316,6 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { err = path.EndpointB.ChanOpenTry() suite.Require().NoError(err) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - heightDiff = 3 // consensus state doesn't exist at this height }, false}, {"invalid counterparty channel identifier", func() { @@ -387,8 +329,6 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { suite.Require().NoError(err) counterpartyChannelID = "otheridentifier" - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"channel verification failed", func() { // chainB is INIT, chainA in TRYOPEN @@ -400,19 +340,6 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { err = path.EndpointA.ChanOpenTry() suite.Require().NoError(err) - - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - }, false}, - {"channel capability not found", func() { - path.SetupConnections() - path.SetChannelOrdered() - err := path.EndpointA.ChanOpenInit() - suite.Require().NoError(err) - - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) - - channelCap = capabilitytypes.NewCapability(6) }, false}, } @@ -440,7 +367,7 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { proof, proofHeight := suite.chainB.QueryProof(channelKey) err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.ChanOpenAck( - suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channelCap, path.EndpointB.ChannelConfig.Version, counterpartyChannelID, + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.Version, counterpartyChannelID, proof, malleateHeight(proofHeight, heightDiff), ) @@ -459,7 +386,6 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { func (suite *KeeperTestSuite) TestChanOpenConfirm() { var ( path *ibctesting.Path - channelCap *capabilitytypes.Capability heightDiff uint64 ) testCases := []testCase{ @@ -475,14 +401,11 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { err = path.EndpointA.ChanOpenAck() suite.Require().NoError(err) - - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, true}, {"channel doesn't exist", func() {}, false}, {"channel state is not TRYOPEN", func() { // create fully open channels on both chains path.Setup() - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, false}, {"connection not found", func() { path.SetupConnections() @@ -497,8 +420,6 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { err = path.EndpointA.ChanOpenAck() suite.Require().NoError(err) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - // set the channel's connection hops to wrong connection ID channel := path.EndpointB.GetChannel() channel.ConnectionHops[0] = doesnotexist @@ -511,7 +432,6 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { suite.Require().NoError(err) suite.chainB.CreateChannelCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID) }, false}, {"consensus state not found", func() { path.SetupConnections() @@ -526,8 +446,6 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { err = path.EndpointA.ChanOpenAck() suite.Require().NoError(err) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - heightDiff = 3 }, false}, {"channel verification failed", func() { @@ -540,23 +458,6 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { err = path.EndpointB.ChanOpenTry() suite.Require().NoError(err) - - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - }, false}, - {"channel capability not found", func() { - path.SetupConnections() - path.SetChannelOrdered() - - err := path.EndpointA.ChanOpenInit() - suite.Require().NoError(err) - - err = path.EndpointB.ChanOpenTry() - suite.Require().NoError(err) - - err = path.EndpointA.ChanOpenAck() - suite.Require().NoError(err) - - channelCap = capabilitytypes.NewCapability(6) }, false}, } @@ -580,8 +481,7 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { proof, proofHeight := suite.chainA.QueryProof(channelKey) err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.ChanOpenConfirm( - suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, - channelCap, proof, malleateHeight(proofHeight, heightDiff), + suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, proof, malleateHeight(proofHeight, heightDiff), ) if tc.expPass { @@ -598,14 +498,12 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { func (suite *KeeperTestSuite) TestChanCloseInit() { var ( path *ibctesting.Path - channelCap *capabilitytypes.Capability expErrorMsgSubstring string ) testCases := []testCase{ {"success", func() { path.Setup() - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, true}, {"channel doesn't exist", func() { // any non-nil values work for connections @@ -617,18 +515,15 @@ func (suite *KeeperTestSuite) TestChanCloseInit() { // ensure channel capability check passes suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"channel state is CLOSED", func() { path.Setup() - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) // close channel path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) }, false}, {"connection not found", func() { path.Setup() - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) // set the channel's connection hops to wrong connection ID channel := path.EndpointA.GetChannel() @@ -648,18 +543,12 @@ func (suite *KeeperTestSuite) TestChanCloseInit() { // ensure channel capability check passes suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - }, false}, - {"channel capability not found", func() { - path.Setup() - channelCap = capabilitytypes.NewCapability(3) }, false}, { msg: "unauthorized client", expPass: false, malleate: func() { path.Setup() - channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) // remove client from allowed list params := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetParams(suite.chainA.GetContext()) @@ -680,7 +569,7 @@ func (suite *KeeperTestSuite) TestChanCloseInit() { tc.malleate() err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.ChanCloseInit( - suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channelCap, + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ) if tc.expPass { @@ -699,7 +588,6 @@ func (suite *KeeperTestSuite) TestChanCloseInit() { func (suite *KeeperTestSuite) TestChanCloseConfirm() { var ( path *ibctesting.Path - channelCap *capabilitytypes.Capability heightDiff uint64 counterpartyUpgradeSequence uint64 ) @@ -707,13 +595,11 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() { testCases := []testCase{ {"success", func() { path.Setup() - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) }, true}, {"success with upgrade info", func() { path.Setup() - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) err := path.EndpointA.SetChannelState(types.CLOSED) suite.Require().NoError(err) @@ -740,17 +626,14 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() { // ensure channel capability check passes suite.chainB.CreateChannelCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID) }, false}, {"channel state is CLOSED", func() { path.Setup() - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) }, false}, {"connection not found", func() { path.Setup() - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) // set the channel's connection hops to wrong connection ID channel := path.EndpointB.GetChannel() @@ -770,11 +653,9 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() { // ensure channel capability check passes suite.chainB.CreateChannelCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, false}, {"consensus state not found", func() { path.Setup() - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) @@ -783,30 +664,17 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() { {"channel verification failed", func() { // channel not closed path.Setup() - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - }, false}, - {"channel capability not found", func() { - path.Setup() - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - - path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) - - channelCap = capabilitytypes.NewCapability(3) }, false}, { "failure: invalid counterparty upgrade sequence", func() { path.Setup() - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - - // trigger upgradeInit on B which will bump the counterparty upgrade sequence. - path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion - err := path.EndpointB.ChanUpgradeInit() + // trigger upgradeInit on A which will bump the counterparty upgrade sequence. + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + err := path.EndpointA.ChanUpgradeInit() suite.Require().NoError(err) path.EndpointA.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) - - channelCap = capabilitytypes.NewCapability(3) }, false, }, @@ -827,7 +695,7 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() { ctx := suite.chainB.GetContext() err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.ChanCloseConfirm( - ctx, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channelCap, + ctx, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, proof, malleateHeight(proofHeight, heightDiff), counterpartyUpgradeSequence, ) diff --git a/modules/core/05-port/keeper/keeper.go b/modules/core/05-port/keeper/keeper.go index 93ef74bc79b..20b1108c1c8 100644 --- a/modules/core/05-port/keeper/keeper.go +++ b/modules/core/05-port/keeper/keeper.go @@ -87,7 +87,19 @@ func (k *Keeper) LookupModuleByPort(ctx sdk.Context, portID string) (string, *ca // Route returns a IBCModule for a given module, and a boolean indicating // whether or not the route is present. func (k *Keeper) Route(module string) (types.IBCModule, bool) { - return k.Router.GetRoute(module) + routes, ok := k.Router.GetRoute(module) + + if ok { + return routes, true + } + + for _, prefix := range k.Keys() { + if strings.Contains(module, prefix) { + return k.Router.GetRoute(prefix) + } + } + + return nil, false } // AppRoute returns an ordered list of IBCModule callbacks for a given module name, and a boolean indicating diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index a7312fb846a..149702f24fb 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -3,7 +3,6 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" @@ -28,7 +27,6 @@ type IBCModule interface { connectionHops []string, portID string, channelID string, - channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, ) (string, error) @@ -47,7 +45,6 @@ type IBCModule interface { connectionHops []string, portID, channelID string, - channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (version string, err error) diff --git a/modules/core/ante/ante.go b/modules/core/ante/ante.go index 0e483f6ee64..5e32230e929 100644 --- a/modules/core/ante/ante.go +++ b/modules/core/ante/ante.go @@ -108,16 +108,10 @@ func (rrd RedundantRelayDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula // recvPacketCheckTx runs a subset of ibc recv packet logic to be used specifically within the RedundantRelayDecorator AnteHandler. // It only performs core IBC receiving logic and skips any application logic. func (rrd RedundantRelayDecorator) recvPacketCheckTx(ctx sdk.Context, msg *channeltypes.MsgRecvPacket) (*channeltypes.MsgRecvPacketResponse, error) { - // grab channel capability - _, _, err := rrd.k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel) - if err != nil { - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // If the packet was already received, perform a no-op // Use a cached context to prevent accidental state changes cacheCtx, writeFn := ctx.CacheContext() - err = rrd.k.ChannelKeeper.RecvPacket(cacheCtx, msg.Packet, msg.ProofCommitment, msg.ProofHeight) + err := rrd.k.ChannelKeeper.RecvPacket(cacheCtx, msg.Packet, msg.ProofCommitment, msg.ProofHeight) switch err { case nil: diff --git a/modules/core/ante/ante_test.go b/modules/core/ante/ante_test.go index 4f998f05d62..757fca29d98 100644 --- a/modules/core/ante/ante_test.go +++ b/modules/core/ante/ante_test.go @@ -10,7 +10,6 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" @@ -503,15 +502,6 @@ func (suite *AnteTestSuite) TestAnteDecoratorCheckTx() { }, channeltypes.ErrRedundantTx, }, - { - "no success on recvPacket checkTx, no capability found", - func(suite *AnteTestSuite) []sdk.Msg { - msg := suite.createRecvPacketMessage(false) - msg.Packet.DestinationPort = "invalid-port" - return []sdk.Msg{msg} - }, - capabilitytypes.ErrCapabilityNotFound, - }, } for _, tc := range testCases { diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 1b276a5fa9f..0e98ba20bb0 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -204,24 +204,17 @@ func (k *Keeper) ConnectionOpenConfirm(goCtx context.Context, msg *connectiontyp func (k *Keeper) ChannelOpenInit(goCtx context.Context, msg *channeltypes.MsgChannelOpenInit) (*channeltypes.MsgChannelOpenInitResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // Lookup module by port capability - module, portCap, err := k.PortKeeper.LookupModuleByPort(ctx, msg.PortId) - if err != nil { - ctx.Logger().Error("channel open init failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve application callbacks from router - cbs, ok := k.PortKeeper.Route(module) + cbs, ok := k.PortKeeper.Route(msg.PortId) if !ok { - ctx.Logger().Error("channel open init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel open init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) } // Perform 04-channel verification - channelID, capability, err := k.ChannelKeeper.ChanOpenInit( + channelID, err := k.ChannelKeeper.ChanOpenInit( ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, - portCap, msg.Channel.Counterparty, msg.Channel.Version, + msg.Channel.Counterparty, msg.Channel.Version, ) if err != nil { ctx.Logger().Error("channel open init failed", "error", errorsmod.Wrap(err, "channel handshake open init failed")) @@ -229,7 +222,7 @@ func (k *Keeper) ChannelOpenInit(goCtx context.Context, msg *channeltypes.MsgCha } // Perform application logic callback - version, err := cbs.OnChanOpenInit(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, channelID, capability, msg.Channel.Counterparty, msg.Channel.Version) + version, err := cbs.OnChanOpenInit(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, channelID, msg.Channel.Counterparty, msg.Channel.Version) if err != nil { ctx.Logger().Error("channel open init failed", "port-id", msg.PortId, "channel-id", channelID, "error", errorsmod.Wrap(err, "channel open init callback failed")) return nil, errorsmod.Wrapf(err, "channel open init callback failed for port ID: %s, channel ID: %s", msg.PortId, channelID) @@ -252,23 +245,16 @@ func (k *Keeper) ChannelOpenInit(goCtx context.Context, msg *channeltypes.MsgCha func (k *Keeper) ChannelOpenTry(goCtx context.Context, msg *channeltypes.MsgChannelOpenTry) (*channeltypes.MsgChannelOpenTryResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // Lookup module by port capability - module, portCap, err := k.PortKeeper.LookupModuleByPort(ctx, msg.PortId) - if err != nil { - ctx.Logger().Error("channel open try failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve application callbacks from router - cbs, ok := k.PortKeeper.Route(module) + cbs, ok := k.PortKeeper.Route(msg.PortId) if !ok { - ctx.Logger().Error("channel open try failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel open try failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) } // Perform 04-channel verification - channelID, capability, err := k.ChannelKeeper.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, - portCap, msg.Channel.Counterparty, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, + channelID, err := k.ChannelKeeper.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, + msg.Channel.Counterparty, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, ) if err != nil { ctx.Logger().Error("channel open try failed", "error", errorsmod.Wrap(err, "channel handshake open try failed")) @@ -276,7 +262,7 @@ func (k *Keeper) ChannelOpenTry(goCtx context.Context, msg *channeltypes.MsgChan } // Perform application logic callback - version, err := cbs.OnChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, channelID, capability, msg.Channel.Counterparty, msg.CounterpartyVersion) + version, err := cbs.OnChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, channelID, msg.Channel.Counterparty, msg.CounterpartyVersion) if err != nil { ctx.Logger().Error("channel open try failed", "port-id", msg.PortId, "channel-id", channelID, "error", errorsmod.Wrap(err, "channel open try callback failed")) return nil, errorsmod.Wrapf(err, "channel open try callback failed for port ID: %s, channel ID: %s", msg.PortId, channelID) @@ -299,23 +285,16 @@ func (k *Keeper) ChannelOpenTry(goCtx context.Context, msg *channeltypes.MsgChan func (k *Keeper) ChannelOpenAck(goCtx context.Context, msg *channeltypes.MsgChannelOpenAck) (*channeltypes.MsgChannelOpenAckResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // Lookup module by channel capability - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("channel open ack failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve application callbacks from router - cbs, ok := k.PortKeeper.Route(module) + cbs, ok := k.PortKeeper.Route(msg.PortId) if !ok { - ctx.Logger().Error("channel open ack failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel open ack failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) } // Perform 04-channel verification - if err = k.ChannelKeeper.ChanOpenAck( - ctx, msg.PortId, msg.ChannelId, capability, msg.CounterpartyVersion, msg.CounterpartyChannelId, msg.ProofTry, msg.ProofHeight, + if err := k.ChannelKeeper.ChanOpenAck( + ctx, msg.PortId, msg.ChannelId, msg.CounterpartyVersion, msg.CounterpartyChannelId, msg.ProofTry, msg.ProofHeight, ); err != nil { ctx.Logger().Error("channel open ack failed", "error", err.Error()) return nil, errorsmod.Wrap(err, "channel handshake open ack failed") @@ -325,7 +304,7 @@ func (k *Keeper) ChannelOpenAck(goCtx context.Context, msg *channeltypes.MsgChan k.ChannelKeeper.WriteOpenAckChannel(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyVersion, msg.CounterpartyChannelId) // Perform application logic callback - if err = cbs.OnChanOpenAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannelId, msg.CounterpartyVersion); err != nil { + if err := cbs.OnChanOpenAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannelId, msg.CounterpartyVersion); err != nil { ctx.Logger().Error("channel open ack failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "channel open ack callback failed")) return nil, errorsmod.Wrapf(err, "channel open ack callback failed for port ID: %s, channel ID: %s", msg.PortId, msg.ChannelId) } @@ -341,22 +320,15 @@ func (k *Keeper) ChannelOpenAck(goCtx context.Context, msg *channeltypes.MsgChan func (k *Keeper) ChannelOpenConfirm(goCtx context.Context, msg *channeltypes.MsgChannelOpenConfirm) (*channeltypes.MsgChannelOpenConfirmResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // Lookup module by channel capability - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("channel open confirm failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve application callbacks from router - cbs, ok := k.PortKeeper.Route(module) + cbs, ok := k.PortKeeper.Route(msg.PortId) if !ok { - ctx.Logger().Error("channel open confirm failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel open confirm failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) } // Perform 04-channel verification - if err = k.ChannelKeeper.ChanOpenConfirm(ctx, msg.PortId, msg.ChannelId, capability, msg.ProofAck, msg.ProofHeight); err != nil { + if err := k.ChannelKeeper.ChanOpenConfirm(ctx, msg.PortId, msg.ChannelId, msg.ProofAck, msg.ProofHeight); err != nil { ctx.Logger().Error("channel open confirm failed", "error", errorsmod.Wrap(err, "channel handshake open confirm failed")) return nil, errorsmod.Wrap(err, "channel handshake open confirm failed") } @@ -365,7 +337,7 @@ func (k *Keeper) ChannelOpenConfirm(goCtx context.Context, msg *channeltypes.Msg k.ChannelKeeper.WriteOpenConfirmChannel(ctx, msg.PortId, msg.ChannelId) // Perform application logic callback - if err = cbs.OnChanOpenConfirm(ctx, msg.PortId, msg.ChannelId); err != nil { + if err := cbs.OnChanOpenConfirm(ctx, msg.PortId, msg.ChannelId); err != nil { ctx.Logger().Error("channel open confirm failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "channel open confirm callback failed")) return nil, errorsmod.Wrapf(err, "channel open confirm callback failed for port ID: %s, channel ID: %s", msg.PortId, msg.ChannelId) } @@ -379,26 +351,19 @@ func (k *Keeper) ChannelOpenConfirm(goCtx context.Context, msg *channeltypes.Msg func (k *Keeper) ChannelCloseInit(goCtx context.Context, msg *channeltypes.MsgChannelCloseInit) (*channeltypes.MsgChannelCloseInitResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // Lookup module by channel capability - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("channel close init failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(module) + cbs, ok := k.PortKeeper.Route(msg.PortId) if !ok { - ctx.Logger().Error("channel close init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel close init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) } - if err = cbs.OnChanCloseInit(ctx, msg.PortId, msg.ChannelId); err != nil { + if err := cbs.OnChanCloseInit(ctx, msg.PortId, msg.ChannelId); err != nil { ctx.Logger().Error("channel close init failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "channel close init callback failed")) return nil, errorsmod.Wrapf(err, "channel close init callback failed for port ID: %s, channel ID: %s", msg.PortId, msg.ChannelId) } - err = k.ChannelKeeper.ChanCloseInit(ctx, msg.PortId, msg.ChannelId, capability) + err := k.ChannelKeeper.ChanCloseInit(ctx, msg.PortId, msg.ChannelId) if err != nil { ctx.Logger().Error("channel close init failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", err.Error()) return nil, errorsmod.Wrap(err, "channel handshake close init failed") @@ -413,26 +378,19 @@ func (k *Keeper) ChannelCloseInit(goCtx context.Context, msg *channeltypes.MsgCh func (k *Keeper) ChannelCloseConfirm(goCtx context.Context, msg *channeltypes.MsgChannelCloseConfirm) (*channeltypes.MsgChannelCloseConfirmResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // Lookup module by channel capability - module, capability, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("channel close confirm failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(module) + cbs, ok := k.PortKeeper.Route(msg.PortId) if !ok { - ctx.Logger().Error("channel close confirm failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel close confirm failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) } - if err = cbs.OnChanCloseConfirm(ctx, msg.PortId, msg.ChannelId); err != nil { + if err := cbs.OnChanCloseConfirm(ctx, msg.PortId, msg.ChannelId); err != nil { ctx.Logger().Error("channel close confirm failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", errorsmod.Wrap(err, "channel close confirm callback failed")) return nil, errorsmod.Wrapf(err, "channel close confirm callback failed for port ID: %s, channel ID: %s", msg.PortId, msg.ChannelId) } - err = k.ChannelKeeper.ChanCloseConfirm(ctx, msg.PortId, msg.ChannelId, capability, msg.ProofInit, msg.ProofHeight, msg.CounterpartyUpgradeSequence) + err := k.ChannelKeeper.ChanCloseConfirm(ctx, msg.PortId, msg.ChannelId, msg.ProofInit, msg.ProofHeight, msg.CounterpartyUpgradeSequence) if err != nil { ctx.Logger().Error("channel close confirm failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", err.Error()) return nil, errorsmod.Wrap(err, "channel handshake close confirm failed") @@ -488,18 +446,11 @@ func (k *Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPack return nil, errorsmod.Wrap(err, "Invalid address for msg Signer") } - // Lookup module by channel capability - module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.DestinationPort, msg.Packet.DestinationChannel) - if err != nil { - ctx.Logger().Error("receive packet failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(module) + cbs, ok := k.PortKeeper.Route(msg.Packet.DestinationPort) if !ok { - ctx.Logger().Error("receive packet failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("receive packet failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.DestinationPort)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.DestinationPort) } // Perform TAO verification @@ -560,18 +511,11 @@ func (k *Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (* return nil, errorsmod.Wrap(err, "Invalid address for msg Signer") } - // Lookup module by channel capability - module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.SourcePort, msg.Packet.SourceChannel) - if err != nil { - ctx.Logger().Error("timeout failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(module) + cbs, ok := k.PortKeeper.Route(msg.Packet.SourcePort) if !ok { - ctx.Logger().Error("timeout failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("timeout failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort) } // Perform TAO verification @@ -622,18 +566,11 @@ func (k *Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTime return nil, errorsmod.Wrap(err, "Invalid address for msg Signer") } - // Lookup module by channel capability - module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.SourcePort, msg.Packet.SourceChannel) - if err != nil { - ctx.Logger().Error("timeout on close failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(module) + cbs, ok := k.PortKeeper.Route(msg.Packet.SourcePort) if !ok { - ctx.Logger().Error("timeout on close failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("timeout on close failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort) } // Perform TAO verification @@ -687,18 +624,11 @@ func (k *Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAck return nil, errorsmod.Wrap(err, "Invalid address for msg Signer") } - // Lookup module by channel capability - module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.Packet.SourcePort, msg.Packet.SourceChannel) - if err != nil { - ctx.Logger().Error("acknowledgement failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(module) + cbs, ok := k.PortKeeper.Route(msg.Packet.SourcePort) if !ok { - ctx.Logger().Error("acknowledgement failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("acknowledgement failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort) } // Perform TAO verification @@ -742,22 +672,16 @@ func (k *Keeper) ChannelUpgradeInit(goCtx context.Context, msg *channeltypes.Msg return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "expected %s, got %s", k.GetAuthority(), msg.Signer) } - module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("channel upgrade init failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - - app, ok := k.PortKeeper.Route(module) + app, ok := k.PortKeeper.Route(msg.PortId) if !ok { - ctx.Logger().Error("channel upgrade init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel upgrade init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) } cbs, ok := app.(porttypes.UpgradableModule) if !ok { - ctx.Logger().Error("channel upgrade init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module) + ctx.Logger().Error("channel upgrade init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", msg.PortId) } upgrade, err := k.ChannelKeeper.ChanUpgradeInit(ctx, msg.PortId, msg.ChannelId, msg.Fields) @@ -790,22 +714,16 @@ func (k *Keeper) ChannelUpgradeInit(goCtx context.Context, msg *channeltypes.Msg func (k *Keeper) ChannelUpgradeTry(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeTry) (*channeltypes.MsgChannelUpgradeTryResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("channel upgrade try failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - - app, ok := k.PortKeeper.Route(module) + app, ok := k.PortKeeper.Route(msg.PortId) if !ok { - ctx.Logger().Error("channel upgrade try failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + ctx.Logger().Error("channel upgrade try failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) } cbs, ok := app.(porttypes.UpgradableModule) if !ok { - ctx.Logger().Error("channel upgrade try failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module) + ctx.Logger().Error("channel upgrade try failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", msg.PortId)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", msg.PortId) } channel, upgrade, err := k.ChannelKeeper.ChanUpgradeTry(ctx, msg.PortId, msg.ChannelId, msg.ProposedUpgradeConnectionHops, msg.CounterpartyUpgradeFields, msg.CounterpartyUpgradeSequence, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) @@ -851,27 +769,21 @@ func (k *Keeper) ChannelUpgradeTry(goCtx context.Context, msg *channeltypes.MsgC func (k *Keeper) ChannelUpgradeAck(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeAck) (*channeltypes.MsgChannelUpgradeAckResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - - app, ok := k.PortKeeper.Route(module) + app, ok := k.PortKeeper.Route(msg.PortId) if !ok { - err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + err := errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", err) return nil, err } cbs, ok := app.(porttypes.UpgradableModule) if !ok { - err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module) + err := errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", msg.PortId) ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", err) return nil, err } - err = k.ChannelKeeper.ChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) + err := k.ChannelKeeper.ChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) if err != nil { ctx.Logger().Error("channel upgrade ack failed", "error", errorsmod.Wrap(err, "channel upgrade ack failed")) if channeltypes.IsUpgradeError(err) { @@ -917,27 +829,21 @@ func (k *Keeper) ChannelUpgradeAck(goCtx context.Context, msg *channeltypes.MsgC func (k *Keeper) ChannelUpgradeConfirm(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeConfirm) (*channeltypes.MsgChannelUpgradeConfirmResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("channel upgrade confirm failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - - app, ok := k.PortKeeper.Route(module) + app, ok := k.PortKeeper.Route(msg.PortId) if !ok { - err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + err := errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) ctx.Logger().Error("channel upgrade confirm failed", "port-id", msg.PortId, "error", err) return nil, err } cbs, ok := app.(porttypes.UpgradableModule) if !ok { - err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module) + err := errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", msg.PortId) ctx.Logger().Error("channel upgrade confirm failed", "port-id", msg.PortId, "error", err) return nil, err } - err = k.ChannelKeeper.ChanUpgradeConfirm(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannelState, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) + err := k.ChannelKeeper.ChanUpgradeConfirm(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannelState, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) if err != nil { ctx.Logger().Error("channel upgrade confirm failed", "error", errorsmod.Wrap(err, "channel upgrade confirm failed")) if channeltypes.IsUpgradeError(err) { @@ -978,27 +884,21 @@ func (k *Keeper) ChannelUpgradeConfirm(goCtx context.Context, msg *channeltypes. func (k *Keeper) ChannelUpgradeOpen(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeOpen) (*channeltypes.MsgChannelUpgradeOpenResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("channel upgrade open failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - - app, ok := k.PortKeeper.Route(module) + app, ok := k.PortKeeper.Route(msg.PortId) if !ok { - err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + err := errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) ctx.Logger().Error("channel upgrade open failed", "port-id", msg.PortId, "error", err) return nil, err } cbs, ok := app.(porttypes.UpgradableModule) if !ok { - err = errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", module) + err := errorsmod.Wrapf(porttypes.ErrInvalidRoute, "upgrade route not found to module: %s", msg.PortId) ctx.Logger().Error("channel upgrade open failed", "port-id", msg.PortId, "error", err) return nil, err } - if err = k.ChannelKeeper.ChanUpgradeOpen(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannelState, msg.CounterpartyUpgradeSequence, msg.ProofChannel, msg.ProofHeight); err != nil { + if err := k.ChannelKeeper.ChanUpgradeOpen(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannelState, msg.CounterpartyUpgradeSequence, msg.ProofChannel, msg.ProofHeight); err != nil { ctx.Logger().Error("channel upgrade open failed", "error", errorsmod.Wrap(err, "channel upgrade open failed")) return nil, errorsmod.Wrap(err, "channel upgrade open failed") } diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index b9e744ecc58..6cdd2342be2 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -11,7 +11,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -1098,20 +1097,6 @@ func (suite *KeeperTestSuite) TestChannelUpgradeTry() { ibctesting.AssertEvents(&suite.Suite, expEvents, events) }, }, - { - "module capability not found", - func() { - msg.PortId = "invalid-port" - msg.ChannelId = "invalid-channel" - }, - func(res *channeltypes.MsgChannelUpgradeTryResponse, events []abci.Event, err error) { - suite.Require().Error(err) - suite.Require().Nil(res) - - suite.Require().ErrorIs(err, capabilitytypes.ErrCapabilityNotFound) - suite.Require().Empty(events) - }, - }, { "unsynchronized upgrade sequence writes upgrade error receipt", func() { @@ -1313,20 +1298,6 @@ func (suite *KeeperTestSuite) TestChannelUpgradeAck() { ibctesting.AssertEvents(&suite.Suite, expEvents, events) }, }, - { - "module capability not found", - func() { - msg.PortId = ibctesting.InvalidID - msg.ChannelId = ibctesting.InvalidID - }, - func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { - suite.Require().Error(err) - suite.Require().Nil(res) - - suite.Require().ErrorIs(err, capabilitytypes.ErrCapabilityNotFound) - suite.Require().Empty(events) - }, - }, { "core handler returns error and no upgrade error receipt is written", func() { @@ -1682,20 +1653,6 @@ func (suite *KeeperTestSuite) TestChannelUpgradeConfirm() { ibctesting.AssertEvents(&suite.Suite, expEvents, events) }, }, - { - "module capability not found", - func() { - msg.PortId = ibctesting.InvalidID - msg.ChannelId = ibctesting.InvalidID - }, - func(res *channeltypes.MsgChannelUpgradeConfirmResponse, events []abci.Event, err error) { - suite.Require().Error(err) - suite.Require().Nil(res) - - suite.Require().ErrorIs(err, capabilitytypes.ErrCapabilityNotFound) - suite.Require().Empty(events) - }, - }, { "core handler returns error and no upgrade error receipt is written", func() { @@ -1922,20 +1879,6 @@ func (suite *KeeperTestSuite) TestChannelUpgradeOpen() { ibctesting.AssertEvents(&suite.Suite, expEvents, events) }, }, - { - "module capability not found", - func() { - msg.PortId = ibctesting.InvalidID - msg.ChannelId = ibctesting.InvalidID - }, - func(res *channeltypes.MsgChannelUpgradeOpenResponse, events []abci.Event, err error) { - suite.Require().Error(err) - suite.Require().Nil(res) - - suite.Require().ErrorIs(err, capabilitytypes.ErrCapabilityNotFound) - suite.Require().Empty(events) - }, - }, { "core handler fails", func() { diff --git a/simapp/app.go b/simapp/app.go index 074cae85ed4..e5235750f4b 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -461,6 +461,7 @@ func NewSimApp( ) // Create IBC Router + ibcAppRouter := porttypes.NewAppRouter() ibcRouter := porttypes.NewRouter() // Middleware Stacks @@ -487,6 +488,7 @@ func NewSimApp( mockIBCModule := mock.NewIBCModule(&mockModule, mock.NewIBCApp(mock.ModuleName, scopedIBCMockKeeper)) app.IBCMockModule = mockIBCModule ibcRouter.AddRoute(mock.ModuleName, mockIBCModule) + ibcAppRouter.AddRoute(mock.ModuleName, mockIBCModule) // Mock IBC app wrapped with a middleware which does not implement the UpgradeableModule interface. // NOTE: this is used to test integration with apps which do not yet fulfill the UpgradeableModule interface and error when @@ -509,6 +511,7 @@ func NewSimApp( // create IBC module from bottom to top of stack var transferStack porttypes.IBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) + ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) // Add transfer stack to IBC Router @@ -527,7 +530,9 @@ func NewSimApp( panic(fmt.Errorf("cannot convert %T into %T", icaControllerStack, app.ICAAuthModule)) } icaControllerStack = icacontroller.NewIBCMiddleware(app.ICAControllerKeeper) + ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) + ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) // RecvPacket, message that originates from core IBC and goes down to app, the flow is: // channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket @@ -545,6 +550,9 @@ func NewSimApp( AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(mock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) + ibcAppRouter. + AddRoute(icahosttypes.SubModuleName, icaHostStack). + AddRoute(mock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // Create Mock IBC Fee module stack for testing // SendPacket, mock module cannot send packets @@ -559,9 +567,11 @@ func NewSimApp( app.FeeMockModule = feeMockModule feeWithMockModule := ibcfee.NewIBCMiddleware(feeMockModule, app.IBCFeeKeeper) ibcRouter.AddRoute(MockFeePort, feeWithMockModule) + ibcAppRouter.AddRoute(MockFeePort, feeWithMockModule) // Seal the IBC Router app.IBCKeeper.SetRouter(ibcRouter) + app.IBCKeeper.SetAppRouter(ibcAppRouter) clientRouter := app.IBCKeeper.ClientKeeper.GetRouter() diff --git a/testing/mock/ibc_app.go b/testing/mock/ibc_app.go index 5b53f47dcc0..ae2aaf4451d 100644 --- a/testing/mock/ibc_app.go +++ b/testing/mock/ibc_app.go @@ -4,7 +4,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -20,7 +19,6 @@ type IBCApp struct { connectionHops []string, portID string, channelID string, - channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, ) (string, error) @@ -31,7 +29,6 @@ type IBCApp struct { connectionHops []string, portID, channelID string, - channelCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (version string, err error) diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index eb20f79e0fe..92d783e97cc 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -9,11 +9,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -48,21 +46,14 @@ func NewIBCModule(appModule *AppModule, app *IBCApp) IBCModule { // OnChanOpenInit implements the IBCModule interface. func (im IBCModule) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, - channelID string, chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, + channelID string, counterparty channeltypes.Counterparty, version string, ) (string, error) { if strings.TrimSpace(version) == "" { version = Version } if im.IBCApp.OnChanOpenInit != nil { - return im.IBCApp.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) - } - - if chanCap != nil { - // Claim channel capability passed back by IBC module - if err := im.IBCApp.ScopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } + return im.IBCApp.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, version) } return version, nil @@ -71,17 +62,10 @@ func (im IBCModule) OnChanOpenInit( // OnChanOpenTry implements the IBCModule interface. func (im IBCModule) OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, - channelID string, chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, + channelID string, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (version string, err error) { if im.IBCApp.OnChanOpenTry != nil { - return im.IBCApp.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, counterpartyVersion) - } - - if chanCap != nil { - // Claim channel capability passed back by IBC module - if err := im.IBCApp.ScopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } + return im.IBCApp.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, counterpartyVersion) } return Version, nil diff --git a/testing/mock/middleware.go b/testing/mock/middleware.go index df69faea296..a0bf14f5d21 100644 --- a/testing/mock/middleware.go +++ b/testing/mock/middleware.go @@ -6,11 +6,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -38,21 +36,14 @@ func NewBlockUpgradeMiddleware(appModule *AppModule, app *IBCApp) BlockUpgradeMi // OnChanOpenInit implements the IBCModule interface. func (im BlockUpgradeMiddleware) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, - channelID string, chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, version string, + channelID string, counterparty channeltypes.Counterparty, version string, ) (string, error) { if strings.TrimSpace(version) == "" { version = Version } if im.IBCApp.OnChanOpenInit != nil { - return im.IBCApp.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, version) - } - - if chanCap != nil { - // Claim channel capability passed back by IBC module - if err := im.IBCApp.ScopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } + return im.IBCApp.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, version) } return version, nil @@ -61,17 +52,10 @@ func (im BlockUpgradeMiddleware) OnChanOpenInit( // OnChanOpenTry implements the IBCModule interface. func (im BlockUpgradeMiddleware) OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, - channelID string, chanCap *capabilitytypes.Capability, counterparty channeltypes.Counterparty, counterpartyVersion string, + channelID string, counterparty channeltypes.Counterparty, counterpartyVersion string, ) (version string, err error) { if im.IBCApp.OnChanOpenTry != nil { - return im.IBCApp.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, chanCap, counterparty, counterpartyVersion) - } - - if chanCap != nil { - // Claim channel capability passed back by IBC module - if err := im.IBCApp.ScopedKeeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { - return "", err - } + return im.IBCApp.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, counterpartyVersion) } return Version, nil From 832a0fc26dca332a3ae80d8186f0c980b9fa6b88 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Mon, 5 Aug 2024 17:03:25 +0100 Subject: [PATCH 26/46] Adding updates to composite router and scaffolding for LegacyIBCModule (#7010) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: adding updates to composite router and scaffolding for IBCLegacyModule * chore: support construction of LegacyIBCModules over consecutive calls to AddRoute * chore: removed ack handhsake impl * chore: fix linter * chore: lint * Linter * chore: addressing PR feedback * chore: routeToLegacyModule returns a single item * Update modules/core/05-port/types/router_v2.go * Update modules/core/05-port/types/router_v2.go * Update modules/core/05-port/types/router_v2.go * chore: fix errors from merge conflict --------- Co-authored-by: bznein Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> --- modules/apps/callbacks/ibc_middleware_test.go | 9 +- modules/core/05-port/keeper/keeper.go | 32 +--- .../core/05-port/types/ibc_legacy_module.go | 172 ++++++++++++++++++ modules/core/05-port/types/router.go | 16 +- modules/core/05-port/types/router_v2.go | 117 ++++++++---- modules/core/keeper/keeper.go | 5 - 6 files changed, 279 insertions(+), 72 deletions(-) create mode 100644 modules/core/05-port/types/ibc_legacy_module.go diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 817302b4857..71a96f1b96c 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -169,7 +169,14 @@ func (s *CallbacksTestSuite) TestSendPacket() { cbs, ok := GetSimApp(s.chainA).IBCKeeper.PortKeeper.AppRoute(transfertypes.ModuleName) s.Require().True(ok) - callbacksModule, ok := cbs[1].(ibccallbacks.IBCMiddleware) // callbacks module is routed second + s.Require().Len(cbs, 1, "expected 1 legacy module") + + legacyModule, ok := cbs[0].(porttypes.LegacyIBCModule) + s.Require().True(ok, "expected there to be a single legacy ibc module") + + legacyModuleCbs := legacyModule.GetCallbacks() + + callbacksModule, ok := legacyModuleCbs[1].(ibccallbacks.IBCMiddleware) // callbacks module is routed second s.Require().True(ok) packetData = transfertypes.NewFungibleTokenPacketDataV2( diff --git a/modules/core/05-port/keeper/keeper.go b/modules/core/05-port/keeper/keeper.go index 20b1108c1c8..22b41d9d317 100644 --- a/modules/core/05-port/keeper/keeper.go +++ b/modules/core/05-port/keeper/keeper.go @@ -2,7 +2,6 @@ package keeper import ( "fmt" - "strings" "cosmossdk.io/log" @@ -87,38 +86,11 @@ func (k *Keeper) LookupModuleByPort(ctx sdk.Context, portID string) (string, *ca // Route returns a IBCModule for a given module, and a boolean indicating // whether or not the route is present. func (k *Keeper) Route(module string) (types.IBCModule, bool) { - routes, ok := k.Router.GetRoute(module) - - if ok { - return routes, true - } - - for _, prefix := range k.Keys() { - if strings.Contains(module, prefix) { - return k.Router.GetRoute(prefix) - } - } - - return nil, false + return k.Router.GetRoute(module) } // AppRoute returns an ordered list of IBCModule callbacks for a given module name, and a boolean indicating // whether or not the callbacks are present. func (k *Keeper) AppRoute(module string) ([]types.IBCModule, bool) { - routes, ok := k.AppRouter.GetRoute(module) - if ok { - return routes, true - } - - for _, prefix := range k.Keys() { - if strings.Contains(module, prefix) { - return k.AppRouter.GetRoute(prefix) - } - } - - return nil, false -} - -func (k *Keeper) Keys() []string { - return k.AppRouter.Keys() + return k.AppRouter.PacketRoute(module) } diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go new file mode 100644 index 00000000000..212025e9f55 --- /dev/null +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -0,0 +1,172 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +// TODO: IBCModule will be renamed to ClassicIBCModule in a follow up. +type ClassicIBCModule IBCModule + +// LegacyIBCModule implements the ICS26 interface for transfer given the transfer keeper. +type LegacyIBCModule struct { + cbs []ClassicIBCModule +} + +// TODO: added this for testing purposes, we can remove later if tests are refactored. +func (im *LegacyIBCModule) GetCallbacks() []ClassicIBCModule { + return im.cbs +} + +// NewLegacyIBCModule creates a new IBCModule given the keeper +func NewLegacyIBCModule(cbs ...ClassicIBCModule) ClassicIBCModule { + return LegacyIBCModule{ + cbs: cbs, + } +} + +// OnChanOpenInit implements the IBCModule interface +func (LegacyIBCModule) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + counterparty channeltypes.Counterparty, + version string, +) (string, error) { + return "", nil +} + +// OnChanOpenTry implements the IBCModule interface. +func (LegacyIBCModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + return "", nil +} + +// OnChanOpenAck implements the IBCModule interface +func (LegacyIBCModule) OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyChannelID string, + counterpartyVersion string, +) error { + return nil +} + +// OnChanOpenConfirm implements the IBCModule interface +func (LegacyIBCModule) OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +// OnChanCloseInit implements the IBCModule interface +func (LegacyIBCModule) OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +// OnChanCloseConfirm implements the IBCModule interface +func (LegacyIBCModule) OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + return nil +} + +// OnSendPacket implements the IBCModule interface. +func (im LegacyIBCModule) OnSendPacket( + ctx sdk.Context, + portID string, + channelID string, + sequence uint64, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + dataBz []byte, + signer sdk.AccAddress, +) error { + // to maintain backwards compatibility, OnSendPacket iterates over the callbacks in order, as they are wired from bottom to top of the stack. + for _, cb := range im.cbs { + if err := cb.OnSendPacket(ctx, portID, channelID, sequence, timeoutHeight, timeoutTimestamp, dataBz, signer); err != nil { + return errorsmod.Wrapf(err, "send packet callback failed for portID %s channelID %s", portID, channelID) + } + } + return nil +} + +// OnRecvPacket implements the IBCModule interface. A successful acknowledgement +// is returned if the packet data is successfully decoded and the receive application +// logic returns without error. +// A nil acknowledgement may be returned when using the packet forwarding feature. This signals to core IBC that the acknowledgement will be written asynchronously. +func (LegacyIBCModule) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) ibcexported.Acknowledgement { + return nil +} + +// OnAcknowledgementPacket implements the IBCModule interface +func (LegacyIBCModule) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + relayer sdk.AccAddress, +) error { + return nil +} + +// OnTimeoutPacket implements the IBCModule interface +func (LegacyIBCModule) OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) error { + return nil +} + +// OnChanUpgradeInit implements the IBCModule interface +func (LegacyIBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { + return "", nil +} + +// OnChanUpgradeTry implements the IBCModule interface +func (LegacyIBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + return "", nil +} + +// OnChanUpgradeAck implements the IBCModule interface +func (LegacyIBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + return nil +} + +// OnChanUpgradeOpen implements the IBCModule interface +func (LegacyIBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { +} + +// UnmarshalPacketData attempts to unmarshal the provided packet data bytes +// into a FungibleTokenPacketData. This function implements the optional +// PacketDataUnmarshaler interface required for ADR 008 support. +func (LegacyIBCModule) UnmarshalPacketData(ctx sdk.Context, portID, channelID string, bz []byte) (interface{}, error) { + return nil, nil +} diff --git a/modules/core/05-port/types/router.go b/modules/core/05-port/types/router.go index b66999644f5..53896c74271 100644 --- a/modules/core/05-port/types/router.go +++ b/modules/core/05-port/types/router.go @@ -3,6 +3,7 @@ package types import ( "errors" "fmt" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -59,8 +60,17 @@ func (rtr *Router) HasRoute(module string) bool { // GetRoute returns a IBCModule for a given module. func (rtr *Router) GetRoute(module string) (IBCModule, bool) { - if !rtr.HasRoute(module) { - return nil, false + route, ok := rtr.routes[module] + if ok { + return route, true } - return rtr.routes[module], true + + // it's possible that some routes have been dynamically added e.g. with interchain accounts. + // in this case, we need to check if the module has the specified prefix. + for prefix := range rtr.routes { + if strings.Contains(module, prefix) { + return rtr.routes[prefix], true + } + } + return nil, false } diff --git a/modules/core/05-port/types/router_v2.go b/modules/core/05-port/types/router_v2.go index e165ae257e0..e706436a09b 100644 --- a/modules/core/05-port/types/router_v2.go +++ b/modules/core/05-port/types/router_v2.go @@ -5,67 +5,118 @@ package types import ( "errors" "fmt" - - "golang.org/x/exp/maps" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" ) -// AppRouter contains a map from module name to an ordered list of IBCModules -// which contains all the module-defined callbacks required by ICS-26. +// TODO: this is a temporary constant that is subject to change based on the final spec. +// https://github.com/cosmos/ibc/issues/1129 +const sentinelMultiPacketData = "MultiPacketData" + +// AppRouter contains all the module-defined callbacks required by ICS-26 type AppRouter struct { - routes map[string][]IBCModule - sealed bool + routes map[string]IBCModule + legacyRoutes map[string]ClassicIBCModule + + // classicRoutes facilitates the consecutive calls to AddRoute for existing modules. + // TODO: this should be removed once app.gos have been refactored to use AddClassicRoute. + // https://github.com/cosmos/ibc-go/issues/7025 + classicRoutes map[string][]ClassicIBCModule } -// NewAppRouter creates and returns a new IBCModule application router. func NewAppRouter() *AppRouter { return &AppRouter{ - routes: make(map[string][]IBCModule), + routes: make(map[string]IBCModule), + legacyRoutes: make(map[string]ClassicIBCModule), + classicRoutes: make(map[string][]ClassicIBCModule), } } -// Seal prevents the Router from any subsequent route handlers to be registered. -// Seal will panic if called more than once. -func (rtr *AppRouter) Seal() { - if rtr.sealed { - panic(errors.New("router already sealed")) +// AddClassicRoute takes a ordered list of ClassicIBCModules and creates a LegacyIBCModule. This is then added +// to the legacy mapping. +func (rtr *AppRouter) AddClassicRoute(module string, cbs ...ClassicIBCModule) *AppRouter { + if !sdk.IsAlphaNumeric(module) { + panic(errors.New("route expressions can only contain alphanumeric characters")) } - rtr.sealed = true -} -// Sealed returns a boolean signifying if the Router is sealed or not. -func (rtr AppRouter) Sealed() bool { - return rtr.sealed + if _, ok := rtr.legacyRoutes[module]; ok { + panic(fmt.Errorf("route %s has already been registered", module)) + } + + if len(cbs) == 0 { + panic(errors.New("no callbacks provided")) + } + + rtr.legacyRoutes[module] = NewLegacyIBCModule(cbs...) + + return rtr } // AddRoute adds IBCModule for a given module name. It returns the Router // so AddRoute calls can be linked. It will panic if the Router is sealed. func (rtr *AppRouter) AddRoute(module string, cbs IBCModule) *AppRouter { - if rtr.sealed { - panic(fmt.Errorf("router sealed; cannot register %s route callbacks", module)) - } if !sdk.IsAlphaNumeric(module) { panic(errors.New("route expressions can only contain alphanumeric characters")) } - rtr.routes[module] = append(rtr.routes[module], cbs) + + if _, ok := cbs.(ClassicIBCModule); ok { + rtr.classicRoutes[module] = append(rtr.classicRoutes[module], cbs) + + // in order to facilitate having a single LegacyIBCModule, but also allowing for + // consecutive calls to AddRoute to support existing functionality, we can re-create + // the legacy module with the routes as they get added. + if classicRoutes, ok := rtr.classicRoutes[module]; ok && len(classicRoutes) > 1 { + rtr.legacyRoutes[module] = NewLegacyIBCModule(classicRoutes...) + } + } else { + rtr.routes[module] = cbs + } + return rtr } -// HasRoute returns true if the Router has a module registered or false otherwise. -func (rtr *AppRouter) HasRoute(module string) bool { - _, ok := rtr.routes[module] - return ok +func (rtr *AppRouter) PacketRoute(module string) ([]IBCModule, bool) { + if module == sentinelMultiPacketData { + return rtr.routeMultiPacketData(module) + } + legacyModule, ok := rtr.routeToLegacyModule(module) + if !ok { + return nil, false + } + return []IBCModule{legacyModule}, true +} + +// TODO: docstring once implementation is complete +// https://github.com/cosmos/ibc-go/issues/7056 +func (*AppRouter) routeMultiPacketData(module string) ([]IBCModule, bool) { + panic("unimplemented") + // for _, pd := range packet.Data { + // cbs = append(cbs, rtr.routes[pd.PortId]) + // } + // return cbs, true } -// GetRoute returns a IBCModule for a given module. -func (rtr *AppRouter) GetRoute(module string) ([]IBCModule, bool) { - if !rtr.HasRoute(module) { - return nil, false +// routeToLegacyModule routes to any legacy modules which have been registered with AddClassicRoute. +func (rtr *AppRouter) routeToLegacyModule(module string) (IBCModule, bool) { + route, ok := rtr.legacyRoutes[module] + if ok { + return route, true + } + + // it's possible that some routes have been dynamically added e.g. with interchain accounts. + // in this case, we need to check if the module has the specified prefix. + for prefix := range rtr.legacyRoutes { + if strings.Contains(module, prefix) { + return rtr.legacyRoutes[prefix], true + } } - return rtr.routes[module], true + return nil, false } -func (rtr *AppRouter) Keys() []string { - return maps.Keys(rtr.routes) +// HandshakeRoute returns the ClassicIBCModule which will implement all handshake functions +// and is required only for those callbacks. +func (rtr *AppRouter) HandshakeRoute(portID string) (ClassicIBCModule, bool) { + route, ok := rtr.routeToLegacyModule(portID) + return route, ok } diff --git a/modules/core/keeper/keeper.go b/modules/core/keeper/keeper.go index 4fedba4b0f4..d5e077ba1e0 100644 --- a/modules/core/keeper/keeper.go +++ b/modules/core/keeper/keeper.go @@ -92,12 +92,7 @@ func (k *Keeper) SetConsensusHost(consensusHost clienttypes.ConsensusHost) { // SetAppRouter sets the Router in IBC Keeper and seals it. The method panics if // there is an existing router that's already sealed. func (k *Keeper) SetAppRouter(rtr *porttypes.AppRouter) { - if k.PortKeeper.AppRouter != nil && k.PortKeeper.AppRouter.Sealed() { - panic(errors.New("cannot reset a sealed router")) - } - k.PortKeeper.AppRouter = rtr - k.PortKeeper.AppRouter.Seal() } // SetRouter sets the Router in IBC Keeper and seals it. The method panics if From d701aa227e6849d39512212c5db5e43161a65c76 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Mon, 5 Aug 2024 17:49:43 +0100 Subject: [PATCH 27/46] Rename IBCModule to ClassicIBCModule (#7015) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: adding updates to composite router and scaffolding for IBCLegacyModule * chore: support construction of LegacyIBCModules over consecutive calls to AddRoute * chore: removed ack handhsake impl * chore: fix linter * chore: lint * Linter * chore: addressing PR feedback * chore: rename IBCModule to ClassicIBCModule and add new IBCModule interface * fix: e2e for fee wrapped channels --------- Co-authored-by: bznein Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> --- .../27-interchain-accounts/controller/ibc_middleware.go | 4 ++-- modules/apps/27-interchain-accounts/host/ibc_module.go | 2 +- modules/apps/27-interchain-accounts/module.go | 2 +- modules/apps/29-fee/ibc_middleware.go | 4 ++-- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/apps/callbacks/testing/simapp/app.go | 6 +++--- modules/apps/callbacks/types/callbacks.go | 2 +- modules/apps/transfer/ibc_module.go | 2 +- modules/apps/transfer/module.go | 2 +- modules/core/05-port/keeper/keeper.go | 2 +- modules/core/05-port/types/ibc_legacy_module.go | 3 --- modules/core/05-port/types/module.go | 9 ++++++--- modules/core/05-port/types/router.go | 8 ++++---- modules/core/05-port/types/router_v2.go | 6 +++--- modules/light-clients/08-wasm/testing/simapp/app.go | 6 +++--- simapp/app.go | 7 ++++--- testing/mock/ibc_module.go | 2 +- testing/mock/mock.go | 2 +- testing/simapp/app.go | 6 +++--- 19 files changed, 39 insertions(+), 38 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index b6999af4c4a..c60ebcee70f 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -26,7 +26,7 @@ var ( // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the // ICA controller keeper and the underlying application. type IBCMiddleware struct { - app porttypes.IBCModule + app porttypes.ClassicIBCModule keeper keeper.Keeper } @@ -41,7 +41,7 @@ func NewIBCMiddleware(k keeper.Keeper) IBCMiddleware { } // NewIBCMiddlewareWithAuth creates a new IBCMiddleware given the associated keeper and underlying application -func NewIBCMiddlewareWithAuth(app porttypes.IBCModule, k keeper.Keeper) IBCMiddleware { +func NewIBCMiddlewareWithAuth(app porttypes.ClassicIBCModule, k keeper.Keeper) IBCMiddleware { return IBCMiddleware{ app: app, keeper: k, diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 8b5abdaf1c7..fabfde741e2 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -18,7 +18,7 @@ import ( ) var ( - _ porttypes.IBCModule = (*IBCModule)(nil) + _ porttypes.ClassicIBCModule = (*IBCModule)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCModule)(nil) _ porttypes.UpgradableModule = (*IBCModule)(nil) ) diff --git a/modules/apps/27-interchain-accounts/module.go b/modules/apps/27-interchain-accounts/module.go index d3b7d00d1e1..9894bd53e2b 100644 --- a/modules/apps/27-interchain-accounts/module.go +++ b/modules/apps/27-interchain-accounts/module.go @@ -40,7 +40,7 @@ var ( _ module.HasProposalMsgs = (*AppModule)(nil) _ appmodule.AppModule = (*AppModule)(nil) - _ porttypes.IBCModule = (*host.IBCModule)(nil) + _ porttypes.ClassicIBCModule = (*host.IBCModule)(nil) ) // AppModuleBasic is the IBC interchain accounts AppModuleBasic diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index f60ca2ee70c..3af5ea4b82f 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -24,12 +24,12 @@ var ( // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the // fee keeper and the underlying application. type IBCMiddleware struct { - app porttypes.IBCModule + app porttypes.ClassicIBCModule keeper keeper.Keeper } // NewIBCMiddleware creates a new IBCMiddleware given the keeper and underlying application -func NewIBCMiddleware(app porttypes.IBCModule, k keeper.Keeper) IBCMiddleware { +func NewIBCMiddleware(app porttypes.ClassicIBCModule, k keeper.Keeper) IBCMiddleware { return IBCMiddleware{ app: app, keeper: k, diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 95b0a35e29b..0d30be9503b 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -40,7 +40,7 @@ type IBCMiddleware struct { // NewIBCMiddleware creates a new IBCMiddleware given the keeper and underlying application. // The underlying application must implement the required callback interfaces. func NewIBCMiddleware( - app porttypes.IBCModule, ics4Wrapper porttypes.ICS4Wrapper, + app porttypes.ClassicIBCModule, ics4Wrapper porttypes.ICS4Wrapper, contractKeeper types.ContractKeeper, maxCallbackGas uint64, ) IBCMiddleware { packetDataUnmarshalerApp, ok := app.(types.CallbacksCompatibleModule) diff --git a/modules/apps/callbacks/testing/simapp/app.go b/modules/apps/callbacks/testing/simapp/app.go index 0e04d95fd4b..fe8eea14d48 100644 --- a/modules/apps/callbacks/testing/simapp/app.go +++ b/modules/apps/callbacks/testing/simapp/app.go @@ -511,7 +511,7 @@ func NewSimApp( // - Transfer // create IBC module from bottom to top of stack - var transferStack porttypes.IBCModule + var transferStack porttypes.ClassicIBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) transferStack = ibccallbacks.NewIBCMiddleware(transferStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) @@ -537,7 +537,7 @@ func NewSimApp( // icaControllerKeeper.SendTx -> callbacks.SendPacket -> fee.SendPacket -> channel.SendPacket // initialize ICA module with mock module as the authentication module on the controller side - var icaControllerStack porttypes.IBCModule + var icaControllerStack porttypes.ClassicIBCModule icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp("", scopedICAMockKeeper)) app.ICAAuthModule, ok = icaControllerStack.(ibcmock.IBCModule) if !ok { @@ -560,7 +560,7 @@ func NewSimApp( // 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 + var icaHostStack porttypes.ClassicIBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 98da8ac1e6d..08c0491d831 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -47,7 +47,7 @@ keeper to verify that the packet sender is the same as the callback address if d // CallbacksCompatibleModule is an interface that combines the IBCModule and PacketDataUnmarshaler // interfaces to assert that the underlying application supports both. type CallbacksCompatibleModule interface { - porttypes.IBCModule + porttypes.ClassicIBCModule porttypes.PacketDataUnmarshaler } diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 3774020b639..8fa6c3b3aee 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -22,7 +22,7 @@ import ( ) var ( - _ porttypes.IBCModule = (*IBCModule)(nil) + _ porttypes.ClassicIBCModule = (*IBCModule)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCModule)(nil) _ porttypes.UpgradableModule = (*IBCModule)(nil) ) diff --git a/modules/apps/transfer/module.go b/modules/apps/transfer/module.go index ee63b97f941..59d7e02f68c 100644 --- a/modules/apps/transfer/module.go +++ b/modules/apps/transfer/module.go @@ -36,7 +36,7 @@ var ( _ module.HasProposalMsgs = (*AppModule)(nil) _ appmodule.AppModule = (*AppModule)(nil) - _ porttypes.IBCModule = (*IBCModule)(nil) + _ porttypes.ClassicIBCModule = (*IBCModule)(nil) ) // AppModuleBasic is the IBC Transfer AppModuleBasic diff --git a/modules/core/05-port/keeper/keeper.go b/modules/core/05-port/keeper/keeper.go index 22b41d9d317..a64f5ded7c5 100644 --- a/modules/core/05-port/keeper/keeper.go +++ b/modules/core/05-port/keeper/keeper.go @@ -85,7 +85,7 @@ func (k *Keeper) LookupModuleByPort(ctx sdk.Context, portID string) (string, *ca // Route returns a IBCModule for a given module, and a boolean indicating // whether or not the route is present. -func (k *Keeper) Route(module string) (types.IBCModule, bool) { +func (k *Keeper) Route(module string) (types.ClassicIBCModule, bool) { return k.Router.GetRoute(module) } diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index 212025e9f55..32d3d66ad02 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -10,9 +10,6 @@ import ( ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" ) -// TODO: IBCModule will be renamed to ClassicIBCModule in a follow up. -type ClassicIBCModule IBCModule - // LegacyIBCModule implements the ICS26 interface for transfer given the transfer keeper. type LegacyIBCModule struct { cbs []ClassicIBCModule diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 149702f24fb..3ab037a1e5d 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -8,9 +8,10 @@ import ( "github.com/cosmos/ibc-go/v8/modules/core/exported" ) -// IBCModule defines an interface that implements all the callbacks +// ClassicIBCModule defines an interface that implements all the callbacks // that modules must define as specified in ICS-26 -type IBCModule interface { +type ClassicIBCModule interface { + IBCModule // OnChanOpenInit will verify that the relayer-chosen parameters // are valid and perform any custom INIT logic. // It may return an error if the chosen parameters are invalid @@ -77,7 +78,9 @@ type IBCModule interface { portID, channelID string, ) error +} +type IBCModule interface { // TODO: consider removing timeout height and timeout timestamp added back for callbacks OnSendPacket( ctx sdk.Context, @@ -185,7 +188,7 @@ type ICS4Wrapper interface { // Middleware must implement IBCModule to wrap communication from core IBC to underlying application // and ICS4Wrapper to wrap communication from underlying application to core IBC. type Middleware interface { - IBCModule + ClassicIBCModule ICS4Wrapper } diff --git a/modules/core/05-port/types/router.go b/modules/core/05-port/types/router.go index 53896c74271..19259894fa4 100644 --- a/modules/core/05-port/types/router.go +++ b/modules/core/05-port/types/router.go @@ -11,13 +11,13 @@ import ( // The router is a map from module name to the IBCModule // which contains all the module-defined callbacks required by ICS-26 type Router struct { - routes map[string]IBCModule + routes map[string]ClassicIBCModule sealed bool } func NewRouter() *Router { return &Router{ - routes: make(map[string]IBCModule), + routes: make(map[string]ClassicIBCModule), } } @@ -37,7 +37,7 @@ func (rtr Router) Sealed() bool { // AddRoute adds IBCModule for a given module name. It returns the Router // so AddRoute calls can be linked. It will panic if the Router is sealed. -func (rtr *Router) AddRoute(module string, cbs IBCModule) *Router { +func (rtr *Router) AddRoute(module string, cbs ClassicIBCModule) *Router { if rtr.sealed { panic(fmt.Errorf("router sealed; cannot register %s route callbacks", module)) } @@ -59,7 +59,7 @@ func (rtr *Router) HasRoute(module string) bool { } // GetRoute returns a IBCModule for a given module. -func (rtr *Router) GetRoute(module string) (IBCModule, bool) { +func (rtr *Router) GetRoute(module string) (ClassicIBCModule, bool) { route, ok := rtr.routes[module] if ok { return route, true diff --git a/modules/core/05-port/types/router_v2.go b/modules/core/05-port/types/router_v2.go index e706436a09b..1c52e4a06ba 100644 --- a/modules/core/05-port/types/router_v2.go +++ b/modules/core/05-port/types/router_v2.go @@ -60,8 +60,8 @@ func (rtr *AppRouter) AddRoute(module string, cbs IBCModule) *AppRouter { panic(errors.New("route expressions can only contain alphanumeric characters")) } - if _, ok := cbs.(ClassicIBCModule); ok { - rtr.classicRoutes[module] = append(rtr.classicRoutes[module], cbs) + if classicModule, ok := cbs.(ClassicIBCModule); ok { + rtr.classicRoutes[module] = append(rtr.classicRoutes[module], classicModule) // in order to facilitate having a single LegacyIBCModule, but also allowing for // consecutive calls to AddRoute to support existing functionality, we can re-create @@ -98,7 +98,7 @@ func (*AppRouter) routeMultiPacketData(module string) ([]IBCModule, bool) { } // routeToLegacyModule routes to any legacy modules which have been registered with AddClassicRoute. -func (rtr *AppRouter) routeToLegacyModule(module string) (IBCModule, bool) { +func (rtr *AppRouter) routeToLegacyModule(module string) (ClassicIBCModule, bool) { route, ok := rtr.legacyRoutes[module] if ok { return route, true diff --git a/modules/light-clients/08-wasm/testing/simapp/app.go b/modules/light-clients/08-wasm/testing/simapp/app.go index b76dcb4f79b..650a9692ac8 100644 --- a/modules/light-clients/08-wasm/testing/simapp/app.go +++ b/modules/light-clients/08-wasm/testing/simapp/app.go @@ -551,7 +551,7 @@ func NewSimApp( // - Transfer // create IBC module from bottom to top of stack - var transferStack porttypes.IBCModule + var transferStack porttypes.ClassicIBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) @@ -563,7 +563,7 @@ func NewSimApp( // icaControllerKeeper.SendTx -> fee.SendPacket -> channel.SendPacket // initialize ICA module with mock module as the authentication module on the controller side - var icaControllerStack porttypes.IBCModule + var icaControllerStack porttypes.ClassicIBCModule var ok bool icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp("", scopedICAMockKeeper)) app.ICAAuthModule, ok = icaControllerStack.(ibcmock.IBCModule) @@ -576,7 +576,7 @@ func NewSimApp( // 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 + var icaHostStack porttypes.ClassicIBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) diff --git a/simapp/app.go b/simapp/app.go index e5235750f4b..1c757103a4b 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -509,10 +509,11 @@ func NewSimApp( // - Transfer // create IBC module from bottom to top of stack - var transferStack porttypes.IBCModule + var transferStack porttypes.ClassicIBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) + ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) // Add transfer stack to IBC Router ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) @@ -522,7 +523,7 @@ func NewSimApp( // icaControllerKeeper.SendTx -> fee.SendPacket -> channel.SendPacket // initialize ICA module with mock module as the authentication module on the controller side - var icaControllerStack porttypes.IBCModule + var icaControllerStack porttypes.ClassicIBCModule icaControllerStack = mock.NewIBCModule(&mockModule, mock.NewIBCApp("", scopedICAMockKeeper)) var ok bool app.ICAAuthModule, ok = icaControllerStack.(mock.IBCModule) @@ -537,7 +538,7 @@ func NewSimApp( // 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 + var icaHostStack porttypes.ClassicIBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 92d783e97cc..18587584686 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -16,7 +16,7 @@ import ( ) var ( - _ porttypes.IBCModule = (*IBCModule)(nil) + _ porttypes.ClassicIBCModule = (*IBCModule)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCModule)(nil) _ porttypes.UpgradableModule = (*IBCModule)(nil) ) diff --git a/testing/mock/mock.go b/testing/mock/mock.go index 3a15d776a63..c4347db969e 100644 --- a/testing/mock/mock.go +++ b/testing/mock/mock.go @@ -60,7 +60,7 @@ var ( _ module.AppModuleBasic = (*AppModuleBasic)(nil) _ appmodule.AppModule = (*AppModule)(nil) - _ porttypes.IBCModule = (*IBCModule)(nil) + _ porttypes.ClassicIBCModule = (*IBCModule)(nil) ) // Expected Interface diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 699111b325d..c51f9b50291 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -474,7 +474,7 @@ func NewSimApp( // - Transfer // create IBC module from bottom to top of stack - var transferStack porttypes.IBCModule + var transferStack porttypes.ClassicIBCModule transferStack = transfer.NewIBCModule(app.TransferKeeper) ibcAppRouter.AddRoute(ibctransfertypes.ModuleName, transferStack) transferStack = ibcfee.NewIBCMiddleware(transferStack, app.IBCFeeKeeper) @@ -488,7 +488,7 @@ func NewSimApp( // icaControllerKeeper.SendTx -> fee.SendPacket -> channel.SendPacket // initialize ICA module with mock module as the authentication module on the controller side - var icaControllerStack porttypes.IBCModule + var icaControllerStack porttypes.ClassicIBCModule icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp("", scopedICAMockKeeper)) var ok bool app.ICAAuthModule, ok = icaControllerStack.(ibcmock.IBCModule) @@ -503,7 +503,7 @@ func NewSimApp( // 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 + var icaHostStack porttypes.ClassicIBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) From 3eaf2ce45872938181184239477161a4f09efe1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:47:41 +0200 Subject: [PATCH 28/46] fix: tests --- .../controller/ibc_middleware_test.go | 1 + modules/apps/29-fee/ibc_middleware.go | 1 + modules/apps/callbacks/forwarding_test.go | 14 ++++---------- modules/apps/transfer/ibc_module.go | 7 ++++++- modules/core/05-port/types/ibc_legacy_module.go | 3 +++ modules/core/ante/ante.go | 2 +- testing/events.go | 2 +- testing/events_test.go | 4 ++-- 8 files changed, 19 insertions(+), 15 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 19ed3908110..620e3792a4d 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -19,6 +19,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v9/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v9/modules/core/24-host" + ibcerrors "github.com/cosmos/ibc-go/v9/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v9/testing" ibcmock "github.com/cosmos/ibc-go/v9/testing/mock" ) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 95e09f49f97..36699316901 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -13,6 +13,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v9/modules/core/05-port/types" + ibcerrors "github.com/cosmos/ibc-go/v9/modules/core/errors" "github.com/cosmos/ibc-go/v9/modules/core/exported" ) diff --git a/modules/apps/callbacks/forwarding_test.go b/modules/apps/callbacks/forwarding_test.go index f52ebb34437..8a2946a86ec 100644 --- a/modules/apps/callbacks/forwarding_test.go +++ b/modules/apps/callbacks/forwarding_test.go @@ -78,23 +78,17 @@ func (s *CallbacksForwardingTestSuite) TestForwardingWithMemoCallback() { expCallbackMapOnChainC: map[callbacktypes.CallbackType]int{callbacktypes.CallbackTypeReceivePacket: 1}, }, { - name: "ack callback", + name: "send and ack callback", testMemo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract), - expCallbackMapOnChainB: map[callbacktypes.CallbackType]int{callbacktypes.CallbackTypeAcknowledgementPacket: 1}, + expCallbackMapOnChainB: map[callbacktypes.CallbackType]int{callbacktypes.CallbackTypeSendPacket: 1, callbacktypes.CallbackTypeAcknowledgementPacket: 1}, expCallbackMapOnChainC: map[callbacktypes.CallbackType]int{}, }, { - name: "ack and recv callback", + name: "send, ack and recv callback", testMemo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address": "%s"}}`, simapp.SuccessContract, simapp.SuccessContract), - expCallbackMapOnChainB: map[callbacktypes.CallbackType]int{callbacktypes.CallbackTypeAcknowledgementPacket: 1}, + expCallbackMapOnChainB: map[callbacktypes.CallbackType]int{callbacktypes.CallbackTypeSendPacket: 1, callbacktypes.CallbackTypeAcknowledgementPacket: 1}, expCallbackMapOnChainC: map[callbacktypes.CallbackType]int{callbacktypes.CallbackTypeReceivePacket: 1}, }, - { - name: "ack callback with low gas (error)", - testMemo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.OogErrorContract), - expCallbackMapOnChainB: map[callbacktypes.CallbackType]int{callbacktypes.CallbackTypeAcknowledgementPacket: 1}, - expCallbackMapOnChainC: map[callbacktypes.CallbackType]int{}, - }, { name: "recv callback with low gas (error)", testMemo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, simapp.OogErrorContract), diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 11232730b00..e624761bd57 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -172,7 +172,12 @@ func (im IBCModule) OnSendPacket( dataBz []byte, signer sdk.AccAddress, ) error { - data, err := im.getICS20PacketData(ctx, dataBz, portID, channelID) + ics20Version, found := im.keeper.GetICS4Wrapper().GetAppVersion(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", portID, channelID) + } + + data, err := types.UnmarshalPacketData(dataBz, ics20Version) if err != nil { return err } diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index 7af12075ce1..6879a3a1683 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -117,6 +117,7 @@ func (im LegacyIBCModule) OnSendPacket( // A nil acknowledgement may be returned when using the packet forwarding feature. This signals to core IBC that the acknowledgement will be written asynchronously. func (LegacyIBCModule) OnRecvPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, ) ibcexported.Acknowledgement { @@ -126,6 +127,7 @@ func (LegacyIBCModule) OnRecvPacket( // OnAcknowledgementPacket implements the IBCModule interface func (LegacyIBCModule) OnAcknowledgementPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, @@ -136,6 +138,7 @@ func (LegacyIBCModule) OnAcknowledgementPacket( // OnTimeoutPacket implements the IBCModule interface func (LegacyIBCModule) OnTimeoutPacket( ctx sdk.Context, + channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, ) error { diff --git a/modules/core/ante/ante.go b/modules/core/ante/ante.go index f191d3d3b15..243a25f7442 100644 --- a/modules/core/ante/ante.go +++ b/modules/core/ante/ante.go @@ -111,7 +111,7 @@ func (rrd RedundantRelayDecorator) recvPacketCheckTx(ctx sdk.Context, msg *chann // If the packet was already received, perform a no-op // Use a cached context to prevent accidental state changes cacheCtx, writeFn := ctx.CacheContext() - _, err = rrd.k.ChannelKeeper.RecvPacket(cacheCtx, msg.Packet, msg.ProofCommitment, msg.ProofHeight) + _, err := rrd.k.ChannelKeeper.RecvPacket(cacheCtx, msg.Packet, msg.ProofCommitment, msg.ProofHeight) switch err { case nil: diff --git a/testing/events.go b/testing/events.go index fa11fd031db..81ea471daf0 100644 --- a/testing/events.go +++ b/testing/events.go @@ -142,7 +142,7 @@ func ParsePacketsFromEvents(eventType string, events []abci.Event) ([]channeltyp } } if len(packets) == 0 { - return ferr(errors.New("acknowledgement event attribute not found")) + return ferr(fmt.Errorf("%s event attribute not found", eventType)) } return packets, nil } diff --git a/testing/events_test.go b/testing/events_test.go index c18a75866a4..98a502864e5 100644 --- a/testing/events_test.go +++ b/testing/events_test.go @@ -137,7 +137,7 @@ func TestParsePacketsFromEvents(t *testing.T) { { name: "fail: no events", events: []abci.Event{}, - expectedError: "acknowledgement event attribute not found", + expectedError: "send_packet event attribute not found", }, { name: "fail: events without packet", @@ -149,7 +149,7 @@ func TestParsePacketsFromEvents(t *testing.T) { Type: "yyy", }, }, - expectedError: "acknowledgement event attribute not found", + expectedError: "send_packet event attribute not found", }, { name: "fail: event packet with invalid AttributeKeySequence", From 41c66562969c6b72104ffeed03d7da80eeddb21a Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 7 Aug 2024 12:08:58 +0100 Subject: [PATCH 29/46] Add Wrap/Unwrap Interfaces and implement OnChanOpenInit (#7059) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: adding wrapping functions to ics29 * chore: added docstring to VersionWrapper interface * chore: fix linter * refactor: use unsafe unwrap func in OnChanOpenInit * chore: fixing wiring in app.go and fee tests * fix: fee middleware tests * fix: ics27 controller tests * wip: debugging callbacks * chore: fix linter * chore: fix miswiring in callbacks module * chore: modifications to binary simapp * chore: do not unwrap a version if it is an empty string * Update modules/apps/27-interchain-accounts/controller/ibc_middleware.go * Apply suggestions from code review * chore: add more code docs --------- Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> --- .../controller/ibc_middleware.go | 24 ++--- .../controller/ibc_middleware_test.go | 85 +++++------------- modules/apps/29-fee/ibc_middleware.go | 68 +++++++-------- modules/apps/29-fee/ibc_middleware_test.go | 87 +++++-------------- modules/apps/callbacks/ibc_middleware.go | 4 +- modules/apps/callbacks/ibc_middleware_test.go | 2 +- modules/apps/callbacks/testing/simapp/app.go | 12 ++- .../core/05-port/types/ibc_legacy_module.go | 58 ++++++++++++- modules/core/05-port/types/module.go | 18 ++++ modules/core/05-port/types/router_v2.go | 2 +- modules/core/keeper/msg_server.go | 2 +- simapp/app.go | 12 ++- testing/simapp/app.go | 4 +- 13 files changed, 185 insertions(+), 193 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 1277eceb93b..864e060f062 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -71,16 +71,6 @@ func (im IBCMiddleware) OnChanOpenInit( if err != nil { return "", err } - - // call underlying app's OnChanOpenInit callback with the passed in version - // the version returned is discarded as the ica-auth module does not have permission to edit the version string. - // ics27 will always return the version string containing the Metadata struct which is created during the `RegisterInterchainAccount` call. - if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionHops[0]) { - if _, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, version); err != nil { - return "", err - } - } - return version, nil } @@ -395,3 +385,17 @@ func (im IBCMiddleware) UnmarshalPacketData(ctx sdk.Context, portID string, chan return data, version, nil } + +// WrapVersion returns the wrapped version based on the provided version string and underlying application version. +// TODO: decide how we want to handle the underlying app. For now I made it backwards compatible. +// https://github.com/cosmos/ibc-go/issues/7063 +func (IBCMiddleware) WrapVersion(cbVersion, underlyingAppVersion string) string { + // ignore underlying app version + return cbVersion +} + +// UnwrapVersionUnsafe returns the version. Interchain accounts does not wrap versions. +func (IBCMiddleware) UnwrapVersionUnsafe(version string) (string, string, error) { + // ignore underlying app version + return version, "", nil +} diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 620e3792a4d..f621e84ca62 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -113,72 +113,28 @@ func SetupICAPath(path *ibctesting.Path, owner string) error { func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { var ( - channel *channeltypes.Channel - isNilApp bool - path *ibctesting.Path + channel *channeltypes.Channel + counterparty channeltypes.Counterparty + path *ibctesting.Path ) testCases := []struct { name string malleate func() - expPass bool + expError error }{ { - "success", func() {}, true, - }, - { - "ICA auth module does not claim channel capability", func() { - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, - counterparty channeltypes.Counterparty, version string, - ) (string, error) { - return version, nil - } - }, true, - }, - { - "ICA auth module modification of channel version is ignored", func() { - // NOTE: explicitly modify the channel version via the auth module callback, - // ensuring the expected JSON encoded metadata is not modified upon return - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, - counterparty channeltypes.Counterparty, version string, - ) (string, error) { - return "invalid-version", nil - } - }, true, + "success", func() {}, nil, }, { "controller submodule disabled", func() { suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) - }, false, - }, - { - "ICA auth module callback fails", func() { - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, - counterparty channeltypes.Counterparty, version string, - ) (string, error) { - return "", fmt.Errorf("mock ica auth fails") - } - }, false, - }, - { - "nil underlying app", func() { - isNilApp = true - }, true, + }, types.ErrControllerSubModuleDisabled, }, { - "middleware disabled", func() { - suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) - - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, - counterparty channeltypes.Counterparty, version string, - ) (string, error) { - return "", fmt.Errorf("error should be unreachable") - } - }, true, + "keeper call fails - counterparty portID incorrect", func() { + counterparty.PortId = "invalid-portID" + }, icatypes.ErrInvalidHostPort, }, } @@ -188,7 +144,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { suite.Run(tc.name, func() { suite.SetupTest() // reset - isNilApp = false path = NewICAPath(suite.chainA, suite.chainB, ordering) path.SetupConnections() @@ -206,7 +161,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { suite.chainA.GetSimApp().ICAControllerKeeper.SetMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) // default values - counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + counterparty = channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) channel = &channeltypes.Channel{ State: channeltypes.INIT, Ordering: ordering, @@ -220,21 +175,21 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenInit() { // ensure channel on chainA is set in state suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, *channel) - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointA.ChannelConfig.PortID) suite.Require().True(ok) - if isNilApp { - cbs = controller.NewIBCMiddleware(suite.chainA.GetSimApp().ICAControllerKeeper) - } + legacyModule, ok := cbs.(*porttypes.LegacyIBCModule) + suite.Require().True(ok, "expected there to be a single legacy ibc module") + + legacyModuleCbs := legacyModule.GetCallbacks() + controllerModule, ok := legacyModuleCbs[1].(controller.IBCMiddleware) // fee module is routed second + suite.Require().True(ok) - version, err := cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel.Counterparty, channel.Version, + version, err := controllerModule.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterparty, channel.Version, ) - if tc.expPass { + if tc.expError == nil { suite.Require().Equal(TestVersion, version) suite.Require().NoError(err) } else { diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 36699316901..50cc1257bb9 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -2,6 +2,7 @@ package fee import ( "encoding/json" + "fmt" "strings" errorsmod "cosmossdk.io/errors" @@ -21,6 +22,7 @@ var ( _ porttypes.Middleware = (*IBCMiddleware)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) _ porttypes.UpgradableModule = (*IBCMiddleware)(nil) + _ porttypes.VersionWrapper = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the @@ -48,45 +50,12 @@ func (im IBCMiddleware) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) (string, error) { - var versionMetadata types.Metadata - - if strings.TrimSpace(version) == "" { - // default version - versionMetadata = types.Metadata{ - FeeVersion: types.Version, - AppVersion: "", - } - } else { - metadata, err := types.MetadataFromVersion(version) - if err != nil { - // Since it is valid for fee version to not be specified, the above middleware version may be for a middleware - // lower down in the stack. Thus, if it is not a fee version we pass the entire version string onto the underlying - // application. - return im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, - counterparty, version) - } - versionMetadata = metadata - } - - if versionMetadata.FeeVersion != types.Version { - return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) - } - - appVersion, err := im.app.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, versionMetadata.AppVersion) - if err != nil { - return "", err - } - - versionMetadata.AppVersion = appVersion - versionBytes, err := types.ModuleCdc.MarshalJSON(&versionMetadata) - if err != nil { - return "", err + if strings.TrimSpace(version) != "" && version != types.Version { + return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, version) } im.keeper.SetFeeEnabled(ctx, portID, channelID) - - // call underlying app's OnChanOpenInit callback with the appVersion - return string(versionBytes), nil + return types.Version, nil } // OnChanOpenTry implements the IBCMiddleware interface @@ -501,3 +470,30 @@ func unwrapAppVersion(channelVersion string) string { return metadata.AppVersion } + +// WrapVersion returns the wrapped ics29 version based on the provided ics29 version and the underlying application version. +func (IBCMiddleware) WrapVersion(cbVersion, underlyingAppVersion string) string { + if cbVersion != types.Version { + panic(fmt.Errorf("invalid ics29 version provided. expected: %s, got: %s", types.Version, cbVersion)) + } + + metadata := types.Metadata{ + FeeVersion: cbVersion, + AppVersion: underlyingAppVersion, + } + + versionBytes := types.ModuleCdc.MustMarshalJSON(&metadata) + + return string(versionBytes) +} + +// UnwrapVersionUnsafe attempts to unmarshal the version string into a ics29 version. An error is returned if unsuccessful. +func (IBCMiddleware) UnwrapVersionUnsafe(version string) (string, string, error) { + metadata, err := types.MetadataFromVersion(version) + if err != nil { + // not an ics29 version + return "", version, err + } + + return metadata.FeeVersion, metadata.AppVersion, nil +} diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 9ea47a7f204..25b882bd1d0 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -29,46 +29,24 @@ var ( // Tests OnChanOpenInit on ChainA func (suite *FeeTestSuite) TestOnChanOpenInit() { testCases := []struct { - name string - version string - expPass bool - isFeeEnabled bool + name string + version string + expError error }{ { - "success - valid fee middleware and mock version", - string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), - true, - true, + "success - valid fee version", + types.Version, + nil, }, { - "success - fee version not included, only perform mock logic", - ibcmock.Version, - true, - false, + "success - empty version", + "", + nil, }, { "invalid fee middleware version", - string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: "invalid-ics29-1", AppVersion: ibcmock.Version})), - false, - false, - }, - { - "invalid mock version", - string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: "invalid-mock-version"})), - false, - false, - }, - { - "mock version not wrapped", - types.Version, - false, - false, - }, - { - "passing an empty string returns default version", - "", - true, - true, + "invalid-ics29-1", + types.ErrInvalidVersion, }, } @@ -81,17 +59,6 @@ func (suite *FeeTestSuite) TestOnChanOpenInit() { suite.SetupTest() suite.path.SetupConnections() - // setup mock callback - suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenInit = func(ctx sdk.Context, order channeltypes.Order, connectionHops []string, - portID, channelID string, - counterparty channeltypes.Counterparty, version string, - ) (string, error) { - if version != ibcmock.Version { - return "", fmt.Errorf("incorrect mock version") - } - return ibcmock.Version, nil - } - suite.path.EndpointA.ChannelID = ibctesting.FirstChannelID counterparty := channeltypes.NewCounterparty(suite.path.EndpointB.ChannelConfig.PortID, suite.path.EndpointB.ChannelID) @@ -103,34 +70,24 @@ func (suite *FeeTestSuite) TestOnChanOpenInit() { Version: tc.version, } - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(ibctesting.MockFeePort) + suite.Require().True(ok) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + legacyModule, ok := cbs.(*porttypes.LegacyIBCModule) + suite.Require().True(ok, "expected there to be a single legacy ibc module") + + legacyModuleCbs := legacyModule.GetCallbacks() + feeModule, ok := legacyModuleCbs[1].(ibcfee.IBCMiddleware) // fee module is routed second suite.Require().True(ok) - version, err := cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, + version, err := feeModule.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, counterparty, channel.Version) - if tc.expPass { - // check if the channel is fee enabled. If so version string should include metaData - if tc.isFeeEnabled { - versionMetadata := types.Metadata{ - FeeVersion: types.Version, - AppVersion: ibcmock.Version, - } - - versionBytes, err := types.ModuleCdc.MarshalJSON(&versionMetadata) - suite.Require().NoError(err) - - suite.Require().Equal(version, string(versionBytes)) - } else { - suite.Require().Equal(ibcmock.Version, version) - } - + if tc.expError == nil { + suite.Require().Equal(types.Version, version) suite.Require().NoError(err, "unexpected error from version: %s", tc.version) } else { - suite.Require().Error(err, "error not returned for version: %s", tc.version) + suite.Require().ErrorIs(err, tc.expError, "error not returned for version: %s", tc.version) suite.Require().Equal("", version) } }) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 99b63fb5501..01e40351bca 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -307,7 +307,7 @@ func (IBCMiddleware) processCallback( } // OnChanOpenInit defers to the underlying application -func (im IBCMiddleware) OnChanOpenInit( +func (IBCMiddleware) OnChanOpenInit( ctx sdk.Context, channelOrdering channeltypes.Order, connectionHops []string, @@ -316,7 +316,7 @@ func (im IBCMiddleware) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) (string, error) { - return im.app.OnChanOpenInit(ctx, channelOrdering, connectionHops, portID, channelID, counterparty, version) + return "", nil } // OnChanOpenTry defers to the underlying application diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 302f6c02868..d79aaddc8e3 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -171,7 +171,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { s.Require().Len(cbs, 1, "expected 1 legacy module") - legacyModule, ok := cbs[0].(porttypes.LegacyIBCModule) + legacyModule, ok := cbs[0].(*porttypes.LegacyIBCModule) s.Require().True(ok, "expected there to be a single legacy ibc module") legacyModuleCbs := legacyModule.GetCallbacks() diff --git a/modules/apps/callbacks/testing/simapp/app.go b/modules/apps/callbacks/testing/simapp/app.go index 36e14716323..43a9b74eb3a 100644 --- a/modules/apps/callbacks/testing/simapp/app.go +++ b/modules/apps/callbacks/testing/simapp/app.go @@ -526,6 +526,7 @@ func NewSimApp( // initialize ICA module with mock module as the authentication module on the controller side var icaControllerStack porttypes.ClassicIBCModule icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp("", scopedICAMockKeeper)) + ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) app.ICAAuthModule, ok = icaControllerStack.(ibcmock.IBCModule) if !ok { panic(fmt.Errorf("cannot convert %T to %T", icaControllerStack, app.ICAAuthModule)) @@ -549,7 +550,9 @@ func NewSimApp( var icaHostStack porttypes.ClassicIBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) + ibcAppRouter.AddRoute(icahosttypes.SubModuleName, icaHostStack) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) + ibcAppRouter.AddRoute(icahosttypes.SubModuleName, icaHostStack) // Add host, controller & ica auth modules to IBC router ibcRouter. @@ -560,9 +563,7 @@ func NewSimApp( AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) - ibcAppRouter. - AddRoute(icahosttypes.SubModuleName, icaHostStack). - AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // Create Mock IBC Fee module stack for testing // SendPacket, mock module cannot send packets @@ -576,10 +577,13 @@ func NewSimApp( // create fee wrapped mock module feeMockModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(MockFeePort, scopedFeeMockKeeper)) app.FeeMockModule = feeMockModule + ibcAppRouter.AddRoute(MockFeePort, feeMockModule) + var feeWithMockModule porttypes.Middleware = ibcfee.NewIBCMiddleware(feeMockModule, app.IBCFeeKeeper) + ibcAppRouter.AddRoute(MockFeePort, feeWithMockModule) + feeWithMockModule = ibccallbacks.NewIBCMiddleware(feeWithMockModule, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) ibcRouter.AddRoute(MockFeePort, feeWithMockModule) - ibcAppRouter.AddRoute(MockFeePort, feeWithMockModule) // Seal the IBC Router diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index 6879a3a1683..858c5d49b6e 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -1,12 +1,15 @@ package types import ( + "strings" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types" + ibcerrors "github.com/cosmos/ibc-go/v9/modules/core/errors" ibcexported "github.com/cosmos/ibc-go/v9/modules/core/exported" ) @@ -22,13 +25,13 @@ func (im *LegacyIBCModule) GetCallbacks() []ClassicIBCModule { // NewLegacyIBCModule creates a new IBCModule given the keeper func NewLegacyIBCModule(cbs ...ClassicIBCModule) ClassicIBCModule { - return LegacyIBCModule{ + return &LegacyIBCModule{ cbs: cbs, } } -// OnChanOpenInit implements the IBCModule interface -func (LegacyIBCModule) OnChanOpenInit( +// OnChanOpenInit implements the IBCModule interface. +func (im *LegacyIBCModule) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, connectionHops []string, @@ -37,7 +40,54 @@ func (LegacyIBCModule) OnChanOpenInit( counterparty channeltypes.Counterparty, version string, ) (string, error) { - return "", nil + negotiatedVersions := make([]string, len(im.cbs)) + + for i := len(im.cbs) - 1; i >= 0; i-- { + cbVersion := version + + // To maintain backwards compatibility, we must handle two cases: + // - relayer provides empty version (use default versions) + // - relayer provides version which chooses to not enable a middleware + // + // If an application is a VersionWrapper which means it modifies the version string + // and the version string is non-empty (don't use default), then the application must + // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. + // If it is unsuccessful, no callback will occur to this application as the version + // indicates it should be disabled. + if wrapper, ok := im.cbs[i].(VersionWrapper); ok && strings.TrimSpace(version) != "" { + appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(version) + if err != nil { + // middleware disabled + negotiatedVersions[i] = "" + continue + } + cbVersion, version = appVersion, underlyingAppVersion + } + + negotiatedVersion, err := im.cbs[i].OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, cbVersion) + if err != nil { + return "", errorsmod.Wrapf(err, "channel open init callback failed for port ID: %s, channel ID: %s", portID, channelID) + } + negotiatedVersions[i] = negotiatedVersion + } + + return reconstructVersion(im.cbs, negotiatedVersions) +} + +// reconstructVersion will generate the channel version by applying any version wrapping as necessary. +// Version wrapping will only occur if the negotiated version is non=empty and the application is a VersionWrapper. +func reconstructVersion(cbs []ClassicIBCModule, negotiatedVersions []string) (string, error) { + version := negotiatedVersions[0] // base version + for i := 1; i < len(cbs); i++ { // iterate over the remaining callbacks + if strings.TrimSpace(negotiatedVersions[i]) != "" { + wrapper, ok := cbs[i].(VersionWrapper) + if !ok { + return "", ibcerrors.ErrInvalidVersion + } + version = wrapper.WrapVersion(negotiatedVersions[i], version) + } + } + return version, nil } // OnChanOpenTry implements the IBCModule interface. diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index bfcdd6bee1d..f43a6efc504 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -121,6 +121,24 @@ type IBCModule interface { ) error } +// VersionWrapper is an optional interface which should be implemented by middleware which wrap the channel version +// to ensure backwards compatibility. +type VersionWrapper interface { + // WrapVersion is required in order to remove middleware wiring and the ICS4Wrapper + // while maintaining backwards compatibility. It will be removed in the future. + // Applications should wrap the provided version with their application version. + // If they do not need to wrap, they may simply return the version provided. + WrapVersion(cbVersion, underlyingAppVersion string) string + // UnwrapVersionUnsafe is required in order to remove middleware wiring and the ICS4Wrapper + // while maintaining backwards compatibility. It will be removed in the future. + // Applications should unwrap the provided version with into their application version. + // and the underlying application version. If they are unsuccessful they should return an error. + // UnwrapVersionUnsafe will be used during opening handshakes and channel upgrades when the version + // is still being negotiated. + UnwrapVersionUnsafe(string) (cbVersion, underlyingAppVersion string, err error) + // UnwrapVersionSafe(ctx sdk.Context, portID, channelID, version string) (appVersion, version string) +} + // UpgradableModule defines the callbacks required to perform a channel upgrade. // Note: applications must ensure that state related to packet processing remains unmodified until the OnChanUpgradeOpen callback is executed. // This guarantees that in-flight packets are correctly flushed using the existing channel parameters. diff --git a/modules/core/05-port/types/router_v2.go b/modules/core/05-port/types/router_v2.go index 1c52e4a06ba..83c40e2ecd0 100644 --- a/modules/core/05-port/types/router_v2.go +++ b/modules/core/05-port/types/router_v2.go @@ -66,7 +66,7 @@ func (rtr *AppRouter) AddRoute(module string, cbs IBCModule) *AppRouter { // in order to facilitate having a single LegacyIBCModule, but also allowing for // consecutive calls to AddRoute to support existing functionality, we can re-create // the legacy module with the routes as they get added. - if classicRoutes, ok := rtr.classicRoutes[module]; ok && len(classicRoutes) > 1 { + if classicRoutes, ok := rtr.classicRoutes[module]; ok { rtr.legacyRoutes[module] = NewLegacyIBCModule(classicRoutes...) } } else { diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index eb534a12958..08c8c66cf00 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -194,7 +194,7 @@ func (k *Keeper) ChannelOpenInit(goCtx context.Context, msg *channeltypes.MsgCha ctx := sdk.UnwrapSDKContext(goCtx) // Retrieve application callbacks from router - cbs, ok := k.PortKeeper.Route(msg.PortId) + cbs, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { ctx.Logger().Error("channel open init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) diff --git a/simapp/app.go b/simapp/app.go index 9fbd17c744f..cf9a8cc0a7a 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -514,6 +514,8 @@ func NewSimApp( // initialize ICA module with mock module as the authentication module on the controller side var icaControllerStack porttypes.ClassicIBCModule icaControllerStack = mock.NewIBCModule(&mockModule, mock.NewIBCApp("", scopedICAMockKeeper)) + ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(mock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) var ok bool app.ICAAuthModule, ok = icaControllerStack.(mock.IBCModule) if !ok { @@ -521,15 +523,20 @@ func NewSimApp( } icaControllerStack = icacontroller.NewIBCMiddleware(app.ICAControllerKeeper) ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(mock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) + icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(mock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // RecvPacket, message that originates from core IBC and goes down to app, the flow is: // channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket var icaHostStack porttypes.ClassicIBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) + ibcAppRouter.AddRoute(icahosttypes.SubModuleName, icaHostStack) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) + ibcAppRouter.AddRoute(icahosttypes.SubModuleName, icaHostStack) // Add host, controller & ica auth modules to IBC router ibcRouter. @@ -540,9 +547,6 @@ func NewSimApp( AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(mock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) - ibcAppRouter. - AddRoute(icahosttypes.SubModuleName, icaHostStack). - AddRoute(mock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // Create Mock IBC Fee module stack for testing // SendPacket, mock module cannot send packets @@ -555,6 +559,8 @@ func NewSimApp( // create fee wrapped mock module feeMockModule := mock.NewIBCModule(&mockModule, mock.NewIBCApp(MockFeePort, scopedFeeMockKeeper)) app.FeeMockModule = feeMockModule + ibcAppRouter.AddRoute(MockFeePort, feeMockModule) + feeWithMockModule := ibcfee.NewIBCMiddleware(feeMockModule, app.IBCFeeKeeper) ibcRouter.AddRoute(MockFeePort, feeWithMockModule) ibcAppRouter.AddRoute(MockFeePort, feeWithMockModule) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 4c5d688eb7f..b1449658164 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -479,6 +479,7 @@ func NewSimApp( // initialize ICA module with mock module as the authentication module on the controller side var icaControllerStack porttypes.ClassicIBCModule icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp("", scopedICAMockKeeper)) + ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) var ok bool app.ICAAuthModule, ok = icaControllerStack.(ibcmock.IBCModule) if !ok { @@ -521,9 +522,10 @@ func NewSimApp( // create fee wrapped mock module feeMockModule := ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp(MockFeePort, scopedFeeMockKeeper)) app.FeeMockModule = feeMockModule + ibcAppRouter.AddRoute(MockFeePort, feeMockModule) + feeWithMockModule := ibcfee.NewIBCMiddleware(feeMockModule, app.IBCFeeKeeper) ibcRouter.AddRoute(MockFeePort, feeWithMockModule) - ibcAppRouter.AddRoute(MockFeePort, feeWithMockModule) // Seal the IBC Router From 946040082aa3d901d910f391ff9bb2629ea30613 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 7 Aug 2024 15:07:17 +0100 Subject: [PATCH 30/46] Use new port router for onchanupgradetry (#7067) * chore: add fee implementation for OnChanOpenTry * chore: fix wiring in app.gos * chore: updated callbacks tests to handle new OnChanOpenTry * chore: lint, correct error string * chore: remove commented code * chore: addressing PR feedback --- .../host/ibc_module_test.go | 5 +- modules/apps/29-fee/fee_test.go | 6 ++ modules/apps/29-fee/ibc_middleware.go | 30 ++-------- modules/apps/29-fee/ibc_middleware_test.go | 5 +- modules/apps/callbacks/ibc_middleware.go | 8 +-- modules/apps/callbacks/ibc_middleware_test.go | 6 +- modules/apps/callbacks/testing/simapp/app.go | 7 ++- modules/apps/transfer/ibc_module_test.go | 5 +- .../core/05-port/types/ibc_legacy_module.go | 57 ++++++++++++++----- modules/core/keeper/msg_server.go | 2 +- testing/simapp/app.go | 9 +-- 11 files changed, 74 insertions(+), 66 deletions(-) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 1709c77b1f7..17071dabdc6 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -203,10 +203,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenTry() { // ensure channel on chainB is set in state suite.chainB.GetSimApp().IBCKeeper.ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, *channel) - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(icatypes.HostPortID) suite.Require().True(ok) version, err := cbs.OnChanOpenTry(suite.chainB.GetContext(), channel.Ordering, channel.ConnectionHops, diff --git a/modules/apps/29-fee/fee_test.go b/modules/apps/29-fee/fee_test.go index b2d266c8090..ed888265b72 100644 --- a/modules/apps/29-fee/fee_test.go +++ b/modules/apps/29-fee/fee_test.go @@ -76,23 +76,29 @@ func RemoveFeeMiddleware(chain *ibctesting.TestChain) { chain.GetSimApp().IBCKeeper.PortKeeper.Router = nil newRouter := porttypes.NewRouter() // Create a new router + newAppRouter := porttypes.NewAppRouter() + // Remove Fee middleware from transfer module chain.GetSimApp().TransferKeeper.WithICS4Wrapper(channelKeeper) transferStack := transfer.NewIBCModule(chain.GetSimApp().TransferKeeper) newRouter.AddRoute(transfertypes.ModuleName, transferStack) + newAppRouter.AddRoute(transfertypes.ModuleName, transferStack) // Remove Fee middleware from icahost submodule chain.GetSimApp().ICAHostKeeper.WithICS4Wrapper(channelKeeper) icaHostStack := icahost.NewIBCModule(chain.GetSimApp().ICAHostKeeper) newRouter.AddRoute(icahosttypes.SubModuleName, icaHostStack) + newAppRouter.AddRoute(icahosttypes.SubModuleName, icaHostStack) // Remove Fee middleware from icacontroller submodule chain.GetSimApp().ICAControllerKeeper.WithICS4Wrapper(channelKeeper) icaControllerStack := icacontroller.NewIBCMiddleware(chain.GetSimApp().ICAControllerKeeper) newRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + newAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) // Override and seal the router chain.GetSimApp().IBCKeeper.SetRouter(newRouter) + chain.GetSimApp().IBCKeeper.SetAppRouter(newAppRouter) } // helper function diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 50cc1257bb9..49b439c1e3e 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -70,33 +70,11 @@ func (im IBCMiddleware) OnChanOpenTry( counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { - versionMetadata, err := types.MetadataFromVersion(counterpartyVersion) - if err != nil { - // Since it is valid for fee version to not be specified, the above middleware version may be for a middleware - // lower down in the stack. Thus, if it is not a fee version we pass the entire version string onto the underlying - // application. - return im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, counterpartyVersion) + if counterpartyVersion != types.Version { + return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, counterpartyVersion) } - - if versionMetadata.FeeVersion != types.Version { - return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) - } - im.keeper.SetFeeEnabled(ctx, portID, channelID) - - // call underlying app's OnChanOpenTry callback with the app versions - appVersion, err := im.app.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, versionMetadata.AppVersion) - if err != nil { - return "", err - } - - versionMetadata.AppVersion = appVersion - versionBytes, err := types.ModuleCdc.MarshalJSON(&versionMetadata) - if err != nil { - return "", err - } - - return string(versionBytes), nil + return counterpartyVersion, nil } // OnChanOpenAck implements the IBCMiddleware interface @@ -487,7 +465,7 @@ func (IBCMiddleware) WrapVersion(cbVersion, underlyingAppVersion string) string return string(versionBytes) } -// UnwrapVersionUnsafe attempts to unmarshal the version string into a ics29 version. An error is returned if unsuccessful. +// UnwrapVersionUnsafe attempts to unmarshal the version string into a ics29 version. An error is returned if unsuccessful. func (IBCMiddleware) UnwrapVersionUnsafe(version string) (string, string, error) { metadata, err := types.MetadataFromVersion(version) if err != nil { diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 25b882bd1d0..cb3a2030210 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -159,10 +159,7 @@ func (suite *FeeTestSuite) TestOnChanOpenTry() { Version: tc.cpVersion, } - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(ibctesting.MockFeePort) suite.Require().True(ok) _, err = cbs.OnChanOpenTry(suite.chainA.GetContext(), channel.Ordering, channel.ConnectionHops, diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 01e40351bca..f8e067485b1 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -306,7 +306,7 @@ func (IBCMiddleware) processCallback( return err } -// OnChanOpenInit defers to the underlying application +// OnChanOpenInit is a no-op for the callbacks middleware. func (IBCMiddleware) OnChanOpenInit( ctx sdk.Context, channelOrdering channeltypes.Order, @@ -319,8 +319,8 @@ func (IBCMiddleware) OnChanOpenInit( return "", nil } -// OnChanOpenTry defers to the underlying application -func (im IBCMiddleware) OnChanOpenTry( +// OnChanOpenTry is a no-op for the callbacks middleware. +func (IBCMiddleware) OnChanOpenTry( ctx sdk.Context, channelOrdering channeltypes.Order, connectionHops []string, portID, @@ -328,7 +328,7 @@ func (im IBCMiddleware) OnChanOpenTry( counterparty channeltypes.Counterparty, counterpartyVersion string, ) (string, error) { - return im.app.OnChanOpenTry(ctx, channelOrdering, connectionHops, portID, channelID, counterparty, counterpartyVersion) + return "", nil } // OnChanOpenAck defers to the underlying application diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index d79aaddc8e3..b682435d065 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -166,12 +166,10 @@ func (s *CallbacksTestSuite) TestSendPacket() { s.Run(tc.name, func() { s.SetupTransferTest() - cbs, ok := GetSimApp(s.chainA).IBCKeeper.PortKeeper.AppRoute(transfertypes.ModuleName) + cbs, ok := GetSimApp(s.chainA).IBCKeeper.PortKeeper.AppRouter.HandshakeRoute(transfertypes.ModuleName) s.Require().True(ok) - s.Require().Len(cbs, 1, "expected 1 legacy module") - - legacyModule, ok := cbs[0].(*porttypes.LegacyIBCModule) + legacyModule, ok := cbs.(*porttypes.LegacyIBCModule) s.Require().True(ok, "expected there to be a single legacy ibc module") legacyModuleCbs := legacyModule.GetCallbacks() diff --git a/modules/apps/callbacks/testing/simapp/app.go b/modules/apps/callbacks/testing/simapp/app.go index 43a9b74eb3a..b2747a32209 100644 --- a/modules/apps/callbacks/testing/simapp/app.go +++ b/modules/apps/callbacks/testing/simapp/app.go @@ -527,14 +527,18 @@ func NewSimApp( var icaControllerStack porttypes.ClassicIBCModule icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp("", scopedICAMockKeeper)) ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) app.ICAAuthModule, ok = icaControllerStack.(ibcmock.IBCModule) if !ok { panic(fmt.Errorf("cannot convert %T to %T", icaControllerStack, app.ICAAuthModule)) } icaControllerStack = icacontroller.NewIBCMiddlewareWithAuth(icaControllerStack, app.ICAControllerKeeper) ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) icaControllerStack = ibccallbacks.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper, app.MockContractKeeper, maxCallbackGas) ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) + var icaICS4Wrapper porttypes.ICS4Wrapper icaICS4Wrapper, ok = icaControllerStack.(porttypes.ICS4Wrapper) if !ok { @@ -542,6 +546,7 @@ func NewSimApp( } icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // Since the callbacks middleware itself is an ics4wrapper, it needs to be passed to the ica controller keeper app.ICAControllerKeeper.WithICS4Wrapper(icaICS4Wrapper) @@ -563,8 +568,6 @@ func NewSimApp( AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) - ibcAppRouter.AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) - // Create Mock IBC Fee module stack for testing // SendPacket, mock module cannot send packets diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index bfd7db73962..d66118d773e 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -180,10 +180,7 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { } counterpartyVersion = types.V2 - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(ibctesting.TransferPort) suite.Require().True(ok) tc.malleate() // explicitly change fields in channel and testChannel diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index 858c5d49b6e..cf849155682 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -74,6 +74,50 @@ func (im *LegacyIBCModule) OnChanOpenInit( return reconstructVersion(im.cbs, negotiatedVersions) } +// OnChanOpenTry implements the IBCModule interface. +func (im *LegacyIBCModule) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + counterparty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + negotiatedVersions := make([]string, len(im.cbs)) + + for i := len(im.cbs) - 1; i >= 0; i-- { + cbVersion := counterpartyVersion + + // To maintain backwards compatibility, we must handle two cases: + // - relayer provides empty version (use default versions) + // - relayer provides version which chooses to not enable a middleware + // + // If an application is a VersionWrapper which means it modifies the version string + // and the version string is non-empty (don't use default), then the application must + // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. + // If it is unsuccessful, no callback will occur to this application as the version + // indicates it should be disabled. + if wrapper, ok := im.cbs[i].(VersionWrapper); ok && strings.TrimSpace(counterpartyVersion) != "" { + appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(counterpartyVersion) + if err != nil { + // middleware disabled + negotiatedVersions[i] = "" + continue + } + cbVersion, counterpartyVersion = appVersion, underlyingAppVersion + } + + negotiatedVersion, err := im.cbs[i].OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, cbVersion) + if err != nil { + return "", errorsmod.Wrapf(err, "channel open try callback failed for port ID: %s, channel ID: %s", portID, channelID) + } + negotiatedVersions[i] = negotiatedVersion + } + + return reconstructVersion(im.cbs, negotiatedVersions) +} + // reconstructVersion will generate the channel version by applying any version wrapping as necessary. // Version wrapping will only occur if the negotiated version is non=empty and the application is a VersionWrapper. func reconstructVersion(cbs []ClassicIBCModule, negotiatedVersions []string) (string, error) { @@ -90,19 +134,6 @@ func reconstructVersion(cbs []ClassicIBCModule, negotiatedVersions []string) (st return version, nil } -// OnChanOpenTry implements the IBCModule interface. -func (LegacyIBCModule) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (string, error) { - return "", nil -} - // OnChanOpenAck implements the IBCModule interface func (LegacyIBCModule) OnChanOpenAck( ctx sdk.Context, diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 08c8c66cf00..0989b60ccdd 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -235,7 +235,7 @@ func (k *Keeper) ChannelOpenTry(goCtx context.Context, msg *channeltypes.MsgChan ctx := sdk.UnwrapSDKContext(goCtx) // Retrieve application callbacks from router - cbs, ok := k.PortKeeper.Route(msg.PortId) + cbs, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { ctx.Logger().Error("channel open try failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index b1449658164..d53bde01793 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -480,6 +480,7 @@ func NewSimApp( var icaControllerStack porttypes.ClassicIBCModule icaControllerStack = ibcmock.NewIBCModule(&mockModule, ibcmock.NewIBCApp("", scopedICAMockKeeper)) ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) var ok bool app.ICAAuthModule, ok = icaControllerStack.(ibcmock.IBCModule) if !ok { @@ -487,15 +488,19 @@ func NewSimApp( } icaControllerStack = icacontroller.NewIBCMiddlewareWithAuth(icaControllerStack, app.ICAControllerKeeper) ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) icaControllerStack = ibcfee.NewIBCMiddleware(icaControllerStack, app.IBCFeeKeeper) ibcAppRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack) + ibcAppRouter.AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // RecvPacket, message that originates from core IBC and goes down to app, the flow is: // channel.RecvPacket -> fee.OnRecvPacket -> icaHost.OnRecvPacket var icaHostStack porttypes.ClassicIBCModule icaHostStack = icahost.NewIBCModule(app.ICAHostKeeper) + ibcAppRouter.AddRoute(icahosttypes.SubModuleName, icaHostStack) icaHostStack = ibcfee.NewIBCMiddleware(icaHostStack, app.IBCFeeKeeper) + ibcAppRouter.AddRoute(icahosttypes.SubModuleName, icaHostStack) // Add host, controller & ica auth modules to IBC router ibcRouter. @@ -506,10 +511,6 @@ func NewSimApp( AddRoute(icahosttypes.SubModuleName, icaHostStack). AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) // ica with mock auth module stack route to ica (top level of middleware stack) - ibcAppRouter. - AddRoute(icahosttypes.SubModuleName, icaHostStack). - AddRoute(ibcmock.ModuleName+icacontrollertypes.SubModuleName, icaControllerStack) - // Create Mock IBC Fee module stack for testing // SendPacket, mock module cannot send packets From 6ec1efa9f60579ae9e9188cd57813fe86462348f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:00:22 +0200 Subject: [PATCH 31/46] Use new port router for OnChanOpenAck (#7084) * refactor: use new port router for OnChanOpenAck * fix: transfer test * fix: controller tests * fix: legacy ibc module handler on disabling --- .../controller/ibc_middleware.go | 10 --- .../controller/ibc_middleware_test.go | 59 +++++------------- modules/apps/29-fee/ibc_middleware.go | 25 +++----- modules/apps/29-fee/ibc_middleware_test.go | 61 ++++++------------- modules/apps/callbacks/ibc_middleware.go | 6 +- modules/apps/transfer/ibc_module_test.go | 9 +-- .../core/05-port/types/ibc_legacy_module.go | 37 ++++++++++- modules/core/keeper/msg_server.go | 2 +- 8 files changed, 85 insertions(+), 124 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 864e060f062..8608d8fb8f9 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -108,16 +108,6 @@ func (im IBCMiddleware) OnChanOpenAck( return err } - connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) - if err != nil { - return err - } - - // call underlying app's OnChanOpenAck callback with the counterparty app version. - if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionID) { - return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) - } - return nil } diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index f621e84ca62..d36b8a729a8 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -252,53 +252,25 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenTry() { } func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { - var ( - path *ibctesting.Path - isNilApp bool - ) + var path *ibctesting.Path testCases := []struct { name string malleate func() - expPass bool + expError error }{ { - "success", func() {}, true, + "success", func() {}, nil, }, { "controller submodule disabled", func() { suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) - }, false, + }, types.ErrControllerSubModuleDisabled, }, { "ICA OnChanOpenACK fails - invalid version", func() { path.EndpointB.ChannelConfig.Version = invalidVersion - }, false, - }, - { - "ICA auth module callback fails", func() { - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenAck = func( - ctx sdk.Context, portID, channelID string, counterpartyChannelID string, counterpartyVersion string, - ) error { - return fmt.Errorf("mock ica auth fails") - } - }, false, - }, - { - "nil underlying app", func() { - isNilApp = true - }, true, - }, - { - "middleware disabled", func() { - suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) - - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenAck = func( - ctx sdk.Context, portID, channelID string, counterpartyChannelID string, counterpartyVersion string, - ) error { - return fmt.Errorf("error should be unreachable") - } - }, true, + }, ibcerrors.ErrInvalidType, }, } @@ -308,7 +280,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { suite.Run(tc.name, func() { suite.SetupTest() // reset - isNilApp = false path = NewICAPath(suite.chainA, suite.chainB, ordering) path.SetupConnections() @@ -321,22 +292,22 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenAck() { tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointA.ChannelConfig.PortID) suite.Require().True(ok) - err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelID, path.EndpointB.ChannelConfig.Version) + legacyModule, ok := cbs.(*porttypes.LegacyIBCModule) + suite.Require().True(ok, "expected there to be a single legacy ibc module") - if isNilApp { - cbs = controller.NewIBCMiddleware(suite.chainA.GetSimApp().ICAControllerKeeper) - } + legacyModuleCbs := legacyModule.GetCallbacks() + controllerModule, ok := legacyModuleCbs[1].(controller.IBCMiddleware) // fee module is routed second + suite.Require().True(ok) - if tc.expPass { + err = controllerModule.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelID, path.EndpointB.ChannelConfig.Version) + + if tc.expError == nil { suite.Require().NoError(err) } else { - suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expError) } }) } diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 49b439c1e3e..dc07ffc7d6f 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -85,25 +85,18 @@ func (im IBCMiddleware) OnChanOpenAck( counterpartyChannelID string, counterpartyVersion string, ) error { - if im.keeper.IsFeeEnabled(ctx, portID, channelID) { - versionMetadata, err := types.MetadataFromVersion(counterpartyVersion) - if err != nil { - // we pass the entire version string onto the underlying application. - // and disable fees for this channel - im.keeper.DeleteFeeEnabled(ctx, portID, channelID) - return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) - } - - if versionMetadata.FeeVersion != types.Version { - return errorsmod.Wrapf(types.ErrInvalidVersion, "expected counterparty fee version: %s, got: %s", types.Version, versionMetadata.FeeVersion) - } + if strings.TrimSpace(counterpartyVersion) == "" { + // disable fees for this channel + im.keeper.DeleteFeeEnabled(ctx, portID, channelID) + return nil + } - // call underlying app's OnChanOpenAck callback with the counterparty app version. - return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, versionMetadata.AppVersion) + if counterpartyVersion != types.Version { + return errorsmod.Wrapf(types.ErrInvalidVersion, "expected counterparty fee version: %s, got: %s", types.Version, counterpartyVersion) } - // call underlying app's OnChanOpenAck callback with the counterparty app version. - return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) + im.keeper.SetFeeEnabled(ctx, portID, channelID) + return nil } // OnChanOpenConfirm implements the IBCMiddleware interface diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index cb3a2030210..107b736f6d1 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -181,41 +181,26 @@ func (suite *FeeTestSuite) TestOnChanOpenAck() { name string cpVersion string malleate func(suite *FeeTestSuite) - expPass bool + expError error }{ { "success", - string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), - func(suite *FeeTestSuite) {}, - true, - }, - { - "invalid fee version", - string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: "invalid-ics29-1", AppVersion: ibcmock.Version})), + types.Version, func(suite *FeeTestSuite) {}, - false, + nil, }, { - "invalid mock version", - string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: "invalid-mock-version"})), + "success, empty version string (disable middleware)", + "", func(suite *FeeTestSuite) {}, - false, + nil, }, + { - "invalid version fails to unmarshal metadata", - ibctesting.InvalidID, + "invalid fee version", + "invalid-ics29-1", func(suite *FeeTestSuite) {}, - false, - }, - { - "previous INIT set without fee, however counterparty set fee version", // note this can only happen with incompetent or malicious counterparty chain - string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: ibcmock.Version})), - func(suite *FeeTestSuite) { - // do the first steps without fee version, then pass the fee version as counterparty version in ChanOpenACK - suite.path.EndpointA.ChannelConfig.Version = ibcmock.Version - suite.path.EndpointB.ChannelConfig.Version = ibcmock.Version - }, - false, + types.ErrInvalidVersion, }, } @@ -225,16 +210,6 @@ func (suite *FeeTestSuite) TestOnChanOpenAck() { suite.SetupTest() suite.path.SetupConnections() - // setup mock callback - suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanOpenAck = func( - ctx sdk.Context, portID, channelID string, counterpartyChannelID string, counterpartyVersion string, - ) error { - if counterpartyVersion != ibcmock.Version { - return fmt.Errorf("incorrect mock version") - } - return nil - } - // malleate test case tc.malleate(suite) @@ -243,17 +218,21 @@ func (suite *FeeTestSuite) TestOnChanOpenAck() { err = suite.path.EndpointB.ChanOpenTry() suite.Require().NoError(err) - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(ibctesting.MockFeePort) + suite.Require().True(ok) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + legacyModule, ok := cbs.(*porttypes.LegacyIBCModule) + suite.Require().True(ok, "expected there to be a single legacy ibc module") + + legacyModuleCbs := legacyModule.GetCallbacks() + feeModule, ok := legacyModuleCbs[1].(ibcfee.IBCMiddleware) // fee module is routed second suite.Require().True(ok) - err = cbs.OnChanOpenAck(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.path.EndpointA.Counterparty.ChannelID, tc.cpVersion) - if tc.expPass { + err = feeModule.OnChanOpenAck(suite.chainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID, suite.path.EndpointA.Counterparty.ChannelID, tc.cpVersion) + if tc.expError == nil { suite.Require().NoError(err, "unexpected error for case: %s", tc.name) } else { - suite.Require().Error(err, "%s expected error but returned none", tc.name) + suite.Require().ErrorIs(err, tc.expError, "%s expected error but returned none", tc.name) } }) } diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index f8e067485b1..024fd1c8d6e 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -331,15 +331,15 @@ func (IBCMiddleware) OnChanOpenTry( return "", nil } -// OnChanOpenAck defers to the underlying application -func (im IBCMiddleware) OnChanOpenAck( +// OnChanOpenAck is a no-op for the callbacks middleware. +func (IBCMiddleware) OnChanOpenAck( ctx sdk.Context, portID, channelID, counterpartyChannelID, counterpartyVersion string, ) error { - return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) + return nil } // OnChanOpenConfirm defers to the underlying application diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index d66118d773e..aa09bdf15f6 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -231,15 +231,10 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { path.EndpointA.ChannelID = ibctesting.FirstChannelID counterpartyVersion = types.V2 - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - tc.malleate() // explicitly change fields in channel and testChannel - err = cbs.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointA.Counterparty.ChannelID, counterpartyVersion) + transferModule := transfer.NewIBCModule(suite.chainA.GetSimApp().TransferKeeper) + err := transferModule.OnChanOpenAck(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointA.Counterparty.ChannelID, counterpartyVersion) expPass := tc.expError == nil if expPass { diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index cf849155682..3776d6bc2be 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -31,6 +31,10 @@ func NewLegacyIBCModule(cbs ...ClassicIBCModule) ClassicIBCModule { } // OnChanOpenInit implements the IBCModule interface. +// NOTE: The application callback is skipped if all the following are true: +// - the relayer provided channel version is not empty +// - the callback application is a VersionWrapper +// - the application cannot unwrap the version func (im *LegacyIBCModule) OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, @@ -75,6 +79,10 @@ func (im *LegacyIBCModule) OnChanOpenInit( } // OnChanOpenTry implements the IBCModule interface. +// NOTE: The application callback is skipped if all the following are true: +// - the relayer provided channel version is not empty +// - the callback application is a VersionWrapper +// - the application cannot unwrap the version func (im *LegacyIBCModule) OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, @@ -134,14 +142,39 @@ func reconstructVersion(cbs []ClassicIBCModule, negotiatedVersions []string) (st return version, nil } -// OnChanOpenAck implements the IBCModule interface -func (LegacyIBCModule) OnChanOpenAck( +// OnChanOpenAck implements the IBCModule interface. +// NOTE: The callback will occur for all applications in the callback list. +// If the application is provided an empty string for the counterparty version, +// this indicates the module should be disabled for this portID and channelID. +func (im *LegacyIBCModule) OnChanOpenAck( ctx sdk.Context, portID, channelID string, counterpartyChannelID string, counterpartyVersion string, ) error { + for i := len(im.cbs) - 1; i >= 0; i-- { + cbVersion := counterpartyVersion + + // To maintain backwards compatibility, we must handle counterparty version negotiation. + // This means the version may have changed, and applications must be allowed to be disabled. + // Applications should be disabled when receiving an empty counterparty version. Callbacks + // for all applications must occur to allow disabling. + if wrapper, ok := im.cbs[i].(VersionWrapper); ok { + appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(counterpartyVersion) + if err != nil { + cbVersion = "" // disable application + } else { + cbVersion, counterpartyVersion = appVersion, underlyingAppVersion + } + } + + err := im.cbs[i].OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cbVersion) + if err != nil { + return errorsmod.Wrapf(err, "channel open ack callback failed for port ID: %s, channel ID: %s", portID, channelID) + } + } + return nil } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 0989b60ccdd..212e74ed489 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -275,7 +275,7 @@ func (k *Keeper) ChannelOpenAck(goCtx context.Context, msg *channeltypes.MsgChan ctx := sdk.UnwrapSDKContext(goCtx) // Retrieve application callbacks from router - cbs, ok := k.PortKeeper.Route(msg.PortId) + cbs, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { ctx.Logger().Error("channel open ack failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) From dc6e0725777a496b06e5ad6411be89091350ae0b Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Thu, 8 Aug 2024 10:01:38 +0100 Subject: [PATCH 32/46] Use new port router for OnChanUpgradeInit (#7082) * chore: add fee implementation for OnChanOpenTry * chore: fix wiring in app.gos * chore: updated callbacks tests to handle new OnChanOpenTry * chore: lint, correct error string * chore: remove commented code * chore: implementing OnChanUpgradeInit * chore: linter * chore: removed redundant test * chore: addressing PR feedback --- .../controller/ibc_middleware.go | 21 +----- .../controller/ibc_middleware_test.go | 13 +--- .../host/ibc_module_test.go | 6 +- modules/apps/29-fee/ibc_middleware.go | 32 +------- modules/apps/callbacks/ibc_middleware.go | 9 +-- .../core/05-port/types/ibc_legacy_module.go | 73 ++++++++++++++----- modules/core/keeper/msg_server.go | 2 +- modules/core/keeper/msg_server_test.go | 23 ------ 8 files changed, 65 insertions(+), 114 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index 8608d8fb8f9..cf9905781f6 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -273,26 +273,7 @@ func (im IBCMiddleware) OnChanUpgradeInit(ctx sdk.Context, portID, channelID str return "", types.ErrControllerSubModuleDisabled } - proposedVersion, err := im.keeper.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) - if err != nil { - return "", err - } - - connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) - if err != nil { - return "", err - } - - if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionID) { - // Only cast to UpgradableModule if the application is set. - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - return "", errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") - } - return cbs.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) - } - - return proposedVersion, nil + return im.keeper.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) } // OnChanUpgradeTry implements the IBCModule interface diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index d36b8a729a8..9b6a9f6f50f 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -747,14 +747,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() { } }, ibcmock.MockApplicationCallbackError, }, - { - "middleware disabled", func() { - suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanUpgradeInit = func(ctx sdk.Context, portID, channelID string, order channeltypes.Order, connectionHops []string, version string) (string, error) { - return "", ibcmock.MockApplicationCallbackError - } - }, nil, - }, } for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { @@ -775,10 +767,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() { tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(types.SubModuleName) suite.Require().True(ok) cbs, ok := app.(porttypes.UpgradableModule) suite.Require().True(ok) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 17071dabdc6..7be9f6c431b 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -658,11 +658,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeInit() { err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - // call application callback directly - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) - - app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(types.SubModuleName) suite.Require().True(ok) cbs, ok := app.(porttypes.UpgradableModule) suite.Require().True(ok) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index dc07ffc7d6f..060977d1e62 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -294,7 +294,7 @@ func (im IBCMiddleware) OnTimeoutPacket( } // OnChanUpgradeInit implements the IBCModule interface -func (im IBCMiddleware) OnChanUpgradeInit( +func (IBCMiddleware) OnChanUpgradeInit( ctx sdk.Context, portID string, channelID string, @@ -302,34 +302,10 @@ func (im IBCMiddleware) OnChanUpgradeInit( proposedConnectionHops []string, proposedVersion string, ) (string, error) { - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - return "", errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") + if proposedVersion != types.Version { + return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, proposedVersion) } - - versionMetadata, err := types.MetadataFromVersion(proposedVersion) - if err != nil { - // since it is valid for fee version to not be specified, the upgrade version may be for a middleware - // or application further down in the stack. Thus, pass through to next middleware or application in callstack. - return cbs.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) - } - - if versionMetadata.FeeVersion != types.Version { - return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) - } - - appVersion, err := cbs.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, versionMetadata.AppVersion) - if err != nil { - return "", err - } - - versionMetadata.AppVersion = appVersion - versionBz, err := types.ModuleCdc.MarshalJSON(&versionMetadata) - if err != nil { - return "", err - } - - return string(versionBz), nil + return types.Version, nil } // OnChanUpgradeTry implements the IBCModule interface diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 024fd1c8d6e..a5935e1b177 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -358,13 +358,8 @@ func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID st } // OnChanUpgradeInit implements the IBCModule interface -func (im IBCMiddleware) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - return "", errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") - } - - return cbs.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) +func (IBCMiddleware) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { + return "", nil } // OnChanUpgradeTry implements the IBCModule interface diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index 3776d6bc2be..43415290a8e 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -126,22 +126,6 @@ func (im *LegacyIBCModule) OnChanOpenTry( return reconstructVersion(im.cbs, negotiatedVersions) } -// reconstructVersion will generate the channel version by applying any version wrapping as necessary. -// Version wrapping will only occur if the negotiated version is non=empty and the application is a VersionWrapper. -func reconstructVersion(cbs []ClassicIBCModule, negotiatedVersions []string) (string, error) { - version := negotiatedVersions[0] // base version - for i := 1; i < len(cbs); i++ { // iterate over the remaining callbacks - if strings.TrimSpace(negotiatedVersions[i]) != "" { - wrapper, ok := cbs[i].(VersionWrapper) - if !ok { - return "", ibcerrors.ErrInvalidVersion - } - version = wrapper.WrapVersion(negotiatedVersions[i], version) - } - } - return version, nil -} - // OnChanOpenAck implements the IBCModule interface. // NOTE: The callback will occur for all applications in the callback list. // If the application is provided an empty string for the counterparty version, @@ -260,8 +244,45 @@ func (LegacyIBCModule) OnTimeoutPacket( } // OnChanUpgradeInit implements the IBCModule interface -func (LegacyIBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { - return "", nil +func (im *LegacyIBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { + negotiatedVersions := make([]string, len(im.cbs)) + + for i := len(im.cbs) - 1; i >= 0; i-- { + cbVersion := proposedVersion + + // To maintain backwards compatibility, we must handle two cases: + // - relayer provides empty version (use default versions) + // - relayer provides version which chooses to not enable a middleware + // + // If an application is a VersionWrapper which means it modifies the version string + // and the version string is non-empty (don't use default), then the application must + // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. + // If it is unsuccessful, no callback will occur to this application as the version + // indicates it should be disabled. + if wrapper, ok := im.cbs[i].(VersionWrapper); ok && strings.TrimSpace(proposedVersion) != "" { + appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(proposedVersion) + if err != nil { + // middleware disabled + negotiatedVersions[i] = "" + continue + } + cbVersion, proposedVersion = appVersion, underlyingAppVersion + } + + // in order to maintain backwards compatibility, every callback in the stack must implement the UpgradableModule interface. + upgradableModule, ok := im.cbs[i].(UpgradableModule) + if !ok { + return "", errorsmod.Wrap(ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + + negotiatedVersion, err := upgradableModule.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, cbVersion) + if err != nil { + return "", errorsmod.Wrapf(err, "channel open init callback failed for port ID: %s, channel ID: %s", portID, channelID) + } + negotiatedVersions[i] = negotiatedVersion + } + + return reconstructVersion(im.cbs, negotiatedVersions) } // OnChanUpgradeTry implements the IBCModule interface @@ -284,3 +305,19 @@ func (LegacyIBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID stri func (LegacyIBCModule) UnmarshalPacketData(ctx sdk.Context, portID, channelID string, bz []byte) (interface{}, error) { return nil, nil } + +// reconstructVersion will generate the channel version by applying any version wrapping as necessary. +// Version wrapping will only occur if the negotiated version is non=empty and the application is a VersionWrapper. +func reconstructVersion(cbs []ClassicIBCModule, negotiatedVersions []string) (string, error) { + version := negotiatedVersions[0] // base version + for i := 1; i < len(cbs); i++ { // iterate over the remaining callbacks + if strings.TrimSpace(negotiatedVersions[i]) != "" { + wrapper, ok := cbs[i].(VersionWrapper) + if !ok { + return "", ibcerrors.ErrInvalidVersion + } + version = wrapper.WrapVersion(negotiatedVersions[i], version) + } + } + return version, nil +} diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 212e74ed489..6af62cdc465 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -661,7 +661,7 @@ func (k *Keeper) ChannelUpgradeInit(goCtx context.Context, msg *channeltypes.Msg return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "expected %s, got %s", k.GetAuthority(), msg.Signer) } - app, ok := k.PortKeeper.Route(msg.PortId) + app, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { ctx.Logger().Error("channel upgrade init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 74e426e99e3..9824358cef4 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -974,29 +974,6 @@ func (suite *KeeperTestSuite) TestChannelUpgradeInit() { suite.Require().Empty(events) }, }, - { - "ibc application does not implement the UpgradeableModule interface", - func() { - path = ibctesting.NewPath(suite.chainA, suite.chainB) - path.EndpointA.ChannelConfig.PortID = ibcmock.MockBlockUpgrade - path.EndpointB.ChannelConfig.PortID = ibcmock.MockBlockUpgrade - - path.Setup() - - msg = channeltypes.NewMsgChannelUpgradeInit( - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - path.EndpointA.GetProposedUpgrade().Fields, - path.EndpointA.Chain.GetSimApp().IBCKeeper.GetAuthority(), - ) - }, - func(res *channeltypes.MsgChannelUpgradeInitResponse, events []abci.Event, err error) { - suite.Require().ErrorIs(err, porttypes.ErrInvalidRoute) - suite.Require().Nil(res) - - suite.Require().Empty(events) - }, - }, { "ibc application does not commit state changes in callback", func() { From ae43f7ab4ccd17412590df5342ecdbaea036c0fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:07:47 +0200 Subject: [PATCH 33/46] refactor: implement OnChanOpenConfirm using new port router (#7088) --- .../controller/ibc_middleware_test.go | 13 +++++--- .../host/ibc_module_test.go | 32 ++++++++----------- modules/apps/29-fee/ibc_middleware.go | 5 ++- modules/apps/callbacks/ibc_middleware.go | 6 ++-- .../core/05-port/types/ibc_legacy_module.go | 8 ++++- modules/core/keeper/msg_server.go | 2 +- 6 files changed, 34 insertions(+), 32 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 9b6a9f6f50f..93b25b9a3b0 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -352,14 +352,17 @@ func (suite *InterchainAccountsTestSuite) TestChanOpenConfirm() { suite.Require().Error(err) - // call application callback directly - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointA.ChannelConfig.PortID) + suite.Require().True(ok) - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + legacyModule, ok := cbs.(*porttypes.LegacyIBCModule) + suite.Require().True(ok, "expected there to be a single legacy ibc module") + + legacyModuleCbs := legacyModule.GetCallbacks() + controllerModule, ok := legacyModuleCbs[1].(controller.IBCMiddleware) // fee module is routed second suite.Require().True(ok) - err = cbs.OnChanOpenConfirm( + err = controllerModule.OnChanOpenConfirm( suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ) suite.Require().Error(err) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 7be9f6c431b..eddd588c552 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -266,25 +266,15 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { testCases := []struct { name string malleate func() - expPass bool + expError error }{ { - "success", func() {}, true, + "success", func() {}, nil, }, { "host submodule disabled", func() { suite.chainB.GetSimApp().ICAHostKeeper.SetParams(suite.chainB.GetContext(), types.NewParams(false, []string{})) - }, false, - }, - { - "success: ICA auth module callback returns error", func() { - // mock module callback should not be called on host side - suite.chainB.GetSimApp().ICAAuthModule.IBCApp.OnChanOpenConfirm = func( - ctx sdk.Context, portID, channelID string, - ) error { - return fmt.Errorf("mock ica auth fails") - } - }, true, + }, types.ErrHostSubModuleDisabled, }, } @@ -308,18 +298,22 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { tc.malleate() - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointB.ChannelConfig.PortID) + suite.Require().True(ok) - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + legacyModule, ok := cbs.(*porttypes.LegacyIBCModule) + suite.Require().True(ok, "expected there to be a single legacy ibc module") + + legacyModuleCbs := legacyModule.GetCallbacks() + hostModule, ok := legacyModuleCbs[0].(icahost.IBCModule) // fee module is routed second suite.Require().True(ok) - err = cbs.OnChanOpenConfirm(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + err = hostModule.OnChanOpenConfirm(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - if tc.expPass { + if tc.expError == nil { suite.Require().NoError(err) } else { - suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expError) } }) } diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 060977d1e62..d74cc269579 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -100,13 +100,12 @@ func (im IBCMiddleware) OnChanOpenAck( } // OnChanOpenConfirm implements the IBCMiddleware interface -func (im IBCMiddleware) OnChanOpenConfirm( +func (IBCMiddleware) OnChanOpenConfirm( ctx sdk.Context, portID, channelID string, ) error { - // call underlying app's OnChanOpenConfirm callback. - return im.app.OnChanOpenConfirm(ctx, portID, channelID) + return nil } // OnChanCloseInit implements the IBCMiddleware interface diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index a5935e1b177..d2966f1e7e9 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -342,9 +342,9 @@ func (IBCMiddleware) OnChanOpenAck( return nil } -// OnChanOpenConfirm defers to the underlying application -func (im IBCMiddleware) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanOpenConfirm(ctx, portID, channelID) +// OnChanOpenConfirm is a no-op for the callbacks middleware. +func (IBCMiddleware) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { + return nil } // OnChanCloseInit defers to the underlying application diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index 43415290a8e..bfc1ba8fe52 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -163,11 +163,17 @@ func (im *LegacyIBCModule) OnChanOpenAck( } // OnChanOpenConfirm implements the IBCModule interface -func (LegacyIBCModule) OnChanOpenConfirm( +func (im *LegacyIBCModule) OnChanOpenConfirm( ctx sdk.Context, portID, channelID string, ) error { + for i := len(im.cbs) - 1; i >= 0; i-- { + err := im.cbs[i].OnChanOpenConfirm(ctx, portID, channelID) + if err != nil { + return errorsmod.Wrapf(err, "channel open confirm callback failed for port ID: %s, channel ID: %s", portID, channelID) + } + } return nil } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 6af62cdc465..4236ce69ae7 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -310,7 +310,7 @@ func (k *Keeper) ChannelOpenConfirm(goCtx context.Context, msg *channeltypes.Msg ctx := sdk.UnwrapSDKContext(goCtx) // Retrieve application callbacks from router - cbs, ok := k.PortKeeper.Route(msg.PortId) + cbs, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { ctx.Logger().Error("channel open confirm failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) From 63dd2896c029262863f94d71d6349ba1a4f2ac80 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Thu, 8 Aug 2024 11:34:49 +0100 Subject: [PATCH 34/46] chore: implement OnChanUpgradeTry (#7092) --- .../controller/ibc_middleware_test.go | 7 +-- .../host/ibc_module_test.go | 6 +-- modules/apps/29-fee/ibc_middleware.go | 32 ++----------- modules/apps/callbacks/ibc_middleware.go | 9 +--- modules/apps/transfer/ibc_module_test.go | 5 +- .../core/05-port/types/ibc_legacy_module.go | 41 +++++++++++++++- modules/core/keeper/msg_server.go | 2 +- modules/core/keeper/msg_server_test.go | 47 ------------------- 8 files changed, 51 insertions(+), 98 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 93b25b9a3b0..1fd0d884b5d 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -809,12 +809,9 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() { err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - // call application callback directly - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointA.ChannelConfig.PortID) suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) suite.Require().True(ok) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index eddd588c552..cee5d45d9f1 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -710,11 +710,9 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() { tc.malleate() // malleate mutates test data - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) - - app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointB.ChannelConfig.PortID) suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) suite.Require().True(ok) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index d74cc269579..4745f45ba2f 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -308,35 +308,11 @@ func (IBCMiddleware) OnChanUpgradeInit( } // OnChanUpgradeTry implements the IBCModule interface -func (im IBCMiddleware) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - return "", errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") - } - - versionMetadata, err := types.MetadataFromVersion(counterpartyVersion) - if err != nil { - // since it is valid for fee version to not be specified, the counterparty upgrade version may be for a middleware - // or application further down in the stack. Thus, pass through to next middleware or application in callstack. - return cbs.OnChanUpgradeTry(ctx, portID, channelID, proposedOrder, proposedConnectionHops, counterpartyVersion) - } - - if versionMetadata.FeeVersion != types.Version { - return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, versionMetadata.FeeVersion) - } - - appVersion, err := cbs.OnChanUpgradeTry(ctx, portID, channelID, proposedOrder, proposedConnectionHops, versionMetadata.AppVersion) - if err != nil { - return "", err - } - - versionMetadata.AppVersion = appVersion - versionBz, err := types.ModuleCdc.MarshalJSON(&versionMetadata) - if err != nil { - return "", err +func (IBCMiddleware) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + if counterpartyVersion != types.Version { + return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, counterpartyVersion) } - - return string(versionBz), nil + return counterpartyVersion, nil } // OnChanUpgradeAck implements the IBCModule interface diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index d2966f1e7e9..66ddd659305 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -363,13 +363,8 @@ func (IBCMiddleware) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string } // OnChanUpgradeTry implements the IBCModule interface -func (im IBCMiddleware) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - return "", errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") - } - - return cbs.OnChanUpgradeTry(ctx, portID, channelID, proposedOrder, proposedConnectionHops, counterpartyVersion) +func (IBCMiddleware) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + return "", nil } // OnChanUpgradeAck implements the IBCModule interface diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index aa09bdf15f6..39b23e0945c 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -621,10 +621,7 @@ func (suite *TransferTestSuite) TestOnChanUpgradeTry() { tc.malleate() - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), types.PortID) - suite.Require().NoError(err) - - app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(types.PortID) suite.Require().True(ok) cbs, ok := app.(porttypes.UpgradableModule) diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index bfc1ba8fe52..0c36d557728 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -292,8 +292,45 @@ func (im *LegacyIBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID } // OnChanUpgradeTry implements the IBCModule interface -func (LegacyIBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { - return "", nil +func (im *LegacyIBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { + negotiatedVersions := make([]string, len(im.cbs)) + + for i := len(im.cbs) - 1; i >= 0; i-- { + cbVersion := counterpartyVersion + + // To maintain backwards compatibility, we must handle two cases: + // - relayer provides empty version (use default versions) + // - relayer provides version which chooses to not enable a middleware + // + // If an application is a VersionWrapper which means it modifies the version string + // and the version string is non-empty (don't use default), then the application must + // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. + // If it is unsuccessful, no callback will occur to this application as the version + // indicates it should be disabled. + if wrapper, ok := im.cbs[i].(VersionWrapper); ok && strings.TrimSpace(counterpartyVersion) != "" { + appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(counterpartyVersion) + if err != nil { + // middleware disabled + negotiatedVersions[i] = "" + continue + } + cbVersion, counterpartyVersion = appVersion, underlyingAppVersion + } + + // in order to maintain backwards compatibility, every callback in the stack must implement the UpgradableModule interface. + upgradableModule, ok := im.cbs[i].(UpgradableModule) + if !ok { + return "", errorsmod.Wrap(ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + + negotiatedVersion, err := upgradableModule.OnChanUpgradeTry(ctx, portID, channelID, proposedOrder, proposedConnectionHops, cbVersion) + if err != nil { + return "", errorsmod.Wrapf(err, "channel open init callback failed for port ID: %s, channel ID: %s", portID, channelID) + } + negotiatedVersions[i] = negotiatedVersion + } + + return reconstructVersion(im.cbs, negotiatedVersions) } // OnChanUpgradeAck implements the IBCModule interface diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 4236ce69ae7..b05e69066df 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -703,7 +703,7 @@ func (k *Keeper) ChannelUpgradeInit(goCtx context.Context, msg *channeltypes.Msg func (k *Keeper) ChannelUpgradeTry(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeTry) (*channeltypes.MsgChannelUpgradeTryResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - app, ok := k.PortKeeper.Route(msg.PortId) + app, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { ctx.Logger().Error("channel upgrade try failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 9824358cef4..205683b8d2c 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -1109,53 +1109,6 @@ func (suite *KeeperTestSuite) TestChannelUpgradeTry() { ibctesting.AssertEvents(&suite.Suite, expEvents, events) }, }, - { - "ibc application does not implement the UpgradeableModule interface", - func() { - path = ibctesting.NewPath(suite.chainA, suite.chainB) - path.EndpointA.ChannelConfig.PortID = ibcmock.MockBlockUpgrade - path.EndpointB.ChannelConfig.PortID = ibcmock.MockBlockUpgrade - - path.Setup() - - msg.PortId = path.EndpointB.ChannelConfig.PortID - msg.ChannelId = path.EndpointB.ChannelID - }, - func(res *channeltypes.MsgChannelUpgradeTryResponse, events []abci.Event, err error) { - suite.Require().ErrorIs(err, porttypes.ErrInvalidRoute) - suite.Require().Nil(res) - - suite.Require().Empty(events) - }, - }, - { - "ibc application does not commit state changes in callback", - func() { - suite.chainA.GetSimApp().IBCMockModule.IBCApp.OnChanUpgradeTry = func(ctx sdk.Context, portID, channelID string, order channeltypes.Order, connectionHops []string, counterpartyVersion string) (string, error) { - storeKey := suite.chainA.GetSimApp().GetKey(exported.ModuleName) - store := ctx.KVStore(storeKey) - store.Set(ibcmock.TestKey, ibcmock.TestValue) - - ctx.EventManager().EmitEvent(sdk.NewEvent(ibcmock.MockEventType)) - return ibcmock.UpgradeVersion, nil - } - }, - func(res *channeltypes.MsgChannelUpgradeTryResponse, events []abci.Event, err error) { - suite.Require().NoError(err) - suite.Require().NotNil(res) - suite.Require().Equal(uint64(1), res.UpgradeSequence) - - storeKey := suite.chainA.GetSimApp().GetKey(exported.ModuleName) - store := suite.chainA.GetContext().KVStore(storeKey) - suite.Require().Nil(store.Get(ibcmock.TestKey)) - - for _, event := range events { - if event.GetType() == ibcmock.MockEventType { - suite.Fail("expected application callback events to be discarded") - } - } - }, - }, } for _, tc := range cases { From 0c47e45619dc4604f5e7fa364e08d40f2fa588c1 Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Thu, 8 Aug 2024 12:15:51 +0100 Subject: [PATCH 35/46] chore(api)!: move checks from Transfer to OnSendPacket (#7068) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * deps: bump cosmos-sdk to v0.50.9 (#6828) * deps: bump cosmos-sdk to v0.50.8 * chore: update changelog * deps: bump cosmossdk.io/client to v2.0.0-beta.3. bump x/upgrade to v0.1.4 * chore: make tidy-all * test: bump to 3f6796fba413cca for testing purposes. * deps: bump cosmos sdk to 0.50.9 * Update CHANGELOG.md * chore: update CHANGELOG for submodules. --------- Co-authored-by: DimitrisJim * chore(api!): move checks from Transfer to OnSendPacket * Fix merge error * fix to test * Add Require() back * Update modules/apps/transfer/ibc_module.go Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Linter * Removed wrong merge results * reintroduce test * Move check for isSendEnabledCoins to keeper * new tests * fixed test * linter * Removed checks and added comment * removed extra parentheses * Revert "Merge remote-tracking branch 'origin' into bznein/6949/msgTransferWrapperToSendPacket" This reverts commit be9f5583c22f4c31e767e7baaaa6ecbce9079d99, reversing changes made to 36e4b05adfd7746899d96f25590b192747673fe9. * Delete commented out code --------- Co-authored-by: Damian Nolan Co-authored-by: DimitrisJim Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- modules/apps/transfer/ibc_module.go | 12 +++ modules/apps/transfer/ibc_module_test.go | 87 +++++++++++++++++++++ modules/apps/transfer/keeper/export_test.go | 5 -- modules/apps/transfer/keeper/keeper.go | 2 +- modules/apps/transfer/keeper/msg_server.go | 41 ++-------- modules/apps/transfer/keeper/relay.go | 8 +- 6 files changed, 112 insertions(+), 43 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index e624761bd57..14830a35770 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -172,6 +172,13 @@ func (im IBCModule) OnSendPacket( dataBz []byte, signer sdk.AccAddress, ) error { + if !im.keeper.GetParams(ctx).SendEnabled { + return types.ErrSendDisabled + } + if im.keeper.IsBlockedAddr(signer) { + return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to send funds", signer) + } + ics20Version, found := im.keeper.GetICS4Wrapper().GetAppVersion(ctx, portID, channelID) if !found { return errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", portID, channelID) @@ -182,6 +189,11 @@ func (im IBCModule) OnSendPacket( return err } + // If the ics20version is V1, we can't have multiple tokens nor forwarding info. + // However, we do not need to check it here, as a packet containing that data would + // fail the unmarshaling above, where if ics20version == types.V1 we first unmarshal + // into a V1 packet and then convert. + if data.Sender != signer.String() { return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "invalid signer address: expected %s, got %s", data.Sender, signer) } diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 39b23e0945c..7162cebd967 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/ibc-go/v9/modules/apps/transfer" "github.com/cosmos/ibc-go/v9/modules/apps/transfer/types" @@ -883,3 +884,89 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { }) } } + +func (suite *TransferTestSuite) TestOnSendPacket() { + var ( + packetData types.FungibleTokenPacketDataV2 + path *ibctesting.Path + signer sdk.AccAddress + ) + + testCases := []struct { + name string + malleate func() + expError error + }{ + { + "success", + func() {}, + nil, + }, + { + "failure: send disabled", + func() { + suite.chainA.GetSimApp().TransferKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false, true)) + }, + types.ErrSendDisabled, + }, + { + "failure: blocked address", + func() { + signer = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(minttypes.ModuleName) + }, + ibcerrors.ErrUnauthorized, + }, + { + "failure: sender is not signer", + func() { + packetData.Sender = suite.chainB.SenderAccount.GetAddress().String() + }, + ibcerrors.ErrInvalidAddress, + }, + { + "failure: V2 packet can't be unmarshaled if version is V1 and it contains V2 data", + func() { + path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { + channel.Version = types.V1 + }) + packetData.Forwarding = types.NewForwardingPacketData("", types.NewHop(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + ibcerrors.ErrInvalidType, + }, + } + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + signer = sdk.MustAccAddressFromBech32(suite.chainA.SenderAccount.GetAddress().String()) + + path = ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path.Setup() + + packetData = types.NewFungibleTokenPacketDataV2( + []types.Token{{Denom: types.NewDenom(sdk.DefaultBondDenom), Amount: ibctesting.TestCoin.Amount.String()}}, + suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.String(), "", types.ForwardingPacketData{}, + ) + + tc.malleate() + + dataBytes := packetData.GetBytes() + + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRoute(path.EndpointA.ChannelConfig.PortID) + suite.Require().True(ok) + + err := cbs[0].OnSendPacket( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + 0, clienttypes.ZeroHeight(), 0, + dataBytes, + signer, + ) + + if tc.expError == nil { + suite.Require().NoError(err) + } else { + suite.Require().ErrorIs(err, tc.expError) + } + }) + } +} diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index 5efd6a85910..dedfd560b9b 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -54,11 +54,6 @@ func (k Keeper) GetAllForwardedPackets(ctx sdk.Context) []types.ForwardedPacket return k.getAllForwardedPackets(ctx) } -// IsBlockedAddr is a wrapper around isBlockedAddr for testing purposes -func (k Keeper) IsBlockedAddr(addr sdk.AccAddress) bool { - return k.isBlockedAddr(addr) -} - // CreatePacketDataBytesFromVersion is a wrapper around createPacketDataBytesFromVersion for testing purposes func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, hops []types.Hop) ([]byte, error) { return createPacketDataBytesFromVersion(appVersion, sender, receiver, memo, tokens, hops) diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index c63d90a7ab2..17aef2757d9 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -391,7 +391,7 @@ func (k Keeper) iterateForwardedPackets(ctx sdk.Context, cb func(packet types.Fo // IsBlockedAddr checks if the given address is allowed to send or receive tokens. // The module account is always allowed to send and receive tokens. -func (k Keeper) isBlockedAddr(addr sdk.AccAddress) bool { +func (k Keeper) IsBlockedAddr(addr sdk.AccAddress) bool { moduleAddr := k.authKeeper.GetModuleAddress(types.ModuleName) if addr.Equals(moduleAddr) { return false diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index e74e60a8dad..9f8457481b6 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -19,41 +19,11 @@ var _ types.MsgServer = (*Keeper)(nil) func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - if !k.GetParams(ctx).SendEnabled { - return nil, types.ErrSendDisabled - } - sender, err := sdk.AccAddressFromBech32(msg.Sender) if err != nil { return nil, err } - coins := msg.GetCoins() - if err := k.bankKeeper.IsSendEnabledCoins(ctx, coins...); err != nil { - return nil, errorsmod.Wrapf(types.ErrSendDisabled, err.Error()) - } - - if k.isBlockedAddr(sender) { - return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to send funds", sender) - } - - appVersion, found := k.ics4Wrapper.GetAppVersion(ctx, msg.SourcePort, msg.SourceChannel) - if !found { - return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "application version not found for source port: %s and source channel: %s", msg.SourcePort, msg.SourceChannel) - } - - if appVersion == types.V1 { - // ics20-1 only supports a single coin, so if that is the current version, we must only process a single coin. - if len(msg.Tokens) > 1 { - return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "cannot transfer multiple coins with %s", types.V1) - } - - // ics20-1 does not support forwarding, so if that is the current version, we must reject the transfer. - if msg.HasForwarding() { - return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "cannot forward coins with %s", types.V1) - } - } - if msg.Forwarding.GetUnwind() { msg, err = k.unwindHops(ctx, msg) if err != nil { @@ -61,6 +31,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. } } + coins := msg.GetCoins() tokens := make([]types.Token, 0, len(coins)) for _, coin := range coins { token, err := k.tokenFromCoin(ctx, coin) @@ -71,15 +42,15 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. tokens = append(tokens, token) } + appVersion, found := k.ics4Wrapper.GetAppVersion(ctx, msg.SourcePort, msg.SourceChannel) + if !found { + return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "application version not found for source port: %s and source channel: %s", msg.SourcePort, msg.SourceChannel) + } packetDataBz, err := createPacketDataBytesFromVersion(appVersion, sender.String(), msg.Receiver, msg.Memo, tokens, msg.Forwarding.GetHops()) if err != nil { return nil, err } - // packetData := types.NewFungibleTokenPacketData( - // fullDenomPath, msg.Token.Amount.String(), sender.String(), msg.Receiver, msg.Memo, - // ) - msgSendPacket := &channeltypes.MsgSendPacket{ PortId: msg.SourcePort, ChannelId: msg.SourceChannel, @@ -149,7 +120,7 @@ func (k Keeper) unwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgT msg.Forwarding.Hops = append(unwindHops[1:], msg.Forwarding.Hops...) msg.Forwarding.Unwind = false - // Message is validate again, this would only fail if hops now exceeds maximum allowed. + // Message is validated again, this would only fail if hops now exceeds maximum allowed. if err := msg.ValidateBasic(); err != nil { return nil, err } diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 213ca9bc732..3e328ab9063 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -73,6 +73,10 @@ func (k Keeper) OnSendPacket( coins = append(coins, sdk.NewCoin(token.Denom.IBCDenom(), transferAmount)) } + if err := k.bankKeeper.IsSendEnabledCoins(ctx, coins...); err != nil { + return errorsmod.Wrapf(types.ErrSendDisabled, err.Error()) + } + destinationPort := channel.Counterparty.PortId destinationChannel := channel.Counterparty.ChannelId @@ -155,7 +159,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return err } - if k.isBlockedAddr(receiver) { + if k.IsBlockedAddr(receiver) { return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) } @@ -323,7 +327,7 @@ func (k Keeper) refundPacketTokens(ctx sdk.Context, packet channeltypes.Packet, if err != nil { return err } - if k.isBlockedAddr(sender) { + if k.IsBlockedAddr(sender) { return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", sender) } From 467819dcfa3795a2f689c76fe88cec3a0d0bf6bc Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Thu, 8 Aug 2024 13:26:11 +0100 Subject: [PATCH 36/46] refactor: implement OnChanCloseInit using new port router. (#7095) --- .../controller/ibc_middleware_test.go | 5 +---- .../host/ibc_module_test.go | 5 +---- modules/apps/29-fee/ibc_middleware.go | 4 ---- modules/apps/29-fee/ibc_middleware_test.go | 9 --------- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/apps/callbacks/ibc_middleware_test.go | 15 --------------- modules/core/05-port/types/ibc_legacy_module.go | 9 +++++++-- modules/core/keeper/msg_server.go | 2 +- 8 files changed, 11 insertions(+), 40 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 1fd0d884b5d..a136f3c756b 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -380,10 +380,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanCloseInit() { err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointA.ChannelConfig.PortID) suite.Require().True(ok) err = cbs.OnChanCloseInit( diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index cee5d45d9f1..71b00cd64d5 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -331,10 +331,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanCloseInit() { err := SetupICAPath(path, TestOwnerAddress) suite.Require().NoError(err) - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointB.ChannelConfig.PortID) suite.Require().True(ok) err = cbs.OnChanCloseInit( diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 4745f45ba2f..5a2acfd2a4b 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -114,10 +114,6 @@ func (im IBCMiddleware) OnChanCloseInit( portID, channelID string, ) error { - if err := im.app.OnChanCloseInit(ctx, portID, channelID); err != nil { - return err - } - if !im.keeper.IsFeeEnabled(ctx, portID, channelID) { return nil } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 107b736f6d1..64f494cbbca 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -252,15 +252,6 @@ func (suite *FeeTestSuite) TestOnChanCloseInit() { { "success", func() {}, true, }, - { - "application callback fails", func() { - suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanCloseInit = func( - ctx sdk.Context, portID, channelID string, - ) error { - return fmt.Errorf("application callback fails") - } - }, false, - }, { "RefundFeesOnChannelClosure continues - invalid refund address", func() { // store the fee in state & update escrow account balance diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 66ddd659305..69876944e94 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -349,7 +349,7 @@ func (IBCMiddleware) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string // OnChanCloseInit defers to the underlying application func (im IBCMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanCloseInit(ctx, portID, channelID) + return nil } // OnChanCloseConfirm defers to the underlying application diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index b682435d065..49a3876fa22 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -1075,21 +1075,6 @@ func (s *CallbacksTestSuite) TestGetAppVersion() { s.Require().Equal(s.path.EndpointA.ChannelConfig.Version, appVersion) } -func (s *CallbacksTestSuite) TestOnChanCloseInit() { - s.SetupICATest() - - // We will pass the function call down the icacontroller stack to the icacontroller module - // icacontroller stack OnChanCloseInit call order: callbacks -> fee -> icacontroller - icaControllerStack, ok := s.chainA.App.GetIBCKeeper().PortKeeper.Route(icacontrollertypes.SubModuleName) - s.Require().True(ok) - - controllerStack, ok := icaControllerStack.(porttypes.Middleware) - s.Require().True(ok) - err := controllerStack.OnChanCloseInit(s.chainA.GetContext(), s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) - // we just check that this call is passed down to the icacontroller to return an error - s.Require().ErrorIs(err, errorsmod.Wrap(ibcerrors.ErrInvalidRequest, "user cannot close channel")) -} - func (s *CallbacksTestSuite) TestOnChanCloseConfirm() { s.SetupICATest() diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index 0c36d557728..f9291c68ab8 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -178,11 +178,16 @@ func (im *LegacyIBCModule) OnChanOpenConfirm( } // OnChanCloseInit implements the IBCModule interface -func (LegacyIBCModule) OnChanCloseInit( +func (im *LegacyIBCModule) OnChanCloseInit( ctx sdk.Context, portID, channelID string, ) error { + for i := len(im.cbs) - 1; i >= 0; i-- { + if err := im.cbs[i].OnChanCloseInit(ctx, portID, channelID); err != nil { + return errorsmod.Wrapf(err, "channel close init callback failed for port ID: %s, channel ID: %s", portID, channelID) + } + } return nil } @@ -196,7 +201,7 @@ func (LegacyIBCModule) OnChanCloseConfirm( } // OnSendPacket implements the IBCModule interface. -func (im LegacyIBCModule) OnSendPacket( +func (im *LegacyIBCModule) OnSendPacket( ctx sdk.Context, portID string, channelID string, diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index b05e69066df..efb200dfd3e 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -341,7 +341,7 @@ func (k *Keeper) ChannelCloseInit(goCtx context.Context, msg *channeltypes.MsgCh ctx := sdk.UnwrapSDKContext(goCtx) // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(msg.PortId) + cbs, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { ctx.Logger().Error("channel close init failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) From d779697be9d5164dae547e6e390772461d3887e3 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Thu, 8 Aug 2024 14:34:19 +0100 Subject: [PATCH 37/46] Use new port router for OnChanUpgradeAck (#7094) * chore: implement OnChanUpgradeTry * wip: partial implementation for OnChanUpgradeAck * chore: updated tests to work with new OnChanUpgradeAck implementation --- .../controller/ibc_middleware.go | 20 +----- .../controller/ibc_middleware_test.go | 24 +------ .../host/ibc_module_test.go | 5 +- modules/apps/29-fee/ibc_middleware.go | 22 ++----- modules/apps/29-fee/ibc_middleware_test.go | 5 +- modules/apps/callbacks/ibc_middleware.go | 9 +-- modules/apps/transfer/ibc_module_test.go | 5 +- .../core/05-port/types/ibc_legacy_module.go | 34 +++++++++- modules/core/keeper/msg_server.go | 2 +- modules/core/keeper/msg_server_test.go | 64 ------------------- 10 files changed, 47 insertions(+), 143 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index cf9905781f6..b36cf9736d1 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -287,25 +287,7 @@ func (im IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, cou return types.ErrControllerSubModuleDisabled } - if err := im.keeper.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion); err != nil { - return err - } - - connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) - if err != nil { - return err - } - - if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionID) { - // Only cast to UpgradableModule if the application is set. - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - return errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") - } - return cbs.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion) - } - - return nil + return im.keeper.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion) } // OnChanUpgradeOpen implements the IBCModule interface diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index a136f3c756b..70562c1216d 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -825,7 +825,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeTry() { func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { var ( path *ibctesting.Path - isNilApp bool counterpartyVersion string ) @@ -839,9 +838,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { }, { "success: nil underlying app", - func() { - isNilApp = true - }, + func() {}, nil, }, { @@ -861,14 +858,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { } }, ibcmock.MockApplicationCallbackError, }, - { - "middleware disabled", func() { - suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanUpgradeAck = func(ctx sdk.Context, portID, channelID string, counterpartyVersion string) error { - return ibcmock.MockApplicationCallbackError - } - }, nil, - }, } for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { @@ -877,7 +866,6 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { suite.Run(tc.name, func() { suite.SetupTest() // reset - isNilApp = false path = NewICAPath(suite.chainA, suite.chainB, ordering) path.SetupConnections() @@ -889,18 +877,12 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointA.ChannelConfig.PortID) suite.Require().True(ok) + cbs, ok := app.(porttypes.UpgradableModule) suite.Require().True(ok) - if isNilApp { - cbs = controller.NewIBCMiddleware(suite.chainA.GetSimApp().ICAControllerKeeper) - } - err = cbs.OnChanUpgradeAck( suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 71b00cd64d5..dfdaedcf3ea 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -745,10 +745,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { suite.Require().NoError(err) // call application callback directly - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) - - app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + app, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointB.ChannelConfig.PortID) suite.Require().True(ok) cbs, ok := app.(porttypes.UpgradableModule) suite.Require().True(ok) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 5a2acfd2a4b..e0c3f96599a 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -312,25 +312,11 @@ func (IBCMiddleware) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, } // OnChanUpgradeAck implements the IBCModule interface -func (im IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - return errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") - } - - versionMetadata, err := types.MetadataFromVersion(counterpartyVersion) - if err != nil { - // since it is valid for fee version to not be specified, the counterparty upgrade version may be for a middleware - // or application further down in the stack. Thus, pass through to next middleware or application in callstack. - return cbs.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion) - } - - if versionMetadata.FeeVersion != types.Version { - return errorsmod.Wrapf(types.ErrInvalidVersion, "expected counterparty fee version: %s, got: %s", types.Version, versionMetadata.FeeVersion) +func (IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + if counterpartyVersion != types.Version { + return errorsmod.Wrapf(types.ErrInvalidVersion, "expected counterparty fee version: %s, got: %s", types.Version, counterpartyVersion) } - - // call underlying app's OnChanUpgradeAck callback with the counterparty app version. - return cbs.OnChanUpgradeAck(ctx, portID, channelID, versionMetadata.AppVersion) + return nil } // OnChanUpgradeOpen implements the IBCModule interface diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 64f494cbbca..39199d58d10 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1274,10 +1274,7 @@ func (suite *FeeTestSuite) TestOnChanUpgradeAck() { counterpartyUpgrade := path.EndpointB.GetChannelUpgrade() - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) - - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(ibctesting.MockFeePort) suite.Require().True(ok) cbs, ok := app.(porttypes.UpgradableModule) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 69876944e94..19cccab81ed 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -368,13 +368,8 @@ func (IBCMiddleware) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, } // OnChanUpgradeAck implements the IBCModule interface -func (im IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - return errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack") - } - - return cbs.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion) +func (IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + return nil } // OnChanUpgradeOpen implements the IBCModule interface diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 7162cebd967..c610d6d9503 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -690,10 +690,7 @@ func (suite *TransferTestSuite) TestOnChanUpgradeAck() { tc.malleate() - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), types.PortID) - suite.Require().NoError(err) - - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(types.PortID) suite.Require().True(ok) cbs, ok := app.(porttypes.UpgradableModule) diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index f9291c68ab8..e58d18daefa 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -339,7 +339,39 @@ func (im *LegacyIBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID s } // OnChanUpgradeAck implements the IBCModule interface -func (LegacyIBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { +func (im *LegacyIBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + for i := len(im.cbs) - 1; i >= 0; i-- { + cbVersion := counterpartyVersion + + // To maintain backwards compatibility, we must handle two cases: + // - relayer provides empty version (use default versions) + // - relayer provides version which chooses to not enable a middleware + // + // If an application is a VersionWrapper which means it modifies the version string + // and the version string is non-empty (don't use default), then the application must + // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. + // If it is unsuccessful, no callback will occur to this application as the version + // indicates it should be disabled. + if wrapper, ok := im.cbs[i].(VersionWrapper); ok && strings.TrimSpace(counterpartyVersion) != "" { + appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(counterpartyVersion) + if err != nil { + // middleware disabled + continue + } + cbVersion, counterpartyVersion = appVersion, underlyingAppVersion + } + + // in order to maintain backwards compatibility, every callback in the stack must implement the UpgradableModule interface. + upgradableModule, ok := im.cbs[i].(UpgradableModule) + if !ok { + return errorsmod.Wrap(ErrInvalidRoute, "upgrade route not found to module in application callstack") + } + + err := upgradableModule.OnChanUpgradeAck(ctx, portID, channelID, cbVersion) + if err != nil { + return errorsmod.Wrapf(err, "channel open init callback failed for port ID: %s, channel ID: %s", portID, channelID) + } + } return nil } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index efb200dfd3e..dd1372c7d43 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -758,7 +758,7 @@ func (k *Keeper) ChannelUpgradeTry(goCtx context.Context, msg *channeltypes.MsgC func (k *Keeper) ChannelUpgradeAck(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeAck) (*channeltypes.MsgChannelUpgradeAckResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - app, ok := k.PortKeeper.Route(msg.PortId) + app, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { err := errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", err) diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 205683b8d2c..02c1592e3ad 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -1285,70 +1285,6 @@ func (suite *KeeperTestSuite) TestChannelUpgradeAck() { ibctesting.AssertEvents(&suite.Suite, expEvents, events) }, }, - { - "application callback returns error and error receipt is written", - func() { - suite.chainA.GetSimApp().IBCMockModule.IBCApp.OnChanUpgradeAck = func( - ctx sdk.Context, portID, channelID, counterpartyVersion string, - ) error { - // set arbitrary value in store to mock application state changes - store := ctx.KVStore(suite.chainA.GetSimApp().GetKey(exported.ModuleName)) - store.Set([]byte("foo"), []byte("bar")) - return fmt.Errorf("mock app callback failed") - } - }, - func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { - suite.Require().NoError(err) - - suite.Require().NotNil(res) - suite.Require().Equal(channeltypes.FAILURE, res.Result) - - errorReceipt, found := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgradeErrorReceipt(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - suite.Require().True(found) - suite.Require().Equal(uint64(1), errorReceipt.Sequence) - - // assert application state changes are not committed - store := suite.chainA.GetContext().KVStore(suite.chainA.GetSimApp().GetKey(exported.ModuleName)) - suite.Require().False(store.Has([]byte("foo"))) - - channel := path.EndpointB.GetChannel() - expEvents := sdk.Events{ - sdk.NewEvent( - channeltypes.EventTypeChannelUpgradeError, - sdk.NewAttribute(channeltypes.AttributeKeyPortID, path.EndpointA.ChannelConfig.PortID), - sdk.NewAttribute(channeltypes.AttributeKeyChannelID, path.EndpointA.ChannelID), - sdk.NewAttribute(channeltypes.AttributeCounterpartyPortID, path.EndpointB.ChannelConfig.PortID), - sdk.NewAttribute(channeltypes.AttributeCounterpartyChannelID, path.EndpointB.ChannelID), - sdk.NewAttribute(channeltypes.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", channel.UpgradeSequence)), - // need to manually insert this because the errorReceipt is a string constant as it is written into state - sdk.NewAttribute(channeltypes.AttributeKeyErrorReceipt, "mock app callback failed"), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, channeltypes.AttributeValueCategory), - ), - }.ToABCIEvents() - ibctesting.AssertEvents(&suite.Suite, expEvents, events) - }, - }, - { - "ibc application does not implement the UpgradeableModule interface", - func() { - path = ibctesting.NewPath(suite.chainA, suite.chainB) - path.EndpointA.ChannelConfig.PortID = ibcmock.MockBlockUpgrade - path.EndpointB.ChannelConfig.PortID = ibcmock.MockBlockUpgrade - - path.Setup() - - msg.PortId = path.EndpointA.ChannelConfig.PortID - msg.ChannelId = path.EndpointA.ChannelID - }, - func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { - suite.Require().ErrorIs(err, porttypes.ErrInvalidRoute) - suite.Require().Nil(res) - suite.Require().Empty(events) - }, - }, { "application callback returns an upgrade error", func() { From 179025da1c1d1655bf8080c4fbf8eb502dc818ed Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Thu, 8 Aug 2024 15:13:29 +0100 Subject: [PATCH 38/46] refactor: implement onchancloseconfirm using new port router (#7096) --- .../controller/ibc_middleware.go | 15 +-------------- modules/apps/29-fee/ibc_middleware.go | 4 ---- modules/apps/29-fee/ibc_middleware_test.go | 9 --------- modules/apps/callbacks/ibc_middleware.go | 2 +- modules/core/05-port/types/ibc_legacy_module.go | 7 ++++++- modules/core/keeper/msg_server.go | 2 +- 6 files changed, 9 insertions(+), 30 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index b36cf9736d1..e43870f967c 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -136,20 +136,7 @@ func (im IBCMiddleware) OnChanCloseConfirm( portID, channelID string, ) error { - if err := im.keeper.OnChanCloseConfirm(ctx, portID, channelID); err != nil { - return err - } - - connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) - if err != nil { - return err - } - - if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionID) { - return im.app.OnChanCloseConfirm(ctx, portID, channelID) - } - - return nil + return im.keeper.OnChanCloseConfirm(ctx, portID, channelID) } // OnSendPacket implements the IBCModule interface. diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index e0c3f96599a..6919918efe8 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -131,10 +131,6 @@ func (im IBCMiddleware) OnChanCloseConfirm( portID, channelID string, ) error { - if err := im.app.OnChanCloseConfirm(ctx, portID, channelID); err != nil { - return err - } - if !im.keeper.IsFeeEnabled(ctx, portID, channelID) { return nil } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 39199d58d10..53559a9f41c 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -332,15 +332,6 @@ func (suite *FeeTestSuite) TestOnChanCloseConfirm() { { "success", func() {}, true, }, - { - "application callback fails", func() { - suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnChanCloseConfirm = func( - ctx sdk.Context, portID, channelID string, - ) error { - return fmt.Errorf("application callback fails") - } - }, false, - }, { "RefundChannelFeesOnClosure continues - refund address is invalid", func() { // store the fee in state & update escrow account balance diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 19cccab81ed..59cf3442067 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -354,7 +354,7 @@ func (im IBCMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID strin // OnChanCloseConfirm defers to the underlying application func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanCloseConfirm(ctx, portID, channelID) + return nil } // OnChanUpgradeInit implements the IBCModule interface diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index e58d18daefa..cbc1d8a31df 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -192,11 +192,16 @@ func (im *LegacyIBCModule) OnChanCloseInit( } // OnChanCloseConfirm implements the IBCModule interface -func (LegacyIBCModule) OnChanCloseConfirm( +func (im *LegacyIBCModule) OnChanCloseConfirm( ctx sdk.Context, portID, channelID string, ) error { + for i := len(im.cbs) - 1; i >= 0; i-- { + if err := im.cbs[i].OnChanCloseConfirm(ctx, portID, channelID); err != nil { + return errorsmod.Wrapf(err, "channel close confirm callback failed for port ID: %s, channel ID: %s", portID, channelID) + } + } return nil } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index dd1372c7d43..4775143dd3f 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -368,7 +368,7 @@ func (k *Keeper) ChannelCloseConfirm(goCtx context.Context, msg *channeltypes.Ms ctx := sdk.UnwrapSDKContext(goCtx) // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(msg.PortId) + cbs, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { ctx.Logger().Error("channel close confirm failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) From 62db72131bb4389535b1335158870b718914b416 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Thu, 8 Aug 2024 15:38:01 +0100 Subject: [PATCH 39/46] Use new port router for OnChanUpgradeOpen (#7102) * chore: implement OnChanUpgradeTry * wip: partial implementation for OnChanUpgradeAck * chore: updated tests to work with new OnChanUpgradeAck implementation * chore: implemented OnChanUpgradeOpen * chore: addressing PR feedback --- .../controller/ibc_middleware.go | 15 +-- .../controller/ibc_middleware_test.go | 100 +++++------------- modules/apps/29-fee/ibc_middleware.go | 10 +- modules/apps/29-fee/ibc_middleware_test.go | 5 +- modules/apps/callbacks/ibc_middleware.go | 10 +- .../core/05-port/types/ibc_legacy_module.go | 31 +++++- modules/core/keeper/msg_server.go | 4 +- modules/core/keeper/msg_server_test.go | 39 ------- 8 files changed, 65 insertions(+), 149 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index e43870f967c..c16e16200bf 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -278,20 +278,7 @@ func (im IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, cou } // OnChanUpgradeOpen implements the IBCModule interface -func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { - connectionID, err := im.keeper.GetConnectionID(ctx, portID, channelID) - if err != nil { - panic(err) - } - - if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, portID, connectionID) { - // Only cast to UpgradableModule if the application is set. - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - panic(errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")) - } - cbs.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) - } +func (IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { } // WriteAcknowledgement implements the ICS4 Wrapper interface diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 70562c1216d..c5f2584307c 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -7,8 +7,6 @@ import ( testifysuite "github.com/stretchr/testify/suite" - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v9/modules/apps/27-interchain-accounts/controller" @@ -903,98 +901,56 @@ func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeAck() { func (suite *InterchainAccountsTestSuite) TestOnChanUpgradeOpen() { var ( path *ibctesting.Path - isNilApp bool counterpartyVersion string ) testCases := []struct { name string malleate func() - expPanic error + ordering channeltypes.Order }{ { - "success", func() {}, nil, + "success: unordered", func() {}, channeltypes.UNORDERED, }, { - "success: nil app", func() { - isNilApp = true - }, nil, - }, - { - "middleware disabled", func() { - suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnChanUpgradeAck = func(ctx sdk.Context, portID, channelID string, counterpartyVersion string) error { - return ibcmock.MockApplicationCallbackError - } - }, - nil, - }, - { - "failure: upgrade route not found", - func() {}, - errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack"), - }, - { - "failure: connection not found", - func() { - path.EndpointA.ChannelID = "invalid-channel" - }, - errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", TestPortID, "invalid-channel"), + "success: ordered", func() {}, channeltypes.ORDERED, }, } - for _, ordering := range []channeltypes.Order{channeltypes.UNORDERED, channeltypes.ORDERED} { - for _, tc := range testCases { - tc := tc + for _, tc := range testCases { + tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset - isNilApp = false + suite.Run(tc.name, func() { + suite.SetupTest() // reset - path = NewICAPath(suite.chainA, suite.chainB, ordering) - path.SetupConnections() - - err := SetupICAPath(path, TestOwnerAddress) - suite.Require().NoError(err) - - counterpartyVersion = path.EndpointB.GetChannel().Version - - tc.malleate() // malleate mutates test data + path = NewICAPath(suite.chainA, suite.chainB, tc.ordering) + path.SetupConnections() - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) + err := SetupICAPath(path, TestOwnerAddress) + suite.Require().NoError(err) - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) - suite.Require().True(ok) - cbs, ok := app.(porttypes.UpgradableModule) - suite.Require().True(ok) + counterpartyVersion = path.EndpointB.GetChannel().Version - upgradeOpenCb := func(cbs porttypes.UpgradableModule) { - cbs.OnChanUpgradeOpen( - suite.chainA.GetContext(), - path.EndpointA.ChannelConfig.PortID, - path.EndpointA.ChannelID, - ordering, - []string{path.EndpointA.ConnectionID}, - counterpartyVersion, - ) - } + tc.malleate() // malleate mutates test data - if tc.expPanic != nil { - mockModule := ibcmock.NewAppModule(suite.chainA.App.GetIBCKeeper().PortKeeper) - mockApp := ibcmock.NewIBCApp(path.EndpointA.ChannelConfig.PortID, suite.chainA.App.GetScopedIBCKeeper()) - cbs = controller.NewIBCMiddlewareWithAuth(ibcmock.NewBlockUpgradeMiddleware(&mockModule, mockApp), suite.chainA.GetSimApp().ICAControllerKeeper) + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(path.EndpointA.ChannelConfig.PortID) + suite.Require().True(ok) - suite.Require().PanicsWithError(tc.expPanic.Error(), func() { upgradeOpenCb(cbs) }) - } else { - if isNilApp { - cbs = controller.NewIBCMiddleware(suite.chainA.GetSimApp().ICAControllerKeeper) - } + callbacks := app.(*porttypes.LegacyIBCModule).GetCallbacks() + icaStack, ok := callbacks[1].(porttypes.UpgradableModule) + suite.Require().True(ok) - upgradeOpenCb(cbs) - } + suite.Require().NotPanics(func() { + icaStack.OnChanUpgradeOpen( + suite.chainA.GetContext(), + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + tc.ordering, + []string{path.EndpointA.ConnectionID}, + counterpartyVersion, + ) }) - } + }) } } diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 6919918efe8..f29621139f2 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -317,22 +317,14 @@ func (IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counte // OnChanUpgradeOpen implements the IBCModule interface func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - panic(errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")) - } - - versionMetadata, err := types.MetadataFromVersion(proposedVersion) - if err != nil { + if strings.TrimSpace(proposedVersion) == "" { // set fee disabled and pass through to the next middleware or application in callstack. im.keeper.DeleteFeeEnabled(ctx, portID, channelID) - cbs.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) return } // set fee enabled and pass through to the next middleware of application in callstack. im.keeper.SetFeeEnabled(ctx, portID, channelID) - cbs.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, versionMetadata.AppVersion) } // WriteAcknowledgement implements the ICS4 Wrapper interface diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 53559a9f41c..e445996039c 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1372,10 +1372,7 @@ func (suite *FeeTestSuite) TestOnChanUpgradeOpen() { err = path.EndpointB.ChanUpgradeConfirm() suite.Require().NoError(err) - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) - - app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + app, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.HandshakeRoute(ibctesting.MockFeePort) suite.Require().True(ok) cbs, ok := app.(porttypes.UpgradableModule) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 59cf3442067..5fb3acb127f 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -348,7 +348,7 @@ func (IBCMiddleware) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string } // OnChanCloseInit defers to the underlying application -func (im IBCMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { +func (IBCMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { return nil } @@ -373,13 +373,7 @@ func (IBCMiddleware) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counte } // OnChanUpgradeOpen implements the IBCModule interface -func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { - cbs, ok := im.app.(porttypes.UpgradableModule) - if !ok { - panic(errorsmod.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")) - } - - cbs.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion) +func (IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { } // GetAppVersion implements the ICS4Wrapper interface. Callbacks has no version, diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index cbc1d8a31df..fdf48c457df 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -381,7 +381,36 @@ func (im *LegacyIBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, } // OnChanUpgradeOpen implements the IBCModule interface -func (LegacyIBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { +func (im *LegacyIBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { + for i := len(im.cbs) - 1; i >= 0; i-- { + cbVersion := proposedVersion + + // To maintain backwards compatibility, we must handle two cases: + // - relayer provides empty version (use default versions) + // - relayer provides version which chooses to not enable a middleware + // + // If an application is a VersionWrapper which means it modifies the version string + // and the version string is non-empty (don't use default), then the application must + // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. + // If it is unsuccessful, no callback will occur to this application as the version + // indicates it should be disabled. + if wrapper, ok := im.cbs[i].(VersionWrapper); ok { + appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(proposedVersion) + if err != nil { + cbVersion = "" // disable application + } else { + cbVersion, proposedVersion = appVersion, underlyingAppVersion + } + } + + // in order to maintain backwards compatibility, every callback in the stack must implement the UpgradableModule interface. + upgradableModule, ok := im.cbs[i].(UpgradableModule) + if !ok { + panic(errorsmod.Wrap(ErrInvalidRoute, "upgrade route not found to module in application callstack")) + } + + upgradableModule.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, cbVersion) + } } // UnmarshalPacketData attempts to unmarshal the provided packet data bytes diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 4775143dd3f..58c9c65b850 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -818,7 +818,7 @@ func (k *Keeper) ChannelUpgradeAck(goCtx context.Context, msg *channeltypes.MsgC func (k *Keeper) ChannelUpgradeConfirm(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeConfirm) (*channeltypes.MsgChannelUpgradeConfirmResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - app, ok := k.PortKeeper.Route(msg.PortId) + app, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { err := errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) ctx.Logger().Error("channel upgrade confirm failed", "port-id", msg.PortId, "error", err) @@ -873,7 +873,7 @@ func (k *Keeper) ChannelUpgradeConfirm(goCtx context.Context, msg *channeltypes. func (k *Keeper) ChannelUpgradeOpen(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeOpen) (*channeltypes.MsgChannelUpgradeOpenResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - app, ok := k.PortKeeper.Route(msg.PortId) + app, ok := k.PortKeeper.AppRouter.HandshakeRoute(msg.PortId) if !ok { err := errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.PortId) ctx.Logger().Error("channel upgrade open failed", "port-id", msg.PortId, "error", err) diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 02c1592e3ad..83785fbb37d 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -14,7 +14,6 @@ import ( clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v9/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v9/modules/core/05-port/types" commitmenttypes "github.com/cosmos/ibc-go/v9/modules/core/23-commitment/types" host "github.com/cosmos/ibc-go/v9/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v9/modules/core/errors" @@ -1589,25 +1588,6 @@ func (suite *KeeperTestSuite) TestChannelUpgradeConfirm() { ibctesting.AssertEvents(&suite.Suite, expEvents, events) }, }, - { - "ibc application does not implement the UpgradeableModule interface", - func() { - path = ibctesting.NewPath(suite.chainA, suite.chainB) - path.EndpointA.ChannelConfig.PortID = ibcmock.MockBlockUpgrade - path.EndpointB.ChannelConfig.PortID = ibcmock.MockBlockUpgrade - - path.Setup() - - msg.PortId = path.EndpointB.ChannelConfig.PortID - msg.ChannelId = path.EndpointB.ChannelID - }, - func(res *channeltypes.MsgChannelUpgradeConfirmResponse, events []abci.Event, err error) { - suite.Require().ErrorIs(err, porttypes.ErrInvalidRoute) - suite.Require().Nil(res) - - suite.Require().Empty(events) - }, - }, } for _, tc := range cases { @@ -1758,25 +1738,6 @@ func (suite *KeeperTestSuite) TestChannelUpgradeOpen() { suite.Require().Empty(events) }, }, - { - "ibc application does not implement the UpgradeableModule interface", - func() { - path = ibctesting.NewPath(suite.chainA, suite.chainB) - path.EndpointA.ChannelConfig.PortID = ibcmock.MockBlockUpgrade - path.EndpointB.ChannelConfig.PortID = ibcmock.MockBlockUpgrade - - path.Setup() - - msg.PortId = path.EndpointA.ChannelConfig.PortID - msg.ChannelId = path.EndpointA.ChannelID - }, - func(res *channeltypes.MsgChannelUpgradeOpenResponse, events []abci.Event, err error) { - suite.Require().ErrorIs(err, porttypes.ErrInvalidRoute) - suite.Require().Nil(res) - - suite.Require().Empty(events) - }, - }, } for _, tc := range cases { From 48b6a3f5df9fe1a85bbcaa04754d5fe73619faf3 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 8 Aug 2024 17:44:33 +0200 Subject: [PATCH 40/46] refactor: replace ack interface with result type for OnRecvPacket (#7093) * refactor: update OnRecvPacket to use result type in favour of ack interface * refactor: update recv packet handling in interchain accounts, update event func arg to use concrete type * api! remove Acknowledgement interface from exported pkg * refactor: modifications to test code for api removal * lint: fix duplicate imports * refactor: use concrete acknowledgement in callbacks test * doc: update inline godocs for OnRecvPacket in ibccallbacks * fix: remove wrapping of result ack in callbacks recv packet * test: refactor writeAck tests to use expected error format * chore: add godocs and stringer impl for new recv result types * chore: add issue link for async acknowledgements in 29-fee * doc: update godocs for RecvPacketResult and status enums * chore: address pr comments, test updates and inline docs --- .../controller/ibc_middleware.go | 9 +- .../controller/ibc_middleware_test.go | 13 +-- .../controller/keeper/events.go | 3 +- .../27-interchain-accounts/host/ibc_module.go | 28 +++++-- .../host/ibc_module_test.go | 17 ++-- .../host/keeper/events.go | 3 +- modules/apps/29-fee/ibc_middleware.go | 17 ++-- modules/apps/29-fee/ibc_middleware_test.go | 16 ++-- modules/apps/29-fee/keeper/relay.go | 8 +- modules/apps/29-fee/keeper/relay_test.go | 4 +- modules/apps/callbacks/ibc_middleware.go | 23 +++--- modules/apps/callbacks/ibc_middleware_test.go | 22 ++--- modules/apps/callbacks/replay_test.go | 2 +- .../testing/simapp/contract_keeper.go | 8 +- .../apps/callbacks/types/expected_keepers.go | 2 +- modules/apps/transfer/ibc_module.go | 21 +++-- modules/apps/transfer/ibc_module_test.go | 24 +++--- modules/apps/transfer/keeper/forwarding.go | 2 +- .../core/03-connection/keeper/verify_test.go | 10 +-- modules/core/04-channel/keeper/packet.go | 13 +-- modules/core/04-channel/keeper/packet_test.go | 82 +++++++++++-------- .../core/05-port/types/ibc_legacy_module.go | 4 +- modules/core/05-port/types/module.go | 4 +- modules/core/ante/ante_test.go | 4 +- modules/core/exported/packet.go | 46 +++++++---- modules/core/keeper/msg_server.go | 9 +- testing/endpoint.go | 4 +- testing/mock/ibc_app.go | 2 +- testing/mock/ibc_module.go | 16 +++- testing/mock/middleware.go | 18 ++-- 30 files changed, 258 insertions(+), 176 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index c16e16200bf..f1516784292 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -195,11 +195,14 @@ func (IBCMiddleware) OnRecvPacket( _ string, packet channeltypes.Packet, _ sdk.AccAddress, -) ibcexported.Acknowledgement { +) ibcexported.RecvPacketResult { err := errorsmod.Wrapf(icatypes.ErrInvalidChannelFlow, "cannot receive packet on controller chain") ack := channeltypes.NewErrorAcknowledgement(err) keeper.EmitAcknowledgementEvent(ctx, packet, ack, err) - return ack + return ibcexported.RecvPacketResult{ + Status: ibcexported.Failure, + Acknowledgement: ack.Acknowledgement(), + } } // OnAcknowledgementPacket implements the IBCMiddleware interface @@ -285,7 +288,7 @@ func (IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string func (IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, + ack []byte, ) error { panic(errors.New("WriteAcknowledgement not supported for ICA controller module")) } diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index c5f2584307c..64f22ae0503 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -18,6 +18,7 @@ import ( porttypes "github.com/cosmos/ibc-go/v9/modules/core/05-port/types" host "github.com/cosmos/ibc-go/v9/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v9/modules/core/errors" + "github.com/cosmos/ibc-go/v9/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v9/testing" ibcmock "github.com/cosmos/ibc-go/v9/testing/mock" ) @@ -450,12 +451,12 @@ func (suite *InterchainAccountsTestSuite) TestOnChanCloseConfirm() { func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { testCases := []struct { - name string - malleate func() - expPass bool + name string + malleate func() + expStatus exported.RecvPacketStatus }{ { - "ICA OnRecvPacket fails with ErrInvalidChannelFlow", func() {}, false, + "ICA OnRecvPacket fails with ErrInvalidChannelFlow", func() {}, exported.Failure, }, } @@ -492,8 +493,8 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { ) ctx := suite.chainA.GetContext() - ack := cbs.OnRecvPacket(ctx, path.EndpointA.GetChannel().Version, packet, nil) - suite.Require().Equal(tc.expPass, ack.Success()) + res := cbs.OnRecvPacket(ctx, path.EndpointA.GetChannel().Version, packet, nil) + suite.Require().Equal(tc.expStatus, res.Status, "expected %s but got %s", tc.expStatus, res.Status) expectedEvents := sdk.Events{ sdk.NewEvent( diff --git a/modules/apps/27-interchain-accounts/controller/keeper/events.go b/modules/apps/27-interchain-accounts/controller/keeper/events.go index 5743253b530..44dbf111289 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/events.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/events.go @@ -7,12 +7,11 @@ import ( icatypes "github.com/cosmos/ibc-go/v9/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v9/modules/core/exported" ) // EmitAcknowledgementEvent emits an event signalling a successful or failed acknowledgement and including the error // details if any. -func EmitAcknowledgementEvent(ctx sdk.Context, packet channeltypes.Packet, ack exported.Acknowledgement, err error) { +func EmitAcknowledgementEvent(ctx sdk.Context, packet channeltypes.Packet, ack channeltypes.Acknowledgement, err error) { attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), sdk.NewAttribute(icatypes.AttributeKeyControllerChannelID, packet.GetDestChannel()), diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 1285e97f36f..709011a8c50 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -128,27 +128,41 @@ func (im IBCModule) OnRecvPacket( _ string, packet channeltypes.Packet, _ sdk.AccAddress, -) ibcexported.Acknowledgement { +) ibcexported.RecvPacketResult { if !im.keeper.GetParams(ctx).HostEnabled { im.keeper.Logger(ctx).Info("host submodule is disabled") keeper.EmitHostDisabledEvent(ctx, packet) - return channeltypes.NewErrorAcknowledgement(types.ErrHostSubModuleDisabled) + return ibcexported.RecvPacketResult{ + Status: ibcexported.Failure, + Acknowledgement: channeltypes.NewErrorAcknowledgement(types.ErrHostSubModuleDisabled).Acknowledgement(), + } } txResponse, err := im.keeper.OnRecvPacket(ctx, packet) - ack := channeltypes.NewResultAcknowledgement(txResponse) if err != nil { - ack = channeltypes.NewErrorAcknowledgement(err) + ack := channeltypes.NewErrorAcknowledgement(err) + + // Emit an event indicating a successful or failed acknowledgement. + keeper.EmitAcknowledgementEvent(ctx, packet, ack, err) im.keeper.Logger(ctx).Error(fmt.Sprintf("%s sequence %d", err.Error(), packet.Sequence)) - } else { - im.keeper.Logger(ctx).Info("successfully handled packet", "sequence", packet.Sequence) + + return ibcexported.RecvPacketResult{ + Status: ibcexported.Failure, + Acknowledgement: ack.Acknowledgement(), + } } + ack := channeltypes.NewResultAcknowledgement(txResponse) + // Emit an event indicating a successful or failed acknowledgement. keeper.EmitAcknowledgementEvent(ctx, packet, ack, err) + im.keeper.Logger(ctx).Info("successfully handled packet", "sequence", packet.Sequence) // NOTE: acknowledgement will be written synchronously during IBC handler execution. - return ack + return ibcexported.RecvPacketResult{ + Status: ibcexported.Success, + Acknowledgement: ack.Acknowledgement(), + } } // OnAcknowledgementPacket implements the IBCModule interface diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index dfdaedcf3ea..3b85a210d10 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -409,8 +409,11 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { "success with ICA auth module callback failure", func() { suite.chainB.GetSimApp().ICAAuthModule.IBCApp.OnRecvPacket = func( ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, - ) exported.Acknowledgement { - return channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed OnRecvPacket mock callback")) + ) exported.RecvPacketResult { + return exported.RecvPacketResult{ + Status: exported.Failure, + Acknowledgement: channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed OnRecvPacket mock callback")).Acknowledgement(), + } } }, true, "failed OnRecvPacket mock callback", @@ -487,17 +490,17 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { suite.Require().True(ok) ctx := suite.chainB.GetContext() - ack := cbs.OnRecvPacket(ctx, path.EndpointB.GetChannel().Version, packet, nil) + res := cbs.OnRecvPacket(ctx, path.EndpointB.GetChannel().Version, packet, nil) expectedAttributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), sdk.NewAttribute(icatypes.AttributeKeyHostChannelID, packet.GetDestChannel()), - sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, strconv.FormatBool(ack.Success())), + sdk.NewAttribute(icatypes.AttributeKeyAckSuccess, strconv.FormatBool(res.Status == exported.Success)), } if tc.expAckSuccess { - suite.Require().True(ack.Success()) - suite.Require().Equal(expectedAck, ack) + suite.Require().Equal(exported.Success, res.Status) + suite.Require().Equal(expectedAck.Acknowledgement(), res.Acknowledgement) expectedEvents := sdk.Events{ sdk.NewEvent( @@ -510,7 +513,7 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents()) } else { - suite.Require().False(ack.Success()) + suite.Require().Equal(exported.Failure, res.Status) expectedAttributes = append(expectedAttributes, sdk.NewAttribute(icatypes.AttributeKeyAckError, tc.eventErrorMsg)) expectedEvents := sdk.Events{ diff --git a/modules/apps/27-interchain-accounts/host/keeper/events.go b/modules/apps/27-interchain-accounts/host/keeper/events.go index 91af1e449c4..e5d04ebab06 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/events.go +++ b/modules/apps/27-interchain-accounts/host/keeper/events.go @@ -8,12 +8,11 @@ import ( "github.com/cosmos/ibc-go/v9/modules/apps/27-interchain-accounts/host/types" icatypes "github.com/cosmos/ibc-go/v9/modules/apps/27-interchain-accounts/types" channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v9/modules/core/exported" ) // EmitAcknowledgementEvent emits an event signalling a successful or failed acknowledgement and including the error // details if any. -func EmitAcknowledgementEvent(ctx sdk.Context, packet channeltypes.Packet, ack exported.Acknowledgement, err error) { +func EmitAcknowledgementEvent(ctx sdk.Context, packet channeltypes.Packet, ack channeltypes.Acknowledgement, err error) { attributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, icatypes.ModuleName), sdk.NewAttribute(icatypes.AttributeKeyHostChannelID, packet.GetDestChannel()), diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index f29621139f2..c8324dc6b08 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -163,24 +163,27 @@ func (im IBCMiddleware) OnRecvPacket( channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, -) exported.Acknowledgement { +) exported.RecvPacketResult { if !im.keeper.IsFeeEnabled(ctx, packet.DestinationPort, packet.DestinationChannel) { return im.app.OnRecvPacket(ctx, channelVersion, packet, relayer) } appVersion := unwrapAppVersion(channelVersion) - ack := im.app.OnRecvPacket(ctx, appVersion, packet, relayer) + res := im.app.OnRecvPacket(ctx, appVersion, packet, relayer) - // in case of async acknowledgement (ack == nil) store the relayer address for use later during async WriteAcknowledgement - if ack == nil { + // in case of async result status store the relayer address for use later during async WriteAcknowledgement + if res.Status == exported.Async { im.keeper.SetRelayerAddressForAsyncAck(ctx, channeltypes.NewPacketID(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()), relayer.String()) - return nil + return res } // if forwardRelayer is not found we refund recv_fee forwardRelayer, _ := im.keeper.GetCounterpartyPayeeAddress(ctx, relayer.String(), packet.GetDestChannel()) - return types.NewIncentivizedAcknowledgement(forwardRelayer, ack.Acknowledgement(), ack.Success()) + return exported.RecvPacketResult{ + Status: res.Status, + Acknowledgement: types.NewIncentivizedAcknowledgement(forwardRelayer, res.Acknowledgement, res.Status == exported.Success).Acknowledgement(), + } } // OnAcknowledgementPacket implements the IBCMiddleware interface @@ -331,7 +334,7 @@ func (im IBCMiddleware) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID str func (im IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, packet exported.PacketI, - ack exported.Acknowledgement, + ack []byte, ) error { return im.keeper.WriteAcknowledgement(ctx, packet, ack) } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index e445996039c..af0f5c28816 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -421,8 +421,10 @@ func (suite *FeeTestSuite) TestOnRecvPacket() { channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, - ) exported.Acknowledgement { - return nil + ) exported.RecvPacketResult { + return exported.RecvPacketResult{ + Status: exported.Async, + } } }, true, @@ -482,13 +484,13 @@ func (suite *FeeTestSuite) TestOnRecvPacket() { ForwardRelayerAddress: forwardAddr, UnderlyingAppSuccess: true, } - suite.Require().Equal(expectedAck, result) + suite.Require().Equal(expectedAck.Acknowledgement(), result.Acknowledgement) case !tc.feeEnabled: - suite.Require().Equal(ibcmock.MockAcknowledgement, result) + suite.Require().Equal(ibcmock.MockAcknowledgement.Acknowledgement(), result.Acknowledgement) - case tc.forwardRelayer && result == nil: - suite.Require().Equal(nil, result) + case tc.forwardRelayer && result.Status == exported.Async: + suite.Require().Nil(result.Acknowledgement) packetID := channeltypes.NewPacketID(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) // retrieve the forward relayer that was stored in `onRecvPacket` @@ -501,7 +503,7 @@ func (suite *FeeTestSuite) TestOnRecvPacket() { ForwardRelayerAddress: "", UnderlyingAppSuccess: true, } - suite.Require().Equal(expectedAck, result) + suite.Require().Equal(expectedAck.Acknowledgement(), result.Acknowledgement) } }) } diff --git a/modules/apps/29-fee/keeper/relay.go b/modules/apps/29-fee/keeper/relay.go index 61cdc06255c..82b5eb4d8de 100644 --- a/modules/apps/29-fee/keeper/relay.go +++ b/modules/apps/29-fee/keeper/relay.go @@ -14,7 +14,7 @@ import ( // WriteAcknowledgement wraps IBC ChannelKeeper's WriteAcknowledgement function // ICS29 WriteAcknowledgement is used for asynchronous acknowledgements -func (k Keeper) WriteAcknowledgement(ctx sdk.Context, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error { +func (k Keeper) WriteAcknowledgement(ctx sdk.Context, packet ibcexported.PacketI, acknowledgement []byte) error { if !k.IsFeeEnabled(ctx, packet.GetDestPort(), packet.GetDestChannel()) { // ics4Wrapper may be core IBC or higher-level middleware return k.ics4Wrapper.WriteAcknowledgement(ctx, packet, acknowledgement) @@ -32,12 +32,14 @@ func (k Keeper) WriteAcknowledgement(ctx sdk.Context, packet ibcexported.PacketI // if there is no registered counterparty address then write acknowledgement with empty relayer address and refund recv_fee. forwardRelayer, _ := k.GetCounterpartyPayeeAddress(ctx, relayer, packet.GetDestChannel()) - ack := types.NewIncentivizedAcknowledgement(forwardRelayer, acknowledgement.Acknowledgement(), acknowledgement.Success()) + // TODO(https://github.com/cosmos/ibc-go/issues/7044): + // The underlying app success bool is temporarily hardcoded to true! This should be revisited for the issue linked above. + ack := types.NewIncentivizedAcknowledgement(forwardRelayer, acknowledgement, true) k.DeleteForwardRelayerAddress(ctx, packetID) // ics4Wrapper may be core IBC or higher-level middleware - return k.ics4Wrapper.WriteAcknowledgement(ctx, packet, ack) + return k.ics4Wrapper.WriteAcknowledgement(ctx, packet, ack.Acknowledgement()) } // GetAppVersion returns the underlying application version. diff --git a/modules/apps/29-fee/keeper/relay_test.go b/modules/apps/29-fee/keeper/relay_test.go index 34350cdb926..1b95514822f 100644 --- a/modules/apps/29-fee/keeper/relay_test.go +++ b/modules/apps/29-fee/keeper/relay_test.go @@ -58,7 +58,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgementAsync() { // malleate test case tc.malleate() - err := suite.chainB.GetSimApp().IBCFeeKeeper.WriteAcknowledgement(suite.chainB.GetContext(), packet, ack) + err := suite.chainB.GetSimApp().IBCFeeKeeper.WriteAcknowledgement(suite.chainB.GetContext(), packet, ack.Acknowledgement()) if tc.expPass { suite.Require().NoError(err) @@ -95,7 +95,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgementAsyncFeeDisabled() { ack := channeltypes.NewResultAcknowledgement([]byte("success")) - err := suite.chainB.GetSimApp().IBCFeeKeeper.WriteAcknowledgement(suite.chainB.GetContext(), packet, ack) + err := suite.chainB.GetSimApp().IBCFeeKeeper.WriteAcknowledgement(suite.chainB.GetContext(), packet, ack.Acknowledgement()) suite.Require().NoError(err) packetAck, _ := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.DestinationPort, packet.DestinationChannel, 1) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 5fb3acb127f..6fa56e62479 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -188,23 +188,24 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, channelVersion string, // It defers to the underlying application and then calls the contract callback. // If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are // reverted via a panic. -func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement { - ack := im.app.OnRecvPacket(ctx, channelVersion, packet, relayer) - // if ack is nil (asynchronous acknowledgements), then the callback will be handled in WriteAcknowledgement - // if ack is not successful, all state changes are reverted. If a packet cannot be received, then there is - // no need to execute a callback on the receiving chain. - if ack == nil || !ack.Success() { - return ack +func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.RecvPacketResult { + res := im.app.OnRecvPacket(ctx, channelVersion, packet, relayer) + // if result status is asynchronous, then the callback will be handled in WriteAcknowledgement + // if result status is failed, then all state changes are reverted. + // if a packet cannot be received, then there is no need to execute a callback on the receiving chain, + // thus we only proceed with the contract keeper callback if the result status is successful. + if res.Status != ibcexported.Success { + return res } // OnRecvPacket is not blocked if the packet does not opt-in to callbacks callbackData, err := types.GetDestCallbackData(ctx, im.app, packet, im.maxCallbackGas) if err != nil { - return ack + return res } callbackExecutor := func(cachedCtx sdk.Context) error { - return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, ack, callbackData.CallbackAddress, callbackData.ApplicationVersion) + return im.contractKeeper.IBCReceivePacketCallback(cachedCtx, packet, res.Acknowledgement, callbackData.CallbackAddress, callbackData.ApplicationVersion) } // callback execution errors are not allowed to block the packet lifecycle, they are only used in event emissions @@ -214,7 +215,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, channelVersion string, pac types.CallbackTypeReceivePacket, callbackData, err, ) - return ack + return res } // WriteAcknowledgement implements the ReceivePacket destination callbacks for the ibc-callbacks middleware @@ -225,7 +226,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, channelVersion string, pac func (im IBCMiddleware) WriteAcknowledgement( ctx sdk.Context, packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, + ack []byte, ) error { err := im.ics4Wrapper.WriteAcknowledgement(ctx, packet, ack) if err != nil { diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 49a3876fa22..48aacda05a7 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -583,7 +583,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { name string malleate func() expResult expResult - expAck ibcexported.Acknowledgement + expAck channeltypes.Acknowledgement }{ { "success", @@ -680,14 +680,15 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { transferStack, ok := s.chainB.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) s.Require().True(ok) - onRecvPacket := func() ibcexported.Acknowledgement { + onRecvPacket := func() ibcexported.RecvPacketResult { return transferStack.OnRecvPacket(ctx, s.path.EndpointA.GetChannel().Version, packet, s.chainB.SenderAccount.GetAddress()) } switch tc.expAck { case successAck: - ack := onRecvPacket() - s.Require().NotNil(ack) + res := onRecvPacket() + s.Require().Equal(ibcexported.Success, res.Status) + s.Require().NotNil(res.Acknowledgement) case panicAck: s.Require().PanicsWithValue(storetypes.ErrorOutOfGas{ @@ -697,8 +698,8 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { }) default: - ack := onRecvPacket() - s.Require().Equal(tc.expAck, ack) + res := onRecvPacket() + s.Require().Equal(tc.expAck.Acknowledgement(), res.Acknowledgement) } destStatefulCounter := GetSimApp(s.chainB).MockContractKeeper.GetStateEntryCounter(s.chainB.GetContext()) @@ -735,7 +736,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { packetData transfertypes.FungibleTokenPacketDataV2 packet channeltypes.Packet ctx sdk.Context - ack ibcexported.Acknowledgement + ack []byte ) successAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) @@ -749,7 +750,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { { "success", func() { - ack = successAck + ack = successAck.Acknowledgement() }, types.CallbackTypeReceivePacket, nil, @@ -1111,7 +1112,8 @@ func (s *CallbacksTestSuite) TestOnRecvPacketAsyncAck() { 0, ) - ack := mockFeeCallbackStack.OnRecvPacket(s.chainA.GetContext(), ibcmock.MockFeeVersion, packet, s.chainA.SenderAccount.GetAddress()) - s.Require().Nil(ack) + res := mockFeeCallbackStack.OnRecvPacket(s.chainA.GetContext(), ibcmock.MockFeeVersion, packet, s.chainA.SenderAccount.GetAddress()) + s.Require().Equal(ibcexported.Async, res.Status) + s.Require().Nil(res.Acknowledgement) s.AssertHasExecutedExpectedCallback("none", true) } diff --git a/modules/apps/callbacks/replay_test.go b/modules/apps/callbacks/replay_test.go index f414f47f5f5..028d89ff2eb 100644 --- a/modules/apps/callbacks/replay_test.go +++ b/modules/apps/callbacks/replay_test.go @@ -264,7 +264,7 @@ func (s *CallbacksTestSuite) TestTransferRecvPacketReplayProtection() { GetSimApp(s.chainB).MockContractKeeper.IBCReceivePacketCallbackFn = func( cachedCtx sdk.Context, packet ibcexported.PacketI, - _ ibcexported.Acknowledgement, + _ []byte, _, _ string, ) error { callbackCount++ diff --git a/modules/apps/callbacks/testing/simapp/contract_keeper.go b/modules/apps/callbacks/testing/simapp/contract_keeper.go index b2206f06fba..6a2c2d73343 100644 --- a/modules/apps/callbacks/testing/simapp/contract_keeper.go +++ b/modules/apps/callbacks/testing/simapp/contract_keeper.go @@ -81,7 +81,7 @@ type ContractKeeper struct { IBCReceivePacketCallbackFn func( cachedCtx sdk.Context, packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, + acknowledgement []byte, contractAddress string, version string, ) error @@ -129,7 +129,7 @@ func NewContractKeeper(key storetypes.StoreKey) *ContractKeeper { return k.ProcessMockCallback(ctx, callbacktypes.CallbackTypeTimeoutPacket, contractAddress) } - k.IBCReceivePacketCallbackFn = func(ctx sdk.Context, _ ibcexported.PacketI, _ ibcexported.Acknowledgement, contractAddress, _ string) error { + k.IBCReceivePacketCallbackFn = func(ctx sdk.Context, _ ibcexported.PacketI, _ []byte, contractAddress, _ string) error { return k.ProcessMockCallback(ctx, callbacktypes.CallbackTypeReceivePacket, contractAddress) } @@ -204,11 +204,11 @@ func (k ContractKeeper) IBCOnTimeoutPacketCallback( func (k ContractKeeper) IBCReceivePacketCallback( ctx sdk.Context, packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, + acknowledgement []byte, contractAddress, version string, ) error { - return k.IBCReceivePacketCallbackFn(ctx, packet, ack, contractAddress, version) + return k.IBCReceivePacketCallbackFn(ctx, packet, acknowledgement, contractAddress, version) } // ProcessMockCallback processes a mock callback. diff --git a/modules/apps/callbacks/types/expected_keepers.go b/modules/apps/callbacks/types/expected_keepers.go index 717a9d6108f..15f72f924d4 100644 --- a/modules/apps/callbacks/types/expected_keepers.go +++ b/modules/apps/callbacks/types/expected_keepers.go @@ -92,7 +92,7 @@ type ContractKeeper interface { IBCReceivePacketCallback( cachedCtx sdk.Context, packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, + acknowledgement []byte, contractAddress string, version string, ) error diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 14830a35770..d91545e2321 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -210,7 +210,7 @@ func (im IBCModule) OnRecvPacket( channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, -) ibcexported.Acknowledgement { +) ibcexported.RecvPacketResult { var ( ackErr error data types.FungibleTokenPacketDataV2 @@ -228,24 +228,35 @@ func (im IBCModule) OnRecvPacket( if ackErr != nil { ack = channeltypes.NewErrorAcknowledgement(ackErr) im.keeper.Logger(ctx).Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence)) - return ack + return ibcexported.RecvPacketResult{ + Status: ibcexported.Failure, + Acknowledgement: ack.Acknowledgement(), + } } if ackErr = im.keeper.OnRecvPacket(ctx, packet, data); ackErr != nil { ack = channeltypes.NewErrorAcknowledgement(ackErr) im.keeper.Logger(ctx).Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence)) - return ack + return ibcexported.RecvPacketResult{ + Status: ibcexported.Failure, + Acknowledgement: ack.Acknowledgement(), + } } im.keeper.Logger(ctx).Info("successfully handled ICS-20 packet", "sequence", packet.Sequence) if data.HasForwarding() { // NOTE: acknowledgement will be written asynchronously - return nil + return ibcexported.RecvPacketResult{ + Status: ibcexported.Async, + } } // NOTE: acknowledgement will be written synchronously during IBC handler execution. - return ack + return ibcexported.RecvPacketResult{ + Status: ibcexported.Success, + Acknowledgement: ack.Acknowledgement(), + } } // OnAcknowledgementPacket implements the IBCModule interface diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index c610d6d9503..531bb801444 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -18,7 +18,6 @@ import ( channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v9/modules/core/05-port/types" ibcerrors "github.com/cosmos/ibc-go/v9/modules/core/errors" - "github.com/cosmos/ibc-go/v9/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v9/testing" ) @@ -256,14 +255,18 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { expectedAttributes []sdk.Attribute path *ibctesting.Path ) + testCases := []struct { name string malleate func() - expAck exported.Acknowledgement + expAck []byte expEventErrorMsg string }{ { - "success", func() {}, channeltypes.NewResultAcknowledgement([]byte{byte(1)}), "", + "success", + func() {}, + channeltypes.NewResultAcknowledgement([]byte{byte(1)}).Acknowledgement(), + "", }, { "success: async aknowledgment with forwarding path", @@ -309,7 +312,7 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { sdk.NewAttribute(types.AttributeKeyAckError, "cannot unmarshal ICS20-V2 transfer packet data: errUnknownField \"*types.FungibleTokenPacketDataV2\": {TagNum: 13, WireType:\"fixed64\"}: invalid type"), } }, - channeltypes.NewErrorAcknowledgement(ibcerrors.ErrInvalidType), + channeltypes.NewErrorAcknowledgement(ibcerrors.ErrInvalidType).Acknowledgement(), "cannot unmarshal ICS20-V2 transfer packet data: unexpected EOF: invalid type", }, { @@ -317,7 +320,7 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { func() { suite.chainB.GetSimApp().TransferKeeper.SetParams(suite.chainB.GetContext(), types.Params{ReceiveEnabled: false}) }, - channeltypes.NewErrorAcknowledgement(types.ErrReceiveDisabled), + channeltypes.NewErrorAcknowledgement(types.ErrReceiveDisabled).Acknowledgement(), "fungible token transfers to this chain are disabled", }, } @@ -354,13 +357,14 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), sdk.NewAttribute(types.AttributeKeyForwardingHops, string(forwardingHopsBz)), } - if tc.expAck == nil || tc.expAck.Success() { - expectedAttributes = append(expectedAttributes, sdk.NewAttribute(types.AttributeKeyAckSuccess, "true")) - } else { + + if tc.expEventErrorMsg != "" { expectedAttributes = append(expectedAttributes, sdk.NewAttribute(types.AttributeKeyAckSuccess, "false"), sdk.NewAttribute(types.AttributeKeyAckError, tc.expEventErrorMsg), ) + } else { + expectedAttributes = append(expectedAttributes, sdk.NewAttribute(types.AttributeKeyAckSuccess, "true")) } seq := uint64(1) @@ -375,9 +379,9 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { tc.malleate() // change fields in packet - ack := cbs.OnRecvPacket(ctx, path.EndpointB.GetChannel().Version, packet, suite.chainB.SenderAccount.GetAddress()) + res := cbs.OnRecvPacket(ctx, path.EndpointB.GetChannel().Version, packet, suite.chainB.SenderAccount.GetAddress()) - suite.Require().Equal(tc.expAck, ack) + suite.Require().Equal(tc.expAck, res.Acknowledgement) expectedEvents := sdk.Events{ sdk.NewEvent( diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index e8c758ca166..41533375235 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -45,7 +45,7 @@ func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDat // acknowledgeForwardedPacket writes the async acknowledgement for forwardedPacket func (k Keeper) acknowledgeForwardedPacket(ctx sdk.Context, forwardedPacket, packet channeltypes.Packet, ack channeltypes.Acknowledgement) error { - if err := k.ics4Wrapper.WriteAcknowledgement(ctx, forwardedPacket, ack); err != nil { + if err := k.ics4Wrapper.WriteAcknowledgement(ctx, forwardedPacket, ack.Acknowledgement()); err != nil { return err } diff --git a/modules/core/03-connection/keeper/verify_test.go b/modules/core/03-connection/keeper/verify_test.go index 4177aebbbce..95e84b438dc 100644 --- a/modules/core/03-connection/keeper/verify_test.go +++ b/modules/core/03-connection/keeper/verify_test.go @@ -235,7 +235,7 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { var ( path *ibctesting.Path - ack exported.Acknowledgement + ack []byte heightDiff uint64 delayTimePeriod uint64 timePerBlock uint64 @@ -266,7 +266,7 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { heightDiff = 5 }, false}, {"verification failed - changed acknowledgement", func() { - ack = ibcmock.MockFailAcknowledgement + ack = ibcmock.MockFailAcknowledgement.Acknowledgement() }, false}, {"client status is not active - client is expired", func() { clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) @@ -280,8 +280,8 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { tc := tc suite.Run(tc.name, func() { - suite.SetupTest() // reset - ack = ibcmock.MockAcknowledgement // must be explicitly changed + suite.SetupTest() // reset + ack = ibcmock.MockAcknowledgement.Acknowledgement() // must be explicitly changed path = ibctesting.NewPath(suite.chainA, suite.chainB) path.Setup() @@ -317,7 +317,7 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { err = suite.chainA.App.GetIBCKeeper().ConnectionKeeper.VerifyPacketAcknowledgement( suite.chainA.GetContext(), connection, malleateHeight(proofHeight, heightDiff), proof, - packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ack.Acknowledgement(), + packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ack, ) if tc.expPass { diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index 6ef738dee2e..6910c98513f 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -276,7 +276,7 @@ func (k *Keeper) applyReplayProtection(ctx sdk.Context, packet types.Packet, cha func (k *Keeper) WriteAcknowledgement( ctx sdk.Context, packet exported.PacketI, - acknowledgement exported.Acknowledgement, + acknowledgement []byte, ) error { channel, found := k.GetChannel(ctx, packet.GetDestPort(), packet.GetDestChannel()) if !found { @@ -304,19 +304,14 @@ func (k *Keeper) WriteAcknowledgement( return types.ErrAcknowledgementExists } - if acknowledgement == nil { - return errorsmod.Wrap(types.ErrInvalidAcknowledgement, "acknowledgement cannot be nil") - } - - bz := acknowledgement.Acknowledgement() - if len(bz) == 0 { + if len(acknowledgement) == 0 { return errorsmod.Wrap(types.ErrInvalidAcknowledgement, "acknowledgement cannot be empty") } // set the acknowledgement so that it can be verified on the other side k.SetPacketAcknowledgement( ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), - types.CommitAcknowledgement(bz), + types.CommitAcknowledgement(acknowledgement), ) // log that a packet acknowledgement has been written @@ -329,7 +324,7 @@ func (k *Keeper) WriteAcknowledgement( "dst_channel", packet.GetDestChannel(), ) - emitWriteAcknowledgementEvent(ctx, packet.(types.Packet), channel, bz) + emitWriteAcknowledgementEvent(ctx, packet.(types.Packet), channel, acknowledgement) return nil } diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index cd10ff75049..e35ddeb70fd 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -627,74 +627,86 @@ func (suite *KeeperTestSuite) TestRecvPacket() { func (suite *KeeperTestSuite) TestWriteAcknowledgement() { var ( - path *ibctesting.Path - ack exported.Acknowledgement + ack []byte packet exported.PacketI + path *ibctesting.Path ) - testCases := []testCase{ + testCases := []struct { + name string + malleate func() + expError error + }{ { "success", func() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - ack = ibcmock.MockAcknowledgement + ack = ibcmock.MockAcknowledgement.Acknowledgement() }, - true, + nil, }, { "success: channel flushing", func() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - ack = ibcmock.MockAcknowledgement + ack = ibcmock.MockAcknowledgement.Acknowledgement() path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHING }) }, - true, + nil, }, { "success: channel flush complete", func() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - ack = ibcmock.MockAcknowledgement + ack = ibcmock.MockAcknowledgement.Acknowledgement() path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.FLUSHCOMPLETE }) }, - true, + nil, }, - {"channel not found", func() { - // use wrong channel naming - path.Setup() - packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ibctesting.InvalidID, ibctesting.InvalidID, defaultTimeoutHeight, disabledTimeoutTimestamp) - ack = ibcmock.MockAcknowledgement - }, false}, - {"channel not open", func() { - path.Setup() - packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - ack = ibcmock.MockAcknowledgement + { + "channel not found", + func() { + // use wrong channel naming + path.Setup() + packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ibctesting.InvalidID, ibctesting.InvalidID, defaultTimeoutHeight, disabledTimeoutTimestamp) + ack = ibcmock.MockAcknowledgement.Acknowledgement() + }, + types.ErrChannelNotFound, + }, + { + "channel not open", + func() { + path.Setup() + packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + ack = ibcmock.MockAcknowledgement.Acknowledgement() - path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) - }, false}, + path.EndpointB.UpdateChannel(func(channel *types.Channel) { channel.State = types.CLOSED }) + }, + types.ErrInvalidChannelState, + }, { - "no-op, already acked", + "acknowledgement already exists", func() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - ack = ibcmock.MockAcknowledgement - suite.chainB.App.GetIBCKeeper().ChannelKeeper.SetPacketAcknowledgement(suite.chainB.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), ack.Acknowledgement()) + ack = ibcmock.MockAcknowledgement.Acknowledgement() + suite.chainB.App.GetIBCKeeper().ChannelKeeper.SetPacketAcknowledgement(suite.chainB.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence(), types.CommitAcknowledgement(ack)) }, - false, + types.ErrAcknowledgementExists, }, { "empty acknowledgement", func() { path.Setup() packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - ack = ibcmock.NewEmptyAcknowledgement() + ack = ibcmock.NewEmptyAcknowledgement().Acknowledgement() }, - false, + types.ErrInvalidAcknowledgement, }, { "acknowledgement is nil", @@ -703,7 +715,7 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) ack = nil }, - false, + types.ErrInvalidAcknowledgement, }, { "packet already received", @@ -713,17 +725,18 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - ack = ibcmock.MockAcknowledgement + ack = ibcmock.MockAcknowledgement.Acknowledgement() // set recv seq start to indicate packet was processed in previous upgrade suite.chainB.App.GetIBCKeeper().ChannelKeeper.SetRecvStartSequence(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sequence+1) }, - false, + types.ErrPacketReceived, }, } - for i, tc := range testCases { + + for _, tc := range testCases { tc := tc - suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.Run(tc.name, func() { suite.SetupTest() // reset path = ibctesting.NewPath(suite.chainA, suite.chainB) @@ -731,10 +744,11 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(suite.chainB.GetContext(), packet, ack) - if tc.expPass { + expPass := tc.expError == nil + if expPass { suite.Require().NoError(err) } else { - suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expError) } }) } diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index fdf48c457df..e4f3e168d0c 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -234,8 +234,8 @@ func (LegacyIBCModule) OnRecvPacket( channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - return nil +) ibcexported.RecvPacketResult { + return ibcexported.RecvPacketResult{} } // OnAcknowledgementPacket implements the IBCModule interface diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index f43a6efc504..bb8a82d0ba9 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -103,7 +103,7 @@ type IBCModule interface { channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, - ) exported.Acknowledgement + ) exported.RecvPacketResult OnAcknowledgementPacket( ctx sdk.Context, @@ -196,7 +196,7 @@ type ICS4Wrapper interface { WriteAcknowledgement( ctx sdk.Context, packet exported.PacketI, - ack exported.Acknowledgement, + ack []byte, ) error GetAppVersion( diff --git a/modules/core/ante/ante_test.go b/modules/core/ante/ante_test.go index 1f8d8ae2614..f597886eb95 100644 --- a/modules/core/ante/ante_test.go +++ b/modules/core/ante/ante_test.go @@ -351,7 +351,7 @@ func (suite *AnteTestSuite) TestAnteDecoratorCheckTx() { func(suite *AnteTestSuite) []sdk.Msg { suite.chainB.GetSimApp().IBCMockModule.IBCApp.OnRecvPacket = func( ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, - ) exported.Acknowledgement { + ) exported.RecvPacketResult { panic(fmt.Errorf("failed OnRecvPacket mock callback")) } @@ -578,7 +578,7 @@ func (suite *AnteTestSuite) TestAnteDecoratorReCheckTx() { func(suite *AnteTestSuite) []sdk.Msg { suite.chainB.GetSimApp().IBCMockModule.IBCApp.OnRecvPacket = func( ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, - ) exported.Acknowledgement { + ) exported.RecvPacketResult { panic(fmt.Errorf("failed OnRecvPacket mock callback")) } diff --git a/modules/core/exported/packet.go b/modules/core/exported/packet.go index f8e6a09ebd6..fc56a8b1597 100644 --- a/modules/core/exported/packet.go +++ b/modules/core/exported/packet.go @@ -13,24 +13,36 @@ type PacketI interface { ValidateBasic() error } -// Acknowledgement defines the interface used to return acknowledgements in the OnRecvPacket callback. -// The Acknowledgement interface is used by core IBC to ensure partial state changes are not committed +// RecvPacketStatus defines an enum type to signal the result status of an IBC application packet datagram and inform +// core IBC of how to handle the application state changes held in the cache store which it was provided for OnRecvPacket callback execution. +type RecvPacketStatus uint32 + +const ( + // Success instructs that the IBC application state should be persisted. + Success RecvPacketStatus = iota + // Failure instructs that the IBC application state should be discarded. + Failure + // Async instructs that the IBC application state should be persisted + // and acknowledgement data will be written later asynchronously. + Async +) + +// String implements the fmt.Stringer interface. +func (r RecvPacketStatus) String() string { + return [...]string{"Success", "Failure", "Async"}[r] +} + +// RecvPacketResult defines a result type used to encapsulate opaque application acknowledgement data, as well as +// a status to indicate success, failure or asynchronous handling of a packet acknowledgement in the OnRecvPacket callback. +// Status is used by core IBC to ensure partial state changes are not committed // when packet receives have not properly succeeded (typically resulting in an error acknowledgement being returned). -// The interface also allows core IBC to obtain the acknowledgement bytes whose encoding is determined by each IBC application or middleware. -// Each custom acknowledgement type must implement this interface. -type Acknowledgement interface { - // Success determines if the IBC application state should be persisted when handling `RecvPacket`. - // During `OnRecvPacket` IBC application callback execution, all state changes are held in a cache store and committed if: - // - the acknowledgement.Success() returns true - // - a nil acknowledgement is returned (asynchronous acknowledgements) - // - // Note 1: IBC application callback events are always persisted so long as `RecvPacket` succeeds without error. - // - // Note 2: The return value should account for the success of the underlying IBC application or middleware. Thus the `acknowledgement.Success` is representative of the entire IBC stack's success when receiving a packet. The individual success of each acknowledgement associated with an IBC application or middleware must be determined by obtaining the actual acknowledgement type after decoding the acknowledgement bytes. - // - // See https://github.com/cosmos/ibc-go/blob/v7.0.0/docs/ibc/apps.md for further explanations. - Success() bool - Acknowledgement() []byte +// During OnRecvPacket callback execution, all state changes are held in a cache store and committed if +// the result status is indicated as Async or Success. +// +// Note: IBC application callback events are always persisted so long as `RecvPacket` succeeds without error. +type RecvPacketResult struct { + Status RecvPacketStatus + Acknowledgement []byte } // PacketData defines an optional interface which an application's packet data structure may implement. diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 58c9c65b850..a6a466a5631 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -14,6 +14,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v9/modules/core/05-port/types" ibcerrors "github.com/cosmos/ibc-go/v9/modules/core/errors" + "github.com/cosmos/ibc-go/v9/modules/core/exported" "github.com/cosmos/ibc-go/v9/modules/core/internal/telemetry" coretypes "github.com/cosmos/ibc-go/v9/modules/core/types" ) @@ -465,8 +466,8 @@ func (k *Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPack // // Cache context so that we may discard state changes from callback if the acknowledgement is unsuccessful. cacheCtx, writeFn = ctx.CacheContext() - ack := cbs.OnRecvPacket(cacheCtx, channelVersion, msg.Packet, relayer) - if ack == nil || ack.Success() { + res := cbs.OnRecvPacket(cacheCtx, channelVersion, msg.Packet, relayer) + if res.Status == exported.Success || res.Status == exported.Async { // write application state changes for asynchronous and successful acknowledgements writeFn() } else { @@ -477,8 +478,8 @@ func (k *Keeper) RecvPacket(goCtx context.Context, msg *channeltypes.MsgRecvPack // Set packet acknowledgement only if the acknowledgement is not nil. // NOTE: IBC applications modules may call the WriteAcknowledgement asynchronously if the // acknowledgement is nil. - if ack != nil { - if err := k.ChannelKeeper.WriteAcknowledgement(ctx, msg.Packet, ack); err != nil { + if res.Acknowledgement != nil { + if err := k.ChannelKeeper.WriteAcknowledgement(ctx, msg.Packet, res.Acknowledgement); err != nil { return nil, err } } diff --git a/testing/endpoint.go b/testing/endpoint.go index 1426a386261..27b2e49750a 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -492,9 +492,9 @@ func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*abc // WriteAcknowledgement writes an acknowledgement on the channel associated with the endpoint. // The counterparty client is updated. -func (endpoint *Endpoint) WriteAcknowledgement(ack exported.Acknowledgement, packet exported.PacketI) error { +func (endpoint *Endpoint) WriteAcknowledgement(acknowledgement []byte, packet exported.PacketI) error { // no need to send message, acting as a handler - err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), packet, ack) + err := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), packet, acknowledgement) if err != nil { return err } diff --git a/testing/mock/ibc_app.go b/testing/mock/ibc_app.go index 73eb1954c36..471f1a85950 100644 --- a/testing/mock/ibc_app.go +++ b/testing/mock/ibc_app.go @@ -78,7 +78,7 @@ type IBCApp struct { channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, - ) exported.Acknowledgement + ) exported.RecvPacketResult OnAcknowledgementPacket func( ctx sdk.Context, diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index 40e27b15cf9..a292d5e98c0 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -117,7 +117,7 @@ func (im IBCModule) OnSendPacket(ctx sdk.Context, portID string, channelID strin } // OnRecvPacket implements the IBCModule interface. -func (im IBCModule) OnRecvPacket(ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress) exported.Acknowledgement { +func (im IBCModule) OnRecvPacket(ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress) exported.RecvPacketResult { if im.IBCApp.OnRecvPacket != nil { return im.IBCApp.OnRecvPacket(ctx, channelVersion, packet, relayer) } @@ -133,12 +133,20 @@ func (im IBCModule) OnRecvPacket(ctx sdk.Context, channelVersion string, packet ctx.EventManager().EmitEvent(NewMockRecvPacketEvent()) if bytes.Equal(MockPacketData, packet.GetData()) { - return MockAcknowledgement + return exported.RecvPacketResult{ + Status: exported.Success, + Acknowledgement: MockAcknowledgement.Acknowledgement(), + } } else if bytes.Equal(MockAsyncPacketData, packet.GetData()) { - return nil + return exported.RecvPacketResult{ + Status: exported.Async, + } } - return MockFailAcknowledgement + return exported.RecvPacketResult{ + Status: exported.Failure, + Acknowledgement: MockFailAcknowledgement.Acknowledgement(), + } } // OnAcknowledgementPacket implements the IBCModule interface. diff --git a/testing/mock/middleware.go b/testing/mock/middleware.go index 46c9ab27232..2093a70a779 100644 --- a/testing/mock/middleware.go +++ b/testing/mock/middleware.go @@ -107,7 +107,7 @@ func (im BlockUpgradeMiddleware) OnSendPacket(ctx sdk.Context, portID string, ch } // OnRecvPacket implements the IBCModule interface. -func (im BlockUpgradeMiddleware) OnRecvPacket(ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress) exported.Acknowledgement { +func (im BlockUpgradeMiddleware) OnRecvPacket(ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress) exported.RecvPacketResult { if im.IBCApp.OnRecvPacket != nil { return im.IBCApp.OnRecvPacket(ctx, channelVersion, packet, relayer) } @@ -121,12 +121,20 @@ func (im BlockUpgradeMiddleware) OnRecvPacket(ctx sdk.Context, channelVersion st } if bytes.Equal(MockPacketData, packet.GetData()) { - return MockAcknowledgement + return exported.RecvPacketResult{ + Status: exported.Success, + Acknowledgement: MockAcknowledgement.Acknowledgement(), + } } else if bytes.Equal(MockAsyncPacketData, packet.GetData()) { - return nil + return exported.RecvPacketResult{ + Status: exported.Async, + } } - return MockFailAcknowledgement + return exported.RecvPacketResult{ + Status: exported.Failure, + Acknowledgement: MockFailAcknowledgement.Acknowledgement(), + } } // OnAcknowledgementPacket implements the IBCModule interface. @@ -165,7 +173,7 @@ func (im BlockUpgradeMiddleware) OnTimeoutPacket(ctx sdk.Context, channelVersion func (BlockUpgradeMiddleware) WriteAcknowledgement( ctx sdk.Context, packet exported.PacketI, - ack exported.Acknowledgement, + ack []byte, ) error { return nil } From d9c4e96963210151635de4d39aedb17269ad7cbe Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Thu, 8 Aug 2024 16:50:19 +0100 Subject: [PATCH 41/46] imp (api)!: convert coins to token only once in MsgTransfer (#7110) * test not working * refactored test and removed unneeded caese --- modules/apps/transfer/keeper/export_test.go | 4 +-- modules/apps/transfer/keeper/msg_server.go | 36 ++++++++----------- .../apps/transfer/keeper/msg_server_test.go | 17 ++++----- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index dedfd560b9b..828267fc49b 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -35,8 +35,8 @@ func (k Keeper) TokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // UnwindHops is a wrapper around unwindHops for testing purposes. -func (k Keeper) UnwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgTransfer, error) { - return k.unwindHops(ctx, msg) +func (k Keeper) UnwindHops(msg *types.MsgTransfer, tokens []types.Token) (*types.MsgTransfer, error) { + return k.unwindHops(msg, tokens) } // GetForwardedPacket is a wrapper around getForwardedPacket for testing purposes. diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 9f8457481b6..27a74d7b7fb 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -24,13 +24,6 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. return nil, err } - if msg.Forwarding.GetUnwind() { - msg, err = k.unwindHops(ctx, msg) - if err != nil { - return nil, err - } - } - coins := msg.GetCoins() tokens := make([]types.Token, 0, len(coins)) for _, coin := range coins { @@ -42,6 +35,13 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. tokens = append(tokens, token) } + if msg.Forwarding.GetUnwind() { + msg, err = k.unwindHops(msg, tokens) + if err != nil { + return nil, err + } + } + appVersion, found := k.ics4Wrapper.GetAppVersion(ctx, msg.SourcePort, msg.SourceChannel) if !found { return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "application version not found for source port: %s and source channel: %s", msg.SourcePort, msg.SourceChannel) @@ -109,8 +109,8 @@ func (k Keeper) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParams) // unwindHops unwinds the hops present in the tokens denomination and returns the message modified to reflect // the unwound path to take. It assumes that only a single token is present (as this is verified in ValidateBasic) // in the tokens list and ensures that the token is not native to the chain. -func (k Keeper) unwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgTransfer, error) { - unwindHops, err := k.getUnwindHops(ctx, msg.GetCoins()) +func (k Keeper) unwindHops(msg *types.MsgTransfer, tokens []types.Token) (*types.MsgTransfer, error) { + unwindHops, err := k.getUnwindHops(tokens) if err != nil { return nil, err } @@ -130,30 +130,22 @@ func (k Keeper) unwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgT // getUnwindHops returns the hops to be used during unwinding. If coins consists of more than // one coin, all coins must have the exact same trace, else an error is returned. getUnwindHops // also validates that the coins are not native to the chain. -func (k Keeper) getUnwindHops(ctx sdk.Context, coins sdk.Coins) ([]types.Hop, error) { +func (Keeper) getUnwindHops(tokens []types.Token) ([]types.Hop, error) { // Sanity: validation for MsgTransfer ensures coins are not empty. - if len(coins) == 0 { + if len(tokens) == 0 { return nil, errorsmod.Wrap(types.ErrInvalidForwarding, "coins cannot be empty") } - token, err := k.tokenFromCoin(ctx, coins[0]) - if err != nil { - return nil, err - } + token := tokens[0] if token.Denom.IsNative() { return nil, errorsmod.Wrap(types.ErrInvalidForwarding, "cannot unwind a native token") } unwindTrace := token.Denom.Trace - for _, coin := range coins[1:] { - token, err := k.tokenFromCoin(ctx, coin) - if err != nil { - return nil, err - } - + for _, t := range tokens[1:] { // Implicitly ensures coin we're iterating over is not native. - if !slices.Equal(token.Denom.Trace, unwindTrace) { + if !slices.Equal(t.Denom.Trace, unwindTrace) { return nil, errorsmod.Wrap(types.ErrInvalidForwarding, "cannot unwind tokens with different traces.") } } diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 4ce62f89eba..53b3e3a1460 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -327,13 +327,6 @@ func (suite *KeeperTestSuite) TestUnwindHops() { suite.Require().Equal(*msg, *modified, "expected msg and modified msg are different") }, }, - { - "failure: no denom set on keeper", - func() {}, - func(modified *types.MsgTransfer, err error) { - suite.Require().ErrorIs(err, types.ErrDenomNotFound) - }, - }, { "failure: validateBasic() fails due to invalid channelID", func() { @@ -398,7 +391,15 @@ func (suite *KeeperTestSuite) TestUnwindHops() { ) tc.malleate() - gotMsg, err := suite.chainA.GetSimApp().TransferKeeper.UnwindHops(suite.chainA.GetContext(), msg) + + tokens := make([]types.Token, 0, len(coins)) + for _, c := range msg.GetCoins() { + token, err := suite.chainA.GetSimApp().TransferKeeper.TokenFromCoin(suite.chainA.GetContext(), c) + suite.Require().NoError(err) + tokens = append(tokens, token) + } + + gotMsg, err := suite.chainA.GetSimApp().TransferKeeper.UnwindHops(msg, tokens) tc.assertResult(gotMsg, err) }) } From 0ea612adb2a08ff70fe459000bd9dca5a3b91326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:50:52 +0200 Subject: [PATCH 42/46] use new port router with OnAcknowledgementPacket (#7108) * refactor: use new port router for OnAcknowledgementPacket * fix: msg server update * fix: ics27 host tests * fix: ics27 controller tests * lint * chore: docs * add type assertions * add 29 type assertion --- .../controller/ibc_middleware.go | 17 +++--- .../controller/ibc_middleware_test.go | 57 +++++-------------- .../host/ibc_module_test.go | 14 +++-- modules/apps/29-fee/ibc_middleware.go | 49 +++++++++++----- modules/apps/29-fee/ibc_middleware_test.go | 10 ---- modules/apps/callbacks/ibc_middleware.go | 6 -- modules/apps/callbacks/ibc_middleware_test.go | 22 +++---- .../core/05-port/types/ibc_legacy_module.go | 21 ++++++- modules/core/05-port/types/module.go | 21 ++++++- modules/core/keeper/msg_server.go | 12 ++-- 10 files changed, 123 insertions(+), 106 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index f1516784292..a2f5b1537f3 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -21,6 +21,7 @@ var ( _ porttypes.Middleware = (*IBCMiddleware)(nil) _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) _ porttypes.UpgradableModule = (*IBCMiddleware)(nil) + _ porttypes.VersionWrapper = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the @@ -217,16 +218,6 @@ func (im IBCMiddleware) OnAcknowledgementPacket( return types.ErrControllerSubModuleDisabled } - connectionID, err := im.keeper.GetConnectionID(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) - if err != nil { - return err - } - - // call underlying app's OnAcknowledgementPacket callback. - if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, packet.GetSourcePort(), connectionID) { - return im.app.OnAcknowledgementPacket(ctx, channelVersion, packet, acknowledgement, relayer) - } - return nil } @@ -329,3 +320,9 @@ func (IBCMiddleware) UnwrapVersionUnsafe(version string) (string, string, error) // ignore underlying app version return version, "", nil } + +// UnwrapVersionSafe returns the version. Interchain accounts does not wrap versions. +func (IBCMiddleware) UnwrapVersionSafe(ctx sdk.Context, portID, channelID, version string) (string, string) { + // ignore underlying app version + return version, "" +} diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 64f22ae0503..6232f18f9f8 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -514,50 +514,22 @@ func (suite *InterchainAccountsTestSuite) TestOnRecvPacket() { } func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { - var ( - path *ibctesting.Path - isNilApp bool - ) + var path *ibctesting.Path testCases := []struct { msg string malleate func() - expPass bool + expError error }{ { "success", func() {}, - true, + nil, }, { "controller submodule disabled", func() { suite.chainA.GetSimApp().ICAControllerKeeper.SetParams(suite.chainA.GetContext(), types.NewParams(false)) - }, false, - }, - { - "ICA auth module callback fails", func() { - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnAcknowledgementPacket = func( - ctx sdk.Context, channelVersion string, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, - ) error { - return fmt.Errorf("mock ica auth fails") - } - }, false, - }, - { - "nil underlying app", func() { - isNilApp = true - }, true, - }, - { - "middleware disabled", func() { - suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) - - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnAcknowledgementPacket = func( - ctx sdk.Context, channelVersion string, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, - ) error { - return fmt.Errorf("error should be unreachable") - } - }, true, + }, types.ErrControllerSubModuleDisabled, }, } @@ -567,7 +539,6 @@ func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { suite.Run(tc.msg, func() { suite.SetupTest() // reset - isNilApp = false path = NewICAPath(suite.chainA, suite.chainB, ordering) path.SetupConnections() @@ -588,22 +559,22 @@ func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.PacketRoute(path.EndpointA.ChannelConfig.PortID) suite.Require().True(ok) - if isNilApp { - cbs = controller.NewIBCMiddleware(suite.chainA.GetSimApp().ICAControllerKeeper) - } + legacyModule, ok := cbs[0].(*porttypes.LegacyIBCModule) + suite.Require().True(ok, "expected there to be a single legacy ibc module") + + legacyModuleCbs := legacyModule.GetCallbacks() + controllerModule, ok := legacyModuleCbs[1].(controller.IBCMiddleware) // controller module is routed second + suite.Require().True(ok) - err = cbs.OnAcknowledgementPacket(suite.chainA.GetContext(), path.EndpointA.GetChannel().Version, packet, []byte("ack"), nil) + err = controllerModule.OnAcknowledgementPacket(suite.chainA.GetContext(), path.EndpointA.GetChannel().Version, packet, []byte("ack"), nil) - if tc.expPass { + if tc.expError == nil { suite.Require().NoError(err) } else { - suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expError) } }) } diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index 3b85a210d10..c15628f8cab 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -305,7 +305,7 @@ func (suite *InterchainAccountsTestSuite) TestOnChanOpenConfirm() { suite.Require().True(ok, "expected there to be a single legacy ibc module") legacyModuleCbs := legacyModule.GetCallbacks() - hostModule, ok := legacyModuleCbs[0].(icahost.IBCModule) // fee module is routed second + hostModule, ok := legacyModuleCbs[0].(icahost.IBCModule) suite.Require().True(ok) err = hostModule.OnChanOpenConfirm(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) @@ -557,10 +557,14 @@ func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { tc.malleate() // malleate mutates test data - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.AppRouter.PacketRoute(path.EndpointB.ChannelConfig.PortID) + suite.Require().True(ok) - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + legacyModule, ok := cbs[0].(*porttypes.LegacyIBCModule) + suite.Require().True(ok, "expected there to be a single legacy ibc module") + + legacyModuleCbs := legacyModule.GetCallbacks() + hostModule, ok := legacyModuleCbs[0].(icahost.IBCModule) suite.Require().True(ok) packet := channeltypes.NewPacket( @@ -574,7 +578,7 @@ func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { 0, ) - err = cbs.OnAcknowledgementPacket(suite.chainB.GetContext(), path.EndpointB.GetChannel().Version, packet, []byte("ackBytes"), nil) + err = hostModule.OnAcknowledgementPacket(suite.chainB.GetContext(), path.EndpointB.GetChannel().Version, packet, []byte("ackBytes"), nil) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index c8324dc6b08..d4cf8de7323 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -19,10 +19,11 @@ import ( ) var ( - _ porttypes.Middleware = (*IBCMiddleware)(nil) - _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) - _ porttypes.UpgradableModule = (*IBCMiddleware)(nil) - _ porttypes.VersionWrapper = (*IBCMiddleware)(nil) + _ porttypes.Middleware = (*IBCMiddleware)(nil) + _ porttypes.PacketDataUnmarshaler = (*IBCMiddleware)(nil) + _ porttypes.UpgradableModule = (*IBCMiddleware)(nil) + _ porttypes.VersionWrapper = (*IBCMiddleware)(nil) + _ porttypes.AcknowledgementWrapper = (*IBCMiddleware)(nil) ) // IBCMiddleware implements the ICS26 callbacks for the fee middleware given the @@ -196,11 +197,9 @@ func (im IBCMiddleware) OnAcknowledgementPacket( relayer sdk.AccAddress, ) error { if !im.keeper.IsFeeEnabled(ctx, packet.SourcePort, packet.SourceChannel) { - return im.app.OnAcknowledgementPacket(ctx, channelVersion, packet, acknowledgement, relayer) + return nil } - appVersion := unwrapAppVersion(channelVersion) - var ack types.IncentivizedAcknowledgement if err := json.Unmarshal(acknowledgement, &ack); err != nil { return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-29 incentivized packet acknowledgement %v: %s", ack, err) @@ -215,14 +214,13 @@ func (im IBCMiddleware) OnAcknowledgementPacket( // for fee enabled channels // // Please see ADR 004 for more information. - return im.app.OnAcknowledgementPacket(ctx, appVersion, packet, ack.AppAcknowledgement, relayer) + return nil } packetID := channeltypes.NewPacketID(packet.SourcePort, packet.SourceChannel, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) if !found { - // call underlying callback - return im.app.OnAcknowledgementPacket(ctx, appVersion, packet, ack.AppAcknowledgement, relayer) + return nil } payee, found := im.keeper.GetPayeeAddress(ctx, relayer.String(), packet.SourceChannel) @@ -236,9 +234,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( } im.keeper.DistributePacketFeesOnAcknowledgement(ctx, ack.ForwardRelayerAddress, payeeAddr, feesInEscrow.PacketFees, packetID) - - // call underlying callback - return im.app.OnAcknowledgementPacket(ctx, appVersion, packet, ack.AppAcknowledgement, relayer) + return nil } // OnTimeoutPacket implements the IBCMiddleware interface @@ -392,3 +388,30 @@ func (IBCMiddleware) UnwrapVersionUnsafe(version string) (string, string, error) return metadata.FeeVersion, metadata.AppVersion, nil } + +// UnwrapVersionSafe unwraps a version contextually by relying on storage and the given portID and channelID. +func (im IBCMiddleware) UnwrapVersionSafe(ctx sdk.Context, portID, channelID, version string) (string, string) { + if !im.keeper.IsFeeEnabled(ctx, portID, channelID) { + return "", version + } + metadata, err := types.MetadataFromVersion(version) + if err != nil { + // This should not happen, as it would mean that the channel is broken. Only a severe bug would cause this. + panic(errorsmod.Wrap(err, "failed to unwrap app version from channel version")) + } + return metadata.FeeVersion, metadata.AppVersion +} + +// UnwrapAcknowledgement unwraps an acnkowledgement contextually by relying on storage and the given portID and channelID. +func (im IBCMiddleware) UnwrapAcknowledgement(ctx sdk.Context, portID, channelID string, ack []byte) ([]byte, []byte) { + if !im.keeper.IsFeeEnabled(ctx, portID, channelID) { + return nil, ack + } + + var incentivizedAck types.IncentivizedAcknowledgement + if err := json.Unmarshal(ack, &incentivizedAck); err != nil { + panic(errorsmod.Wrap(err, "failed to unwrap acknowledgement")) + } + + return ack, incentivizedAck.AppAcknowledgement +} diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index af0f5c28816..751b9fc982d 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -703,16 +703,6 @@ func (suite *FeeTestSuite) TestOnAcknowledgementPacket() { false, func() {}, }, - { - "application callback fails", - func() { - suite.chainA.GetSimApp().FeeMockModule.IBCApp.OnAcknowledgementPacket = func(_ sdk.Context, _ string, _ channeltypes.Packet, _ []byte, _ sdk.AccAddress) error { - return fmt.Errorf("mock fee app callback fails") - } - }, - false, - func() {}, - }, } for _, tc := range testCases { diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 6fa56e62479..3962bae2d37 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -125,12 +125,6 @@ func (im IBCMiddleware) OnAcknowledgementPacket( acknowledgement []byte, relayer sdk.AccAddress, ) error { - // we first call the underlying app to handle the acknowledgement - err := im.app.OnAcknowledgementPacket(ctx, channelVersion, packet, acknowledgement, relayer) - if err != nil { - return err - } - // OnAcknowledgementPacket is not blocked if the packet does not opt-in to callbacks callbackData, err := types.GetSourceCallbackData(ctx, im.app, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetData(), im.maxCallbackGas) if err != nil { diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 48aacda05a7..0c67244aa91 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -258,14 +258,6 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { callbackSuccess, nil, }, - { - "failure: underlying app OnAcknolwedgePacket fails", - func() { - ack = []byte("invalid ack") - }, - noExecution, - ibcerrors.ErrUnknownRequest, - }, { "success: no-op on callback data is not valid", func() { @@ -345,11 +337,19 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { tc.malleate() // callbacks module is routed as top level middleware - transferStack, ok := s.chainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) + cbs, ok := s.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.PacketRoute(transfertypes.ModuleName) + s.Require().True(ok) + + legacyModule, ok := cbs[0].(*porttypes.LegacyIBCModule) + s.Require().True(ok, "expected there to be a single legacy ibc module") + + legacyModuleCbs := legacyModule.GetCallbacks() + + callbacksModule, ok := legacyModuleCbs[1].(ibccallbacks.IBCMiddleware) // callbacks module is routed second s.Require().True(ok) onAcknowledgementPacket := func() error { - return transferStack.OnAcknowledgementPacket(ctx, s.path.EndpointA.GetChannel().Version, packet, ack, s.chainA.SenderAccount.GetAddress()) + return callbacksModule.OnAcknowledgementPacket(ctx, s.path.EndpointA.GetChannel().Version, packet, ack, s.chainA.SenderAccount.GetAddress()) } switch tc.expError { @@ -388,7 +388,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { s.Require().Equal(uint8(1), sourceStatefulCounter) expEvent, exists := GetExpectedEvent( - ctx, transferStack.(porttypes.PacketDataUnmarshaler), gasLimit, packet.Data, packet.SourcePort, + ctx, callbacksModule, gasLimit, packet.Data, packet.SourcePort, packet.SourcePort, packet.SourceChannel, packet.Sequence, types.CallbackTypeAcknowledgementPacket, nil, ) s.Require().True(exists) diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index e4f3e168d0c..429b504a453 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -239,13 +239,32 @@ func (LegacyIBCModule) OnRecvPacket( } // OnAcknowledgementPacket implements the IBCModule interface -func (LegacyIBCModule) OnAcknowledgementPacket( +func (im *LegacyIBCModule) OnAcknowledgementPacket( ctx sdk.Context, channelVersion string, packet channeltypes.Packet, acknowledgement []byte, relayer sdk.AccAddress, ) error { + for i := len(im.cbs) - 1; i >= 0; i-- { + var ( + cbVersion = channelVersion + cbAck = acknowledgement + ) + + if wrapper, ok := im.cbs[i].(VersionWrapper); ok { + cbVersion, channelVersion = wrapper.UnwrapVersionSafe(ctx, packet.SourcePort, packet.SourceChannel, cbVersion) + } + + if wrapper, ok := im.cbs[i].(AcknowledgementWrapper); ok { + cbAck, acknowledgement = wrapper.UnwrapAcknowledgement(ctx, packet.SourcePort, packet.SourceChannel, cbAck) + } + + err := im.cbs[i].OnAcknowledgementPacket(ctx, cbVersion, packet, cbAck, relayer) + if err != nil { + return errorsmod.Wrap(err, "acknowledge packet callback failed") + } + } return nil } diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index bb8a82d0ba9..8c448049e9d 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -131,12 +131,29 @@ type VersionWrapper interface { WrapVersion(cbVersion, underlyingAppVersion string) string // UnwrapVersionUnsafe is required in order to remove middleware wiring and the ICS4Wrapper // while maintaining backwards compatibility. It will be removed in the future. - // Applications should unwrap the provided version with into their application version. + // Applications should unwrap the provided version with into their application version. // and the underlying application version. If they are unsuccessful they should return an error. // UnwrapVersionUnsafe will be used during opening handshakes and channel upgrades when the version // is still being negotiated. UnwrapVersionUnsafe(string) (cbVersion, underlyingAppVersion string, err error) - // UnwrapVersionSafe(ctx sdk.Context, portID, channelID, version string) (appVersion, version string) + // UnwrapVersionSafe is required in order to remove middleware wiring and the ICS4Wrapper + // while maintaining backwards compatibility. It will be removed in the future. + // Applications should unwrap the provided version into their application version. + // They should use the context and associated portID and channelID to safely do so. + // UnwrapVersionSafe will be used during packet processing to provide callbacks + // their application version. + UnwrapVersionSafe(ctx sdk.Context, portID, channelID, version string) (cbVersion, underlyingAppVersion string) +} + +// AcknowledgementWrapper is an optional interface which should be implemented by middlewares which wrap the acknowledgement +// to ensure backwards compatibility. +type AcknowledgementWrapper interface { + // UnwrapAcknowledgement is required in order to remove middleware wiring and the ICS4Wrapper + // while maintaining backwards compatibility. It will be removed in the future. + // Applications should unwrap the underlying app acknowledgement using the context + // and the given portID and channelID. They should return their application acknowledgement + // as the bytes it expects to decode in OnAcknowledgement. + UnwrapAcknowledgement(ctx sdk.Context, portID, channelID string, acknowledgment []byte) (cbAcknowledgement, underlyingAppAcknowledgement []byte) } // UpgradableModule defines the callbacks required to perform a channel upgrade. diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index a6a466a5631..99c05f45bae 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -615,7 +615,7 @@ func (k *Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAck } // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(msg.Packet.SourcePort) + cbs, ok := k.PortKeeper.AppRouter.PacketRoute(msg.Packet.SourcePort) if !ok { ctx.Logger().Error("acknowledgement failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort) @@ -641,10 +641,12 @@ func (k *Keeper) Acknowledgement(goCtx context.Context, msg *channeltypes.MsgAck } // Perform application logic callback - err = cbs.OnAcknowledgementPacket(ctx, channelVersion, msg.Packet, msg.Acknowledgement, relayer) - if err != nil { - ctx.Logger().Error("acknowledgement failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "acknowledge packet callback failed")) - return nil, errorsmod.Wrap(err, "acknowledge packet callback failed") + for _, cb := range cbs { + err = cb.OnAcknowledgementPacket(ctx, channelVersion, msg.Packet, msg.Acknowledgement, relayer) + if err != nil { + ctx.Logger().Error("acknowledgement failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "acknowledge packet callback failed")) + return nil, errorsmod.Wrap(err, "acknowledge packet callback failed") + } } defer telemetry.ReportAcknowledgePacket(msg.Packet) From a9d34ba132dfec4815eaf278116a01c4bf963780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 12 Aug 2024 10:07:00 +0200 Subject: [PATCH 43/46] chore: docs (#7111) --- modules/core/05-port/types/router_v2.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/core/05-port/types/router_v2.go b/modules/core/05-port/types/router_v2.go index 83c40e2ecd0..c0df1a343e5 100644 --- a/modules/core/05-port/types/router_v2.go +++ b/modules/core/05-port/types/router_v2.go @@ -76,6 +76,10 @@ func (rtr *AppRouter) AddRoute(module string, cbs IBCModule) *AppRouter { return rtr } +// PacketRoute returns a list of callbacks. It takes the portID of the packet +// (used for classic IBC packets) and the packet data (used for multi-packetdata's). +// PacketRoute is explicitly seprated from the handshake route which only handles +// ClassicIBCModule's. Non ClassicIBCModule routing does not work on handshakes. func (rtr *AppRouter) PacketRoute(module string) ([]IBCModule, bool) { if module == sentinelMultiPacketData { return rtr.routeMultiPacketData(module) @@ -115,7 +119,8 @@ func (rtr *AppRouter) routeToLegacyModule(module string) (ClassicIBCModule, bool } // HandshakeRoute returns the ClassicIBCModule which will implement all handshake functions -// and is required only for those callbacks. +// as it is required only for those callbacks. It takes in the portID associated with the +// handshake. func (rtr *AppRouter) HandshakeRoute(portID string) (ClassicIBCModule, bool) { route, ok := rtr.routeToLegacyModule(portID) return route, ok From ec593cba0ea319b55dfaf3913f84fb089f607df5 Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Tue, 13 Aug 2024 12:05:47 +0100 Subject: [PATCH 44/46] Bznein/7023/on timeout packet (#7144) * initial commit * revert change * loop callbacks * fix loop * wip * chore: fixing remainder of timeout test failures * chore: check type assertion * PR feedbacK --------- Co-authored-by: chatton --- .../controller/ibc_middleware.go | 9 ----- .../controller/ibc_middleware_test.go | 38 +++---------------- .../host/ibc_module_test.go | 7 +--- modules/apps/29-fee/ibc_middleware.go | 11 ++---- modules/apps/29-fee/ibc_middleware_test.go | 7 +--- modules/apps/callbacks/ibc_middleware.go | 8 +--- modules/apps/callbacks/ibc_middleware_test.go | 20 ++++++++-- modules/apps/transfer/ibc_module_test.go | 14 ++----- .../transfer/keeper/relay_forwarding_test.go | 7 +--- .../core/05-port/types/ibc_legacy_module.go | 18 ++++++++- modules/core/keeper/msg_server.go | 14 ++++--- 11 files changed, 62 insertions(+), 91 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index a2f5b1537f3..fc68f0ee825 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -236,15 +236,6 @@ func (im IBCMiddleware) OnTimeoutPacket( return err } - connectionID, err := im.keeper.GetConnectionID(ctx, packet.GetSourcePort(), packet.GetSourceChannel()) - if err != nil { - return err - } - - if im.app != nil && im.keeper.IsMiddlewareEnabled(ctx, packet.GetSourcePort(), connectionID) { - return im.app.OnTimeoutPacket(ctx, channelVersion, packet, relayer) - } - return nil } diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go index 6232f18f9f8..d1b4053772b 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -1,7 +1,6 @@ package controller_test import ( - "fmt" "strconv" "testing" @@ -582,10 +581,7 @@ func (suite *InterchainAccountsTestSuite) TestOnAcknowledgementPacket() { } func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { - var ( - path *ibctesting.Path - isNilApp bool - ) + var path *ibctesting.Path testCases := []struct { msg string @@ -603,29 +599,15 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { }, false, }, { - "ICA auth module callback fails", func() { - suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnTimeoutPacket = func( - ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, - ) error { - return fmt.Errorf("mock ica auth fails") - } - }, false, - }, - { - "nil underlying app", func() { - isNilApp = true - }, true, - }, - { - "middleware disabled", func() { + "disabling ICA has no effect separate wired app", func() { suite.chainA.GetSimApp().ICAControllerKeeper.DeleteMiddlewareEnabled(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ConnectionID) suite.chainA.GetSimApp().ICAAuthModule.IBCApp.OnTimeoutPacket = func( ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, ) error { - return fmt.Errorf("error should be unreachable") + return ibcmock.MockApplicationCallbackError } - }, true, + }, false, }, } @@ -635,7 +617,6 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { suite.Run(tc.msg, func() { suite.SetupTest() // reset - isNilApp = false path = NewICAPath(suite.chainA, suite.chainB, ordering) path.SetupConnections() @@ -656,17 +637,10 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.PacketRoute(path.EndpointA.ChannelConfig.PortID) suite.Require().True(ok) - if isNilApp { - cbs = controller.NewIBCMiddleware(suite.chainA.GetSimApp().ICAControllerKeeper) - } - - err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), path.EndpointA.GetChannel().Version, packet, nil) + err = cbs[0].OnTimeoutPacket(suite.chainA.GetContext(), path.EndpointA.GetChannel().Version, packet, nil) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/apps/27-interchain-accounts/host/ibc_module_test.go b/modules/apps/27-interchain-accounts/host/ibc_module_test.go index c15628f8cab..deab3e2231d 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -616,10 +616,7 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { tc.malleate() // malleate mutates test data - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), path.EndpointB.ChannelConfig.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.PacketRoute(path.EndpointB.ChannelConfig.PortID) suite.Require().True(ok) packet := channeltypes.NewPacket( @@ -633,7 +630,7 @@ func (suite *InterchainAccountsTestSuite) TestOnTimeoutPacket() { 0, ) - err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), path.EndpointA.GetChannel().Version, packet, nil) + err = cbs[0].OnTimeoutPacket(suite.chainA.GetContext(), path.EndpointA.GetChannel().Version, packet, nil) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index d4cf8de7323..3458459e9f1 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -246,25 +246,22 @@ func (im IBCMiddleware) OnTimeoutPacket( relayer sdk.AccAddress, ) error { if !im.keeper.IsFeeEnabled(ctx, packet.SourcePort, packet.SourceChannel) { - return im.app.OnTimeoutPacket(ctx, channelVersion, packet, relayer) + return nil } - appVersion := unwrapAppVersion(channelVersion) - // if the fee keeper is locked then fee logic should be skipped // this may occur in the presence of a severe bug which leads to invalid state // the fee keeper will be unlocked after manual intervention // // Please see ADR 004 for more information. if im.keeper.IsLocked(ctx) { - return im.app.OnTimeoutPacket(ctx, appVersion, packet, relayer) + return nil } packetID := channeltypes.NewPacketID(packet.SourcePort, packet.SourceChannel, packet.Sequence) feesInEscrow, found := im.keeper.GetFeesInEscrow(ctx, packetID) if !found { - // call underlying callback - return im.app.OnTimeoutPacket(ctx, appVersion, packet, relayer) + return nil } payee, found := im.keeper.GetPayeeAddress(ctx, relayer.String(), packet.SourceChannel) @@ -280,7 +277,7 @@ func (im IBCMiddleware) OnTimeoutPacket( im.keeper.DistributePacketFeesOnTimeout(ctx, payeeAddr, feesInEscrow.PacketFees, packetID) // call underlying callback - return im.app.OnTimeoutPacket(ctx, appVersion, packet, relayer) + return nil } // OnChanUpgradeInit implements the IBCModule interface diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index 751b9fc982d..3a0115f9bbc 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -942,13 +942,10 @@ func (suite *FeeTestSuite) TestOnTimeoutPacket() { initialRelayerAccBal = sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), relayerAddr, sdk.DefaultBondDenom)) // retrieve module callbacks - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.MockFeePort) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.PacketRoute(ibctesting.MockFeePort) suite.Require().True(ok) - err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), suite.path.EndpointA.GetChannel().Version, packet, relayerAddr) + err = cbs[0].OnTimeoutPacket(suite.chainA.GetContext(), suite.path.EndpointA.GetChannel().Version, packet, relayerAddr) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 3962bae2d37..8e3eaad540a 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -152,11 +152,6 @@ func (im IBCMiddleware) OnAcknowledgementPacket( // If the contract callback runs out of gas and may be retried with a higher gas limit then the state changes are // reverted via a panic. func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress) error { - err := im.app.OnTimeoutPacket(ctx, channelVersion, packet, relayer) - if err != nil { - return err - } - // OnTimeoutPacket is not blocked if the packet does not opt-in to callbacks callbackData, err := types.GetSourceCallbackData(ctx, im.app, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetData(), im.maxCallbackGas) if err != nil { @@ -173,7 +168,6 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, channelVersion string, ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence(), types.CallbackTypeTimeoutPacket, callbackData, err, ) - return nil } @@ -348,7 +342,7 @@ func (IBCMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID string) } // OnChanCloseConfirm defers to the underlying application -func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { +func (IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { return nil } diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 0c67244aa91..01108f507d7 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -509,11 +509,11 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { tc.malleate() // callbacks module is routed as top level middleware - transferStack, ok := s.chainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) + cbs, ok := s.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.PacketRoute(transfertypes.ModuleName) s.Require().True(ok) onTimeoutPacket := func() error { - return transferStack.OnTimeoutPacket(ctx, s.path.EndpointA.GetChannel().Version, packet, s.chainA.SenderAccount.GetAddress()) + return cbs[0].OnTimeoutPacket(ctx, s.path.EndpointA.GetChannel().Version, packet, s.chainA.SenderAccount.GetAddress()) } switch expValue := tc.expValue.(type) { @@ -550,8 +550,22 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { s.Require().Equal(1, sourceCounters[types.CallbackTypeSendPacket]) s.Require().Equal(uint8(2), sourceStatefulCounter) + // TODO: in order to unmarshal the transfer stack, we need to extract the transferstack + // from the legacy ibc module as the legacy ibc module UnmarshalPacketData is not what we need. + // This can be removed after https://github.com/cosmos/ibc-go/issues/7083 + var unmarshaller porttypes.PacketDataUnmarshaler + if legacyModule, ok := cbs[0].(*porttypes.LegacyIBCModule); ok { + legacyModuleCbs := legacyModule.GetCallbacks() + // transfer stack is at index 0 + unmarshaller, ok = legacyModuleCbs[0].(porttypes.PacketDataUnmarshaler) + s.Require().True(ok) + } else { + unmarshaller, ok = cbs[0].(porttypes.PacketDataUnmarshaler) + s.Require().True(ok) + } + expEvent, exists := GetExpectedEvent( - ctx, transferStack.(porttypes.PacketDataUnmarshaler), gasLimit, packet.Data, packet.SourcePort, + ctx, unmarshaller, gasLimit, packet.Data, packet.SourcePort, packet.SourcePort, packet.SourceChannel, packet.Sequence, types.CallbackTypeTimeoutPacket, nil, ) s.Require().True(exists) diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 531bb801444..87adb3c365e 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -438,13 +438,10 @@ func (suite *TransferTestSuite) TestOnTimeoutPacket() { "already timed-out packet", sdk.NewCoins(ibctesting.TestCoin), func() { - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.PacketRoute(ibctesting.TransferPort) suite.Require().True(ok) - suite.Require().NoError(cbs.OnTimeoutPacket(suite.chainA.GetContext(), path.EndpointA.GetChannel().Version, packet, suite.chainA.SenderAccount.GetAddress())) + suite.Require().NoError(cbs[0].OnTimeoutPacket(suite.chainA.GetContext(), path.EndpointA.GetChannel().Version, packet, suite.chainA.SenderAccount.GetAddress())) }, errors.New("unable to unescrow tokens"), }, @@ -476,15 +473,12 @@ func (suite *TransferTestSuite) TestOnTimeoutPacket() { packet, err = ibctesting.ParsePacketFromEvents(res.Events) suite.Require().NoError(err) - module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) - suite.Require().NoError(err) - - cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.AppRouter.PacketRoute(ibctesting.TransferPort) suite.Require().True(ok) tc.malleate() // change fields in packet - err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), path.EndpointA.GetChannel().Version, packet, suite.chainA.SenderAccount.GetAddress()) + err = cbs[0].OnTimeoutPacket(suite.chainA.GetContext(), path.EndpointA.GetChannel().Version, packet, suite.chainA.SenderAccount.GetAddress()) expPass := tc.expError == nil if expPass { diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 8e54eac8f6e..3606140b1be 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -975,14 +975,11 @@ func (suite *ForwardingTestSuite) TestOnTimeoutPacketForwarding() { packet.TimeoutTimestamp) // retrieve module callbacks - module, _, err := suite.chainB.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainB.GetContext(), pathBtoC.EndpointA.ChannelConfig.PortID) - suite.Require().NoError(err) - - cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Route(module) + cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.AppRouter.PacketRoute(pathBtoC.EndpointA.ChannelConfig.PortID) suite.Require().True(ok) // Trigger OnTimeoutPacket for chainB - err = cbs.OnTimeoutPacket(suite.chainB.GetContext(), pathBtoC.EndpointA.GetChannel().Version, packet, nil) + err = cbs[0].OnTimeoutPacket(suite.chainB.GetContext(), pathBtoC.EndpointA.GetChannel().Version, packet, nil) suite.Require().NoError(err) // Ensure that chainB has an ack. diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index 429b504a453..183710e696d 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -1,6 +1,7 @@ package types import ( + "slices" "strings" errorsmod "cosmossdk.io/errors" @@ -269,12 +270,25 @@ func (im *LegacyIBCModule) OnAcknowledgementPacket( } // OnTimeoutPacket implements the IBCModule interface -func (LegacyIBCModule) OnTimeoutPacket( +func (im *LegacyIBCModule) OnTimeoutPacket( ctx sdk.Context, channelVersion string, packet channeltypes.Packet, relayer sdk.AccAddress, ) error { + cbs := slices.Clone(im.cbs) + slices.Reverse(cbs) + for _, cb := range cbs { + cbVersion := channelVersion + + if wrapper, ok := cb.(VersionWrapper); ok { + cbVersion, channelVersion = wrapper.UnwrapVersionSafe(ctx, packet.SourcePort, packet.SourceChannel, cbVersion) + } + + if err := cb.OnTimeoutPacket(ctx, cbVersion, packet, relayer); err != nil { + return errorsmod.Wrapf(err, "on timeout packet callback failed for packet with source Port ID: %s, source channel ID: %s", packet.SourcePort, packet.SourceChannel) + } + } return nil } @@ -435,7 +449,7 @@ func (im *LegacyIBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID // UnmarshalPacketData attempts to unmarshal the provided packet data bytes // into a FungibleTokenPacketData. This function implements the optional // PacketDataUnmarshaler interface required for ADR 008 support. -func (LegacyIBCModule) UnmarshalPacketData(ctx sdk.Context, portID, channelID string, bz []byte) (interface{}, error) { +func (*LegacyIBCModule) UnmarshalPacketData(ctx sdk.Context, portID, channelID string, bz []byte) (interface{}, error) { return nil, nil } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 99c05f45bae..a4c32b10f70 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -502,7 +502,7 @@ func (k *Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (* } // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(msg.Packet.SourcePort) + cbs, ok := k.PortKeeper.AppRouter.PacketRoute(msg.Packet.SourcePort) if !ok { ctx.Logger().Error("timeout failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort) @@ -532,11 +532,13 @@ func (k *Keeper) Timeout(goCtx context.Context, msg *channeltypes.MsgTimeout) (* return nil, err } - // Perform application logic callback - err = cbs.OnTimeoutPacket(ctx, channelVersion, msg.Packet, relayer) - if err != nil { - ctx.Logger().Error("timeout failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "timeout packet callback failed")) - return nil, errorsmod.Wrap(err, "timeout packet callback failed") + for _, cb := range cbs { + // Perform application logic callback + err = cb.OnTimeoutPacket(ctx, channelVersion, msg.Packet, relayer) + if err != nil { + ctx.Logger().Error("timeout failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "timeout packet callback failed")) + return nil, errorsmod.Wrap(err, "timeout packet callback failed") + } } defer telemetry.ReportTimeoutPacket(msg.Packet, "height") From f5ab15b11fbb9fb013fc8d5382229f3f10a5a7eb Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 13 Aug 2024 14:30:22 +0100 Subject: [PATCH 45/46] Add convenience func to reverse callbacks and refactor other methods (#7142) * chore: updated handlers to use reverseCallbacks function * chore: add reconstructVersion to im * chore: remove duplicate import * chore: pr feedback --- .../core/05-port/types/ibc_legacy_module.go | 100 ++++++++++-------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/modules/core/05-port/types/ibc_legacy_module.go b/modules/core/05-port/types/ibc_legacy_module.go index 183710e696d..3653f550f6c 100644 --- a/modules/core/05-port/types/ibc_legacy_module.go +++ b/modules/core/05-port/types/ibc_legacy_module.go @@ -46,8 +46,7 @@ func (im *LegacyIBCModule) OnChanOpenInit( version string, ) (string, error) { negotiatedVersions := make([]string, len(im.cbs)) - - for i := len(im.cbs) - 1; i >= 0; i-- { + for i, cb := range im.reversedCallbacks() { cbVersion := version // To maintain backwards compatibility, we must handle two cases: @@ -59,7 +58,7 @@ func (im *LegacyIBCModule) OnChanOpenInit( // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. // If it is unsuccessful, no callback will occur to this application as the version // indicates it should be disabled. - if wrapper, ok := im.cbs[i].(VersionWrapper); ok && strings.TrimSpace(version) != "" { + if wrapper, ok := cb.(VersionWrapper); ok && strings.TrimSpace(version) != "" { appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(version) if err != nil { // middleware disabled @@ -69,14 +68,14 @@ func (im *LegacyIBCModule) OnChanOpenInit( cbVersion, version = appVersion, underlyingAppVersion } - negotiatedVersion, err := im.cbs[i].OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, cbVersion) + negotiatedVersion, err := cb.OnChanOpenInit(ctx, order, connectionHops, portID, channelID, counterparty, cbVersion) if err != nil { return "", errorsmod.Wrapf(err, "channel open init callback failed for port ID: %s, channel ID: %s", portID, channelID) } negotiatedVersions[i] = negotiatedVersion } - return reconstructVersion(im.cbs, negotiatedVersions) + return im.reconstructVersion(negotiatedVersions) } // OnChanOpenTry implements the IBCModule interface. @@ -94,8 +93,7 @@ func (im *LegacyIBCModule) OnChanOpenTry( counterpartyVersion string, ) (string, error) { negotiatedVersions := make([]string, len(im.cbs)) - - for i := len(im.cbs) - 1; i >= 0; i-- { + for i, cb := range im.reversedCallbacks() { cbVersion := counterpartyVersion // To maintain backwards compatibility, we must handle two cases: @@ -107,7 +105,7 @@ func (im *LegacyIBCModule) OnChanOpenTry( // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. // If it is unsuccessful, no callback will occur to this application as the version // indicates it should be disabled. - if wrapper, ok := im.cbs[i].(VersionWrapper); ok && strings.TrimSpace(counterpartyVersion) != "" { + if wrapper, ok := cb.(VersionWrapper); ok && strings.TrimSpace(counterpartyVersion) != "" { appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(counterpartyVersion) if err != nil { // middleware disabled @@ -117,14 +115,14 @@ func (im *LegacyIBCModule) OnChanOpenTry( cbVersion, counterpartyVersion = appVersion, underlyingAppVersion } - negotiatedVersion, err := im.cbs[i].OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, cbVersion) + negotiatedVersion, err := cb.OnChanOpenTry(ctx, order, connectionHops, portID, channelID, counterparty, cbVersion) if err != nil { return "", errorsmod.Wrapf(err, "channel open try callback failed for port ID: %s, channel ID: %s", portID, channelID) } negotiatedVersions[i] = negotiatedVersion } - return reconstructVersion(im.cbs, negotiatedVersions) + return im.reconstructVersion(negotiatedVersions) } // OnChanOpenAck implements the IBCModule interface. @@ -138,14 +136,14 @@ func (im *LegacyIBCModule) OnChanOpenAck( counterpartyChannelID string, counterpartyVersion string, ) error { - for i := len(im.cbs) - 1; i >= 0; i-- { + for _, cb := range im.reversedCallbacks() { cbVersion := counterpartyVersion // To maintain backwards compatibility, we must handle counterparty version negotiation. // This means the version may have changed, and applications must be allowed to be disabled. // Applications should be disabled when receiving an empty counterparty version. Callbacks // for all applications must occur to allow disabling. - if wrapper, ok := im.cbs[i].(VersionWrapper); ok { + if wrapper, ok := cb.(VersionWrapper); ok { appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(counterpartyVersion) if err != nil { cbVersion = "" // disable application @@ -154,7 +152,7 @@ func (im *LegacyIBCModule) OnChanOpenAck( } } - err := im.cbs[i].OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cbVersion) + err := cb.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, cbVersion) if err != nil { return errorsmod.Wrapf(err, "channel open ack callback failed for port ID: %s, channel ID: %s", portID, channelID) } @@ -169,8 +167,8 @@ func (im *LegacyIBCModule) OnChanOpenConfirm( portID, channelID string, ) error { - for i := len(im.cbs) - 1; i >= 0; i-- { - err := im.cbs[i].OnChanOpenConfirm(ctx, portID, channelID) + for _, cb := range im.reversedCallbacks() { + err := cb.OnChanOpenConfirm(ctx, portID, channelID) if err != nil { return errorsmod.Wrapf(err, "channel open confirm callback failed for port ID: %s, channel ID: %s", portID, channelID) } @@ -184,8 +182,8 @@ func (im *LegacyIBCModule) OnChanCloseInit( portID, channelID string, ) error { - for i := len(im.cbs) - 1; i >= 0; i-- { - if err := im.cbs[i].OnChanCloseInit(ctx, portID, channelID); err != nil { + for _, cb := range im.reversedCallbacks() { + if err := cb.OnChanCloseInit(ctx, portID, channelID); err != nil { return errorsmod.Wrapf(err, "channel close init callback failed for port ID: %s, channel ID: %s", portID, channelID) } } @@ -198,8 +196,8 @@ func (im *LegacyIBCModule) OnChanCloseConfirm( portID, channelID string, ) error { - for i := len(im.cbs) - 1; i >= 0; i-- { - if err := im.cbs[i].OnChanCloseConfirm(ctx, portID, channelID); err != nil { + for _, cb := range im.reversedCallbacks() { + if err := cb.OnChanCloseConfirm(ctx, portID, channelID); err != nil { return errorsmod.Wrapf(err, "channel close confirm callback failed for port ID: %s, channel ID: %s", portID, channelID) } } @@ -230,7 +228,7 @@ func (im *LegacyIBCModule) OnSendPacket( // is returned if the packet data is successfully decoded and the receive application // logic returns without error. // A nil acknowledgement may be returned when using the packet forwarding feature. This signals to core IBC that the acknowledgement will be written asynchronously. -func (LegacyIBCModule) OnRecvPacket( +func (*LegacyIBCModule) OnRecvPacket( ctx sdk.Context, channelVersion string, packet channeltypes.Packet, @@ -247,21 +245,21 @@ func (im *LegacyIBCModule) OnAcknowledgementPacket( acknowledgement []byte, relayer sdk.AccAddress, ) error { - for i := len(im.cbs) - 1; i >= 0; i-- { + for _, cb := range im.reversedCallbacks() { var ( cbVersion = channelVersion cbAck = acknowledgement ) - if wrapper, ok := im.cbs[i].(VersionWrapper); ok { + if wrapper, ok := cb.(VersionWrapper); ok { cbVersion, channelVersion = wrapper.UnwrapVersionSafe(ctx, packet.SourcePort, packet.SourceChannel, cbVersion) } - if wrapper, ok := im.cbs[i].(AcknowledgementWrapper); ok { + if wrapper, ok := cb.(AcknowledgementWrapper); ok { cbAck, acknowledgement = wrapper.UnwrapAcknowledgement(ctx, packet.SourcePort, packet.SourceChannel, cbAck) } - err := im.cbs[i].OnAcknowledgementPacket(ctx, cbVersion, packet, cbAck, relayer) + err := cb.OnAcknowledgementPacket(ctx, cbVersion, packet, cbAck, relayer) if err != nil { return errorsmod.Wrap(err, "acknowledge packet callback failed") } @@ -276,9 +274,7 @@ func (im *LegacyIBCModule) OnTimeoutPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) error { - cbs := slices.Clone(im.cbs) - slices.Reverse(cbs) - for _, cb := range cbs { + for _, cb := range im.reversedCallbacks() { cbVersion := channelVersion if wrapper, ok := cb.(VersionWrapper); ok { @@ -295,8 +291,7 @@ func (im *LegacyIBCModule) OnTimeoutPacket( // OnChanUpgradeInit implements the IBCModule interface func (im *LegacyIBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) (string, error) { negotiatedVersions := make([]string, len(im.cbs)) - - for i := len(im.cbs) - 1; i >= 0; i-- { + for i, cb := range im.reversedCallbacks() { cbVersion := proposedVersion // To maintain backwards compatibility, we must handle two cases: @@ -308,7 +303,7 @@ func (im *LegacyIBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. // If it is unsuccessful, no callback will occur to this application as the version // indicates it should be disabled. - if wrapper, ok := im.cbs[i].(VersionWrapper); ok && strings.TrimSpace(proposedVersion) != "" { + if wrapper, ok := cb.(VersionWrapper); ok && strings.TrimSpace(proposedVersion) != "" { appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(proposedVersion) if err != nil { // middleware disabled @@ -319,7 +314,7 @@ func (im *LegacyIBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID } // in order to maintain backwards compatibility, every callback in the stack must implement the UpgradableModule interface. - upgradableModule, ok := im.cbs[i].(UpgradableModule) + upgradableModule, ok := cb.(UpgradableModule) if !ok { return "", errorsmod.Wrap(ErrInvalidRoute, "upgrade route not found to module in application callstack") } @@ -331,14 +326,14 @@ func (im *LegacyIBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID negotiatedVersions[i] = negotiatedVersion } - return reconstructVersion(im.cbs, negotiatedVersions) + return im.reconstructVersion(negotiatedVersions) } // OnChanUpgradeTry implements the IBCModule interface func (im *LegacyIBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) { negotiatedVersions := make([]string, len(im.cbs)) - for i := len(im.cbs) - 1; i >= 0; i-- { + for i, cb := range im.reversedCallbacks() { cbVersion := counterpartyVersion // To maintain backwards compatibility, we must handle two cases: @@ -350,7 +345,7 @@ func (im *LegacyIBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID s // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. // If it is unsuccessful, no callback will occur to this application as the version // indicates it should be disabled. - if wrapper, ok := im.cbs[i].(VersionWrapper); ok && strings.TrimSpace(counterpartyVersion) != "" { + if wrapper, ok := cb.(VersionWrapper); ok && strings.TrimSpace(counterpartyVersion) != "" { appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(counterpartyVersion) if err != nil { // middleware disabled @@ -361,7 +356,7 @@ func (im *LegacyIBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID s } // in order to maintain backwards compatibility, every callback in the stack must implement the UpgradableModule interface. - upgradableModule, ok := im.cbs[i].(UpgradableModule) + upgradableModule, ok := cb.(UpgradableModule) if !ok { return "", errorsmod.Wrap(ErrInvalidRoute, "upgrade route not found to module in application callstack") } @@ -373,12 +368,12 @@ func (im *LegacyIBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID s negotiatedVersions[i] = negotiatedVersion } - return reconstructVersion(im.cbs, negotiatedVersions) + return im.reconstructVersion(negotiatedVersions) } // OnChanUpgradeAck implements the IBCModule interface func (im *LegacyIBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { - for i := len(im.cbs) - 1; i >= 0; i-- { + for _, cb := range im.reversedCallbacks() { cbVersion := counterpartyVersion // To maintain backwards compatibility, we must handle two cases: @@ -390,7 +385,7 @@ func (im *LegacyIBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. // If it is unsuccessful, no callback will occur to this application as the version // indicates it should be disabled. - if wrapper, ok := im.cbs[i].(VersionWrapper); ok && strings.TrimSpace(counterpartyVersion) != "" { + if wrapper, ok := cb.(VersionWrapper); ok && strings.TrimSpace(counterpartyVersion) != "" { appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(counterpartyVersion) if err != nil { // middleware disabled @@ -400,7 +395,7 @@ func (im *LegacyIBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, } // in order to maintain backwards compatibility, every callback in the stack must implement the UpgradableModule interface. - upgradableModule, ok := im.cbs[i].(UpgradableModule) + upgradableModule, ok := cb.(UpgradableModule) if !ok { return errorsmod.Wrap(ErrInvalidRoute, "upgrade route not found to module in application callstack") } @@ -415,7 +410,7 @@ func (im *LegacyIBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, // OnChanUpgradeOpen implements the IBCModule interface func (im *LegacyIBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) { - for i := len(im.cbs) - 1; i >= 0; i-- { + for _, cb := range im.reversedCallbacks() { cbVersion := proposedVersion // To maintain backwards compatibility, we must handle two cases: @@ -427,7 +422,7 @@ func (im *LegacyIBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID // attempt to unmarshal the version using the UnwrapVersionUnsafe interface function. // If it is unsuccessful, no callback will occur to this application as the version // indicates it should be disabled. - if wrapper, ok := im.cbs[i].(VersionWrapper); ok { + if wrapper, ok := cb.(VersionWrapper); ok { appVersion, underlyingAppVersion, err := wrapper.UnwrapVersionUnsafe(proposedVersion) if err != nil { cbVersion = "" // disable application @@ -437,7 +432,7 @@ func (im *LegacyIBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID } // in order to maintain backwards compatibility, every callback in the stack must implement the UpgradableModule interface. - upgradableModule, ok := im.cbs[i].(UpgradableModule) + upgradableModule, ok := cb.(UpgradableModule) if !ok { panic(errorsmod.Wrap(ErrInvalidRoute, "upgrade route not found to module in application callstack")) } @@ -453,13 +448,28 @@ func (*LegacyIBCModule) UnmarshalPacketData(ctx sdk.Context, portID, channelID s return nil, nil } +// reversedCallbacks returns a copy of the callbacks in reverse order. +// the majority of handlers are called in reverse order, so this can be used +// in those cases to prevent needing to iterate backwards over the callbacks. +func (im *LegacyIBCModule) reversedCallbacks() []ClassicIBCModule { + cbs := slices.Clone(im.cbs) + slices.Reverse(cbs) + return cbs +} + // reconstructVersion will generate the channel version by applying any version wrapping as necessary. // Version wrapping will only occur if the negotiated version is non=empty and the application is a VersionWrapper. -func reconstructVersion(cbs []ClassicIBCModule, negotiatedVersions []string) (string, error) { +func (im *LegacyIBCModule) reconstructVersion(negotiatedVersions []string) (string, error) { + // the negotiated versions are expected to be in reverse order, as callbacks are executed in reverse order. + // in order to ensure that the indices match im.cbs, they must be reversed. + // the slice is cloned to prevent modifying the input argument. + negotiatedVersions = slices.Clone(negotiatedVersions) + slices.Reverse(negotiatedVersions) + version := negotiatedVersions[0] // base version - for i := 1; i < len(cbs); i++ { // iterate over the remaining callbacks + for i := 1; i < len(im.cbs); i++ { if strings.TrimSpace(negotiatedVersions[i]) != "" { - wrapper, ok := cbs[i].(VersionWrapper) + wrapper, ok := im.cbs[i].(VersionWrapper) if !ok { return "", ibcerrors.ErrInvalidVersion } From 6327b580a29da4c7f585a21313fed21ea0c56614 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 14 Aug 2024 09:50:12 +0100 Subject: [PATCH 46/46] chore: use app router in OnTimeoutPacket handler (#7164) --- modules/core/keeper/msg_server.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index a4c32b10f70..1070be1b338 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -559,7 +559,7 @@ func (k *Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTime } // Retrieve callbacks from router - cbs, ok := k.PortKeeper.Route(msg.Packet.SourcePort) + cbs, ok := k.PortKeeper.AppRouter.PacketRoute(msg.Packet.SourcePort) if !ok { ctx.Logger().Error("timeout on close failed", "port-id", msg.Packet.SourcePort, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort)) return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", msg.Packet.SourcePort) @@ -593,10 +593,12 @@ func (k *Keeper) TimeoutOnClose(goCtx context.Context, msg *channeltypes.MsgTime // // NOTE: MsgTimeout and MsgTimeoutOnClose use the same "OnTimeoutPacket" // application logic callback. - err = cbs.OnTimeoutPacket(ctx, channelVersion, msg.Packet, relayer) - if err != nil { - ctx.Logger().Error("timeout on close failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "timeout on close callback failed")) - return nil, errorsmod.Wrap(err, "timeout on close callback failed") + for _, cb := range cbs { + err = cb.OnTimeoutPacket(ctx, channelVersion, msg.Packet, relayer) + if err != nil { + ctx.Logger().Error("timeout on close failed", "port-id", msg.Packet.SourcePort, "channel-id", msg.Packet.SourceChannel, "error", errorsmod.Wrap(err, "timeout on close callback failed")) + return nil, errorsmod.Wrap(err, "timeout on close callback failed") + } } defer telemetry.ReportTimeoutPacket(msg.Packet, "channel-closed")