From c07bca9c2381a218b61ec3872e5616b350875db7 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Mon, 8 Apr 2024 13:00:20 +0100 Subject: [PATCH 001/141] Adding proto files for ics20-v2 (#6110) * chore: adding proto files for ics20-v2 * chore: add newline --- modules/apps/transfer/types/v3/packet.pb.go | 760 ++++++++++++++++++ .../ibc/applications/transfer/v3/packet.proto | 29 + 2 files changed, 789 insertions(+) create mode 100644 modules/apps/transfer/types/v3/packet.pb.go create mode 100644 proto/ibc/applications/transfer/v3/packet.proto diff --git a/modules/apps/transfer/types/v3/packet.pb.go b/modules/apps/transfer/types/v3/packet.pb.go new file mode 100644 index 00000000000..a97568e7521 --- /dev/null +++ b/modules/apps/transfer/types/v3/packet.pb.go @@ -0,0 +1,760 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ibc/applications/transfer/v3/packet.proto + +package v3 + +import ( + fmt "fmt" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// FungibleTokenPacketData defines a struct for the packet payload +// See FungibleTokenPacketData spec: +// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures +type FungibleTokenPacketData struct { + // the tokens to be transferred + Tokens []*Token `protobuf:"bytes,1,rep,name=tokens,proto3" json:"tokens,omitempty"` + // the sender address + Sender string `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` + // the recipient address on the destination chain + Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` + // optional memo + Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` +} + +func (m *FungibleTokenPacketData) Reset() { *m = FungibleTokenPacketData{} } +func (m *FungibleTokenPacketData) String() string { return proto.CompactTextString(m) } +func (*FungibleTokenPacketData) ProtoMessage() {} +func (*FungibleTokenPacketData) Descriptor() ([]byte, []int) { + return fileDescriptor_760742a8894acdbe, []int{0} +} +func (m *FungibleTokenPacketData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FungibleTokenPacketData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FungibleTokenPacketData.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 *FungibleTokenPacketData) XXX_Merge(src proto.Message) { + xxx_messageInfo_FungibleTokenPacketData.Merge(m, src) +} +func (m *FungibleTokenPacketData) XXX_Size() int { + return m.Size() +} +func (m *FungibleTokenPacketData) XXX_DiscardUnknown() { + xxx_messageInfo_FungibleTokenPacketData.DiscardUnknown(m) +} + +var xxx_messageInfo_FungibleTokenPacketData proto.InternalMessageInfo + +func (m *FungibleTokenPacketData) GetTokens() []*Token { + if m != nil { + return m.Tokens + } + return nil +} + +func (m *FungibleTokenPacketData) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *FungibleTokenPacketData) GetReceiver() string { + if m != nil { + return m.Receiver + } + return "" +} + +func (m *FungibleTokenPacketData) GetMemo() string { + if m != nil { + return m.Memo + } + return "" +} + +// Token defines a struct which represents a token to be transferred. +type Token struct { + // the base token denomination to be transferred + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + // the token amount to be transferred + Amount uint64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` + // the trace of the token + Trace []string `protobuf:"bytes,3,rep,name=trace,proto3" json:"trace,omitempty"` +} + +func (m *Token) Reset() { *m = Token{} } +func (m *Token) String() string { return proto.CompactTextString(m) } +func (*Token) ProtoMessage() {} +func (*Token) Descriptor() ([]byte, []int) { + return fileDescriptor_760742a8894acdbe, []int{1} +} +func (m *Token) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Token) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Token.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 *Token) XXX_Merge(src proto.Message) { + xxx_messageInfo_Token.Merge(m, src) +} +func (m *Token) XXX_Size() int { + return m.Size() +} +func (m *Token) XXX_DiscardUnknown() { + xxx_messageInfo_Token.DiscardUnknown(m) +} + +var xxx_messageInfo_Token proto.InternalMessageInfo + +func (m *Token) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *Token) GetAmount() uint64 { + if m != nil { + return m.Amount + } + return 0 +} + +func (m *Token) GetTrace() []string { + if m != nil { + return m.Trace + } + return nil +} + +func init() { + proto.RegisterType((*FungibleTokenPacketData)(nil), "ibc.applications.transfer.v3.FungibleTokenPacketData") + proto.RegisterType((*Token)(nil), "ibc.applications.transfer.v3.Token") +} + +func init() { + proto.RegisterFile("ibc/applications/transfer/v3/packet.proto", fileDescriptor_760742a8894acdbe) +} + +var fileDescriptor_760742a8894acdbe = []byte{ + // 302 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xc1, 0x4a, 0x33, 0x31, + 0x14, 0x85, 0x9b, 0x7f, 0xda, 0xf2, 0x1b, 0x77, 0x41, 0x74, 0x10, 0x19, 0x4a, 0xdd, 0xd4, 0x85, + 0x09, 0x38, 0x1b, 0xd1, 0x9d, 0x88, 0x1b, 0x37, 0x52, 0xba, 0x72, 0x97, 0xa4, 0xd7, 0x1a, 0xda, + 0xe4, 0x0e, 0x49, 0x66, 0xc0, 0xb7, 0xf0, 0x09, 0x7c, 0x1e, 0x97, 0x5d, 0xba, 0x94, 0xf6, 0x45, + 0x64, 0xe2, 0x28, 0x5d, 0xb9, 0xbb, 0xdf, 0xbd, 0xe7, 0xdc, 0x03, 0x87, 0x9e, 0x19, 0xa5, 0x85, + 0xac, 0xaa, 0x95, 0xd1, 0x32, 0x1a, 0x74, 0x41, 0x44, 0x2f, 0x5d, 0x78, 0x02, 0x2f, 0x9a, 0x52, + 0x54, 0x52, 0x2f, 0x21, 0xf2, 0xca, 0x63, 0x44, 0x76, 0x62, 0x94, 0xe6, 0xbb, 0x52, 0xfe, 0x23, + 0xe5, 0x4d, 0x39, 0x7e, 0x23, 0xf4, 0xe8, 0xae, 0x76, 0x0b, 0xa3, 0x56, 0x30, 0xc3, 0x25, 0xb8, + 0x87, 0xe4, 0xbd, 0x95, 0x51, 0xb2, 0x6b, 0x3a, 0x8c, 0xed, 0x2a, 0xe4, 0x64, 0x94, 0x4d, 0xf6, + 0x2f, 0x4e, 0xf9, 0x5f, 0xaf, 0x78, 0xb2, 0x4f, 0x3b, 0x0b, 0x3b, 0xa4, 0xc3, 0x00, 0x6e, 0x0e, + 0x3e, 0xff, 0x37, 0x22, 0x93, 0xbd, 0x69, 0x47, 0xec, 0x98, 0xfe, 0xf7, 0xa0, 0xc1, 0x34, 0xe0, + 0xf3, 0x2c, 0x5d, 0x7e, 0x99, 0x31, 0xda, 0xb7, 0x60, 0x31, 0xef, 0xa7, 0x7d, 0x9a, 0xc7, 0xf7, + 0x74, 0x90, 0x1e, 0xb3, 0x03, 0x3a, 0x98, 0x83, 0x43, 0x9b, 0x93, 0x74, 0xfd, 0x86, 0x36, 0x46, + 0x5a, 0xac, 0x5d, 0x4c, 0x31, 0xfd, 0x69, 0x47, 0xad, 0x3a, 0x7a, 0xa9, 0x21, 0xcf, 0x46, 0x59, + 0xab, 0x4e, 0x70, 0x33, 0x7b, 0xdf, 0x14, 0x64, 0xbd, 0x29, 0xc8, 0xe7, 0xa6, 0x20, 0xaf, 0xdb, + 0xa2, 0xb7, 0xde, 0x16, 0xbd, 0x8f, 0x6d, 0xd1, 0x7b, 0xbc, 0x5a, 0x98, 0xf8, 0x5c, 0x2b, 0xae, + 0xd1, 0x0a, 0x8d, 0xc1, 0x62, 0x10, 0x46, 0xe9, 0xf3, 0x05, 0x8a, 0xe6, 0x52, 0x58, 0x9c, 0xd7, + 0x2b, 0x08, 0x6d, 0xe1, 0x3b, 0x45, 0xc7, 0x97, 0x0a, 0x82, 0x68, 0x4a, 0x35, 0x4c, 0x45, 0x97, + 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xaf, 0xbe, 0xa6, 0xe8, 0x95, 0x01, 0x00, 0x00, +} + +func (m *FungibleTokenPacketData) 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 *FungibleTokenPacketData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FungibleTokenPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Memo) > 0 { + i -= len(m.Memo) + copy(dAtA[i:], m.Memo) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Memo))) + i-- + dAtA[i] = 0x22 + } + if len(m.Receiver) > 0 { + i -= len(m.Receiver) + copy(dAtA[i:], m.Receiver) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Receiver))) + i-- + dAtA[i] = 0x1a + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0x12 + } + if len(m.Tokens) > 0 { + for iNdEx := len(m.Tokens) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Tokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPacket(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *Token) 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 *Token) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Token) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Trace) > 0 { + for iNdEx := len(m.Trace) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Trace[iNdEx]) + copy(dAtA[i:], m.Trace[iNdEx]) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Trace[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if m.Amount != 0 { + i = encodeVarintPacket(dAtA, i, uint64(m.Amount)) + i-- + dAtA[i] = 0x10 + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintPacket(dAtA []byte, offset int, v uint64) int { + offset -= sovPacket(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *FungibleTokenPacketData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Tokens) > 0 { + for _, e := range m.Tokens { + l = e.Size() + n += 1 + l + sovPacket(uint64(l)) + } + } + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + l = len(m.Receiver) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + l = len(m.Memo) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + return n +} + +func (m *Token) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + if m.Amount != 0 { + n += 1 + sovPacket(uint64(m.Amount)) + } + if len(m.Trace) > 0 { + for _, s := range m.Trace { + l = len(s) + n += 1 + l + sovPacket(uint64(l)) + } + } + return n +} + +func sovPacket(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozPacket(x uint64) (n int) { + return sovPacket(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *FungibleTokenPacketData) 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 ErrIntOverflowPacket + } + 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: FungibleTokenPacketData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FungibleTokenPacketData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tokens", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPacket + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tokens = append(m.Tokens, &Token{}) + if err := m.Tokens[len(m.Tokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Memo", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Memo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPacket(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPacket + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Token) 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 ErrIntOverflowPacket + } + 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: Token: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Token: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + m.Amount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Amount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Trace = append(m.Trace, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPacket(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPacket + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipPacket(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPacket + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPacket + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPacket + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthPacket + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupPacket + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthPacket + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthPacket = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowPacket = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupPacket = fmt.Errorf("proto: unexpected end of group") +) diff --git a/proto/ibc/applications/transfer/v3/packet.proto b/proto/ibc/applications/transfer/v3/packet.proto new file mode 100644 index 00000000000..32fc8938cd5 --- /dev/null +++ b/proto/ibc/applications/transfer/v3/packet.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; + +package ibc.applications.transfer.v3; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3"; + +// FungibleTokenPacketData defines a struct for the packet payload +// See FungibleTokenPacketData spec: +// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures +message FungibleTokenPacketData { + // the tokens to be transferred + repeated Token tokens = 1; + // the sender address + string sender = 2; + // the recipient address on the destination chain + string receiver = 3; + // optional memo + string memo = 4; +} + +// Token defines a struct which represents a token to be transferred. +message Token { + // the base token denomination to be transferred + string denom = 1; + // the token amount to be transferred + uint64 amount = 2; + // the trace of the token + repeated string trace = 3; +} From e66bd89038695b555e59cd6ea78d4b7d8f11bc39 Mon Sep 17 00:00:00 2001 From: Charly Date: Tue, 9 Apr 2024 10:38:50 +0200 Subject: [PATCH 002/141] update amount -> string (#6120) --- modules/apps/transfer/types/v3/packet.pb.go | 70 ++++++++++++------- .../ibc/applications/transfer/v3/packet.proto | 2 +- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/modules/apps/transfer/types/v3/packet.pb.go b/modules/apps/transfer/types/v3/packet.pb.go index a97568e7521..145b51c5eb9 100644 --- a/modules/apps/transfer/types/v3/packet.pb.go +++ b/modules/apps/transfer/types/v3/packet.pb.go @@ -102,7 +102,7 @@ type Token struct { // the base token denomination to be transferred Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` // the token amount to be transferred - Amount uint64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` + Amount string `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"` // the trace of the token Trace []string `protobuf:"bytes,3,rep,name=trace,proto3" json:"trace,omitempty"` } @@ -147,11 +147,11 @@ func (m *Token) GetDenom() string { return "" } -func (m *Token) GetAmount() uint64 { +func (m *Token) GetAmount() string { if m != nil { return m.Amount } - return 0 + return "" } func (m *Token) GetTrace() []string { @@ -171,26 +171,26 @@ func init() { } var fileDescriptor_760742a8894acdbe = []byte{ - // 302 bytes of a gzipped FileDescriptorProto + // 301 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xc1, 0x4a, 0x33, 0x31, 0x14, 0x85, 0x9b, 0x7f, 0xda, 0xf2, 0x1b, 0x77, 0x41, 0x74, 0x10, 0x19, 0x4a, 0xdd, 0xd4, 0x85, 0x09, 0x38, 0x1b, 0xd1, 0x9d, 0x88, 0x1b, 0x37, 0x52, 0xba, 0x72, 0x97, 0xa4, 0xd7, 0x1a, 0xda, 0xe4, 0x0e, 0x49, 0x66, 0xc0, 0xb7, 0xf0, 0x09, 0x7c, 0x1e, 0x97, 0x5d, 0xba, 0x94, 0xf6, 0x45, - 0x64, 0xe2, 0x28, 0x5d, 0xb9, 0xbb, 0xdf, 0xbd, 0xe7, 0xdc, 0x03, 0x87, 0x9e, 0x19, 0xa5, 0x85, - 0xac, 0xaa, 0x95, 0xd1, 0x32, 0x1a, 0x74, 0x41, 0x44, 0x2f, 0x5d, 0x78, 0x02, 0x2f, 0x9a, 0x52, - 0x54, 0x52, 0x2f, 0x21, 0xf2, 0xca, 0x63, 0x44, 0x76, 0x62, 0x94, 0xe6, 0xbb, 0x52, 0xfe, 0x23, - 0xe5, 0x4d, 0x39, 0x7e, 0x23, 0xf4, 0xe8, 0xae, 0x76, 0x0b, 0xa3, 0x56, 0x30, 0xc3, 0x25, 0xb8, - 0x87, 0xe4, 0xbd, 0x95, 0x51, 0xb2, 0x6b, 0x3a, 0x8c, 0xed, 0x2a, 0xe4, 0x64, 0x94, 0x4d, 0xf6, - 0x2f, 0x4e, 0xf9, 0x5f, 0xaf, 0x78, 0xb2, 0x4f, 0x3b, 0x0b, 0x3b, 0xa4, 0xc3, 0x00, 0x6e, 0x0e, - 0x3e, 0xff, 0x37, 0x22, 0x93, 0xbd, 0x69, 0x47, 0xec, 0x98, 0xfe, 0xf7, 0xa0, 0xc1, 0x34, 0xe0, - 0xf3, 0x2c, 0x5d, 0x7e, 0x99, 0x31, 0xda, 0xb7, 0x60, 0x31, 0xef, 0xa7, 0x7d, 0x9a, 0xc7, 0xf7, - 0x74, 0x90, 0x1e, 0xb3, 0x03, 0x3a, 0x98, 0x83, 0x43, 0x9b, 0x93, 0x74, 0xfd, 0x86, 0x36, 0x46, - 0x5a, 0xac, 0x5d, 0x4c, 0x31, 0xfd, 0x69, 0x47, 0xad, 0x3a, 0x7a, 0xa9, 0x21, 0xcf, 0x46, 0x59, - 0xab, 0x4e, 0x70, 0x33, 0x7b, 0xdf, 0x14, 0x64, 0xbd, 0x29, 0xc8, 0xe7, 0xa6, 0x20, 0xaf, 0xdb, - 0xa2, 0xb7, 0xde, 0x16, 0xbd, 0x8f, 0x6d, 0xd1, 0x7b, 0xbc, 0x5a, 0x98, 0xf8, 0x5c, 0x2b, 0xae, - 0xd1, 0x0a, 0x8d, 0xc1, 0x62, 0x10, 0x46, 0xe9, 0xf3, 0x05, 0x8a, 0xe6, 0x52, 0x58, 0x9c, 0xd7, - 0x2b, 0x08, 0x6d, 0xe1, 0x3b, 0x45, 0xc7, 0x97, 0x0a, 0x82, 0x68, 0x4a, 0x35, 0x4c, 0x45, 0x97, - 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xaf, 0xbe, 0xa6, 0xe8, 0x95, 0x01, 0x00, 0x00, + 0x64, 0xd2, 0x56, 0xba, 0x72, 0x77, 0xbf, 0x7b, 0xcf, 0xb9, 0x07, 0x0e, 0xbd, 0x30, 0x4a, 0x0b, + 0x59, 0x55, 0x0b, 0xa3, 0x65, 0x34, 0xe8, 0x82, 0x88, 0x5e, 0xba, 0xf0, 0x02, 0x5e, 0x34, 0xa5, + 0xa8, 0xa4, 0x9e, 0x43, 0xe4, 0x95, 0xc7, 0x88, 0xec, 0xcc, 0x28, 0xcd, 0xf7, 0xa5, 0x7c, 0x27, + 0xe5, 0x4d, 0x39, 0xfc, 0x20, 0xf4, 0xe4, 0xa1, 0x76, 0x33, 0xa3, 0x16, 0x30, 0xc1, 0x39, 0xb8, + 0xa7, 0xe4, 0xbd, 0x97, 0x51, 0xb2, 0x5b, 0xda, 0x8f, 0xed, 0x2a, 0xe4, 0x64, 0x90, 0x8d, 0x0e, + 0xaf, 0xce, 0xf9, 0x5f, 0xaf, 0x78, 0xb2, 0x8f, 0xb7, 0x16, 0x76, 0x4c, 0xfb, 0x01, 0xdc, 0x14, + 0x7c, 0xfe, 0x6f, 0x40, 0x46, 0x07, 0xe3, 0x2d, 0xb1, 0x53, 0xfa, 0xdf, 0x83, 0x06, 0xd3, 0x80, + 0xcf, 0xb3, 0x74, 0xf9, 0x65, 0xc6, 0x68, 0xd7, 0x82, 0xc5, 0xbc, 0x9b, 0xf6, 0x69, 0x1e, 0x3e, + 0xd2, 0x5e, 0x7a, 0xcc, 0x8e, 0x68, 0x6f, 0x0a, 0x0e, 0x6d, 0x4e, 0xd2, 0x75, 0x03, 0x6d, 0x8c, + 0xb4, 0x58, 0xbb, 0xb8, 0x8b, 0xd9, 0x50, 0xab, 0x8e, 0x5e, 0x6a, 0xc8, 0xb3, 0x41, 0xd6, 0xaa, + 0x13, 0xdc, 0x4d, 0x3e, 0x57, 0x05, 0x59, 0xae, 0x0a, 0xf2, 0xbd, 0x2a, 0xc8, 0xfb, 0xba, 0xe8, + 0x2c, 0xd7, 0x45, 0xe7, 0x6b, 0x5d, 0x74, 0x9e, 0x6f, 0x66, 0x26, 0xbe, 0xd6, 0x8a, 0x6b, 0xb4, + 0x42, 0x63, 0xb0, 0x18, 0x84, 0x51, 0xfa, 0x72, 0x86, 0xa2, 0xb9, 0x16, 0x16, 0xa7, 0xf5, 0x02, + 0x42, 0x5b, 0xf8, 0x5e, 0xd1, 0xf1, 0xad, 0x82, 0x20, 0x9a, 0x52, 0xf5, 0x53, 0xd1, 0xe5, 0x4f, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x97, 0x4d, 0xcc, 0xde, 0x95, 0x01, 0x00, 0x00, } func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { @@ -280,10 +280,12 @@ func (m *Token) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x1a } } - if m.Amount != 0 { - i = encodeVarintPacket(dAtA, i, uint64(m.Amount)) + if len(m.Amount) > 0 { + i -= len(m.Amount) + copy(dAtA[i:], m.Amount) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Amount))) i-- - dAtA[i] = 0x10 + dAtA[i] = 0x12 } if len(m.Denom) > 0 { i -= len(m.Denom) @@ -343,8 +345,9 @@ func (m *Token) Size() (n int) { if l > 0 { n += 1 + l + sovPacket(uint64(l)) } - if m.Amount != 0 { - n += 1 + sovPacket(uint64(m.Amount)) + l = len(m.Amount) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) } if len(m.Trace) > 0 { for _, s := range m.Trace { @@ -603,10 +606,10 @@ func (m *Token) Unmarshal(dAtA []byte) error { m.Denom = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 0 { + if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) } - m.Amount = 0 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowPacket @@ -616,11 +619,24 @@ func (m *Token) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Amount |= uint64(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) diff --git a/proto/ibc/applications/transfer/v3/packet.proto b/proto/ibc/applications/transfer/v3/packet.proto index 32fc8938cd5..8971472c69d 100644 --- a/proto/ibc/applications/transfer/v3/packet.proto +++ b/proto/ibc/applications/transfer/v3/packet.proto @@ -23,7 +23,7 @@ message Token { // the base token denomination to be transferred string denom = 1; // the token amount to be transferred - uint64 amount = 2; + string amount = 2; // the trace of the token repeated string trace = 3; } From 034f47210dca7bfe4a74ba9af6675cb901a64095 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 9 Apr 2024 12:52:03 +0100 Subject: [PATCH 003/141] Update MsgTransfer to accept sdk.Coins instead of sdk.Coin (#6113) --- e2e/tests/transfer/authz_test.go | 88 ++++++----- e2e/tests/transfer/incentivized_test.go | 4 +- e2e/tests/transfer/upgrades_test.go | 4 +- e2e/tests/upgrades/upgrade_test.go | 2 +- e2e/testsuite/tx.go | 2 +- e2e/testvalues/values.go | 4 + .../host/keeper/relay_test.go | 38 ++--- modules/apps/29-fee/keeper/events_test.go | 2 +- modules/apps/29-fee/transfer_test.go | 4 +- modules/apps/callbacks/ibc_middleware_test.go | 2 +- modules/apps/callbacks/replay_test.go | 2 +- modules/apps/callbacks/transfer_test.go | 4 +- modules/apps/transfer/client/cli/tx.go | 2 +- .../apps/transfer/keeper/invariants_test.go | 2 +- .../apps/transfer/keeper/mbt_relay_test.go | 2 +- modules/apps/transfer/keeper/msg_server.go | 15 +- .../apps/transfer/keeper/msg_server_test.go | 2 +- modules/apps/transfer/keeper/relay_test.go | 12 +- modules/apps/transfer/transfer_test.go | 6 +- modules/apps/transfer/types/msgs.go | 59 +++++++- modules/apps/transfer/types/msgs_test.go | 48 +++--- .../transfer/types/transfer_authorization.go | 7 +- .../types/transfer_authorization_test.go | 22 +-- modules/apps/transfer/types/tx.pb.go | 137 +++++++++++++----- proto/ibc/applications/transfer/v1/tx.proto | 2 + 25 files changed, 302 insertions(+), 170 deletions(-) diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index dd390ad3da5..33297e0766d 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -104,16 +104,18 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { t.Run("broadcast MsgGrant", createMsgGrantFn) t.Run("broadcast MsgExec for ibc MsgTransfer", func(t *testing.T) { - transferMsg := transfertypes.MsgTransfer{ - SourcePort: channelA.PortID, - SourceChannel: channelA.ChannelID, - Token: testvalues.DefaultTransferAmount(chainADenom), - Sender: granterAddress, - Receiver: receiverWalletAddress, - TimeoutHeight: suite.GetTimeoutHeight(ctx, chainB), - } - - protoAny, err := codectypes.NewAnyWithValue(&transferMsg) + transferMsg := transfertypes.NewMsgTransfer( + channelA.PortID, + channelA.ChannelID, + testvalues.DefaultTransferCoins(chainADenom), + granterAddress, + receiverWalletAddress, + suite.GetTimeoutHeight(ctx, chainB), + 0, + "", + ) + + protoAny, err := codectypes.NewAnyWithValue(transferMsg) suite.Require().NoError(err) msgExec := &authz.MsgExec{ @@ -161,16 +163,18 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { }) t.Run("exec unauthorized MsgTransfer", func(t *testing.T) { - transferMsg := transfertypes.MsgTransfer{ - SourcePort: channelA.PortID, - SourceChannel: channelA.ChannelID, - Token: testvalues.DefaultTransferAmount(chainADenom), - Sender: granterAddress, - Receiver: receiverWalletAddress, - TimeoutHeight: suite.GetTimeoutHeight(ctx, chainB), - } - - protoAny, err := codectypes.NewAnyWithValue(&transferMsg) + transferMsg := transfertypes.NewMsgTransfer( + channelA.PortID, + channelA.ChannelID, + testvalues.DefaultTransferCoins(chainADenom), + granterAddress, + receiverWalletAddress, + suite.GetTimeoutHeight(ctx, chainB), + 0, + "", + ) + + protoAny, err := codectypes.NewAnyWithValue(transferMsg) suite.Require().NoError(err) msgExec := &authz.MsgExec{ @@ -241,16 +245,18 @@ func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { const invalidSpendAmount = spendLimit + 1 t.Run("broadcast MsgExec for ibc MsgTransfer", func(t *testing.T) { - transferMsg := transfertypes.MsgTransfer{ - SourcePort: channelA.PortID, - SourceChannel: channelA.ChannelID, - Token: sdk.Coin{Denom: chainADenom, Amount: sdkmath.NewInt(invalidSpendAmount)}, - Sender: granterAddress, - Receiver: receiverWalletAddress, - TimeoutHeight: suite.GetTimeoutHeight(ctx, chainB), - } - - protoAny, err := codectypes.NewAnyWithValue(&transferMsg) + transferMsg := transfertypes.NewMsgTransfer( + channelA.PortID, + channelA.ChannelID, + sdk.NewCoins(sdk.Coin{Denom: chainADenom, Amount: sdkmath.NewInt(invalidSpendAmount)}), + granterAddress, + receiverWalletAddress, + suite.GetTimeoutHeight(ctx, chainB), + 0, + "", + ) + + protoAny, err := codectypes.NewAnyWithValue(transferMsg) suite.Require().NoError(err) msgExec := &authz.MsgExec{ @@ -298,16 +304,18 @@ func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { invalidWalletAddress := invalidWallet.FormattedAddress() t.Run("broadcast MsgExec for ibc MsgTransfer", func(t *testing.T) { - transferMsg := transfertypes.MsgTransfer{ - SourcePort: channelA.PortID, - SourceChannel: channelA.ChannelID, - Token: sdk.Coin{Denom: chainADenom, Amount: sdkmath.NewInt(spendLimit)}, - Sender: granterAddress, - Receiver: invalidWalletAddress, - TimeoutHeight: suite.GetTimeoutHeight(ctx, chainB), - } - - protoAny, err := codectypes.NewAnyWithValue(&transferMsg) + transferMsg := transfertypes.NewMsgTransfer( + channelA.PortID, + channelA.ChannelID, + sdk.NewCoins(sdk.Coin{Denom: chainADenom, Amount: sdkmath.NewInt(spendLimit)}), + granterAddress, + invalidWalletAddress, + suite.GetTimeoutHeight(ctx, chainB), + 0, + "", + ) + + protoAny, err := codectypes.NewAnyWithValue(transferMsg) suite.Require().NoError(err) msgExec := &authz.MsgExec{ diff --git a/e2e/tests/transfer/incentivized_test.go b/e2e/tests/transfer/incentivized_test.go index 1902c9e0c66..b8818a00002 100644 --- a/e2e/tests/transfer/incentivized_test.go +++ b/e2e/tests/transfer/incentivized_test.go @@ -197,7 +197,7 @@ func (s *IncentivizedTransferTestSuite) TestMsgPayPacketFee_InvalidReceiverAccou transferAmount := testvalues.DefaultTransferAmount(chainADenom) t.Run("send IBC transfer", func(t *testing.T) { - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, transferAmount, chainAWallet.FormattedAddress(), testvalues.InvalidAddress, s.GetTimeoutHeight(ctx, chainB), 0, "") + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), testvalues.InvalidAddress, s.GetTimeoutHeight(ctx, chainB), 0, "") txResp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgTransfer) // this message should be successful, as receiver account is not validated on the sending chain. s.AssertTxSuccess(txResp) @@ -322,7 +322,7 @@ func (s *IncentivizedTransferTestSuite) TestMultiMsg_MsgPayPacketFeeSingleSender }) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, transferAmount, chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "") + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "") resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) diff --git a/e2e/tests/transfer/upgrades_test.go b/e2e/tests/transfer/upgrades_test.go index c1bd43898dd..74f5593d611 100644 --- a/e2e/tests/transfer/upgrades_test.go +++ b/e2e/tests/transfer/upgrades_test.go @@ -13,6 +13,8 @@ import ( sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/e2e/testsuite" "github.com/cosmos/ibc-go/e2e/testvalues" feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" @@ -195,7 +197,7 @@ func (s *TransferChannelUpgradesTestSuite) TestChannelUpgrade_WithFeeMiddleware_ transferAmount := testvalues.DefaultTransferAmount(chainA.Config().Denom) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, transferAmount, chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "") + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "") resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) }) diff --git a/e2e/tests/upgrades/upgrade_test.go b/e2e/tests/upgrades/upgrade_test.go index c3d56fc4f76..494a73a4511 100644 --- a/e2e/tests/upgrades/upgrade_test.go +++ b/e2e/tests/upgrades/upgrade_test.go @@ -960,7 +960,7 @@ func (s *UpgradeTestSuite) TestV8ToV8_1ChainUpgrade_ChannelUpgrades() { transferAmount := testvalues.DefaultTransferAmount(chainA.Config().Denom) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, transferAmount, chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "") + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "") resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) }) diff --git a/e2e/testsuite/tx.go b/e2e/testsuite/tx.go index ecbde19b3ad..b0ee8ab763b 100644 --- a/e2e/testsuite/tx.go +++ b/e2e/testsuite/tx.go @@ -265,7 +265,7 @@ func (s *E2ETestSuite) ExecuteGovV1Beta1Proposal(ctx context.Context, chain ibc. func (s *E2ETestSuite) Transfer(ctx context.Context, chain ibc.Chain, user ibc.Wallet, portID, channelID string, token sdk.Coin, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, ) sdk.TxResponse { - msg := transfertypes.NewMsgTransfer(portID, channelID, token, sender, receiver, timeoutHeight, timeoutTimestamp, memo) + msg := transfertypes.NewMsgTransfer(portID, channelID, sdk.NewCoins(token), sender, receiver, timeoutHeight, timeoutTimestamp, memo) return s.BroadcastMessages(ctx, chain, user, msg) } diff --git a/e2e/testvalues/values.go b/e2e/testvalues/values.go index b6f750ef7f7..07f262296f6 100644 --- a/e2e/testvalues/values.go +++ b/e2e/testvalues/values.go @@ -43,6 +43,10 @@ func DefaultTransferAmount(denom string) sdk.Coin { return sdk.Coin{Denom: denom, Amount: sdkmath.NewInt(IBCTransferAmount)} } +func DefaultTransferCoins(denom string) sdk.Coins { + return sdk.NewCoins(DefaultTransferAmount(denom)) +} + func TransferAmount(amount int64, denom string) sdk.Coin { return sdk.Coin{Denom: denom, Amount: sdkmath.NewInt(amount)} } diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index ac5d41378e3..f49e623e939 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -342,15 +342,16 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) - msg := &transfertypes.MsgTransfer{ - SourcePort: transferPath.EndpointA.ChannelConfig.PortID, - SourceChannel: transferPath.EndpointA.ChannelID, - Token: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)), - Sender: interchainAccountAddr, - Receiver: suite.chainA.SenderAccount.GetAddress().String(), - TimeoutHeight: suite.chainB.GetTimeoutHeight(), - TimeoutTimestamp: uint64(0), - } + msg := transfertypes.NewMsgTransfer( + transferPath.EndpointA.ChannelConfig.PortID, + transferPath.EndpointA.ChannelID, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), + interchainAccountAddr, + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.GetTimeoutHeight(), + 0, + "", + ) data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) suite.Require().NoError(err) @@ -376,15 +377,16 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { interchainAccountAddr, found := suite.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(suite.chainB.GetContext(), ibctesting.FirstConnectionID, path.EndpointA.ChannelConfig.PortID) suite.Require().True(found) - msg := &transfertypes.MsgTransfer{ - SourcePort: transferPath.EndpointA.ChannelConfig.PortID, - SourceChannel: transferPath.EndpointA.ChannelID, - Token: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)), - Sender: interchainAccountAddr, - Receiver: "", - TimeoutHeight: suite.chainB.GetTimeoutHeight(), - TimeoutTimestamp: uint64(0), - } + msg := transfertypes.NewMsgTransfer( + transferPath.EndpointA.ChannelConfig.PortID, + transferPath.EndpointA.ChannelID, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), + interchainAccountAddr, + "", + suite.chainB.GetTimeoutHeight(), + 0, + "", + ) data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) suite.Require().NoError(err) diff --git a/modules/apps/29-fee/keeper/events_test.go b/modules/apps/29-fee/keeper/events_test.go index f4f49abcf0d..d70b8bfd229 100644 --- a/modules/apps/29-fee/keeper/events_test.go +++ b/modules/apps/29-fee/keeper/events_test.go @@ -113,7 +113,7 @@ func (suite *KeeperTestSuite) TestDistributeFeeEvent() { msgTransfer := transfertypes.NewMsgTransfer( path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, - sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", ) diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 79a0405fc0d..f76393bfcf8 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -30,7 +30,7 @@ func (suite *FeeTestSuite) TestFeeTransfer() { msgs := []sdk.Msg{ types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), - transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coin, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, ""), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, ""), } res, err := suite.chainA.SendMsgs(msgs...) suite.Require().NoError(err) // message committed @@ -138,7 +138,7 @@ func (suite *FeeTestSuite) TestTransferFeeUpgrade() { fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) msgs := []sdk.Msg{ types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), - transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ibctesting.TestCoin, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, ""), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, ""), } res, err := suite.chainA.SendMsgs(msgs...) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index d041ea61b2c..180ca3eb056 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -463,7 +463,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano()) msg := transfertypes.NewMsgTransfer( s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, - ibctesting.TestCoin, s.chainA.SenderAccount.GetAddress().String(), + sdk.NewCoins(ibctesting.TestCoin), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), // set user gas limit above panic level in mock contract keeper ) diff --git a/modules/apps/callbacks/replay_test.go b/modules/apps/callbacks/replay_test.go index d23de002613..04a8e5900fb 100644 --- a/modules/apps/callbacks/replay_test.go +++ b/modules/apps/callbacks/replay_test.go @@ -326,7 +326,7 @@ func (s *CallbacksTestSuite) ExecuteFailedTransfer(memo string) { msg := transfertypes.NewMsgTransfer( s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, - amount, + sdk.NewCoins(amount), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 4d288e96bbc..16698f074e6 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -189,7 +189,7 @@ func (s *CallbacksTestSuite) ExecuteTransfer(memo string) { msg := transfertypes.NewMsgTransfer( s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, - amount, + sdk.NewCoins(amount), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, @@ -223,7 +223,7 @@ func (s *CallbacksTestSuite) ExecuteTransferTimeout(memo string) { msg := transfertypes.NewMsgTransfer( s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, - amount, + sdk.NewCoins(amount), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), timeoutHeight, timeoutTimestamp, memo, diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index 497e56370d5..ccdd08af588 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -107,7 +107,7 @@ Relative timeout timestamp is added to the value of the user's local system cloc } msg := types.NewMsgTransfer( - srcPort, srcChannel, coin, sender, receiver, timeoutHeight, timeoutTimestamp, memo, + srcPort, srcChannel, sdk.NewCoins(coin), sender, receiver, timeoutHeight, timeoutTimestamp, memo, ) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/modules/apps/transfer/keeper/invariants_test.go b/modules/apps/transfer/keeper/invariants_test.go index ef1b6ae90ca..e150f9ef7c9 100644 --- a/modules/apps/transfer/keeper/invariants_test.go +++ b/modules/apps/transfer/keeper/invariants_test.go @@ -47,7 +47,7 @@ func (suite *KeeperTestSuite) TestTotalEscrowPerDenomInvariant() { msg := types.NewMsgTransfer( path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, - coin, + sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index fcb466dd468..72c5f0b1f41 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -348,7 +348,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { msg := types.NewMsgTransfer( tc.packet.SourcePort, tc.packet.SourceChannel, - sdk.NewCoin(denom, amount), + sdk.NewCoins(sdk.NewCoin(denom, amount)), sender.String(), tc.packet.Data.Receiver, suite.chainA.GetTimeoutHeight(), 0, // only use timeout height diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index c5171573226..94536cba937 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -26,8 +26,11 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. return nil, err } - if !k.bankKeeper.IsSendEnabledCoin(ctx, msg.Token) { - return nil, errorsmod.Wrapf(types.ErrSendDisabled, "%s transfers are currently disabled", msg.Token.Denom) + // TODO: replace with correct usage. + token := msg.GetTokens()[0] + + if !k.bankKeeper.IsSendEnabledCoin(ctx, token) { + return nil, errorsmod.Wrapf(types.ErrSendDisabled, "%s transfers are currently disabled", token.Denom) } if k.bankKeeper.BlockedAddr(sender) { @@ -35,21 +38,21 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. } sequence, err := k.sendTransfer( - ctx, msg.SourcePort, msg.SourceChannel, msg.Token, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, + ctx, msg.SourcePort, msg.SourceChannel, token, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Memo) if err != nil { return nil, err } - k.Logger(ctx).Info("IBC fungible token transfer", "token", msg.Token.Denom, "amount", msg.Token.Amount.String(), "sender", msg.Sender, "receiver", msg.Receiver) + k.Logger(ctx).Info("IBC fungible token transfer", "token", token.Denom, "amount", token.Amount.String(), "sender", msg.Sender, "receiver", msg.Receiver) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeTransfer, sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), - sdk.NewAttribute(types.AttributeKeyAmount, msg.Token.Amount.String()), - sdk.NewAttribute(types.AttributeKeyDenom, msg.Token.Denom), + sdk.NewAttribute(types.AttributeKeyAmount, token.Amount.String()), + sdk.NewAttribute(types.AttributeKeyDenom, token.Denom), sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), ), sdk.NewEvent( diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 55bc27a8a89..957ccf82c94 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -95,7 +95,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { msg = types.NewMsgTransfer( path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, - coin, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), + sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", ) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 1eb02bba9bd..24ab6f9eb69 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -126,7 +126,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { expEscrowAmount = sdkmath.ZeroInt() // create IBC token on chainA - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, coin, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "") + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "") result, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -141,7 +141,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { msg := types.NewMsgTransfer( path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, - coin, sender.String(), suite.chainB.SenderAccount.GetAddress().String(), + sdk.NewCoins(coin), sender.String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, // only use timeout height memo, ) @@ -206,7 +206,7 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT transferMsg := types.NewMsgTransfer( path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, - coin, + sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, "", @@ -226,7 +226,7 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT msg := types.NewMsgTransfer( path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, - coin, + sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", @@ -383,7 +383,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { if tc.recvIsSource { // send coin from chainB to chainA, receive them, acknowledge them, and send back to chainB coinFromBToA := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, coinFromBToA, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, memo) + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coinFromBToA), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, memo) res, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -403,7 +403,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // send coin from chainA to chainB coin := sdk.NewCoin(trace.IBCDenom(), amount) - transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coin, suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo) + transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo) _, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go index ef8dea295c6..1cb1261c0e3 100644 --- a/modules/apps/transfer/transfer_test.go +++ b/modules/apps/transfer/transfer_test.go @@ -52,7 +52,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) // send from chainA to chainB - msg := types.NewMsgTransfer(pathAtoB.EndpointA.ChannelConfig.PortID, pathAtoB.EndpointA.ChannelID, coinToSendToB, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") + msg := types.NewMsgTransfer(pathAtoB.EndpointA.ChannelConfig.PortID, pathAtoB.EndpointA.ChannelID, sdk.NewCoins(coinToSendToB), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") res, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -82,7 +82,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { pathBtoC.Setup() // send from chainB to chainC - msg = types.NewMsgTransfer(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, coinSentFromAToB, suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") + msg = types.NewMsgTransfer(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, sdk.NewCoins(coinSentFromAToB), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") res, err = suite.chainB.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -105,7 +105,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { suite.Require().Zero(balance.Amount.Int64()) // send from chainC back to chainB - msg = types.NewMsgTransfer(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, coinSentFromBToC, suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") + msg = types.NewMsgTransfer(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, sdk.NewCoins(coinSentFromBToC), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") res, err = suite.chainC.SendMsgs(msg) suite.Require().NoError(err) // message committed diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 2b045fee47e..2994e841951 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -45,19 +45,19 @@ func (msg MsgUpdateParams) ValidateBasic() error { // NewMsgTransfer creates a new MsgTransfer instance func NewMsgTransfer( sourcePort, sourceChannel string, - token sdk.Coin, sender, receiver string, + tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, ) *MsgTransfer { return &MsgTransfer{ SourcePort: sourcePort, SourceChannel: sourceChannel, - Token: token, Sender: sender, Receiver: receiver, TimeoutHeight: timeoutHeight, TimeoutTimestamp: timeoutTimestamp, Memo: memo, + Tokens: tokens, } } @@ -72,11 +72,13 @@ func (msg MsgTransfer) ValidateBasic() error { if err := host.ChannelIdentifierValidator(msg.SourceChannel); err != nil { return errorsmod.Wrap(err, "invalid source channel ID") } - if !msg.Token.IsValid() { - return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, msg.Token.String()) + + if len(msg.Tokens) == 0 && !isValidToken(msg.Token) { + return errorsmod.Wrap(ErrInvalidAmount, "either token or token array must be filled") } - if !msg.Token.IsPositive() { - return errorsmod.Wrap(ibcerrors.ErrInsufficientFunds, msg.Token.String()) + + if len(msg.Tokens) != 0 && isValidToken(msg.Token) { + return errorsmod.Wrap(ErrInvalidAmount, "cannot fill both token and token array") } _, err := sdk.AccAddressFromBech32(msg.Sender) @@ -92,5 +94,48 @@ func (msg MsgTransfer) ValidateBasic() error { if len(msg.Memo) > MaximumMemoLength { return errorsmod.Wrapf(ErrInvalidMemo, "memo must not exceed %d bytes", MaximumMemoLength) } - return ValidateIBCDenom(msg.Token.Denom) + + for _, token := range msg.GetTokens() { + if !isValidToken(token) { + return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, token.String()) + } + if err := ValidateIBCDenom(token.GetDenom()); err != nil { + return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, token.Denom) + } + } + + return nil +} + +// GetTokens returns the tokens which will be transferred. +func (msg MsgTransfer) GetTokens() []sdk.Coin { + tokens := msg.Tokens + if isValidToken(msg.Token) { + tokens = []sdk.Coin{msg.Token} + } + return tokens +} + +// isValidToken returns true if the token provided is valid, +// and should be used to transfer tokens. +// this function is used in case the user constructs a sdk.Coin literal +// instead of using the construction function. +func isValidToken(coin sdk.Coin) bool { + if coin.IsNil() { + return false + } + + if strings.TrimSpace(coin.Denom) == "" { + return false + } + + if coin.Amount.IsZero() { + return false + } + + if coin.Amount.IsNegative() { + return false + } + + return true } diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index e9bb11cac54..e98400bfa45 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -38,11 +38,11 @@ var ( receiver = sdk.AccAddress("testaddr2").String() emptyAddr string - coin = sdk.NewCoin("atom", sdkmath.NewInt(100)) - ibcCoin = sdk.NewCoin("ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdkmath.NewInt(100)) - invalidIBCCoin = sdk.NewCoin("ibc/7F1D3FCF4AE79E1554", sdkmath.NewInt(100)) - invalidDenomCoin = sdk.Coin{Denom: "0atom", Amount: sdkmath.NewInt(100)} - zeroCoin = sdk.Coin{Denom: "atoms", Amount: sdkmath.NewInt(0)} + coins = sdk.NewCoins(sdk.NewCoin("atom", sdkmath.NewInt(100))) + ibcCoins = sdk.NewCoins(sdk.NewCoin("ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdkmath.NewInt(100))) + invalidIBCCoins = sdk.NewCoins(sdk.NewCoin("ibc/7F1D3FCF4AE79E1554", sdkmath.NewInt(100))) + invalidDenomCoins = []sdk.Coin{{Denom: "0atom", Amount: sdkmath.NewInt(100)}} + zeroCoins = sdk.NewCoins(sdk.Coin{Denom: "atoms", Amount: sdkmath.NewInt(0)}) timeoutHeight = clienttypes.NewHeight(0, 10) ) @@ -54,22 +54,26 @@ func TestMsgTransferValidation(t *testing.T) { msg *types.MsgTransfer expPass bool }{ - {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coin, sender, receiver, timeoutHeight, 0, ""), true}, - {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoin, sender, receiver, timeoutHeight, 0, ""), true}, - {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoin, sender, receiver, timeoutHeight, 0, ""), false}, - {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coin, sender, receiver, timeoutHeight, 0, ""), false}, - {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coin, sender, receiver, timeoutHeight, 0, ""), false}, - {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coin, sender, receiver, timeoutHeight, 0, ""), false}, - {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coin, sender, receiver, timeoutHeight, 0, ""), false}, - {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coin, sender, receiver, timeoutHeight, 0, ""), false}, - {"too long memo", types.NewMsgTransfer(validPort, validChannel, coin, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1)), false}, - {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coin, sender, receiver, timeoutHeight, 0, ""), false}, - {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoin, sender, receiver, timeoutHeight, 0, ""), false}, - {"zero coin", types.NewMsgTransfer(validPort, validChannel, zeroCoin, sender, receiver, timeoutHeight, 0, ""), false}, - {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coin, emptyAddr, receiver, timeoutHeight, 0, ""), false}, - {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coin, sender, "", timeoutHeight, 0, ""), false}, - {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coin, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, ""), false}, - {"empty coin", types.NewMsgTransfer(validPort, validChannel, sdk.Coin{}, sender, receiver, timeoutHeight, 0, ""), false}, + {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ""), true}, + {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, timeoutHeight, 0, ""), true}, + {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, timeoutHeight, 0, ""), true}, + {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, timeoutHeight, 0, ""), false}, + {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, + {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, + {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, + {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, + {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, + {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1)), false}, + {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, + {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, timeoutHeight, 0, ""), false}, + {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, ""), false}, + {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, timeoutHeight, 0, ""), false}, + {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", timeoutHeight, 0, ""), false}, + {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, ""), false}, + {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, timeoutHeight, 0, ""), false}, + {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, ""), false}, + {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, ""), false}, + {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, ""), false}, } for i, tc := range testCases { @@ -87,7 +91,7 @@ func TestMsgTransferValidation(t *testing.T) { // TestMsgTransferGetSigners tests GetSigners for MsgTransfer func TestMsgTransferGetSigners(t *testing.T) { addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - msg := types.NewMsgTransfer(validPort, validChannel, coin, addr.String(), receiver, timeoutHeight, 0, "") + msg := types.NewMsgTransfer(validPort, validChannel, coins, addr.String(), receiver, timeoutHeight, 0, "") encodingCfg := moduletestutil.MakeTestEncodingConfig(transfer.AppModuleBasic{}) signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index 242bc86e801..b38702f980a 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -44,6 +44,9 @@ func (a TransferAuthorization) Accept(ctx context.Context, msg proto.Message) (a return authz.AcceptResponse{}, errorsmod.Wrap(ibcerrors.ErrInvalidType, "type mismatch") } + // TODO: replace with correct usage in https://github.com/cosmos/ibc-go/issues/5802 + token := msgTransfer.GetTokens()[0] + for index, allocation := range a.Allocations { if !(allocation.SourceChannel == msgTransfer.SourceChannel && allocation.SourcePort == msgTransfer.SourcePort) { continue @@ -59,11 +62,11 @@ func (a TransferAuthorization) Accept(ctx context.Context, msg proto.Message) (a } // If the spend limit is set to the MaxUint256 sentinel value, do not subtract the amount from the spend limit. - if allocation.SpendLimit.AmountOf(msgTransfer.Token.Denom).Equal(UnboundedSpendLimit()) { + if allocation.SpendLimit.AmountOf(token.Denom).Equal(UnboundedSpendLimit()) { return authz.AcceptResponse{Accept: true, Delete: false, Updated: nil}, nil } - limitLeft, isNegative := allocation.SpendLimit.SafeSub(msgTransfer.Token) + limitLeft, isNegative := allocation.SpendLimit.SafeSub(token) if isNegative { return authz.AcceptResponse{}, errorsmod.Wrapf(ibcerrors.ErrInsufficientFunds, "requested amount is more than spend limit") } diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index 781e5d68e3d..d86c396d335 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -15,7 +15,7 @@ const testMemo = `{"wasm":{"contract":"osmo1c3ljch9dfw5kf52nfwpxd2zmj2ese7agnx0p func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { var ( - msgTransfer types.MsgTransfer + msgTransfer *types.MsgTransfer transferAuthz types.TransferAuthorization ) @@ -247,18 +247,20 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { }, } - msgTransfer = types.MsgTransfer{ - SourcePort: path.EndpointA.ChannelConfig.PortID, - SourceChannel: path.EndpointA.ChannelID, - Token: ibctesting.TestCoin, - Sender: suite.chainA.SenderAccount.GetAddress().String(), - Receiver: ibctesting.TestAccAddress, - TimeoutHeight: suite.chainB.GetTimeoutHeight(), - } + msgTransfer = types.NewMsgTransfer( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + sdk.NewCoins(ibctesting.TestCoin), + suite.chainA.SenderAccount.GetAddress().String(), + ibctesting.TestAccAddress, + suite.chainB.GetTimeoutHeight(), + 0, + "", + ) tc.malleate() - res, err := transferAuthz.Accept(suite.chainA.GetContext(), &msgTransfer) + res, err := transferAuthz.Accept(suite.chainA.GetContext(), msgTransfer) tc.assertResult(res, err) }) } diff --git a/modules/apps/transfer/types/tx.pb.go b/modules/apps/transfer/types/tx.pb.go index 6dbba5651c9..860b32b2549 100644 --- a/modules/apps/transfer/types/tx.pb.go +++ b/modules/apps/transfer/types/tx.pb.go @@ -54,6 +54,8 @@ type MsgTransfer struct { TimeoutTimestamp uint64 `protobuf:"varint,7,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3" json:"timeout_timestamp,omitempty"` // optional memo Memo string `protobuf:"bytes,8,opt,name=memo,proto3" json:"memo,omitempty"` + // tokens to be transferred + Tokens []types.Coin `protobuf:"bytes,9,rep,name=tokens,proto3" json:"tokens"` } func (m *MsgTransfer) Reset() { *m = MsgTransfer{} } @@ -221,46 +223,47 @@ func init() { } var fileDescriptor_7401ed9bed2f8e09 = []byte{ - // 613 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xcf, 0x4f, 0x13, 0x4f, - 0x14, 0xef, 0x7e, 0x29, 0xfd, 0xc2, 0x54, 0x40, 0x56, 0x03, 0xcb, 0xc6, 0x6c, 0x49, 0x23, 0x09, - 0x96, 0x30, 0x93, 0x62, 0x0c, 0xa6, 0xc7, 0x72, 0xf1, 0x20, 0x09, 0x36, 0x78, 0xf1, 0x42, 0x76, - 0xa7, 0xcf, 0xed, 0x84, 0xee, 0xcc, 0x3a, 0x33, 0x6d, 0xf4, 0x62, 0x88, 0x27, 0xe3, 0xc9, 0x3f, - 0xc1, 0xa3, 0x47, 0xfe, 0x0c, 0x8e, 0x1c, 0x3d, 0x19, 0x03, 0x07, 0x2e, 0xfe, 0x11, 0x66, 0x66, - 0xa7, 0x75, 0xf5, 0x50, 0xf5, 0xb2, 0xfb, 0x7e, 0x7c, 0xde, 0xaf, 0xcf, 0x9b, 0x87, 0xb6, 0x58, - 0x42, 0x49, 0x9c, 0xe7, 0x43, 0x46, 0x63, 0xcd, 0x04, 0x57, 0x44, 0xcb, 0x98, 0xab, 0x97, 0x20, - 0xc9, 0xb8, 0x4d, 0xf4, 0x6b, 0x9c, 0x4b, 0xa1, 0x85, 0x7f, 0x8f, 0x25, 0x14, 0x97, 0x61, 0x78, - 0x02, 0xc3, 0xe3, 0x76, 0xb8, 0x1a, 0x67, 0x8c, 0x0b, 0x62, 0xbf, 0x45, 0x40, 0x78, 0x37, 0x15, - 0xa9, 0xb0, 0x22, 0x31, 0x92, 0xb3, 0xae, 0x53, 0xa1, 0x32, 0xa1, 0x48, 0xa6, 0x52, 0x93, 0x3e, - 0x53, 0xa9, 0x73, 0x44, 0xce, 0x91, 0xc4, 0x0a, 0xc8, 0xb8, 0x9d, 0x80, 0x8e, 0xdb, 0x84, 0x0a, - 0xc6, 0x9d, 0xbf, 0x61, 0xda, 0xa4, 0x42, 0x02, 0xa1, 0x43, 0x06, 0x5c, 0x9b, 0xe8, 0x42, 0x72, - 0x80, 0x9d, 0xd9, 0x73, 0x4c, 0x9a, 0xb5, 0xe0, 0xe6, 0xd9, 0x1c, 0xaa, 0x1f, 0xaa, 0xf4, 0xd8, - 0x59, 0xfd, 0x06, 0xaa, 0x2b, 0x31, 0x92, 0x14, 0x4e, 0x72, 0x21, 0x75, 0xe0, 0x6d, 0x7a, 0xdb, - 0x8b, 0x3d, 0x54, 0x98, 0x8e, 0x84, 0xd4, 0xfe, 0x16, 0x5a, 0x76, 0x00, 0x3a, 0x88, 0x39, 0x87, - 0x61, 0xf0, 0x9f, 0xc5, 0x2c, 0x15, 0xd6, 0x83, 0xc2, 0xe8, 0x77, 0xd0, 0xbc, 0x16, 0xa7, 0xc0, - 0x83, 0xb9, 0x4d, 0x6f, 0xbb, 0xbe, 0xb7, 0x81, 0x8b, 0xa9, 0xb0, 0x99, 0x0a, 0xbb, 0xa9, 0xf0, - 0x81, 0x60, 0xbc, 0xbb, 0x78, 0xf1, 0xb5, 0x51, 0xf9, 0x7c, 0x73, 0xde, 0xf2, 0x7a, 0x45, 0x88, - 0xbf, 0x86, 0x6a, 0x0a, 0x78, 0x1f, 0x64, 0x50, 0xb5, 0xa9, 0x9d, 0xe6, 0x87, 0x68, 0x41, 0x02, - 0x05, 0x36, 0x06, 0x19, 0xcc, 0x5b, 0xcf, 0x54, 0xf7, 0x9f, 0xa2, 0x65, 0xcd, 0x32, 0x10, 0x23, - 0x7d, 0x32, 0x00, 0x96, 0x0e, 0x74, 0x50, 0xb3, 0x85, 0x43, 0x6c, 0xd6, 0x65, 0xe8, 0xc2, 0x8e, - 0xa4, 0x71, 0x1b, 0x3f, 0xb1, 0x88, 0x72, 0xe5, 0x25, 0x17, 0x5c, 0x78, 0xfc, 0x1d, 0xb4, 0x3a, - 0xc9, 0x66, 0xfe, 0x4a, 0xc7, 0x59, 0x1e, 0xfc, 0xbf, 0xe9, 0x6d, 0x57, 0x7b, 0xb7, 0x9d, 0xe3, - 0x78, 0x62, 0xf7, 0x7d, 0x54, 0xcd, 0x20, 0x13, 0xc1, 0x82, 0x6d, 0xc9, 0xca, 0x9d, 0xd6, 0xfb, - 0x4f, 0x8d, 0xca, 0xbb, 0x9b, 0xf3, 0x96, 0xeb, 0xfd, 0xc3, 0xcd, 0x79, 0x6b, 0xad, 0xa0, 0x60, - 0x57, 0xf5, 0x4f, 0x49, 0x89, 0xf2, 0xe6, 0x3e, 0xba, 0x53, 0x52, 0x7b, 0xa0, 0x72, 0xc1, 0x15, - 0x98, 0x69, 0x15, 0xbc, 0x1a, 0x01, 0xa7, 0x60, 0xd7, 0x50, 0xed, 0x4d, 0xf5, 0x4e, 0xd5, 0xa4, - 0x6f, 0xbe, 0x45, 0x2b, 0x87, 0x2a, 0x7d, 0x9e, 0xf7, 0x63, 0x0d, 0x47, 0xb1, 0x8c, 0x33, 0x65, - 0xa9, 0x63, 0x29, 0x07, 0xe9, 0x36, 0xe7, 0x34, 0xbf, 0x8b, 0x6a, 0xb9, 0x45, 0xd8, 0x6d, 0xd5, - 0xf7, 0xee, 0xe3, 0x59, 0xaf, 0x18, 0x17, 0xd9, 0xba, 0x55, 0x43, 0x50, 0xcf, 0x45, 0x76, 0x56, - 0x7e, 0xce, 0x64, 0x93, 0x36, 0x37, 0xd0, 0xfa, 0x6f, 0xf5, 0x27, 0xcd, 0xef, 0x7d, 0xf7, 0xd0, - 0xdc, 0xa1, 0x4a, 0xfd, 0x01, 0x5a, 0x98, 0x3e, 0xad, 0x07, 0xb3, 0x6b, 0x96, 0x38, 0x08, 0xdb, - 0x7f, 0x0d, 0x9d, 0xd2, 0xa5, 0xd1, 0xad, 0x5f, 0x98, 0xd8, 0xfd, 0x63, 0x8a, 0x32, 0x3c, 0x7c, - 0xf4, 0x4f, 0xf0, 0x49, 0xd5, 0x70, 0xfe, 0xcc, 0x3c, 0x9f, 0xee, 0xb3, 0x8b, 0xab, 0xc8, 0xbb, - 0xbc, 0x8a, 0xbc, 0x6f, 0x57, 0x91, 0xf7, 0xf1, 0x3a, 0xaa, 0x5c, 0x5e, 0x47, 0x95, 0x2f, 0xd7, - 0x51, 0xe5, 0xc5, 0x7e, 0xca, 0xf4, 0x60, 0x94, 0x60, 0x2a, 0x32, 0xe2, 0x0e, 0x9b, 0x25, 0x74, - 0x37, 0x15, 0x64, 0xfc, 0x98, 0x64, 0xa2, 0x3f, 0x1a, 0x82, 0x32, 0xc7, 0x5a, 0x3a, 0x52, 0xfd, - 0x26, 0x07, 0x95, 0xd4, 0xec, 0x7d, 0x3e, 0xfc, 0x11, 0x00, 0x00, 0xff, 0xff, 0x3b, 0xda, 0xd1, - 0xc3, 0x96, 0x04, 0x00, 0x00, + // 630 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xb1, 0x6e, 0x13, 0x4d, + 0x10, 0xf6, 0xfd, 0x76, 0xfc, 0x27, 0x6b, 0x92, 0x90, 0x05, 0x25, 0x17, 0x0b, 0x9d, 0x2d, 0x8b, + 0x48, 0xc1, 0x51, 0x76, 0xe5, 0x20, 0x14, 0x64, 0x51, 0x39, 0x0d, 0x05, 0x91, 0x82, 0x15, 0x1a, + 0x9a, 0xe8, 0x6e, 0x3d, 0x9c, 0x57, 0xf1, 0xed, 0x1e, 0xb7, 0x6b, 0x0b, 0x1a, 0x84, 0xa8, 0x10, + 0x15, 0x8f, 0x40, 0x49, 0x99, 0x27, 0xa0, 0x4e, 0x99, 0x92, 0x0a, 0xa1, 0xa4, 0x48, 0xc3, 0x43, + 0xa0, 0xdd, 0x5b, 0x9b, 0x83, 0x22, 0x84, 0xc6, 0xde, 0x99, 0xf9, 0xe6, 0x9b, 0xf9, 0x66, 0x3c, + 0x46, 0x1b, 0x3c, 0x62, 0x34, 0x4c, 0xd3, 0x11, 0x67, 0xa1, 0xe6, 0x52, 0x28, 0xaa, 0xb3, 0x50, + 0xa8, 0x17, 0x90, 0xd1, 0x49, 0x87, 0xea, 0x57, 0x24, 0xcd, 0xa4, 0x96, 0xf8, 0x0e, 0x8f, 0x18, + 0x29, 0xc2, 0xc8, 0x14, 0x46, 0x26, 0x9d, 0xfa, 0x4a, 0x98, 0x70, 0x21, 0xa9, 0xfd, 0xcc, 0x13, + 0xea, 0xb7, 0x63, 0x19, 0x4b, 0xfb, 0xa4, 0xe6, 0xe5, 0xbc, 0x6b, 0x4c, 0xaa, 0x44, 0x2a, 0x9a, + 0xa8, 0xd8, 0xd0, 0x27, 0x2a, 0x76, 0x81, 0xc0, 0x05, 0xa2, 0x50, 0x01, 0x9d, 0x74, 0x22, 0xd0, + 0x61, 0x87, 0x32, 0xc9, 0x85, 0x8b, 0x37, 0x4c, 0x9b, 0x4c, 0x66, 0x40, 0xd9, 0x88, 0x83, 0xd0, + 0x26, 0x3b, 0x7f, 0x39, 0xc0, 0xd6, 0xd5, 0x3a, 0xa6, 0xcd, 0x5a, 0x70, 0xeb, 0x4b, 0x19, 0xd5, + 0xf6, 0x55, 0x7c, 0xe8, 0xbc, 0xb8, 0x81, 0x6a, 0x4a, 0x8e, 0x33, 0x06, 0x47, 0xa9, 0xcc, 0xb4, + 0xef, 0x35, 0xbd, 0xcd, 0x85, 0x3e, 0xca, 0x5d, 0x07, 0x32, 0xd3, 0x78, 0x03, 0x2d, 0x39, 0x00, + 0x1b, 0x86, 0x42, 0xc0, 0xc8, 0xff, 0xcf, 0x62, 0x16, 0x73, 0xef, 0x5e, 0xee, 0xc4, 0x5d, 0x34, + 0xa7, 0xe5, 0x31, 0x08, 0xbf, 0xdc, 0xf4, 0x36, 0x6b, 0x3b, 0xeb, 0x24, 0x57, 0x45, 0x8c, 0x2a, + 0xe2, 0x54, 0x91, 0x3d, 0xc9, 0x45, 0x6f, 0xe1, 0xf4, 0x5b, 0xa3, 0xf4, 0xf9, 0xf2, 0xa4, 0xed, + 0xf5, 0xf3, 0x14, 0xbc, 0x8a, 0xaa, 0x0a, 0xc4, 0x00, 0x32, 0xbf, 0x62, 0xa9, 0x9d, 0x85, 0xeb, + 0x68, 0x3e, 0x03, 0x06, 0x7c, 0x02, 0x99, 0x3f, 0x67, 0x23, 0x33, 0x1b, 0x3f, 0x41, 0x4b, 0x9a, + 0x27, 0x20, 0xc7, 0xfa, 0x68, 0x08, 0x3c, 0x1e, 0x6a, 0xbf, 0x6a, 0x0b, 0xd7, 0x89, 0x59, 0x97, + 0x19, 0x17, 0x71, 0x43, 0x9a, 0x74, 0xc8, 0x63, 0x8b, 0x28, 0x56, 0x5e, 0x74, 0xc9, 0x79, 0x04, + 0x6f, 0xa1, 0x95, 0x29, 0x9b, 0xf9, 0x56, 0x3a, 0x4c, 0x52, 0xff, 0xff, 0xa6, 0xb7, 0x59, 0xe9, + 0xdf, 0x74, 0x81, 0xc3, 0xa9, 0x1f, 0x63, 0x54, 0x49, 0x20, 0x91, 0xfe, 0xbc, 0x6d, 0xc9, 0xbe, + 0xf1, 0x23, 0x54, 0xb5, 0x5a, 0x94, 0xbf, 0xd0, 0x2c, 0x5f, 0x5b, 0xbf, 0xcb, 0xe9, 0xb6, 0xdf, + 0x7f, 0x6a, 0x94, 0xde, 0x5d, 0x9e, 0xb4, 0x9d, 0xf2, 0x0f, 0x97, 0x27, 0xed, 0xd5, 0x9c, 0x60, + 0x5b, 0x0d, 0x8e, 0x69, 0x61, 0x61, 0xad, 0x5d, 0x74, 0xab, 0x60, 0xf6, 0x41, 0xa5, 0x52, 0x28, + 0x30, 0xb3, 0x52, 0xf0, 0x72, 0x0c, 0x82, 0x81, 0x5d, 0x62, 0xa5, 0x3f, 0xb3, 0xbb, 0x15, 0x43, + 0xdf, 0x7a, 0x83, 0x96, 0xf7, 0x55, 0xfc, 0x2c, 0x1d, 0x84, 0x1a, 0x0e, 0xc2, 0x2c, 0x4c, 0x94, + 0x1d, 0x3c, 0x8f, 0x05, 0x64, 0x6e, 0xef, 0xce, 0xc2, 0x3d, 0x54, 0x4d, 0x2d, 0xc2, 0xee, 0xba, + 0xb6, 0x73, 0x97, 0x5c, 0x75, 0x03, 0x24, 0x67, 0xeb, 0x55, 0x8c, 0xb0, 0xbe, 0xcb, 0xec, 0x2e, + 0xff, 0xd2, 0x64, 0x49, 0x5b, 0xeb, 0x68, 0xed, 0x8f, 0xfa, 0xd3, 0xe6, 0x77, 0x7e, 0x78, 0xa8, + 0xbc, 0xaf, 0x62, 0x3c, 0x44, 0xf3, 0xb3, 0x1f, 0xe6, 0xbd, 0xab, 0x6b, 0x16, 0x66, 0x50, 0xef, + 0x5c, 0x1b, 0x3a, 0x1b, 0x97, 0x46, 0x37, 0x7e, 0x9b, 0xc4, 0xf6, 0x5f, 0x29, 0x8a, 0xf0, 0xfa, + 0x83, 0x7f, 0x82, 0x4f, 0xab, 0xd6, 0xe7, 0xde, 0x9a, 0xb5, 0xf7, 0x9e, 0x9e, 0x9e, 0x07, 0xde, + 0xd9, 0x79, 0xe0, 0x7d, 0x3f, 0x0f, 0xbc, 0x8f, 0x17, 0x41, 0xe9, 0xec, 0x22, 0x28, 0x7d, 0xbd, + 0x08, 0x4a, 0xcf, 0x77, 0x63, 0xae, 0x87, 0xe3, 0x88, 0x30, 0x99, 0x50, 0xf7, 0xb7, 0xc0, 0x23, + 0xb6, 0x1d, 0x4b, 0x3a, 0x79, 0x48, 0x13, 0x39, 0x18, 0x8f, 0x40, 0x99, 0x53, 0x2f, 0x9c, 0xb8, + 0x7e, 0x9d, 0x82, 0x8a, 0xaa, 0xf6, 0xba, 0xef, 0xff, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x29, 0xee, + 0x20, 0x91, 0xd4, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -403,6 +406,20 @@ func (m *MsgTransfer) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Tokens) > 0 { + for iNdEx := len(m.Tokens) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Tokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } if len(m.Memo) > 0 { i -= len(m.Memo) copy(dAtA[i:], m.Memo) @@ -601,6 +618,12 @@ func (m *MsgTransfer) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + if len(m.Tokens) > 0 { + for _, e := range m.Tokens { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } return n } @@ -920,6 +943,40 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { } m.Memo = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tokens", 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 + } + m.Tokens = append(m.Tokens, types.Coin{}) + if err := m.Tokens[len(m.Tokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/proto/ibc/applications/transfer/v1/tx.proto b/proto/ibc/applications/transfer/v1/tx.proto index 42c70d3bedc..52e5d29b7e1 100644 --- a/proto/ibc/applications/transfer/v1/tx.proto +++ b/proto/ibc/applications/transfer/v1/tx.proto @@ -49,6 +49,8 @@ message MsgTransfer { uint64 timeout_timestamp = 7; // optional memo string memo = 8; + // tokens to be transferred + repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; } // MsgTransferResponse defines the Msg/Transfer response type. From 4cc6a853f9696ad2a908b1e0f406794c53567998 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Apr 2024 18:18:16 +0200 Subject: [PATCH 004/141] fix: allow base denom with trailing slash (#6148) --- modules/apps/transfer/types/trace.go | 4 ++-- modules/apps/transfer/types/trace_test.go | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/apps/transfer/types/trace.go b/modules/apps/transfer/types/trace.go index 93aa7ee14bf..ee7b3c2ad50 100644 --- a/modules/apps/transfer/types/trace.go +++ b/modules/apps/transfer/types/trace.go @@ -199,11 +199,11 @@ func ValidatePrefixedDenom(denom string) error { return nil } - if strings.TrimSpace(denomSplit[len(denomSplit)-1]) == "" { + path, baseDenom := extractPathAndBaseFromFullDenom(denomSplit) + if strings.TrimSpace(baseDenom) == "" { return errorsmod.Wrap(ErrInvalidDenomForTransfer, "base denomination cannot be blank") } - path, _ := extractPathAndBaseFromFullDenom(denomSplit) if path == "" { // NOTE: base denom contains slashes, so no base denomination validation return nil diff --git a/modules/apps/transfer/types/trace_test.go b/modules/apps/transfer/types/trace_test.go index 49623ed1dec..f7634a7a3b0 100644 --- a/modules/apps/transfer/types/trace_test.go +++ b/modules/apps/transfer/types/trace_test.go @@ -132,15 +132,16 @@ func TestValidatePrefixedDenom(t *testing.T) { expError bool }{ {"prefixed denom", "transfer/channel-1/uatom", false}, + {"prefixed denom with base denom with leading slash", "transfer/channel-1/uatom/", false}, {"prefixed denom with '/'", "transfer/channel-1/gamm/pool/1", false}, {"empty prefix", "/uatom", false}, {"empty identifiers", "//uatom", false}, {"base denom", "uatom", false}, {"base denom with single '/'", "erc20/0x85bcBCd7e79Ec36f4fBBDc54F90C643d921151AA", false}, {"base denom with multiple '/'s", "gamm/pool/1", false}, + {"single trace identifier", "transfer/", false}, {"invalid port ID", "(transfer)/channel-1/uatom", true}, {"empty denom", "", true}, - {"single trace identifier", "transfer/", true}, } for _, tc := range testCases { From 71f830cb0f1f01ab1ee44c1d977f4731c31934b7 Mon Sep 17 00:00:00 2001 From: Charly Date: Tue, 16 Apr 2024 14:13:19 +0200 Subject: [PATCH 005/141] imp: add CurrentVersion, EscrowVersion (#6160) * add CurrentVersion, EscrowVersion, update tests * update hardcoded transfer channel version from interchaintest --- e2e/testsuite/testsuite.go | 4 ++++ modules/apps/transfer/keeper/mbt_relay_test.go | 2 +- modules/apps/transfer/types/keys.go | 18 +++++++++++++----- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index 48dbc13adcc..dc188180aa1 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -109,6 +109,10 @@ func (s *E2ETestSuite) ConfigureRelayer(ctx context.Context, chainA, chainB ibc. pathName := s.generatePathName() channelOptions := ibc.DefaultChannelOpts() + // TODO: better way to do this. + // For now, set the version to the latest transfer module version + channelOptions.Version = transfertypes.Version + if channelOpts != nil { channelOpts(&channelOptions) } diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 72c5f0b1f41..e2abbde9f1a 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -108,7 +108,7 @@ func AddressFromTla(addr []string) string { s = addr[2] } else if len(addr[2]) == 0 { // escrow address: ics20-1\x00port/channel - s = fmt.Sprintf("%s\x00%s/%s", types.Version, addr[0], addr[1]) + s = fmt.Sprintf("%s\x00%s/%s", types.Version1, addr[0], addr[1]) } else { panic(errors.New("failed to convert from TLA+ address: neither simple nor escrow address")) } diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index 0b13912cc88..8db04bb87bb 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -11,10 +11,6 @@ const ( // ModuleName defines the IBC transfer name ModuleName = "transfer" - // Version defines the current version the IBC transfer - // module supports - Version = "ics20-1" - // PortID is the default port id that transfer module binds to PortID = "transfer" @@ -38,6 +34,18 @@ const ( ParamsKey = "params" ) +const ( + // Version defines the current version the IBC transfer + // module supports + Version = "ics20-2" + + // Version1 defines first version of the IBC transfer module + Version1 = "ics20-1" + + // escrowAddressVersion should remain as ics20-1 to avoid the address changing. + escrowAddressVersion = "ics20-1" +) + var ( // PortKey defines the key to store the port ID in store PortKey = []byte{0x01} @@ -54,7 +62,7 @@ func GetEscrowAddress(portID, channelID string) sdk.AccAddress { contents := fmt.Sprintf("%s/%s", portID, channelID) // ADR 028 AddressHash construction - preImage := []byte(Version) + preImage := []byte(escrowAddressVersion) preImage = append(preImage, 0) preImage = append(preImage, contents...) hash := sha256.Sum256(preImage) From 28ff9b64cbd31401d70427a7c72a1aff730c07f7 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 16 Apr 2024 14:00:29 +0100 Subject: [PATCH 006/141] chore: add function for converting packet data from v1 to v3 (#6116) --------- Co-authored-by: Charly --- .../apps/transfer/internal/convert/convert.go | 55 ++++++++ .../transfer/internal/convert/convert_test.go | 123 ++++++++++++++++++ modules/apps/transfer/internal/denom/denom.go | 39 ++++++ modules/apps/transfer/types/trace.go | 42 +----- modules/apps/transfer/types/v3/packet.go | 15 +++ 5 files changed, 237 insertions(+), 37 deletions(-) create mode 100644 modules/apps/transfer/internal/convert/convert.go create mode 100644 modules/apps/transfer/internal/convert/convert_test.go create mode 100644 modules/apps/transfer/internal/denom/denom.go create mode 100644 modules/apps/transfer/types/v3/packet.go diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go new file mode 100644 index 00000000000..34ba1da17e6 --- /dev/null +++ b/modules/apps/transfer/internal/convert/convert.go @@ -0,0 +1,55 @@ +package convert + +import ( + "strings" + + v1types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" +) + +// PacketDataV1ToV3 converts a v1 (ICS20-V1) packet data to a v3 (ICS20-V2) packet data. +func PacketDataV1ToV3(packetData v1types.FungibleTokenPacketData) v3types.FungibleTokenPacketData { + if err := packetData.ValidateBasic(); err != nil { + panic(err) + } + + v2Denom, trace := extractDenomAndTraceFromV1Denom(packetData.Denom) + return v3types.FungibleTokenPacketData{ + Tokens: []*v3types.Token{ + { + Denom: v2Denom, + Amount: packetData.Amount, + Trace: trace, + }, + }, + Sender: packetData.Sender, + Receiver: packetData.Receiver, + Memo: packetData.Memo, + } +} + +// extractDenomAndTraceFromV1Denom extracts the base denom and remaining trace from a v1 IBC denom. +func extractDenomAndTraceFromV1Denom(v1Denom string) (string, []string) { + v1DenomTrace := v1types.ParseDenomTrace(v1Denom) + + splitPath := strings.Split(v1DenomTrace.Path, "/") + + // if the path slice is empty, then the base denom is the full native denom. + if len(splitPath) == 0 { + return v1DenomTrace.BaseDenom, nil + } + + // this condition should never be reached. + if len(splitPath)%2 != 0 { + panic("pathSlice length is not even") + } + + // the path slices consists of entries of ports and channel ids separately, + // we need to combine them to form the trace. + var trace []string + for i := 0; i < len(splitPath); i += 2 { + trace = append(trace, strings.Join(splitPath[i:i+2], "/")) + } + + return v1DenomTrace.BaseDenom, trace +} diff --git a/modules/apps/transfer/internal/convert/convert_test.go b/modules/apps/transfer/internal/convert/convert_test.go new file mode 100644 index 00000000000..f43731ad5dd --- /dev/null +++ b/modules/apps/transfer/internal/convert/convert_test.go @@ -0,0 +1,123 @@ +package convert + +import ( + "testing" + + "github.com/stretchr/testify/require" + + errorsmod "cosmossdk.io/errors" + + v1types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" +) + +func TestConvertPacketV1ToPacketV3(t *testing.T) { + const ( + sender = "sender" + receiver = "receiver" + ) + + testCases := []struct { + name string + v1Data v1types.FungibleTokenPacketData + v3Data v3types.FungibleTokenPacketData + expPanic error + }{ + { + "success", + v1types.NewFungibleTokenPacketData("transfer/channel-0/atom", "1000", sender, receiver, ""), + v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: "atom", + Amount: "1000", + Trace: []string{"transfer/channel-0"}, + }, + }, sender, receiver, ""), + nil, + }, + { + "success: base denom with '/'", + v1types.NewFungibleTokenPacketData("transfer/channel-0/atom/withslash", "1000", sender, receiver, ""), + v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: "atom/withslash", + Amount: "1000", + Trace: []string{"transfer/channel-0"}, + }, + }, sender, receiver, ""), + nil, + }, + { + "success: base denom with '/' at the end", + v1types.NewFungibleTokenPacketData("transfer/channel-0/atom/", "1000", sender, receiver, ""), + v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: "atom/", + Amount: "1000", + Trace: []string{"transfer/channel-0"}, + }, + }, sender, receiver, ""), + nil, + }, + { + "success: longer trace base denom with '/'", + v1types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/atom/pool", "1000", sender, receiver, ""), + v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: "atom/pool", + Amount: "1000", + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, sender, receiver, ""), + nil, + }, + { + "success: longer trace with non transfer port", + v1types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/transfer-custom/channel-2/atom", "1000", sender, receiver, ""), + v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: "atom", + Amount: "1000", + Trace: []string{"transfer/channel-0", "transfer/channel-1", "transfer-custom/channel-2"}, + }, + }, sender, receiver, ""), + nil, + }, + { + "success: base denom with slash, trace with non transfer port", + v1types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/transfer-custom/channel-2/atom/pool", "1000", sender, receiver, ""), + v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: "atom/pool", + Amount: "1000", + Trace: []string{"transfer/channel-0", "transfer/channel-1", "transfer-custom/channel-2"}, + }, + }, sender, receiver, ""), + nil, + }, + { + "failure: panics with empty denom", + v1types.NewFungibleTokenPacketData("", "1000", sender, receiver, ""), + v3types.FungibleTokenPacketData{}, + errorsmod.Wrap(v1types.ErrInvalidDenomForTransfer, "base denomination cannot be blank"), + }, + } + + for _, tc := range testCases { + expPass := tc.expPanic == nil + if expPass { + v3Data := PacketDataV1ToV3(tc.v1Data) + require.Equal(t, tc.v3Data, v3Data) + } else { + require.PanicsWithError(t, tc.expPanic.Error(), func() { + PacketDataV1ToV3(tc.v1Data) + }) + } + } +} diff --git a/modules/apps/transfer/internal/denom/denom.go b/modules/apps/transfer/internal/denom/denom.go new file mode 100644 index 00000000000..972528cd0c0 --- /dev/null +++ b/modules/apps/transfer/internal/denom/denom.go @@ -0,0 +1,39 @@ +package denom + +import ( + "strings" + + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" +) + +// ExtractPathAndBaseFromFullDenom returns the trace path and the base denom from +// the elements that constitute the complete denom. +func ExtractPathAndBaseFromFullDenom(fullDenomItems []string) ([]string, string) { + var ( + pathSlice []string + baseDenomSlice []string + ) + + length := len(fullDenomItems) + for i := 0; i < length; i += 2 { + // The IBC specification does not guarantee the expected format of the + // destination port or destination channel identifier. A short term solution + // to determine base denomination is to expect the channel identifier to be the + // one ibc-go specifies. A longer term solution is to separate the path and base + // denomination in the ICS20 packet. If an intermediate hop prefixes the full denom + // with a channel identifier format different from our own, the base denomination + // will be incorrectly parsed, but the token will continue to be treated correctly + // as an IBC denomination. The hash used to store the token internally on our chain + // will be the same value as the base denomination being correctly parsed. + if i < length-1 && length > 2 && channeltypes.IsValidChannelID(fullDenomItems[i+1]) { + pathSlice = append(pathSlice, fullDenomItems[i], fullDenomItems[i+1]) + } else { + baseDenomSlice = fullDenomItems[i:] + break + } + } + + baseDenom := strings.Join(baseDenomSlice, "/") + + return pathSlice, baseDenom +} diff --git a/modules/apps/transfer/types/trace.go b/modules/apps/transfer/types/trace.go index ee7b3c2ad50..00b1d3fd6f4 100644 --- a/modules/apps/transfer/types/trace.go +++ b/modules/apps/transfer/types/trace.go @@ -14,7 +14,7 @@ import ( cmtbytes "github.com/cometbft/cometbft/libs/bytes" cmttypes "github.com/cometbft/cometbft/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + denominternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/denom" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) @@ -38,9 +38,9 @@ func ParseDenomTrace(rawDenom string) DenomTrace { } } - path, baseDenom := extractPathAndBaseFromFullDenom(denomSplit) + pathSlice, baseDenom := denominternal.ExtractPathAndBaseFromFullDenom(denomSplit) return DenomTrace{ - Path: path, + Path: strings.Join(pathSlice, "/"), BaseDenom: baseDenom, } } @@ -82,39 +82,6 @@ func (dt DenomTrace) IsNativeDenom() bool { return dt.Path == "" } -// extractPathAndBaseFromFullDenom returns the trace path and the base denom from -// the elements that constitute the complete denom. -func extractPathAndBaseFromFullDenom(fullDenomItems []string) (string, string) { - var ( - pathSlice []string - baseDenomSlice []string - ) - - length := len(fullDenomItems) - for i := 0; i < length; i += 2 { - // The IBC specification does not guarantee the expected format of the - // destination port or destination channel identifier. A short term solution - // to determine base denomination is to expect the channel identifier to be the - // one ibc-go specifies. A longer term solution is to separate the path and base - // denomination in the ICS20 packet. If an intermediate hop prefixes the full denom - // with a channel identifier format different from our own, the base denomination - // will be incorrectly parsed, but the token will continue to be treated correctly - // as an IBC denomination. The hash used to store the token internally on our chain - // will be the same value as the base denomination being correctly parsed. - if i < length-1 && length > 2 && channeltypes.IsValidChannelID(fullDenomItems[i+1]) { - pathSlice = append(pathSlice, fullDenomItems[i], fullDenomItems[i+1]) - } else { - baseDenomSlice = fullDenomItems[i:] - break - } - } - - path := strings.Join(pathSlice, "/") - baseDenom := strings.Join(baseDenomSlice, "/") - - return path, baseDenom -} - func validateTraceIdentifiers(identifiers []string) error { if len(identifiers) == 0 || len(identifiers)%2 != 0 { return fmt.Errorf("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}', got the identifiers: %s", identifiers) @@ -199,11 +166,12 @@ func ValidatePrefixedDenom(denom string) error { return nil } - path, baseDenom := extractPathAndBaseFromFullDenom(denomSplit) + pathSlice, baseDenom := denominternal.ExtractPathAndBaseFromFullDenom(denomSplit) if strings.TrimSpace(baseDenom) == "" { return errorsmod.Wrap(ErrInvalidDenomForTransfer, "base denomination cannot be blank") } + path := strings.Join(pathSlice, "/") if path == "" { // NOTE: base denom contains slashes, so no base denomination validation return nil diff --git a/modules/apps/transfer/types/v3/packet.go b/modules/apps/transfer/types/v3/packet.go new file mode 100644 index 00000000000..44494bfdefe --- /dev/null +++ b/modules/apps/transfer/types/v3/packet.go @@ -0,0 +1,15 @@ +package v3 + +// NewFungibleTokenPacketData constructs a new FungibleTokenPacketData instance +func NewFungibleTokenPacketData( + tokens []*Token, + sender, receiver string, + memo string, +) FungibleTokenPacketData { + return FungibleTokenPacketData{ + Tokens: tokens, + Sender: sender, + Receiver: receiver, + Memo: memo, + } +} From 4e551372a1b76bda66b2eb76ecbdbb63c5608637 Mon Sep 17 00:00:00 2001 From: Charly Date: Mon, 22 Apr 2024 15:01:40 +0200 Subject: [PATCH 007/141] chore: implement required `FungibleTokenPacketData` v3 interface methods (#6126) --- modules/apps/transfer/internal/denom/denom.go | 22 + modules/apps/transfer/types/trace.go | 22 +- modules/apps/transfer/types/v3/packet.go | 101 +++- modules/apps/transfer/types/v3/packet_test.go | 436 ++++++++++++++++++ modules/apps/transfer/types/v3/token.go | 36 ++ modules/apps/transfer/types/v3/token_test.go | 140 ++++++ 6 files changed, 736 insertions(+), 21 deletions(-) create mode 100644 modules/apps/transfer/types/v3/packet_test.go create mode 100644 modules/apps/transfer/types/v3/token.go create mode 100644 modules/apps/transfer/types/v3/token_test.go diff --git a/modules/apps/transfer/internal/denom/denom.go b/modules/apps/transfer/internal/denom/denom.go index 972528cd0c0..e6b9d7b7680 100644 --- a/modules/apps/transfer/internal/denom/denom.go +++ b/modules/apps/transfer/internal/denom/denom.go @@ -1,9 +1,13 @@ package denom import ( + "fmt" "strings" + errorsmod "cosmossdk.io/errors" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) // ExtractPathAndBaseFromFullDenom returns the trace path and the base denom from @@ -37,3 +41,21 @@ func ExtractPathAndBaseFromFullDenom(fullDenomItems []string) ([]string, string) return pathSlice, baseDenom } + +// ValidateTraceIdentifiers validates the correctness of the trace associated with a particular base denom. +func ValidateTraceIdentifiers(identifiers []string) error { + if len(identifiers) == 0 || len(identifiers)%2 != 0 { + return fmt.Errorf("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}', got the identifiers: %s", identifiers) + } + + // validate correctness of port and channel identifiers + for i := 0; i < len(identifiers); i += 2 { + if err := host.PortIdentifierValidator(identifiers[i]); err != nil { + return errorsmod.Wrapf(err, "invalid port ID at position %d", i) + } + if err := host.ChannelIdentifierValidator(identifiers[i+1]); err != nil { + return errorsmod.Wrapf(err, "invalid channel ID at position %d", i) + } + } + return nil +} diff --git a/modules/apps/transfer/types/trace.go b/modules/apps/transfer/types/trace.go index 00b1d3fd6f4..ab4e7bbce72 100644 --- a/modules/apps/transfer/types/trace.go +++ b/modules/apps/transfer/types/trace.go @@ -15,7 +15,6 @@ import ( cmttypes "github.com/cometbft/cometbft/types" denominternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/denom" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) // ParseDenomTrace parses a string with the ibc prefix (denom trace) and the base denomination @@ -82,23 +81,6 @@ func (dt DenomTrace) IsNativeDenom() bool { return dt.Path == "" } -func validateTraceIdentifiers(identifiers []string) error { - if len(identifiers) == 0 || len(identifiers)%2 != 0 { - return fmt.Errorf("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}', got the identifiers: %s", identifiers) - } - - // validate correctness of port and channel identifiers - for i := 0; i < len(identifiers); i += 2 { - if err := host.PortIdentifierValidator(identifiers[i]); err != nil { - return errorsmod.Wrapf(err, "invalid port ID at position %d", i) - } - if err := host.ChannelIdentifierValidator(identifiers[i+1]); err != nil { - return errorsmod.Wrapf(err, "invalid channel ID at position %d", i) - } - } - return nil -} - // Validate performs a basic validation of the DenomTrace fields. func (dt DenomTrace) Validate() error { // empty trace is accepted when token lives on the original chain @@ -112,7 +94,7 @@ func (dt DenomTrace) Validate() error { // NOTE: no base denomination validation identifiers := strings.Split(dt.Path, "/") - return validateTraceIdentifiers(identifiers) + return denominternal.ValidateTraceIdentifiers(identifiers) } // Traces defines a wrapper type for a slice of DenomTrace. @@ -178,7 +160,7 @@ func ValidatePrefixedDenom(denom string) error { } identifiers := strings.Split(path, "/") - return validateTraceIdentifiers(identifiers) + return denominternal.ValidateTraceIdentifiers(identifiers) } // ValidateIBCDenom validates that the given denomination is either: diff --git a/modules/apps/transfer/types/v3/packet.go b/modules/apps/transfer/types/v3/packet.go index 44494bfdefe..510a1024cac 100644 --- a/modules/apps/transfer/types/v3/packet.go +++ b/modules/apps/transfer/types/v3/packet.go @@ -1,6 +1,24 @@ package v3 -// NewFungibleTokenPacketData constructs a new FungibleTokenPacketData instance +import ( + "encoding/json" + "errors" + "strings" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +var ( + _ ibcexported.PacketData = (*FungibleTokenPacketData)(nil) + _ ibcexported.PacketDataProvider = (*FungibleTokenPacketData)(nil) +) + +// NewFungibleTokenPacketData constructs a new NewFungibleTokenPacketData instance func NewFungibleTokenPacketData( tokens []*Token, sender, receiver string, @@ -13,3 +31,84 @@ func NewFungibleTokenPacketData( Memo: memo, } } + +// ValidateBasic is used for validating the token transfer. +// NOTE: The addresses formats are not validated as the sender and recipient can have different +// formats defined by their corresponding chains that are not known to IBC. +func (ftpd FungibleTokenPacketData) ValidateBasic() error { + if strings.TrimSpace(ftpd.Sender) == "" { + return errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "sender address cannot be blank") + } + + if strings.TrimSpace(ftpd.Receiver) == "" { + return errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "receiver address cannot be blank") + } + + if len(ftpd.Tokens) == 0 { + return errorsmod.Wrap(types.ErrInvalidAmount, "tokens cannot be empty") + } + + for _, token := range ftpd.Tokens { + amount, ok := sdkmath.NewIntFromString(token.Amount) + if !ok { + return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", token.Amount) + } + + if !amount.IsPositive() { + return errorsmod.Wrapf(types.ErrInvalidAmount, "amount must be strictly positive: got %d", amount) + } + + if err := token.Validate(); err != nil { + return err + } + } + + if len(ftpd.Memo) > types.MaximumMemoLength { + return errorsmod.Wrapf(types.ErrInvalidMemo, "memo must not exceed %d bytes", types.MaximumMemoLength) + } + + return nil +} + +// GetBytes is a helper for serialising +func (ftpd FungibleTokenPacketData) GetBytes() []byte { + bz, err := json.Marshal(&ftpd) + if err != nil { + panic(errors.New("cannot marshal v3 FungibleTokenPacketData into bytes")) + } + + return bz +} + +// GetCustomPacketData interprets the memo field of the packet data as a JSON object +// and returns the value associated with the given key. +// If the key is missing or the memo is not properly formatted, then nil is returned. +func (ftpd FungibleTokenPacketData) GetCustomPacketData(key string) interface{} { + if len(ftpd.Memo) == 0 { + return nil + } + + jsonObject := make(map[string]interface{}) + err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) + if err != nil { + return nil + } + + memoData, found := jsonObject[key] + if !found { + return nil + } + + return memoData +} + +// GetPacketSender returns the sender address embedded in the packet data. +// +// NOTE: +// - The sender address is set by the module which requested the packet to be sent, +// and this module may not have validated the sender address by a signature check. +// - The sender address must only be used by modules on the sending chain. +// - sourcePortID is not used in this implementation. +func (ftpd FungibleTokenPacketData) GetPacketSender(sourcePortID string) string { + return ftpd.Sender +} diff --git a/modules/apps/transfer/types/v3/packet_test.go b/modules/apps/transfer/types/v3/packet_test.go new file mode 100644 index 00000000000..63435d8589e --- /dev/null +++ b/modules/apps/transfer/types/v3/packet_test.go @@ -0,0 +1,436 @@ +package v3 + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cometbft/cometbft/crypto/secp256k1" + + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" +) + +const ( + denom = "atom/pool" + amount = "1000" + largeAmount = "18446744073709551616" // one greater than largest uint64 (^uint64(0)) + invalidLargeAmount = "115792089237316195423570985008687907853269984665640564039457584007913129639936" // 2^256 +) + +var ( + sender = secp256k1.GenPrivKey().PubKey().Address().String() + receiver = sdk.AccAddress("testaddr2").String() +) + +// TestFungibleTokenPacketDataValidateBasic tests ValidateBasic for FungibleTokenPacketData +func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { + testCases := []struct { + name string + packetData FungibleTokenPacketData + expErr error + }{ + { + "success: valid packet", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + nil, + }, + { + "success: valid packet with memo", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "memo", + ), + nil, + }, + { + "success: valid packet with large amount", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: largeAmount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "memo", + ), + nil, + }, + { + "failure: invalid denom", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: "", + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + types.ErrInvalidDenomForTransfer, + }, + { + "failure: invalid empty amount", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: "", + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + types.ErrInvalidAmount, + }, + { + "failure: invalid empty token array", + NewFungibleTokenPacketData( + []*Token{}, + sender, + receiver, + "", + ), + types.ErrInvalidAmount, + }, + { + "failure: invalid zero amount", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: "0", + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + types.ErrInvalidAmount, + }, + { + "failure: invalid negative amount", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: "-100", + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + types.ErrInvalidAmount, + }, + { + "failure: invalid large amount", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: invalidLargeAmount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "memo", + ), + types.ErrInvalidAmount, + }, + { + "failure: missing sender address", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + "", + receiver, + "memo", + ), + ibcerrors.ErrInvalidAddress, + }, + { + "failure: missing recipient address", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + "", + "", + ), + ibcerrors.ErrInvalidAddress, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.packetData.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + require.NoError(t, err, tc.name) + } else { + require.ErrorContains(t, err, tc.expErr.Error(), tc.name) + } + }) + } +} + +func TestGetPacketSender(t *testing.T) { + testCases := []struct { + name string + packetData FungibleTokenPacketData + expSender string + }{ + { + "non-empty sender field", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + sender, + }, + { + "empty sender field", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + "", + receiver, + "abc", + ), + "", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + require.Equal(t, tc.expSender, tc.packetData.GetPacketSender(types.PortID)) + }) + } +} + +func TestPacketDataProvider(t *testing.T) { + testCases := []struct { + name string + packetData FungibleTokenPacketData + expCustomData interface{} + }{ + { + "success: src_callback key in memo", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver)), + + map[string]interface{}{ + "address": receiver, + }, + }, + { + "success: src_callback key in memo with additional fields", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, receiver)), + map[string]interface{}{ + "address": receiver, + "gas_limit": "200000", + }, + }, + { + "success: src_callback has string value", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + `{"src_callback": "string"}`), + "string", + }, + { + "failure: src_callback key not found memo", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + fmt.Sprintf(`{"dest_callback": {"address": "%s", "min_gas": "200000"}}`, receiver)), + nil, + }, + { + "failure: empty memo", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + ""), + nil, + }, + { + "failure: non-json memo", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "invalid"), + nil, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + customData := tc.packetData.GetCustomPacketData("src_callback") + require.Equal(t, tc.expCustomData, customData) + }) + } +} + +func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { + testCases := []struct { + name string + packetData FungibleTokenPacketData + expMemo bool + }{ + { + "empty memo field, resulting marshalled bytes should not contain the memo field", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + false, + }, + { + "non-empty memo field, resulting marshalled bytes should contain the memo field", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "abc", + ), + true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + bz, err := json.Marshal(tc.packetData) + if tc.expMemo { + require.NoError(t, err, tc.name) + // check that the memo field is present in the marshalled bytes + require.Contains(t, string(bz), "memo") + } else { + require.NoError(t, err, tc.name) + // check that the memo field is not present in the marshalled bytes + require.NotContains(t, string(bz), "memo") + } + }) + } +} diff --git a/modules/apps/transfer/types/v3/token.go b/modules/apps/transfer/types/v3/token.go new file mode 100644 index 00000000000..21a658723c8 --- /dev/null +++ b/modules/apps/transfer/types/v3/token.go @@ -0,0 +1,36 @@ +package v3 + +import ( + "strings" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + + denominternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/denom" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" +) + +// ValidateToken validates a token denomination and trace identifiers. +func (t Token) Validate() error { + if err := sdk.ValidateDenom(t.Denom); err != nil { + return errorsmod.Wrap(types.ErrInvalidDenomForTransfer, err.Error()) + } + + trace := strings.Join(t.Trace, "/") + identifiers := strings.Split(trace, "/") + + return denominternal.ValidateTraceIdentifiers(identifiers) +} + +// GetFullDenomPath returns the full denomination according to the ICS20 specification: +// tracePath + "/" + baseDenom +// If there exists no trace then the base denomination is returned. +func (t Token) GetFullDenomPath() string { + trace := strings.Join(t.Trace, "/") + if len(trace) == 0 { + return t.Denom + } + + return strings.Join(append(t.Trace, t.Denom), "/") +} diff --git a/modules/apps/transfer/types/v3/token_test.go b/modules/apps/transfer/types/v3/token_test.go new file mode 100644 index 00000000000..13654cfcc1d --- /dev/null +++ b/modules/apps/transfer/types/v3/token_test.go @@ -0,0 +1,140 @@ +package v3 + +import ( + fmt "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" +) + +func TestGetFullDenomPath(t *testing.T) { + testCases := []struct { + name string + packetData FungibleTokenPacketData + expPath string + }{ + { + "denom path with trace", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + "transfer/channel-0/transfer/channel-1/atom/pool", + }, + { + "nil trace", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{}, + }, + }, + sender, + receiver, + "", + ), + denom, + }, + { + "empty string trace", + NewFungibleTokenPacketData( + []*Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{""}, + }, + }, + sender, + receiver, + "", + ), + denom, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + path := tc.packetData.Tokens[0].GetFullDenomPath() + require.Equal(t, tc.expPath, path) + }) + } +} + +func TestValidate(t *testing.T) { + testCases := []struct { + name string + token Token + expError error + }{ + { + "success: multiple port channel pair denom", + Token{ + Denom: "atom", + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + nil, + }, + { + "success: one port channel pair denom", + Token{ + Denom: "uatom", + Amount: amount, + Trace: []string{"transfer/channel-1"}, + }, + nil, + }, + { + "success: non transfer port trace", + Token{ + Denom: "uatom", + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1", "transfer-custom/channel-2"}, + }, + nil, + }, + { + "failure: empty denom", + Token{ + Denom: "", + Amount: amount, + Trace: nil, + }, + types.ErrInvalidDenomForTransfer, + }, + { + "failure: invalid identifier in trace", + Token{ + Denom: "uatom", + Amount: amount, + Trace: []string{"transfer/channel-1", "randomport"}, + }, + fmt.Errorf("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}', got the identifiers: [transfer channel-1 randomport]"), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.token.Validate() + expPass := tc.expError == nil + if expPass { + require.NoError(t, err, tc.name) + } else { + require.ErrorContains(t, err, tc.expError.Error(), tc.name) + } + }) + } +} From ca056cf1fb19c696f870ad9b700fc59212eddc24 Mon Sep 17 00:00:00 2001 From: Charly Date: Mon, 29 Apr 2024 21:27:58 +0200 Subject: [PATCH 008/141] imp: `getMultiDenomFungibleTokenPacketData`to be used in packet unmarshalling/conversion (#6226) * chore: adding proto files for ics20-v2 * chore: add newline * chore: modify MsgTransfer to accept coins instead of coin * chore: reverted unintentional comment changes * chore: reverted unintentional comment changes * chore: adding test for conversion fn * chore: fix e2e linter * chore: adding docs * chore: addressing PR feedback * chore: remove duplicate import * chore: addressing PR feedback * chore: moved extration logic into internal package * chore: commented out failing test * chore: adding link to issue * chore: remove duplicate import * chore: fix linting errors * FungibleTokenPacketData interface methods + tests * linter * wip: token validation * update trace identifier validation in Token + tests * rm Printf * update with pr review * add CurrentVersion, EscrowVersion, update tests * pr review * fix e2e tests * pr review * update e2e test version * linter * update hardcoded transfer channel version from interchaintest * update hardcoded transfer channel version from interchaintest * wip packet unmarshaller * wip * wip testing * update test * linter * rm unnecessary version changes * rm unnecessary artifacts * update callbacks test * update comment * pr review * rename getMultiDenomFungibleTokenPacketData to unmarshalPacketDataBytesToICS20V2 --------- Co-authored-by: chatton Co-authored-by: Carlos Rodriguez --- modules/apps/callbacks/ibc_middleware_test.go | 18 +++- modules/apps/transfer/ibc_module.go | 31 ++++++- modules/apps/transfer/ibc_module_test.go | 88 +++++++++++++++++-- .../apps/transfer/internal/convert/convert.go | 10 +-- .../transfer/internal/convert/convert_test.go | 13 +++ 5 files changed, 140 insertions(+), 20 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 180ca3eb056..1b265db095c 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/ibc-go/modules/apps/callbacks/types" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + multidenom "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/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" @@ -950,14 +951,27 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { unmarshalerStack, ok := transferStack.(types.CallbacksCompatibleModule) s.Require().True(ok) - expPacketData := transfertypes.FungibleTokenPacketData{ + initialPacketData := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: ibctesting.TestAccAddress, Receiver: ibctesting.TestAccAddress, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), } - data := expPacketData.GetBytes() + data := initialPacketData.GetBytes() + + expPacketData := multidenom.FungibleTokenPacketData{ + Tokens: []*multidenom.Token{ + { + Denom: initialPacketData.Denom, + Amount: initialPacketData.Amount, + Trace: []string{""}, + }, + }, + Sender: initialPacketData.Sender, + Receiver: initialPacketData.Receiver, + Memo: initialPacketData.Memo, + } packetData, err := unmarshalerStack.UnmarshalPacketData(data) s.Require().NoError(err) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 4cfd55ffdef..ed9e1526a53 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -11,8 +11,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + convertinternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + multidenom "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" 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" @@ -170,6 +172,27 @@ func (IBCModule) OnChanCloseConfirm( return nil } +func (IBCModule) unmarshalPacketDataBytesToICS20V2(bz []byte) (multidenom.FungibleTokenPacketData, error) { + // TODO: remove support for this function parsing v1 packet data + // TODO: explicit check for packet data type against app version + + var datav1 types.FungibleTokenPacketData + if err := json.Unmarshal(bz, &datav1); err == nil { + if len(datav1.Denom) != 0 { + return convertinternal.PacketDataV1ToV3(datav1), nil + } + } + + var data multidenom.FungibleTokenPacketData + if err := json.Unmarshal(bz, &data); err == nil { + if len(data.Tokens) != 0 { + return data, nil + } + } + + return multidenom.FungibleTokenPacketData{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data") +} + // 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. @@ -351,11 +374,11 @@ func (IBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, pr // 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 (IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { - var packetData types.FungibleTokenPacketData - if err := json.Unmarshal(bz, &packetData); err != nil { +func (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { + ftpd, err := im.unmarshalPacketDataBytesToICS20V2(bz) + if err != nil { return nil, err } - return packetData, nil + return ftpd, nil } diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index ad4b0be3861..62282b5f9a1 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -9,6 +9,7 @@ import ( 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" + multidenom "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" 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" @@ -474,8 +475,8 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - data []byte - expPacketData types.FungibleTokenPacketData + data []byte + initialPacketData interface{} ) testCases := []struct { @@ -484,30 +485,87 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { expPass bool }{ { - "success: valid packet data with memo", + "success: valid packet data single denom -> multidenom conversion with memo", func() { - expPacketData = types.FungibleTokenPacketData{ + initialPacketData = types.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: "some memo", } - data = expPacketData.GetBytes() + + data = initialPacketData.(types.FungibleTokenPacketData).GetBytes() }, true, }, { - "success: valid packet data without memo", + "success: valid packet data single denom -> multidenom conversion without memo", func() { - expPacketData = types.FungibleTokenPacketData{ + initialPacketData = types.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: "", } - data = expPacketData.GetBytes() + + data = initialPacketData.(types.FungibleTokenPacketData).GetBytes() + }, + true, + }, + { + "success: valid packet data single denom with trace -> multidenom conversion with trace", + func() { + initialPacketData = types.FungibleTokenPacketData{ + Denom: "transfer/channel-0/atom", + Amount: ibctesting.TestCoin.Amount.String(), + Sender: sender, + Receiver: receiver, + Memo: "", + } + + data = initialPacketData.(types.FungibleTokenPacketData).GetBytes() + }, + true, + }, + { + "success: valid packet data multidenom with memo", + func() { + initialPacketData = multidenom.FungibleTokenPacketData{ + Tokens: []*multidenom.Token{ + { + Denom: "atom", + Amount: ibctesting.TestCoin.Amount.String(), + Trace: []string{"transfer/channel-0"}, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: "some memo", + } + + data = initialPacketData.(multidenom.FungibleTokenPacketData).GetBytes() + }, + true, + }, + { + "success: valid packet data multidenom without memo", + func() { + initialPacketData = multidenom.FungibleTokenPacketData{ + Tokens: []*multidenom.Token{ + { + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Trace: []string{""}, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: "", + } + + data = initialPacketData.(multidenom.FungibleTokenPacketData).GetBytes() }, true, }, @@ -529,7 +587,19 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { if tc.expPass { suite.Require().NoError(err) - suite.Require().Equal(expPacketData, packetData) + + v3PacketData, ok := packetData.(multidenom.FungibleTokenPacketData) + suite.Require().True(ok) + + if v1PacketData, ok := initialPacketData.(types.FungibleTokenPacketData); ok { + // Note: testing of the denom trace parsing/conversion should be done as part of testing internal conversion functions + suite.Require().Equal(v1PacketData.Amount, v3PacketData.Tokens[0].Amount) + suite.Require().Equal(v1PacketData.Sender, v3PacketData.Sender) + suite.Require().Equal(v1PacketData.Receiver, v3PacketData.Receiver) + suite.Require().Equal(v1PacketData.Memo, v3PacketData.Memo) + } else { + suite.Require().Equal(initialPacketData.(multidenom.FungibleTokenPacketData), v3PacketData) + } } else { suite.Require().Error(err) suite.Require().Nil(packetData) diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go index 34ba1da17e6..f68a9ed808e 100644 --- a/modules/apps/transfer/internal/convert/convert.go +++ b/modules/apps/transfer/internal/convert/convert.go @@ -32,13 +32,13 @@ func PacketDataV1ToV3(packetData v1types.FungibleTokenPacketData) v3types.Fungib func extractDenomAndTraceFromV1Denom(v1Denom string) (string, []string) { v1DenomTrace := v1types.ParseDenomTrace(v1Denom) - splitPath := strings.Split(v1DenomTrace.Path, "/") - - // if the path slice is empty, then the base denom is the full native denom. - if len(splitPath) == 0 { - return v1DenomTrace.BaseDenom, nil + // if the path string is empty, then the base denom is the full native denom. + if v1DenomTrace.Path == "" { + return v1DenomTrace.BaseDenom, []string{""} } + splitPath := strings.Split(v1DenomTrace.Path, "/") + // this condition should never be reached. if len(splitPath)%2 != 0 { panic("pathSlice length is not even") diff --git a/modules/apps/transfer/internal/convert/convert_test.go b/modules/apps/transfer/internal/convert/convert_test.go index f43731ad5dd..006bf3eeb32 100644 --- a/modules/apps/transfer/internal/convert/convert_test.go +++ b/modules/apps/transfer/internal/convert/convert_test.go @@ -36,6 +36,19 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { }, sender, receiver, ""), nil, }, + { + "success with empty trace", + v1types.NewFungibleTokenPacketData("atom", "1000", sender, receiver, ""), + v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: "atom", + Amount: "1000", + Trace: []string{""}, + }, + }, sender, receiver, ""), + nil, + }, { "success: base denom with '/'", v1types.NewFungibleTokenPacketData("transfer/channel-0/atom/withslash", "1000", sender, receiver, ""), From 147cf1789bbde4fc1b479daca94169ed2146a38d Mon Sep 17 00:00:00 2001 From: Charly Date: Mon, 6 May 2024 09:47:02 +0200 Subject: [PATCH 009/141] chore: implement version checking for channel handshake application callbacks (#6175) * add SupportedVersions array for different ics20 versions, add version checking on channel handshake application callbacks * add tests * update pr review * pr review * last few pr review nits * linter * add version counter proposing * fix missing app versino * update code + tests to return our proposed version if counterparty version is invalid * remove if statement * address review comments: return ics20-2 if counterparty version is not supported --------- Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/ibc_module.go | 29 +++++---- modules/apps/transfer/ibc_module_test.go | 78 ++++++++++++++---------- modules/apps/transfer/types/keys.go | 3 + 3 files changed, 64 insertions(+), 46 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index ed9e1526a53..995ba0523e1 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "math" + "slices" "strings" errorsmod "cosmossdk.io/errors" @@ -87,12 +88,13 @@ func (im IBCModule) OnChanOpenInit( return "", err } + // default to latest supported version if strings.TrimSpace(version) == "" { version = types.Version } - if version != types.Version { - return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, version) + if !slices.Contains(types.SupportedVersions, version) { + return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected one of %s, got %s", types.SupportedVersions, version) } // Claim channel capability passed back by IBC module @@ -118,8 +120,8 @@ func (im IBCModule) OnChanOpenTry( return "", err } - if counterpartyVersion != types.Version { - return "", errorsmod.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: expected %s, got %s", types.Version, counterpartyVersion) + if !slices.Contains(types.SupportedVersions, counterpartyVersion) { + return types.Version, nil } // OpenTry must claim the channelCapability that IBC passes into the callback @@ -127,7 +129,7 @@ func (im IBCModule) OnChanOpenTry( return "", err } - return types.Version, nil + return counterpartyVersion, nil } // OnChanOpenAck implements the IBCModule interface @@ -138,9 +140,10 @@ func (IBCModule) OnChanOpenAck( _ string, counterpartyVersion string, ) error { - if counterpartyVersion != types.Version { - return errorsmod.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: expected %s, got %s", types.Version, counterpartyVersion) + if !slices.Contains(types.SupportedVersions, counterpartyVersion) { + return errorsmod.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: expected one of %s, got %s", types.SupportedVersions, counterpartyVersion) } + return nil } @@ -338,8 +341,8 @@ func (im IBCModule) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, return "", err } - if proposedVersion != types.Version { - return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, proposedVersion) + if !slices.Contains(types.SupportedVersions, proposedVersion) { + return "", errorsmod.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: expected one of %s, got %s", types.SupportedVersions, proposedVersion) } return proposedVersion, nil @@ -351,8 +354,8 @@ func (im IBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, return "", err } - if counterpartyVersion != types.Version { - return "", errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, counterpartyVersion) + if !slices.Contains(types.SupportedVersions, counterpartyVersion) { + return types.Version, nil } return counterpartyVersion, nil @@ -360,8 +363,8 @@ func (im IBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, // OnChanUpgradeAck implements the IBCModule interface func (IBCModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { - if counterpartyVersion != types.Version { - return errorsmod.Wrapf(types.ErrInvalidVersion, "expected %s, got %s", types.Version, counterpartyVersion) + if !slices.Contains(types.SupportedVersions, counterpartyVersion) { + return errorsmod.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: expected one of %s, got %s", types.SupportedVersions, counterpartyVersion) } return nil diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 62282b5f9a1..4acb9b6501a 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -26,50 +26,56 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { ) testCases := []struct { - name string - malleate func() - expPass bool + name string + malleate func() + expPass bool + expVersion string }{ { - "success", func() {}, true, + "success", func() {}, true, types.Version, }, { // connection hops is not used in the transfer application callback, // it is already validated in the core OnChanUpgradeInit. "success: invalid connection hops", func() { path.EndpointA.ConnectionID = "invalid-connection-id" - }, true, + }, true, types.Version, }, { - "empty version string", func() { + "success: empty version string", func() { channel.Version = "" - }, true, + }, true, types.Version, + }, + { + "success: ics20-1 legacy", func() { + channel.Version = types.Version1 + }, true, types.Version1, }, { "max channels reached", func() { path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(math.MaxUint32 + 1) - }, false, + }, false, "", }, { "invalid order - ORDERED", func() { channel.Ordering = channeltypes.ORDERED - }, false, + }, false, "", }, { "invalid port ID", func() { path.EndpointA.ChannelConfig.PortID = ibctesting.MockPort - }, false, + }, false, "", }, { "invalid version", func() { channel.Version = "version" //nolint:goconst - }, false, + }, false, "", }, { "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) - }, false, + }, false, "", }, } @@ -104,7 +110,7 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { if tc.expPass { suite.Require().NoError(err) - suite.Require().Equal(types.Version, version) + suite.Require().Equal(tc.expVersion, version) } else { suite.Require().Error(err) suite.Require().Equal(version, "") @@ -123,38 +129,44 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { ) testCases := []struct { - name string - malleate func() - expPass bool + name string + malleate func() + expPass bool + expVersion string }{ { - "success", func() {}, true, + "success", func() {}, true, types.Version, + }, + { + "success: counterparty version is legacy ics20-1", func() { + counterpartyVersion = types.Version1 + }, true, types.Version1, + }, + { + "success: invalid counterparty version, we use our proposed version", func() { + counterpartyVersion = "version" + }, true, types.Version, }, { "max channels reached", func() { path.EndpointA.ChannelID = channeltypes.FormatChannelIdentifier(math.MaxUint32 + 1) - }, false, + }, false, "", }, { "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) - }, false, + }, false, "", }, { "invalid order - ORDERED", func() { channel.Ordering = channeltypes.ORDERED - }, false, + }, false, "", }, { "invalid port ID", func() { path.EndpointA.ChannelConfig.PortID = ibctesting.MockPort - }, false, - }, - { - "invalid counterparty version", func() { - counterpartyVersion = "version" - }, false, + }, false, "", }, } @@ -195,7 +207,7 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { if tc.expPass { suite.Require().NoError(err) - suite.Require().Equal(types.Version, version) + suite.Require().Equal(tc.expVersion, version) } else { suite.Require().Error(err) suite.Require().Equal("", version) @@ -340,18 +352,18 @@ func (suite *TransferTestSuite) TestOnChanUpgradeTry() { nil, }, { - "invalid upgrade ordering", + "success: invalid upgrade version from counterparty, we use our proposed version", func() { - counterpartyUpgrade.Fields.Ordering = channeltypes.ORDERED + counterpartyUpgrade.Fields.Version = ibctesting.InvalidID }, - channeltypes.ErrInvalidChannelOrdering, + nil, }, { - "invalid upgrade version", + "invalid upgrade ordering", func() { - counterpartyUpgrade.Fields.Version = ibctesting.InvalidID + counterpartyUpgrade.Fields.Ordering = channeltypes.ORDERED }, - types.ErrInvalidVersion, + channeltypes.ErrInvalidChannelOrdering, }, } diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index 8db04bb87bb..d985438ab71 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -51,6 +51,9 @@ var ( PortKey = []byte{0x01} // DenomTraceKey defines the key to store the denomination trace info in store DenomTraceKey = []byte{0x02} + + // SupportedVersions defines all versions that are supported by the module + SupportedVersions = []string{Version, Version1} ) // GetEscrowAddress returns the escrow address for the specified channel. From 9bbfa1a5f1cfae05889ca832f22271352d49d429 Mon Sep 17 00:00:00 2001 From: Charly Date: Mon, 6 May 2024 09:51:01 +0200 Subject: [PATCH 010/141] imp: update transfer authz implementation to account for multi denom transfers (#6252) * add transfer authz code + tests * linter * address review comments --------- Co-authored-by: Carlos Rodriguez --- .../transfer/types/transfer_authorization.go | 84 ++++++++++++------- .../types/transfer_authorization_test.go | 27 ++++-- 2 files changed, 76 insertions(+), 35 deletions(-) diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index b38702f980a..e5612c6442e 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -22,6 +22,10 @@ import ( var _ authz.Authorization = (*TransferAuthorization)(nil) +const ( + allocationNotFound = -1 +) + // maxUint256 is the maximum value for a 256 bit unsigned integer. var maxUint256 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1)) @@ -38,48 +42,47 @@ func (TransferAuthorization) MsgTypeURL() string { } // Accept implements Authorization.Accept. -func (a TransferAuthorization) Accept(ctx context.Context, msg proto.Message) (authz.AcceptResponse, error) { +func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) (authz.AcceptResponse, error) { msgTransfer, ok := msg.(*MsgTransfer) if !ok { return authz.AcceptResponse{}, errorsmod.Wrap(ibcerrors.ErrInvalidType, "type mismatch") } - // TODO: replace with correct usage in https://github.com/cosmos/ibc-go/issues/5802 - token := msgTransfer.GetTokens()[0] + index := getAllocationIndex(*msgTransfer, a.Allocations) + if index == allocationNotFound { + return authz.AcceptResponse{}, errorsmod.Wrapf(ibcerrors.ErrNotFound, "requested port and channel allocation does not exist") + } - for index, allocation := range a.Allocations { - if !(allocation.SourceChannel == msgTransfer.SourceChannel && allocation.SourcePort == msgTransfer.SourcePort) { - continue - } + allocation := a.Allocations[index] + ctx := sdk.UnwrapSDKContext(goCtx) - if !isAllowedAddress(sdk.UnwrapSDKContext(ctx), msgTransfer.Receiver, allocation.AllowList) { - return authz.AcceptResponse{}, errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "not allowed receiver address for transfer") - } + if !isAllowedAddress(ctx, msgTransfer.Receiver, allocation.AllowList) { + return authz.AcceptResponse{}, errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "not allowed receiver address for transfer") + } - err := validateMemo(sdk.UnwrapSDKContext(ctx), msgTransfer.Memo, allocation.AllowedPacketData) - if err != nil { - return authz.AcceptResponse{}, err - } + err := validateMemo(ctx, msgTransfer.Memo, allocation.AllowedPacketData) + if err != nil { + return authz.AcceptResponse{}, err + } + // bool flag to see if we have updated any of the allocations + allocationModified := false + + // update spend limit for each token in the MsgTransfer + for _, token := range msgTransfer.GetTokens() { // If the spend limit is set to the MaxUint256 sentinel value, do not subtract the amount from the spend limit. + // if there is no unlimited spend, then we need to subtract the amount from the spend limit to get the limit left if allocation.SpendLimit.AmountOf(token.Denom).Equal(UnboundedSpendLimit()) { - return authz.AcceptResponse{Accept: true, Delete: false, Updated: nil}, nil + continue } - limitLeft, isNegative := allocation.SpendLimit.SafeSub(token) + limitLeft, isNegative := a.Allocations[index].SpendLimit.SafeSub(token) if isNegative { - return authz.AcceptResponse{}, errorsmod.Wrapf(ibcerrors.ErrInsufficientFunds, "requested amount is more than spend limit") + return authz.AcceptResponse{}, errorsmod.Wrapf(ibcerrors.ErrInsufficientFunds, "requested amount of token %s is more than spend limit", token.Denom) } - if limitLeft.IsZero() { - a.Allocations = append(a.Allocations[:index], a.Allocations[index+1:]...) - if len(a.Allocations) == 0 { - return authz.AcceptResponse{Accept: true, Delete: true}, nil - } - return authz.AcceptResponse{Accept: true, Delete: false, Updated: &TransferAuthorization{ - Allocations: a.Allocations, - }}, nil - } + allocationModified = true + a.Allocations[index] = Allocation{ SourcePort: allocation.SourcePort, SourceChannel: allocation.SourceChannel, @@ -87,13 +90,24 @@ func (a TransferAuthorization) Accept(ctx context.Context, msg proto.Message) (a AllowList: allocation.AllowList, AllowedPacketData: allocation.AllowedPacketData, } + } + + // if the spend limit is zero of the associated allocation then we delete it. + if a.Allocations[index].SpendLimit.IsZero() { + a.Allocations = append(a.Allocations[:index], a.Allocations[index+1:]...) + } + + if len(a.Allocations) == 0 { + return authz.AcceptResponse{Accept: true, Delete: true}, nil + } - return authz.AcceptResponse{Accept: true, Delete: false, Updated: &TransferAuthorization{ - Allocations: a.Allocations, - }}, nil + if !allocationModified { + return authz.AcceptResponse{Accept: true, Delete: false, Updated: nil}, nil } - return authz.AcceptResponse{}, errorsmod.Wrapf(ibcerrors.ErrNotFound, "requested port and channel allocation does not exist") + return authz.AcceptResponse{Accept: true, Delete: false, Updated: &TransferAuthorization{ + Allocations: a.Allocations, + }}, nil } // ValidateBasic implements Authorization.ValidateBasic. @@ -212,3 +226,13 @@ func validateMemo(ctx sdk.Context, memo string, allowedPacketDataList []string) func UnboundedSpendLimit() sdkmath.Int { return sdkmath.NewIntFromBigInt(maxUint256) } + +// getAllocationIndex ranges through a set of allocations, and returns the index of the allocation if found. If not, returns -1. +func getAllocationIndex(msg MsgTransfer, allocations []Allocation) int { + for index, allocation := range allocations { + if allocation.SourceChannel == msg.SourceChannel && allocation.SourcePort == msg.SourcePort { + return index + } + } + return allocationNotFound +} diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index d86c396d335..063200c9d92 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -67,15 +67,32 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { }, }, { - "success: with multiple allocations", + "success: with multiple allocations and multidenom transfer", func() { - alloc := types.Allocation{ + coins := sdk.NewCoins( + ibctesting.TestCoin, + sdk.NewCoin("atom", sdkmath.NewInt(100)), + sdk.NewCoin("osmo", sdkmath.NewInt(100)), + ) + + allocation := types.Allocation{ SourcePort: ibctesting.MockPort, SourceChannel: "channel-9", - SpendLimit: ibctesting.TestCoins, + SpendLimit: coins, } - transferAuthz.Allocations = append(transferAuthz.Allocations, alloc) + transferAuthz.Allocations = append(transferAuthz.Allocations, allocation) + + msgTransfer = types.NewMsgTransfer( + ibctesting.MockPort, + "channel-9", + coins, + suite.chainA.SenderAccount.GetAddress().String(), + ibctesting.TestAccAddress, + suite.chainB.GetTimeoutHeight(), + 0, + "", + ) }, func(res authz.AcceptResponse, err error) { suite.Require().NoError(err) @@ -86,7 +103,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { updatedAuthz, ok := res.Updated.(*types.TransferAuthorization) suite.Require().True(ok) - // assert spent spendlimit is removed from the list + // assert spent spendlimits are removed from the list suite.Require().Len(updatedAuthz.Allocations, 1) }, }, From 4f57916f000ce36e9a6a9ab5c07a63f85c11ff31 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 10 May 2024 10:42:22 +0200 Subject: [PATCH 011/141] ics20-v2: backwards compatibility for transfer rpc and packet callbacks (#6189) * chore: adding proto files for ics20-v2 * chore: add newline * chore: modify MsgTransfer to accept coins instead of coin * chore: reverted unintentional comment changes * chore: reverted unintentional comment changes * chore: adding test for conversion fn * chore: fix e2e linter * chore: adding docs * chore: addressing PR feedback * chore: remove duplicate import * chore: addressing PR feedback * chore: moved extration logic into internal package * chore: commented out failing test * chore: adding link to issue * chore: remove duplicate import * chore: fix linting errors * FungibleTokenPacketData interface methods + tests * linter * wip: token validation * update trace identifier validation in Token + tests * rm Printf * update with pr review * pr review * linter * rm unused function: linter * wip pr feedback * fix test * pr review * lintttttt * wip: backwards compatibility for transfer rpc * implement changes for ics20-v2 packet data for onRecvPacket, onAcknowledgePacket and onTimeoutPacket * fix callbacks tests * lint --------- Co-authored-by: chatton Co-authored-by: Charly --- modules/apps/callbacks/ibc_middleware_test.go | 105 +++-- modules/apps/transfer/ibc_module.go | 109 +++-- .../apps/transfer/internal/convert/convert.go | 12 +- .../transfer/internal/convert/convert_test.go | 28 +- .../apps/transfer/keeper/mbt_relay_test.go | 25 +- modules/apps/transfer/keeper/msg_server.go | 48 ++- .../apps/transfer/keeper/msg_server_test.go | 150 +++++-- modules/apps/transfer/keeper/relay.go | 379 ++++++++++-------- modules/apps/transfer/keeper/relay_test.go | 132 +++--- modules/apps/transfer/types/events.go | 1 + modules/apps/transfer/types/v3/token.go | 4 + testing/solomachine.go | 23 +- 12 files changed, 635 insertions(+), 381 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 1b265db095c..c08f531ca3d 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -13,8 +13,8 @@ import ( "github.com/cosmos/ibc-go/modules/apps/callbacks/testing/simapp" "github.com/cosmos/ibc-go/modules/apps/callbacks/types" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - multidenom "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" + transferv1types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + transferv3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/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" @@ -94,7 +94,7 @@ func (s *CallbacksTestSuite) TestWithICS4Wrapper() { } func (s *CallbacksTestSuite) TestSendPacket() { - var packetData transfertypes.FungibleTokenPacketData + var packetData transferv3types.FungibleTokenPacketData testCases := []struct { name string @@ -165,9 +165,17 @@ func (s *CallbacksTestSuite) TestSendPacket() { transferICS4Wrapper := GetSimApp(s.chainA).TransferKeeper.GetICS4Wrapper() - packetData = transfertypes.NewFungibleTokenPacketData( - ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, - ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract), + packetData = transferv3types.NewFungibleTokenPacketData( + []*transferv3types.Token{ + { + Denom: ibctesting.TestCoin.GetDenom(), + Amount: ibctesting.TestCoin.Amount.String(), + Trace: []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) @@ -223,7 +231,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { ) var ( - packetData transfertypes.FungibleTokenPacketData + packetData transferv3types.FungibleTokenPacketData packet channeltypes.Packet ack []byte ctx sdk.Context @@ -299,8 +307,16 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { s.SetupTransferTest() userGasLimit = 600000 - packetData = transfertypes.NewFungibleTokenPacketData( - ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, ibctesting.TestAccAddress, + packetData = transferv3types.NewFungibleTokenPacketData( + []*transferv3types.Token{ + { + Denom: ibctesting.TestCoin.GetDenom(), + Amount: ibctesting.TestCoin.Amount.String(), + Trace: []string{}, + }, + }, + ibctesting.TestAccAddress, + ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, simapp.SuccessContract, userGasLimit), ) @@ -323,7 +339,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { tc.malleate() // callbacks module is routed as top level middleware - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName) s.Require().True(ok) onAcknowledgementPacket := func() error { @@ -385,7 +401,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { ) var ( - packetData transfertypes.FungibleTokenPacketData + packetData transferv3types.FungibleTokenPacketData packet channeltypes.Packet ctx sdk.Context ) @@ -408,7 +424,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { packet.Data = []byte("invalid packet data") }, noExecution, - ibcerrors.ErrUnknownRequest, + ibcerrors.ErrInvalidType, }, { "success: no-op on callback data is not valid", @@ -462,7 +478,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { // succeed on timeout userGasLimit := 600_000 timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano()) - msg := transfertypes.NewMsgTransfer( + msg := transferv1types.NewMsgTransfer( s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp, @@ -486,7 +502,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { tc.malleate() // callbacks module is routed as top level middleware - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName) s.Require().True(ok) onTimeoutPacket := func() error { @@ -547,7 +563,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { ) var ( - packetData transfertypes.FungibleTokenPacketData + packetData transferv3types.FungibleTokenPacketData packet channeltypes.Packet ctx sdk.Context userGasLimit uint64 @@ -624,8 +640,16 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { // set user gas limit above panic level in mock contract keeper userGasLimit = 600_000 - packetData = transfertypes.NewFungibleTokenPacketData( - ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), + packetData = transferv3types.NewFungibleTokenPacketData( + []*transferv3types.Token{ + { + Denom: ibctesting.TestCoin.GetDenom(), + Amount: ibctesting.TestCoin.Amount.String(), + Trace: []string{}, + }, + }, + ibctesting.TestAccAddress, + s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), ) @@ -646,7 +670,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { tc.malleate() // callbacks module is routed as top level middleware - transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName) s.Require().True(ok) onRecvPacket := func() ibcexported.Acknowledgement { @@ -701,7 +725,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { func (s *CallbacksTestSuite) TestWriteAcknowledgement() { var ( - packetData transfertypes.FungibleTokenPacketData + packetData transferv3types.FungibleTokenPacketData packet channeltypes.Packet ctx sdk.Context ack ibcexported.Acknowledgement @@ -748,8 +772,16 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { s.SetupTransferTest() // set user gas limit above panic level in mock contract keeper - packetData = transfertypes.NewFungibleTokenPacketData( - ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), + packetData = transferv3types.NewFungibleTokenPacketData( + []*transferv3types.Token{ + { + Denom: ibctesting.TestCoin.GetDenom(), + Amount: ibctesting.TestCoin.Amount.String(), + Trace: []string{}, + }, + }, + ibctesting.TestAccAddress, + s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), ) @@ -945,37 +977,44 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { // We will pass the function call down the transfer stack to the transfer module // transfer stack UnmarshalPacketData call order: callbacks -> fee -> transfer - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName) s.Require().True(ok) unmarshalerStack, ok := transferStack.(types.CallbacksCompatibleModule) s.Require().True(ok) - initialPacketData := transfertypes.FungibleTokenPacketData{ + expPacketDataICS20V1 := transferv1types.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: ibctesting.TestAccAddress, Receiver: ibctesting.TestAccAddress, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), } - data := initialPacketData.GetBytes() - expPacketData := multidenom.FungibleTokenPacketData{ - Tokens: []*multidenom.Token{ + expPacketDataICS20V2 := transferv3types.FungibleTokenPacketData{ + Tokens: []*transferv3types.Token{ { - Denom: initialPacketData.Denom, - Amount: initialPacketData.Amount, - Trace: []string{""}, + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Trace: nil, }, }, - Sender: initialPacketData.Sender, - Receiver: initialPacketData.Receiver, - Memo: initialPacketData.Memo, + Sender: ibctesting.TestAccAddress, + Receiver: ibctesting.TestAccAddress, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), } + // Unmarshal ICS20 v1 packet data + data := expPacketDataICS20V1.GetBytes() packetData, err := unmarshalerStack.UnmarshalPacketData(data) s.Require().NoError(err) - s.Require().Equal(expPacketData, packetData) + s.Require().Equal(expPacketDataICS20V2, packetData) + + // Unmarshal ICS20 v1 packet data + data = expPacketDataICS20V2.GetBytes() + packetData, err = unmarshalerStack.UnmarshalPacketData(data) + s.Require().NoError(err) + s.Require().Equal(expPacketDataICS20V2, packetData) } func (s *CallbacksTestSuite) TestGetAppVersion() { diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 995ba0523e1..595c014f00b 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -207,10 +207,8 @@ func (im IBCModule) OnRecvPacket( logger := im.keeper.Logger(ctx) ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - var data types.FungibleTokenPacketData - var ackErr error - if err := json.Unmarshal(packet.GetData(), &data); err != nil { - ackErr = errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data") + data, ackErr := im.unmarshalPacketDataBytesToICS20V2(packet.GetData()) + if ackErr != nil { logger.Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence)) ack = channeltypes.NewErrorAcknowledgement(ackErr) } @@ -228,26 +226,32 @@ func (im IBCModule) OnRecvPacket( } } + events := make([]sdk.Event, 0, len(data.Tokens)+1) + for _, token := range data.Tokens { + events = append(events, sdk.NewEvent( + types.EventTypePacket, + sdk.NewAttribute(types.AttributeKeySender, data.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), + sdk.NewAttribute(types.AttributeKeyDenom, token.GetFullDenomPath()), + sdk.NewAttribute(types.AttributeKeyAmount, token.Amount), + sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), + )) + } + eventAttributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), - sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), - sdk.NewAttribute(types.AttributeKeyAmount, data.Amount), - sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), } - if ackErr != nil { eventAttributes = append(eventAttributes, sdk.NewAttribute(types.AttributeKeyAckError, ackErr.Error())) } - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypePacket, - eventAttributes..., - ), - ) + events = append(events, sdk.NewEvent( + sdk.EventTypeMessage, + eventAttributes..., + )) + + ctx.EventManager().EmitEvents(events) // NOTE: acknowledgement will be written synchronously during IBC handler execution. return ack @@ -264,27 +268,35 @@ func (im IBCModule) OnAcknowledgementPacket( if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err) } - var data types.FungibleTokenPacketData - if err := json.Unmarshal(packet.GetData(), &data); err != nil { - return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error()) + + data, err := im.unmarshalPacketDataBytesToICS20V2(packet.GetData()) + if err != nil { + return err } if err := im.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil { return err } - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypePacket, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), - sdk.NewAttribute(types.AttributeKeyDenom, data.Denom), - sdk.NewAttribute(types.AttributeKeyAmount, data.Amount), - sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), - sdk.NewAttribute(types.AttributeKeyAck, ack.String()), - ), - ) + events := make([]sdk.Event, 0, len(data.Tokens)+1) + for _, token := range data.Tokens { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypePacket, + sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), + sdk.NewAttribute(types.AttributeKeyDenom, token.GetFullDenomPath()), + sdk.NewAttribute(types.AttributeKeyAmount, token.Amount), + sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), + ), + ) + } + events = append(events, sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeyAck, ack.String()), + )) + ctx.EventManager().EmitEvents(events) switch resp := ack.Response.(type) { case *channeltypes.Acknowledgement_Result: @@ -312,25 +324,34 @@ func (im IBCModule) OnTimeoutPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) error { - var data types.FungibleTokenPacketData - if err := json.Unmarshal(packet.GetData(), &data); err != nil { - return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error()) + data, err := im.unmarshalPacketDataBytesToICS20V2(packet.GetData()) + if err != nil { + return err } + // refund tokens if err := im.keeper.OnTimeoutPacket(ctx, packet, data); err != nil { return err } - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeTimeout, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(types.AttributeKeyRefundReceiver, data.Sender), - sdk.NewAttribute(types.AttributeKeyRefundDenom, data.Denom), - sdk.NewAttribute(types.AttributeKeyRefundAmount, data.Amount), - sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), - ), - ) + events := make([]sdk.Event, 0, len(data.Tokens)+1) + for _, token := range data.Tokens { + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeTimeout, + sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), + sdk.NewAttribute(types.AttributeKeyDenom, token.GetFullDenomPath()), + sdk.NewAttribute(types.AttributeKeyAmount, token.Amount), + sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), + ), + ) + } + events = append(events, sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + )) + ctx.EventManager().EmitEvents(events) return nil } diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go index f68a9ed808e..2665974d64c 100644 --- a/modules/apps/transfer/internal/convert/convert.go +++ b/modules/apps/transfer/internal/convert/convert.go @@ -3,17 +3,17 @@ package convert import ( "strings" - v1types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" ) // PacketDataV1ToV3 converts a v1 (ICS20-V1) packet data to a v3 (ICS20-V2) packet data. -func PacketDataV1ToV3(packetData v1types.FungibleTokenPacketData) v3types.FungibleTokenPacketData { +func PacketDataV1ToV3(packetData types.FungibleTokenPacketData) v3types.FungibleTokenPacketData { if err := packetData.ValidateBasic(); err != nil { panic(err) } - v2Denom, trace := extractDenomAndTraceFromV1Denom(packetData.Denom) + v2Denom, trace := ExtractDenomAndTraceFromV1Denom(packetData.Denom) return v3types.FungibleTokenPacketData{ Tokens: []*v3types.Token{ { @@ -29,12 +29,12 @@ func PacketDataV1ToV3(packetData v1types.FungibleTokenPacketData) v3types.Fungib } // extractDenomAndTraceFromV1Denom extracts the base denom and remaining trace from a v1 IBC denom. -func extractDenomAndTraceFromV1Denom(v1Denom string) (string, []string) { - v1DenomTrace := v1types.ParseDenomTrace(v1Denom) +func ExtractDenomAndTraceFromV1Denom(v1Denom string) (string, []string) { + v1DenomTrace := types.ParseDenomTrace(v1Denom) // if the path string is empty, then the base denom is the full native denom. if v1DenomTrace.Path == "" { - return v1DenomTrace.BaseDenom, []string{""} + return v1DenomTrace.BaseDenom, nil } splitPath := strings.Split(v1DenomTrace.Path, "/") diff --git a/modules/apps/transfer/internal/convert/convert_test.go b/modules/apps/transfer/internal/convert/convert_test.go index 006bf3eeb32..b406210ad47 100644 --- a/modules/apps/transfer/internal/convert/convert_test.go +++ b/modules/apps/transfer/internal/convert/convert_test.go @@ -7,7 +7,7 @@ import ( errorsmod "cosmossdk.io/errors" - v1types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" ) @@ -19,13 +19,13 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { testCases := []struct { name string - v1Data v1types.FungibleTokenPacketData + v1Data types.FungibleTokenPacketData v3Data v3types.FungibleTokenPacketData expPanic error }{ { "success", - v1types.NewFungibleTokenPacketData("transfer/channel-0/atom", "1000", sender, receiver, ""), + types.NewFungibleTokenPacketData("transfer/channel-0/atom", "1000", sender, receiver, ""), v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -38,20 +38,20 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { }, { "success with empty trace", - v1types.NewFungibleTokenPacketData("atom", "1000", sender, receiver, ""), + types.NewFungibleTokenPacketData("atom", "1000", sender, receiver, ""), v3types.NewFungibleTokenPacketData( []*v3types.Token{ { Denom: "atom", Amount: "1000", - Trace: []string{""}, + Trace: nil, }, }, sender, receiver, ""), nil, }, { "success: base denom with '/'", - v1types.NewFungibleTokenPacketData("transfer/channel-0/atom/withslash", "1000", sender, receiver, ""), + types.NewFungibleTokenPacketData("transfer/channel-0/atom/withslash", "1000", sender, receiver, ""), v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -64,7 +64,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { }, { "success: base denom with '/' at the end", - v1types.NewFungibleTokenPacketData("transfer/channel-0/atom/", "1000", sender, receiver, ""), + types.NewFungibleTokenPacketData("transfer/channel-0/atom/", "1000", sender, receiver, ""), v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -77,7 +77,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { }, { "success: longer trace base denom with '/'", - v1types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/atom/pool", "1000", sender, receiver, ""), + types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/atom/pool", "1000", sender, receiver, ""), v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -90,7 +90,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { }, { "success: longer trace with non transfer port", - v1types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/transfer-custom/channel-2/atom", "1000", sender, receiver, ""), + types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/transfer-custom/channel-2/atom", "1000", sender, receiver, ""), v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -103,7 +103,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { }, { "success: base denom with slash, trace with non transfer port", - v1types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/transfer-custom/channel-2/atom/pool", "1000", sender, receiver, ""), + types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/transfer-custom/channel-2/atom/pool", "1000", sender, receiver, ""), v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -116,9 +116,9 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { }, { "failure: panics with empty denom", - v1types.NewFungibleTokenPacketData("", "1000", sender, receiver, ""), + types.NewFungibleTokenPacketData("", "1000", sender, receiver, ""), v3types.FungibleTokenPacketData{}, - errorsmod.Wrap(v1types.ErrInvalidDenomForTransfer, "base denomination cannot be blank"), + errorsmod.Wrap(types.ErrInvalidDenomForTransfer, "base denomination cannot be blank"), }, } @@ -126,11 +126,11 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { expPass := tc.expPanic == nil if expPass { v3Data := PacketDataV1ToV3(tc.v1Data) - require.Equal(t, tc.v3Data, v3Data) + require.Equal(t, tc.v3Data, v3Data, "test case: %s", tc.name) } else { require.PanicsWithError(t, tc.expPanic.Error(), func() { PacketDataV1ToV3(tc.v1Data) - }) + }, "test case: %s", tc.name) } } } diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index e2abbde9f1a..d12abd8a589 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -19,7 +19,9 @@ import ( "github.com/cometbft/cometbft/crypto" + convert "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" @@ -65,7 +67,7 @@ type FungibleTokenPacket struct { SourcePort string DestChannel string DestPort string - Data types.FungibleTokenPacketData + Data v3types.FungibleTokenPacketData } type OnRecvPacketTestCase = struct { @@ -143,17 +145,24 @@ func BalancesFromTla(tla []TlaBalance) []Balance { } func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPacket { + denom, trace := convert.ExtractDenomAndTraceFromV1Denom(DenomFromTla(packet.Data.Denom)) return FungibleTokenPacket{ SourceChannel: packet.SourceChannel, SourcePort: packet.SourcePort, DestChannel: packet.DestChannel, DestPort: packet.DestPort, - Data: types.NewFungibleTokenPacketData( - DenomFromTla(packet.Data.Denom), - packet.Data.Amount, + Data: v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: denom, + Amount: packet.Data.Amount, + Trace: trace, + }, + }, AddressFromString(packet.Data.Sender), AddressFromString(packet.Data.Receiver), - ""), + "", + ), } } @@ -310,7 +319,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { for i, tlaTc := range tlaTestCases { tc := OnRecvPacketTestCaseFromTla(tlaTc) registerDenomFn := func() { - denomTrace := types.ParseDenomTrace(tc.packet.Data.Denom) + denomTrace := types.ParseDenomTrace(tc.packet.Data.Tokens[0].GetFullDenomPath()) traceHash := denomTrace.Hash() if !suite.chainB.GetSimApp().TransferKeeper.HasDenomTrace(suite.chainB.GetContext(), traceHash) { suite.chainB.GetSimApp().TransferKeeper.SetDenomTrace(suite.chainB.GetContext(), denomTrace) @@ -337,11 +346,11 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { panic(errors.New("MBT failed to convert sender address")) } registerDenomFn() - denomTrace := types.ParseDenomTrace(tc.packet.Data.Denom) + denomTrace := types.ParseDenomTrace(tc.packet.Data.Tokens[0].GetFullDenomPath()) denom := denomTrace.IBCDenom() err = sdk.ValidateDenom(denom) if err == nil { - amount, ok := sdkmath.NewIntFromString(tc.packet.Data.Amount) + amount, ok := sdkmath.NewIntFromString(tc.packet.Data.Tokens[0].Amount) if !ok { panic(errors.New("MBT failed to parse amount from string")) } diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 94536cba937..aa81a9a228a 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -26,11 +26,24 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. return nil, err } - // TODO: replace with correct usage. - token := msg.GetTokens()[0] + // tokens will always be an array, but may contain a single element + // if the ics20-1 token field is populated, and the ics20-2 array is empty. + tokens := msg.GetTokens() - if !k.bankKeeper.IsSendEnabledCoin(ctx, token) { - return nil, errorsmod.Wrapf(types.ErrSendDisabled, "%s transfers are currently disabled", token.Denom) + 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) + } + + // ics20-1 only supports a single token, so if that is the current version, we must only process a single token. + if appVersion == types.Version1 && len(tokens) > 1 { + return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "cannot transfer multiple tokens with ics20-1") + } + + for _, token := range tokens { + if !k.bankKeeper.IsSendEnabledCoin(ctx, token) { + return nil, errorsmod.Wrapf(types.ErrSendDisabled, "transfers are currently disabled for %s", token.Denom) + } } if k.bankKeeper.BlockedAddr(sender) { @@ -38,28 +51,29 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. } sequence, err := k.sendTransfer( - ctx, msg.SourcePort, msg.SourceChannel, token, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, + ctx, msg.SourcePort, msg.SourceChannel, tokens, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Memo) if err != nil { return nil, err } - k.Logger(ctx).Info("IBC fungible token transfer", "token", token.Denom, "amount", token.Amount.String(), "sender", msg.Sender, "receiver", msg.Receiver) - - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( + events := make([]sdk.Event, 0, len(tokens)+1) + for _, token := range tokens { + k.Logger(ctx).Info("IBC fungible token transfer", "token", token.Denom, "amount", token.Amount.String(), "sender", msg.Sender, "receiver", msg.Receiver) + events = append(events, sdk.NewEvent( types.EventTypeTransfer, - sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + sdk.NewAttribute(types.AttributeKeySender, msg.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), - sdk.NewAttribute(types.AttributeKeyAmount, token.Amount.String()), sdk.NewAttribute(types.AttributeKeyDenom, token.Denom), + sdk.NewAttribute(types.AttributeKeyAmount, token.Amount.String()), sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), - ), - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - ), - }) + )) + } + events = append(events, sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + )) + ctx.EventManager().EmitEvents(events) return &types.MsgTransferResponse{Sequence: sequence}, nil } diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 957ccf82c94..355b21e5b88 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -1,27 +1,62 @@ package keeper_test import ( + "errors" + "strings" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + abci "github.com/cometbft/cometbft/abci/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" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) // TestMsgTransfer tests Transfer rpc handler func (suite *KeeperTestSuite) TestMsgTransfer() { var msg *types.MsgTransfer + var path *ibctesting.Path + var coin1 sdk.Coin + var coin2 sdk.Coin testCases := []struct { - name string - malleate func() - expPass bool + name string + malleate func() + expError error + multiDenom bool }{ { - "success", + "success: single denom", func() {}, + nil, + false, + }, + { + "success: multi-denom with version ics20-2", + func() { + coin2 = sdk.NewCoin("bond", sdkmath.NewInt(100)) + coins := sdk.NewCoins(coin1, coin2) + + // send some coins of the second denom from bank module to the sender account as well + suite.Require().NoError(suite.chainA.GetSimApp().BankKeeper.MintCoins(suite.chainA.GetContext(), types.ModuleName, sdk.NewCoins(coin2))) + suite.Require().NoError(suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, suite.chainA.SenderAccount.GetAddress(), sdk.NewCoins(coin2))) + + msg = types.NewMsgTransfer( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + coins, + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + suite.chainB.GetTimeoutHeight(), 0, // only use timeout height + "memo", + ) + }, + nil, true, }, { @@ -34,10 +69,11 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { ) suite.Require().NoError(err) }, - true, + nil, + false, }, { - "send transfers disabled", + "failure: send transfers disabled", func() { suite.chainA.GetSimApp().TransferKeeper.SetParams(suite.chainA.GetContext(), types.Params{ @@ -45,24 +81,27 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { }, ) }, + types.ErrSendDisabled, false, }, { - "invalid sender", + "failure: invalid sender", func() { msg.Sender = "address" }, + errors.New("decoding bech32 failed"), false, }, { - "sender is a blocked address", + "failure: sender is a blocked address", func() { msg.Sender = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName).String() }, + ibcerrors.ErrUnauthorized, false, }, { - "bank send disabled for denom", + "failure: bank send disabled for denom", func() { err := suite.chainA.GetSimApp().BankKeeper.SetParams(suite.chainA.GetContext(), banktypes.Params{ @@ -71,15 +110,45 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { ) suite.Require().NoError(err) }, + types.ErrSendDisabled, false, }, { - "channel does not exist", + "failure: channel does not exist", func() { msg.SourceChannel = "channel-100" }, + ibcerrors.ErrInvalidRequest, false, }, + { + "failure: multidenom with ics20-1", + func() { + coin2 = sdk.NewCoin("bond", sdkmath.NewInt(100)) + coins := sdk.NewCoins(coin1, coin2) + + // send some coins of the second denom from bank module to the sender account as well + suite.Require().NoError(suite.chainA.GetSimApp().BankKeeper.MintCoins(suite.chainA.GetContext(), types.ModuleName, sdk.NewCoins(coin2))) + suite.Require().NoError(suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, suite.chainA.SenderAccount.GetAddress(), sdk.NewCoins(coin2))) + + msg = types.NewMsgTransfer( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + coins, + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + suite.chainB.GetTimeoutHeight(), 0, // only use timeout height + "memo", + ) + + // explicitly set to ics20-1 which does not support multi-denom + path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { + channel.Version = types.Version1 + }) + }, + ibcerrors.ErrInvalidRequest, + true, + }, } for _, tc := range testCases { @@ -88,14 +157,16 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.Run(tc.name, func() { suite.SetupTest() - path := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path = ibctesting.NewTransferPath(suite.chainA, suite.chainB) path.Setup() - coin := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) + coin1 = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) msg = types.NewMsgTransfer( path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, - sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), + sdk.NewCoins(coin1), + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", ) @@ -107,24 +178,55 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { // Verify events events := ctx.EventManager().Events().ToABCIEvents() - expEvents := ibctesting.EventsMap{ - "ibc_transfer": { - "sender": suite.chainA.SenderAccount.GetAddress().String(), - "receiver": suite.chainB.SenderAccount.GetAddress().String(), - "amount": coin.Amount.String(), - "denom": coin.Denom, - "memo": "memo", - }, + + var expEvents []abci.Event + if tc.multiDenom { + expEvents = sdk.Events{ + sdk.NewEvent(types.EventTypeTransfer, + sdk.NewAttribute(types.AttributeKeySender, msg.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), + sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), + sdk.NewAttribute(types.AttributeKeyDenom, coin1.Denom), + sdk.NewAttribute(types.AttributeKeyAmount, coin1.Amount.String()), + ), + sdk.NewEvent(types.EventTypeTransfer, + sdk.NewAttribute(types.AttributeKeySender, msg.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), + sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), + sdk.NewAttribute(types.AttributeKeyDenom, coin2.Denom), + sdk.NewAttribute(types.AttributeKeyAmount, coin2.Amount.String()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }.ToABCIEvents() + } else { + expEvents = sdk.Events{ + sdk.NewEvent(types.EventTypeTransfer, + sdk.NewAttribute(types.AttributeKeySender, msg.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), + sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), + sdk.NewAttribute(types.AttributeKeyDenom, coin1.Denom), + sdk.NewAttribute(types.AttributeKeyAmount, coin1.Amount.String()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }.ToABCIEvents() } - if tc.expPass { + expPass := tc.expError == nil + if expPass { suite.Require().NoError(err) suite.Require().NotNil(res) suite.Require().NotEqual(res.Sequence, uint64(0)) - ibctesting.AssertEventsLegacy(&suite.Suite, expEvents, events) + ibctesting.AssertEvents(&suite.Suite, expEvents, events) } else { - suite.Require().Error(err) suite.Require().Nil(res) + suite.Require().Error(err) + suite.Require().True(errors.Is(err, tc.expError) || strings.Contains(err.Error(), tc.expError.Error()), err.Error()) suite.Require().Len(events, 0) } }) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 3bae0b9da03..0671d64fffd 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -12,7 +12,9 @@ import ( "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" 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" @@ -56,7 +58,7 @@ func (k Keeper) sendTransfer( ctx sdk.Context, sourcePort, sourceChannel string, - token sdk.Coin, + coins sdk.Coins, sender sdk.AccAddress, receiver string, timeoutHeight clienttypes.Height, @@ -71,6 +73,11 @@ func (k Keeper) sendTransfer( destinationPort := channel.Counterparty.PortId destinationChannel := channel.Counterparty.ChannelId + labels := []metrics.Label{ + telemetry.NewLabel(coretypes.LabelDestinationPort, destinationPort), + telemetry.NewLabel(coretypes.LabelDestinationChannel, destinationChannel), + } + // 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)) @@ -78,61 +85,66 @@ func (k Keeper) sendTransfer( 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 tokens []*v3types.Token - var err error + for _, coin := range coins { + // NOTE: denomination and hex hash correctness checked during msg.ValidateBasic + fullDenomPath := coin.Denom - // 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 + var err error + + // deconstruct the token denomination into the denomination trace info + // to determine if the sender is the source chain + if strings.HasPrefix(coin.Denom, "ibc/") { + fullDenomPath, err = k.DenomPathFromHash(ctx, coin.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. - // 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")) - 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, coin); err != nil { + return 0, err + } - // 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")) - } 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(coin), + ); err != nil { + return 0, err + } - // 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(coin), + ); 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)) + } } - 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)) + denom, trace := convert.ExtractDenomAndTraceFromV1Denom(fullDenomPath) + token := &v3types.Token{ + Denom: denom, + Amount: coin.Amount.String(), + Trace: trace, } + tokens = append(tokens, token) } - packetData := types.NewFungibleTokenPacketData( - fullDenomPath, token.Amount.String(), sender.String(), receiver, memo, - ) + packetData := v3types.NewFungibleTokenPacketData(tokens, sender.String(), receiver, memo) sequence, err := k.ics4Wrapper.SendPacket(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, packetData.GetBytes()) if err != nil { @@ -140,12 +152,15 @@ func (k Keeper) sendTransfer( } defer func() { - if token.Amount.IsInt64() { - telemetry.SetGaugeWithLabels( - []string{"tx", "msg", "ibc", "transfer"}, - float32(token.Amount.Int64()), - []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, fullDenomPath)}, - ) + for _, token := range tokens { + amount, ok := sdkmath.NewIntFromString(token.Amount) + if ok && amount.IsInt64() { + telemetry.SetGaugeWithLabels( + []string{"tx", "msg", "ibc", "transfer"}, + float32(amount.Int64()), + []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, token.GetFullDenomPath())}, + ) + } } telemetry.IncrCounterWithLabels( @@ -163,7 +178,7 @@ func (k Keeper) sendTransfer( // and sent to the receiving address. Otherwise if the sender chain is sending // back tokens this chain originally transferred to it, the tokens are // unescrowed and sent to the receiving address. -func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketData) error { +func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { // validate packet data upon receiving if err := data.ValidateBasic(); err != nil { return errorsmod.Wrapf(err, "error validating ICS-20 transfer packet data") @@ -179,49 +194,114 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver) } - // parse the transfer amount - transferAmount, ok := sdkmath.NewIntFromString(data.Amount) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount: %s", data.Amount) - } + for _, token := range data.Tokens { + fullDenomPath := token.GetFullDenomPath() - labels := []metrics.Label{ - telemetry.NewLabel(coretypes.LabelSourcePort, packet.GetSourcePort()), - telemetry.NewLabel(coretypes.LabelSourceChannel, packet.GetSourceChannel()), - } + labels := []metrics.Label{ + telemetry.NewLabel(coretypes.LabelSourcePort, packet.GetSourcePort()), + telemetry.NewLabel(coretypes.LabelSourceChannel, packet.GetSourceChannel()), + } - // This is the prefix that would have been prefixed to the denomination - // on sender chain IF and only if the token originally came from the - // receiving chain. - // - // NOTE: We use SourcePort and SourceChannel here, because the counterparty - // chain would have prefixed with DestPort and DestChannel when originally - // receiving this coin as seen in the "sender chain is the source" condition. - if types.ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) { - // sender chain is not the source, unescrow tokens - - // remove prefix added by sender chain - voucherPrefix := types.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel()) - unprefixedDenom := data.Denom[len(voucherPrefix):] - - // coin denomination used in sending from the escrow address - denom := unprefixedDenom - - // The denomination used to send the coins is either the native denom or the hash of the path - // if the denomination is not native. - denomTrace := types.ParseDenomTrace(unprefixedDenom) - if !denomTrace.IsNativeDenom() { - denom = denomTrace.IBCDenom() + // parse the transfer amount + transferAmount, ok := sdkmath.NewIntFromString(token.Amount) + if !ok { + return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount: %s", token.Amount) } - token := sdk.NewCoin(denom, transferAmount) - if k.bankKeeper.BlockedAddr(receiver) { - return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) + // This is the prefix that would have been prefixed to the denomination + // on sender chain IF and only if the token originally came from the + // receiving chain. + // + // NOTE: We use SourcePort and SourceChannel here, because the counterparty + // chain would have prefixed with DestPort and DestChannel when originally + // receiving this coin as seen in the "sender chain is the source" condition. + if types.ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), fullDenomPath) { + // sender chain is not the source, unescrow tokens + + // remove prefix added by sender chain + voucherPrefix := types.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel()) + unprefixedDenom := fullDenomPath[len(voucherPrefix):] + + // coin denomination used in sending from the escrow address + denom := unprefixedDenom + + // The denomination used to send the coins is either the native denom or the hash of the path + // if the denomination is not native. + denomTrace := types.ParseDenomTrace(unprefixedDenom) + if !denomTrace.IsNativeDenom() { + denom = denomTrace.IBCDenom() + } + token := sdk.NewCoin(denom, transferAmount) + + if k.bankKeeper.BlockedAddr(receiver) { + return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) + } + + escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) + if err := k.unescrowToken(ctx, escrowAddress, receiver, token); err != nil { + return err + } + + defer func() { + if transferAmount.IsInt64() { + telemetry.SetGaugeWithLabels( + []string{"ibc", types.ModuleName, "packet", "receive"}, + float32(transferAmount.Int64()), + []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, unprefixedDenom)}, + ) + } + + telemetry.IncrCounterWithLabels( + []string{"ibc", types.ModuleName, "receive"}, + 1, + append( + labels, telemetry.NewLabel(coretypes.LabelSource, "true"), + ), + ) + }() + + return nil } - escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) - if err := k.unescrowToken(ctx, escrowAddress, receiver, token); err != nil { - return err + // sender chain is the source, mint vouchers + + // since SendPacket did not prefix the denomination, we must prefix denomination here + prefixedDenom := types.GetPrefixedDenom(packet.GetDestPort(), packet.GetDestChannel(), fullDenomPath) + + // construct the denomination trace from the full raw denomination + denomTrace := types.ParseDenomTrace(prefixedDenom) + + traceHash := denomTrace.Hash() + if !k.HasDenomTrace(ctx, traceHash) { + k.SetDenomTrace(ctx, denomTrace) + } + + voucherDenom := denomTrace.IBCDenom() + if !k.bankKeeper.HasDenomMetaData(ctx, voucherDenom) { + k.setDenomMetadata(ctx, denomTrace) + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeDenomTrace, + sdk.NewAttribute(types.AttributeKeyTraceHash, traceHash.String()), + sdk.NewAttribute(types.AttributeKeyDenom, voucherDenom), + ), + ) + voucher := sdk.NewCoin(voucherDenom, transferAmount) + + // mint new tokens if the source of the transfer is the same chain + if err := k.bankKeeper.MintCoins( + ctx, types.ModuleName, sdk.NewCoins(voucher), + ); err != nil { + return errorsmod.Wrap(err, "failed to mint IBC tokens") + } + + // send to receiver + if err := k.bankKeeper.SendCoinsFromModuleToAccount( + ctx, types.ModuleName, receiver, sdk.NewCoins(voucher), + ); err != nil { + return errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()) } defer func() { @@ -229,7 +309,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t telemetry.SetGaugeWithLabels( []string{"ibc", types.ModuleName, "packet", "receive"}, float32(transferAmount.Int64()), - []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, unprefixedDenom)}, + []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, fullDenomPath)}, ) } @@ -237,73 +317,12 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t []string{"ibc", types.ModuleName, "receive"}, 1, append( - labels, telemetry.NewLabel(coretypes.LabelSource, "true"), + labels, telemetry.NewLabel(coretypes.LabelSource, "false"), ), ) }() - - return nil - } - - // sender chain is the source, mint vouchers - - // since SendPacket did not prefix the denomination, we must prefix denomination here - prefixedDenom := types.GetPrefixedDenom(packet.GetDestPort(), packet.GetDestChannel(), data.Denom) - - // construct the denomination trace from the full raw denomination - denomTrace := types.ParseDenomTrace(prefixedDenom) - - traceHash := denomTrace.Hash() - if !k.HasDenomTrace(ctx, traceHash) { - k.SetDenomTrace(ctx, denomTrace) } - voucherDenom := denomTrace.IBCDenom() - if !k.bankKeeper.HasDenomMetaData(ctx, voucherDenom) { - k.setDenomMetadata(ctx, denomTrace) - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeDenomTrace, - sdk.NewAttribute(types.AttributeKeyTraceHash, traceHash.String()), - sdk.NewAttribute(types.AttributeKeyDenom, voucherDenom), - ), - ) - voucher := sdk.NewCoin(voucherDenom, transferAmount) - - // mint new tokens if the source of the transfer is the same chain - if err := k.bankKeeper.MintCoins( - ctx, types.ModuleName, sdk.NewCoins(voucher), - ); err != nil { - return errorsmod.Wrap(err, "failed to mint IBC tokens") - } - - // send to receiver - if err := k.bankKeeper.SendCoinsFromModuleToAccount( - ctx, types.ModuleName, receiver, sdk.NewCoins(voucher), - ); err != nil { - return errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()) - } - - defer func() { - if transferAmount.IsInt64() { - telemetry.SetGaugeWithLabels( - []string{"ibc", types.ModuleName, "packet", "receive"}, - float32(transferAmount.Int64()), - []metrics.Label{telemetry.NewLabel(coretypes.LabelDenom, data.Denom)}, - ) - } - - telemetry.IncrCounterWithLabels( - []string{"ibc", types.ModuleName, "receive"}, - 1, - append( - labels, telemetry.NewLabel(coretypes.LabelSource, "false"), - ), - ) - }() - return nil } @@ -311,7 +330,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t // acknowledgement written on the receiving chain. If the acknowledgement // was a success then nothing occurs. If the acknowledgement failed, then // the sender is refunded their tokens using the refundPacketToken function. -func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketData, ack channeltypes.Acknowledgement) error { +func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData, ack channeltypes.Acknowledgement) error { switch ack.Response.(type) { case *channeltypes.Acknowledgement_Result: // the acknowledgement succeeded on the receiving chain so nothing @@ -326,7 +345,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // OnTimeoutPacket refunds the sender since the original packet sent was // never received and has been timed out. -func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketData) error { +func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { return k.refundPacketToken(ctx, packet, data) } @@ -334,40 +353,44 @@ func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, dat // if the sending chain was the source chain. Otherwise, the sent tokens // were burnt in the original send so new tokens are minted and sent to // the sending address. -func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketData) error { +func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { // NOTE: packet data type already checked in handler.go - // parse the denomination from the full denom path - trace := types.ParseDenomTrace(data.Denom) + for _, token := range data.Tokens { + fullDenomPath := token.GetFullDenomPath() - // parse the transfer amount - transferAmount, ok := sdkmath.NewIntFromString(data.Amount) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", data.Amount) - } - token := sdk.NewCoin(trace.IBCDenom(), transferAmount) + // parse the denomination from the full denom path + trace := types.ParseDenomTrace(fullDenomPath) - // decode the sender address - sender, err := sdk.AccAddressFromBech32(data.Sender) - if err != nil { - return err - } + // parse the transfer amount + transferAmount, ok := sdkmath.NewIntFromString(token.Amount) + if !ok { + return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", transferAmount) + } + token := sdk.NewCoin(trace.IBCDenom(), transferAmount) - if types.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) { - // unescrow tokens back to sender - escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel()) - return k.unescrowToken(ctx, escrowAddress, sender, token) - } + // decode the sender address + sender, err := sdk.AccAddressFromBech32(data.Sender) + if err != nil { + return err + } - // mint vouchers back to sender - if err := k.bankKeeper.MintCoins( - ctx, types.ModuleName, sdk.NewCoins(token), - ); err != nil { - return err - } + if types.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), fullDenomPath) { + // unescrow tokens back to sender + escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel()) + return k.unescrowToken(ctx, escrowAddress, sender, token) + } - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, sdk.NewCoins(token)); err != nil { - panic(fmt.Errorf("unable to send coins from module to account despite previously minting coins to module account: %v", err)) + // mint vouchers back to sender + if err := k.bankKeeper.MintCoins( + ctx, types.ModuleName, sdk.NewCoins(token), + ); err != nil { + return err + } + + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, sdk.NewCoins(token)); err != nil { + panic(fmt.Errorf("unable to send coins from module to account despite previously minting coins to module account: %v", err)) + } } return nil diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 24ab6f9eb69..e4ce18817fb 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -10,7 +10,9 @@ import ( banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -247,10 +249,10 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT // malleate function allows for testing invalid cases. func (suite *KeeperTestSuite) TestOnRecvPacket() { var ( - trace types.DenomTrace amount sdkmath.Int receiver string memo string + denomTrace types.DenomTrace expEscrowAmount sdkmath.Int // total amount in escrow for denom on receiving chain ) @@ -290,7 +292,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "empty coin", func() { - trace = types.DenomTrace{} + denomTrace = types.DenomTrace{} amount = sdkmath.ZeroInt() expEscrowAmount = sdkmath.NewInt(100) }, true, false, @@ -396,20 +398,28 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { seq++ // NOTE: trace must be explicitly changed in malleate to test invalid cases - trace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) + denomTrace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) } else { - trace = types.ParseDenomTrace(sdk.DefaultBondDenom) + denomTrace = types.ParseDenomTrace(sdk.DefaultBondDenom) } // send coin from chainA to chainB - coin := sdk.NewCoin(trace.IBCDenom(), amount) + coin := sdk.NewCoin(denomTrace.IBCDenom(), amount) transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo) _, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed tc.malleate() - data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), suite.chainA.SenderAccount.GetAddress().String(), receiver, memo) + denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + data := v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: denom, + Amount: amount.String(), + Trace: trace, + }, + }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo) packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) @@ -483,12 +493,16 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT BaseDenom: sdk.DefaultBondDenom, Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), } - data := types.NewFungibleTokenPacketData( - denomTrace.GetFullDenomPath(), - amount.String(), - suite.chainA.SenderAccount.GetAddress().String(), - suite.chainB.SenderAccount.GetAddress().String(), "", - ) + + denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + data := v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: denom, + Amount: amount.String(), + Trace: trace, + }, + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "") packet := channeltypes.NewPacket( data.GetBytes(), seq, @@ -537,7 +551,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { var ( successAck = channeltypes.NewResultAcknowledgement([]byte{byte(1)}) failedAck = channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed packet transfer")) - trace types.DenomTrace + denomTrace types.DenomTrace amount sdkmath.Int path *ibctesting.Path expEscrowAmount sdkmath.Int @@ -554,7 +568,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { "success ack causes no-op", successAck, func() { - trace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.DefaultBondDenom)) + denomTrace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.DefaultBondDenom)) }, true, true, }, { @@ -562,7 +576,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { failedAck, func() { escrow := types.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - trace = types.ParseDenomTrace(sdk.DefaultBondDenom) + denomTrace = types.ParseDenomTrace(sdk.DefaultBondDenom) coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) suite.Require().NoError(banktestutil.FundAccount(suite.chainA.GetContext(), suite.chainA.GetSimApp().BankKeeper, escrow, sdk.NewCoins(coin))) @@ -575,7 +589,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { "unsuccessful refund from source", failedAck, func() { - trace = types.ParseDenomTrace(sdk.DefaultBondDenom) + denomTrace = types.ParseDenomTrace(sdk.DefaultBondDenom) // set escrow amount that would have been stored after successful execution of MsgTransfer suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), sdk.NewCoin(sdk.DefaultBondDenom, amount)) @@ -587,8 +601,8 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { failedAck, func() { escrow := types.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - trace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) - coin := sdk.NewCoin(trace.IBCDenom(), amount) + denomTrace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) + coin := sdk.NewCoin(denomTrace.IBCDenom(), amount) suite.Require().NoError(banktestutil.FundAccount(suite.chainA.GetContext(), suite.chainA.GetSimApp().BankKeeper, escrow, sdk.NewCoins(coin))) }, false, true, @@ -607,19 +621,27 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { tc.malleate() - data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "") + denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + data := v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: denom, + Amount: amount.String(), + Trace: trace, + }, + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "") packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom()) + preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denomTrace.IBCDenom()) err := suite.chainA.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, data, tc.ack) // check total amount in escrow of sent token denom on sending chain - totalEscrow := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), trace.IBCDenom()) + totalEscrow := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), denomTrace.IBCDenom()) suite.Require().Equal(expEscrowAmount, totalEscrow.Amount) if tc.expPass { suite.Require().NoError(err) - postCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom()) + postCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denomTrace.IBCDenom()) deltaAmount := postCoin.Amount.Sub(preCoin.Amount) if tc.success { @@ -692,11 +714,18 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo ), ) - data := types.NewFungibleTokenPacketData( - denomTrace.GetFullDenomPath(), - amount.String(), + denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + data := v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: denom, + Amount: amount.String(), + Trace: trace, + }, + }, suite.chainB.SenderAccount.GetAddress().String(), - suite.chainA.SenderAccount.GetAddress().String(), "", + suite.chainA.SenderAccount.GetAddress().String(), + "", ) packet := channeltypes.NewPacket( data.GetBytes(), @@ -726,10 +755,10 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo // so the refunds are occurring on chainA. func (suite *KeeperTestSuite) TestOnTimeoutPacket() { var ( - trace types.DenomTrace path *ibctesting.Path amount sdkmath.Int sender string + denomTrace types.DenomTrace expEscrowAmount sdkmath.Int ) @@ -742,8 +771,8 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { "successful timeout from sender as source chain", func() { escrow := types.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - trace = types.ParseDenomTrace(sdk.DefaultBondDenom) - coin := sdk.NewCoin(trace.IBCDenom(), amount) + denomTrace = types.ParseDenomTrace(sdk.DefaultBondDenom) + coin := sdk.NewCoin(denomTrace.IBCDenom(), amount) expEscrowAmount = sdkmath.ZeroInt() // funds the escrow account to have balance @@ -756,8 +785,8 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { "successful timeout from external chain", func() { escrow := types.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - trace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) - coin := sdk.NewCoin(trace.IBCDenom(), amount) + denomTrace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) + coin := sdk.NewCoin(denomTrace.IBCDenom(), amount) expEscrowAmount = sdkmath.ZeroInt() // funds the escrow account to have balance @@ -767,27 +796,27 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { { "no balance for coin denom", func() { - trace = types.ParseDenomTrace("bitcoin") + denomTrace = types.ParseDenomTrace("bitcoin") expEscrowAmount = amount // set escrow amount that would have been stored after successful execution of MsgTransfer - suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), sdk.NewCoin(trace.IBCDenom(), amount)) + suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), sdk.NewCoin(denomTrace.IBCDenom(), amount)) }, false, }, { "unescrow failed", func() { - trace = types.ParseDenomTrace(sdk.DefaultBondDenom) + denomTrace = types.ParseDenomTrace(sdk.DefaultBondDenom) expEscrowAmount = amount // set escrow amount that would have been stored after successful execution of MsgTransfer - suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), sdk.NewCoin(trace.IBCDenom(), amount)) + suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), sdk.NewCoin(denomTrace.IBCDenom(), amount)) }, false, }, { "mint failed", func() { - trace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) + denomTrace = types.ParseDenomTrace(types.GetPrefixedDenom(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.DefaultBondDenom)) amount = sdkmath.OneInt() sender = "invalid address" }, false, @@ -808,17 +837,25 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { tc.malleate() - data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.String(), sender, suite.chainB.SenderAccount.GetAddress().String(), "") + denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + data := v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: denom, + Amount: amount.String(), + Trace: trace, + }, + }, sender, suite.chainB.SenderAccount.GetAddress().String(), "") packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom()) + preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denomTrace.IBCDenom()) err := suite.chainA.GetSimApp().TransferKeeper.OnTimeoutPacket(suite.chainA.GetContext(), packet, data) - postCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom()) + postCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denomTrace.IBCDenom()) deltaAmount := postCoin.Amount.Sub(preCoin.Amount) // check total amount in escrow of sent token denom on sending chain - totalEscrow := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), trace.IBCDenom()) + totalEscrow := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), denomTrace.IBCDenom()) suite.Require().Equal(expEscrowAmount, totalEscrow.Amount) if tc.expPass { @@ -886,12 +923,15 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI ), ) - data := types.NewFungibleTokenPacketData( - denomTrace.GetFullDenomPath(), - amount.String(), - suite.chainB.SenderAccount.GetAddress().String(), - suite.chainA.SenderAccount.GetAddress().String(), "", - ) + denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + data := v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: denom, + Amount: amount.String(), + Trace: trace, + }, + }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "") packet := channeltypes.NewPacket( data.GetBytes(), seq, diff --git a/modules/apps/transfer/types/events.go b/modules/apps/transfer/types/events.go index 89964a8a9a4..20165a5e576 100644 --- a/modules/apps/transfer/types/events.go +++ b/modules/apps/transfer/types/events.go @@ -8,6 +8,7 @@ const ( EventTypeChannelClose = "channel_closed" EventTypeDenomTrace = "denomination_trace" + AttributeKeySender = "sender" AttributeKeyReceiver = "receiver" AttributeKeyDenom = "denom" AttributeKeyAmount = "amount" diff --git a/modules/apps/transfer/types/v3/token.go b/modules/apps/transfer/types/v3/token.go index 21a658723c8..8eea4eab756 100644 --- a/modules/apps/transfer/types/v3/token.go +++ b/modules/apps/transfer/types/v3/token.go @@ -17,6 +17,10 @@ func (t Token) Validate() error { return errorsmod.Wrap(types.ErrInvalidDenomForTransfer, err.Error()) } + if len(t.Trace) == 0 { + return nil + } + trace := strings.Join(t.Trace, "/") identifiers := strings.Split(trace, "/") diff --git a/testing/solomachine.go b/testing/solomachine.go index 34877aa8535..46151bec3ea 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -369,21 +369,22 @@ func (solo *Solomachine) ChanCloseConfirm(chain *TestChain, portID, channelID st // SendTransfer constructs a MsgTransfer and sends the message to the given chain. Any number of optional // functions can be provided which will modify the MsgTransfer before SendMsgs is called. func (solo *Solomachine) SendTransfer(chain *TestChain, portID, channelID string, fns ...func(*transfertypes.MsgTransfer)) channeltypes.Packet { - msgTransfer := transfertypes.MsgTransfer{ - SourcePort: portID, - SourceChannel: channelID, - Token: sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)), - Sender: chain.SenderAccount.GetAddress().String(), - Receiver: chain.SenderAccount.GetAddress().String(), - TimeoutHeight: clienttypes.ZeroHeight(), - TimeoutTimestamp: uint64(chain.GetContext().BlockTime().Add(time.Hour).UnixNano()), - } + msgTransfer := transfertypes.NewMsgTransfer( + portID, + channelID, + sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), + chain.SenderAccount.GetAddress().String(), + chain.SenderAccount.GetAddress().String(), + clienttypes.ZeroHeight(), + uint64(chain.GetContext().BlockTime().Add(time.Hour).UnixNano()), + "", + ) for _, fn := range fns { - fn(&msgTransfer) + fn(msgTransfer) } - res, err := chain.SendMsgs(&msgTransfer) + res, err := chain.SendMsgs(msgTransfer) require.NoError(solo.t, err) packet, err := ParsePacketFromEvents(res.Events) From e04047ee45221668ef97e14cc4005028616b7606 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Fri, 10 May 2024 13:05:51 +0200 Subject: [PATCH 012/141] add v3 packet proto --- .../ibc/applications/transfer/v3/packet.proto | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/proto/ibc/applications/transfer/v3/packet.proto b/proto/ibc/applications/transfer/v3/packet.proto index 8971472c69d..963a5afc980 100644 --- a/proto/ibc/applications/transfer/v3/packet.proto +++ b/proto/ibc/applications/transfer/v3/packet.proto @@ -16,6 +16,18 @@ message FungibleTokenPacketData { string receiver = 3; // optional memo string memo = 4; + // optional forwardingInfo struct + ForwardingInfo forwardingPath = 10; +} + +message ForwardingInfo { + repeated Hop hop = 1; + string memo = 2; +} + +message Hop { + string portID = 1; + string channelId = 2; } // Token defines a struct which represents a token to be transferred. @@ -27,3 +39,14 @@ message Token { // the trace of the token repeated string trace = 3; } + + +// Token defines a struct which represents a token to be transferred. +message Hop { + // the base token denomination to be transferred + string denom = 1; + // the token amount to be transferred + string amount = 2; + // the trace of the token + repeated string trace = 3; +} \ No newline at end of file From c73d5f66f2ccbd38ccce904c4ab9e1c57fca639d Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Fri, 10 May 2024 13:23:46 +0200 Subject: [PATCH 013/141] fix protos --- modules/apps/transfer/types/transfer.pb.go | 493 +++++++++++++++++- modules/apps/transfer/types/tx.pb.go | 139 +++-- modules/apps/transfer/types/v3/packet.pb.go | 105 +++- .../applications/transfer/v1/transfer.proto | 10 + proto/ibc/applications/transfer/v1/tx.proto | 4 +- .../ibc/applications/transfer/v3/packet.proto | 18 +- 6 files changed, 676 insertions(+), 93 deletions(-) diff --git a/modules/apps/transfer/types/transfer.pb.go b/modules/apps/transfer/types/transfer.pb.go index 99bfa07a587..fb88c9e9e2e 100644 --- a/modules/apps/transfer/types/transfer.pb.go +++ b/modules/apps/transfer/types/transfer.pb.go @@ -139,9 +139,115 @@ func (m *Params) GetReceiveEnabled() bool { return false } +type ForwardingInfo struct { + Hop []*Hop `protobuf:"bytes,1,rep,name=hop,proto3" json:"hop,omitempty"` + Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` +} + +func (m *ForwardingInfo) Reset() { *m = ForwardingInfo{} } +func (m *ForwardingInfo) String() string { return proto.CompactTextString(m) } +func (*ForwardingInfo) ProtoMessage() {} +func (*ForwardingInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_5041673e96e97901, []int{2} +} +func (m *ForwardingInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ForwardingInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ForwardingInfo.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 *ForwardingInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ForwardingInfo.Merge(m, src) +} +func (m *ForwardingInfo) XXX_Size() int { + return m.Size() +} +func (m *ForwardingInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ForwardingInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_ForwardingInfo proto.InternalMessageInfo + +func (m *ForwardingInfo) GetHop() []*Hop { + if m != nil { + return m.Hop + } + return nil +} + +func (m *ForwardingInfo) GetMemo() string { + if m != nil { + return m.Memo + } + return "" +} + +type Hop struct { + PortID string `protobuf:"bytes,1,opt,name=portID,proto3" json:"portID,omitempty"` + ChannelId string `protobuf:"bytes,2,opt,name=channelId,proto3" json:"channelId,omitempty"` +} + +func (m *Hop) Reset() { *m = Hop{} } +func (m *Hop) String() string { return proto.CompactTextString(m) } +func (*Hop) ProtoMessage() {} +func (*Hop) Descriptor() ([]byte, []int) { + return fileDescriptor_5041673e96e97901, []int{3} +} +func (m *Hop) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Hop) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Hop.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 *Hop) XXX_Merge(src proto.Message) { + xxx_messageInfo_Hop.Merge(m, src) +} +func (m *Hop) XXX_Size() int { + return m.Size() +} +func (m *Hop) XXX_DiscardUnknown() { + xxx_messageInfo_Hop.DiscardUnknown(m) +} + +var xxx_messageInfo_Hop proto.InternalMessageInfo + +func (m *Hop) GetPortID() string { + if m != nil { + return m.PortID + } + return "" +} + +func (m *Hop) GetChannelId() string { + if m != nil { + return m.ChannelId + } + return "" +} + func init() { proto.RegisterType((*DenomTrace)(nil), "ibc.applications.transfer.v1.DenomTrace") proto.RegisterType((*Params)(nil), "ibc.applications.transfer.v1.Params") + proto.RegisterType((*ForwardingInfo)(nil), "ibc.applications.transfer.v1.ForwardingInfo") + proto.RegisterType((*Hop)(nil), "ibc.applications.transfer.v1.Hop") } func init() { @@ -149,23 +255,29 @@ func init() { } var fileDescriptor_5041673e96e97901 = []byte{ - // 256 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x90, 0x3f, 0x4b, 0x03, 0x31, - 0x18, 0x87, 0x9b, 0x22, 0xc5, 0x46, 0x51, 0xc8, 0xd4, 0x41, 0x83, 0x76, 0x51, 0x10, 0x2f, 0x14, - 0x07, 0xdd, 0x04, 0xd1, 0x5d, 0x4b, 0x27, 0x97, 0x92, 0xe4, 0x5e, 0xdb, 0xc0, 0xe5, 0x0f, 0x79, - 0xd3, 0x03, 0xbf, 0x85, 0x1f, 0xcb, 0xb1, 0xa3, 0xa3, 0xdc, 0x7d, 0x11, 0xb9, 0x58, 0x8e, 0x6e, - 0x3f, 0x9e, 0x3c, 0x79, 0x87, 0x87, 0xde, 0x18, 0xa5, 0x85, 0x0c, 0xa1, 0x32, 0x5a, 0x26, 0xe3, - 0x1d, 0x8a, 0x14, 0xa5, 0xc3, 0x0f, 0x88, 0xa2, 0x9e, 0xf5, 0xbb, 0x08, 0xd1, 0x27, 0xcf, 0xce, - 0x8c, 0xd2, 0xc5, 0xbe, 0x5c, 0xf4, 0x42, 0x3d, 0x9b, 0x3e, 0x52, 0xfa, 0x0c, 0xce, 0xdb, 0x45, - 0x94, 0x1a, 0x18, 0xa3, 0x07, 0x41, 0xa6, 0xf5, 0x84, 0x5c, 0x90, 0xeb, 0xf1, 0x3c, 0x6f, 0x76, - 0x4e, 0xa9, 0x92, 0x08, 0xcb, 0xb2, 0xd3, 0x26, 0xc3, 0xfc, 0x32, 0xee, 0x48, 0xfe, 0x37, 0x5d, - 0xd0, 0xd1, 0xab, 0x8c, 0xd2, 0x22, 0xbb, 0xa4, 0xc7, 0x08, 0xae, 0x5c, 0x82, 0x93, 0xaa, 0x82, - 0x32, 0x1f, 0x39, 0x9c, 0x1f, 0x75, 0xec, 0xe5, 0x1f, 0xb1, 0x2b, 0x7a, 0x1a, 0x41, 0x83, 0xa9, - 0xa1, 0xb7, 0x86, 0xd9, 0x3a, 0xd9, 0xe1, 0x9d, 0xf8, 0xf4, 0xf6, 0xdd, 0x70, 0xb2, 0x6d, 0x38, - 0xf9, 0x6d, 0x38, 0xf9, 0x6a, 0xf9, 0x60, 0xdb, 0xf2, 0xc1, 0x4f, 0xcb, 0x07, 0xef, 0xf7, 0x2b, - 0x93, 0xd6, 0x1b, 0x55, 0x68, 0x6f, 0x85, 0xf6, 0x68, 0x3d, 0x0a, 0xa3, 0xf4, 0xed, 0xca, 0x8b, - 0xfa, 0x41, 0x58, 0x5f, 0x6e, 0x2a, 0xc0, 0xae, 0xcd, 0x5e, 0x93, 0xf4, 0x19, 0x00, 0xd5, 0x28, - 0xe7, 0xb8, 0xfb, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x24, 0x39, 0xe1, 0x5f, 0x3d, 0x01, 0x00, 0x00, + // 338 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x31, 0x4b, 0xf3, 0x40, + 0x1c, 0xc6, 0x9b, 0xf6, 0xa5, 0xbc, 0xbd, 0x4a, 0x85, 0x1b, 0xa4, 0x43, 0x0d, 0x6d, 0x16, 0x0b, + 0x62, 0x42, 0xed, 0xa0, 0xe0, 0x20, 0x48, 0x95, 0x76, 0xd3, 0xd2, 0x45, 0x97, 0x72, 0xb9, 0xfc, + 0xdb, 0x1c, 0x24, 0xf7, 0x3f, 0xee, 0xd2, 0x88, 0xdf, 0xc2, 0x8f, 0xe5, 0xd8, 0xd1, 0x51, 0xda, + 0x2f, 0x22, 0x39, 0x63, 0xe8, 0xe4, 0xf6, 0xe4, 0x97, 0xdf, 0x1d, 0xf7, 0xf0, 0x90, 0x73, 0x11, + 0xf2, 0x80, 0x29, 0x95, 0x08, 0xce, 0x32, 0x81, 0xd2, 0x04, 0x99, 0x66, 0xd2, 0xac, 0x40, 0x07, + 0xf9, 0xa8, 0xca, 0xbe, 0xd2, 0x98, 0x21, 0xed, 0x89, 0x90, 0xfb, 0x87, 0xb2, 0x5f, 0x09, 0xf9, + 0xc8, 0xbb, 0x25, 0x64, 0x02, 0x12, 0xd3, 0x85, 0x66, 0x1c, 0x28, 0x25, 0xff, 0x14, 0xcb, 0xe2, + 0xae, 0xd3, 0x77, 0x86, 0xad, 0xb9, 0xcd, 0xf4, 0x94, 0x90, 0x90, 0x19, 0x58, 0x46, 0x85, 0xd6, + 0xad, 0xdb, 0x3f, 0xad, 0x82, 0xd8, 0x73, 0xde, 0x82, 0x34, 0x1f, 0x99, 0x66, 0xa9, 0xa1, 0x03, + 0x72, 0x64, 0x40, 0x46, 0x4b, 0x90, 0x2c, 0x4c, 0x20, 0xb2, 0x97, 0xfc, 0x9f, 0xb7, 0x0b, 0x76, + 0xff, 0x83, 0xe8, 0x19, 0x39, 0xd6, 0xc0, 0x41, 0xe4, 0x50, 0x59, 0x75, 0x6b, 0x75, 0x4a, 0x5c, + 0x8a, 0xde, 0x33, 0xe9, 0x3c, 0xa0, 0x7e, 0x65, 0x3a, 0x12, 0x72, 0x3d, 0x93, 0x2b, 0xa4, 0x63, + 0xd2, 0x88, 0x51, 0x75, 0x9d, 0x7e, 0x63, 0xd8, 0xbe, 0x1c, 0xf8, 0x7f, 0x95, 0xf2, 0xa7, 0xa8, + 0xe6, 0x85, 0x5d, 0xf4, 0x49, 0x21, 0xc5, 0xf2, 0xd5, 0x36, 0x7b, 0x37, 0xa4, 0x31, 0x45, 0x45, + 0x4f, 0x48, 0x53, 0xa1, 0xce, 0x66, 0x93, 0xb2, 0x6c, 0xf9, 0x45, 0x7b, 0xa4, 0xc5, 0x63, 0x26, + 0x25, 0x24, 0xb3, 0xe8, 0xb7, 0x6d, 0x05, 0xee, 0x9e, 0x3e, 0x76, 0xae, 0xb3, 0xdd, 0xb9, 0xce, + 0xd7, 0xce, 0x75, 0xde, 0xf7, 0x6e, 0x6d, 0xbb, 0x77, 0x6b, 0x9f, 0x7b, 0xb7, 0xf6, 0x72, 0xb5, + 0x16, 0x59, 0xbc, 0x09, 0x7d, 0x8e, 0x69, 0xc0, 0xd1, 0xa4, 0x68, 0x02, 0x11, 0xf2, 0x8b, 0x35, + 0x06, 0xf9, 0x75, 0x90, 0x62, 0xb4, 0x49, 0xc0, 0x14, 0x9b, 0x1d, 0x6c, 0x95, 0xbd, 0x29, 0x30, + 0x61, 0xd3, 0xce, 0x34, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xeb, 0xfc, 0xb4, 0x1e, 0xd5, 0x01, + 0x00, 0x00, } func (m *DenomTrace) Marshal() (dAtA []byte, err error) { @@ -248,6 +360,87 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *ForwardingInfo) 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 *ForwardingInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ForwardingInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Memo) > 0 { + i -= len(m.Memo) + copy(dAtA[i:], m.Memo) + i = encodeVarintTransfer(dAtA, i, uint64(len(m.Memo))) + i-- + dAtA[i] = 0x12 + } + if len(m.Hop) > 0 { + for iNdEx := len(m.Hop) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Hop[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTransfer(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *Hop) 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 *Hop) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Hop) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ChannelId) > 0 { + i -= len(m.ChannelId) + copy(dAtA[i:], m.ChannelId) + i = encodeVarintTransfer(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 = encodeVarintTransfer(dAtA, i, uint64(len(m.PortID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintTransfer(dAtA []byte, offset int, v uint64) int { offset -= sovTransfer(v) base := offset @@ -291,6 +484,42 @@ func (m *Params) Size() (n int) { return n } +func (m *ForwardingInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Hop) > 0 { + for _, e := range m.Hop { + l = e.Size() + n += 1 + l + sovTransfer(uint64(l)) + } + } + l = len(m.Memo) + if l > 0 { + n += 1 + l + sovTransfer(uint64(l)) + } + return n +} + +func (m *Hop) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortID) + if l > 0 { + n += 1 + l + sovTransfer(uint64(l)) + } + l = len(m.ChannelId) + if l > 0 { + n += 1 + l + sovTransfer(uint64(l)) + } + return n +} + func sovTransfer(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -501,6 +730,236 @@ func (m *Params) Unmarshal(dAtA []byte) error { } return nil } +func (m *ForwardingInfo) 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 ErrIntOverflowTransfer + } + 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: ForwardingInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ForwardingInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hop", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTransfer + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTransfer + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hop = append(m.Hop, &Hop{}) + if err := m.Hop[len(m.Hop)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Memo", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTransfer + } + 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 ErrInvalidLengthTransfer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Memo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTransfer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTransfer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Hop) 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 ErrIntOverflowTransfer + } + 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: Hop: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Hop: 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 ErrIntOverflowTransfer + } + 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 ErrInvalidLengthTransfer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + 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 ErrIntOverflowTransfer + } + 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 ErrInvalidLengthTransfer + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTransfer + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTransfer(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTransfer + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTransfer(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/transfer/types/tx.pb.go b/modules/apps/transfer/types/tx.pb.go index 860b32b2549..557bb6d35ed 100644 --- a/modules/apps/transfer/types/tx.pb.go +++ b/modules/apps/transfer/types/tx.pb.go @@ -55,7 +55,8 @@ type MsgTransfer struct { // optional memo Memo string `protobuf:"bytes,8,opt,name=memo,proto3" json:"memo,omitempty"` // tokens to be transferred - Tokens []types.Coin `protobuf:"bytes,9,rep,name=tokens,proto3" json:"tokens"` + Tokens []types.Coin `protobuf:"bytes,9,rep,name=tokens,proto3" json:"tokens"` + ForwardingPath *ForwardingInfo `protobuf:"bytes,10,opt,name=forwardingPath,proto3" json:"forwardingPath,omitempty"` } func (m *MsgTransfer) Reset() { *m = MsgTransfer{} } @@ -223,47 +224,49 @@ func init() { } var fileDescriptor_7401ed9bed2f8e09 = []byte{ - // 630 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xb1, 0x6e, 0x13, 0x4d, - 0x10, 0xf6, 0xfd, 0x76, 0xfc, 0x27, 0x6b, 0x92, 0x90, 0x05, 0x25, 0x17, 0x0b, 0x9d, 0x2d, 0x8b, - 0x48, 0xc1, 0x51, 0x76, 0xe5, 0x20, 0x14, 0x64, 0x51, 0x39, 0x0d, 0x05, 0x91, 0x82, 0x15, 0x1a, - 0x9a, 0xe8, 0x6e, 0x3d, 0x9c, 0x57, 0xf1, 0xed, 0x1e, 0xb7, 0x6b, 0x0b, 0x1a, 0x84, 0xa8, 0x10, - 0x15, 0x8f, 0x40, 0x49, 0x99, 0x27, 0xa0, 0x4e, 0x99, 0x92, 0x0a, 0xa1, 0xa4, 0x48, 0xc3, 0x43, - 0xa0, 0xdd, 0x5b, 0x9b, 0x83, 0x22, 0x84, 0xc6, 0xde, 0x99, 0xf9, 0xe6, 0x9b, 0xf9, 0x66, 0x3c, - 0x46, 0x1b, 0x3c, 0x62, 0x34, 0x4c, 0xd3, 0x11, 0x67, 0xa1, 0xe6, 0x52, 0x28, 0xaa, 0xb3, 0x50, - 0xa8, 0x17, 0x90, 0xd1, 0x49, 0x87, 0xea, 0x57, 0x24, 0xcd, 0xa4, 0x96, 0xf8, 0x0e, 0x8f, 0x18, - 0x29, 0xc2, 0xc8, 0x14, 0x46, 0x26, 0x9d, 0xfa, 0x4a, 0x98, 0x70, 0x21, 0xa9, 0xfd, 0xcc, 0x13, - 0xea, 0xb7, 0x63, 0x19, 0x4b, 0xfb, 0xa4, 0xe6, 0xe5, 0xbc, 0x6b, 0x4c, 0xaa, 0x44, 0x2a, 0x9a, - 0xa8, 0xd8, 0xd0, 0x27, 0x2a, 0x76, 0x81, 0xc0, 0x05, 0xa2, 0x50, 0x01, 0x9d, 0x74, 0x22, 0xd0, - 0x61, 0x87, 0x32, 0xc9, 0x85, 0x8b, 0x37, 0x4c, 0x9b, 0x4c, 0x66, 0x40, 0xd9, 0x88, 0x83, 0xd0, - 0x26, 0x3b, 0x7f, 0x39, 0xc0, 0xd6, 0xd5, 0x3a, 0xa6, 0xcd, 0x5a, 0x70, 0xeb, 0x4b, 0x19, 0xd5, - 0xf6, 0x55, 0x7c, 0xe8, 0xbc, 0xb8, 0x81, 0x6a, 0x4a, 0x8e, 0x33, 0x06, 0x47, 0xa9, 0xcc, 0xb4, - 0xef, 0x35, 0xbd, 0xcd, 0x85, 0x3e, 0xca, 0x5d, 0x07, 0x32, 0xd3, 0x78, 0x03, 0x2d, 0x39, 0x00, - 0x1b, 0x86, 0x42, 0xc0, 0xc8, 0xff, 0xcf, 0x62, 0x16, 0x73, 0xef, 0x5e, 0xee, 0xc4, 0x5d, 0x34, - 0xa7, 0xe5, 0x31, 0x08, 0xbf, 0xdc, 0xf4, 0x36, 0x6b, 0x3b, 0xeb, 0x24, 0x57, 0x45, 0x8c, 0x2a, - 0xe2, 0x54, 0x91, 0x3d, 0xc9, 0x45, 0x6f, 0xe1, 0xf4, 0x5b, 0xa3, 0xf4, 0xf9, 0xf2, 0xa4, 0xed, - 0xf5, 0xf3, 0x14, 0xbc, 0x8a, 0xaa, 0x0a, 0xc4, 0x00, 0x32, 0xbf, 0x62, 0xa9, 0x9d, 0x85, 0xeb, - 0x68, 0x3e, 0x03, 0x06, 0x7c, 0x02, 0x99, 0x3f, 0x67, 0x23, 0x33, 0x1b, 0x3f, 0x41, 0x4b, 0x9a, - 0x27, 0x20, 0xc7, 0xfa, 0x68, 0x08, 0x3c, 0x1e, 0x6a, 0xbf, 0x6a, 0x0b, 0xd7, 0x89, 0x59, 0x97, - 0x19, 0x17, 0x71, 0x43, 0x9a, 0x74, 0xc8, 0x63, 0x8b, 0x28, 0x56, 0x5e, 0x74, 0xc9, 0x79, 0x04, - 0x6f, 0xa1, 0x95, 0x29, 0x9b, 0xf9, 0x56, 0x3a, 0x4c, 0x52, 0xff, 0xff, 0xa6, 0xb7, 0x59, 0xe9, - 0xdf, 0x74, 0x81, 0xc3, 0xa9, 0x1f, 0x63, 0x54, 0x49, 0x20, 0x91, 0xfe, 0xbc, 0x6d, 0xc9, 0xbe, - 0xf1, 0x23, 0x54, 0xb5, 0x5a, 0x94, 0xbf, 0xd0, 0x2c, 0x5f, 0x5b, 0xbf, 0xcb, 0xe9, 0xb6, 0xdf, - 0x7f, 0x6a, 0x94, 0xde, 0x5d, 0x9e, 0xb4, 0x9d, 0xf2, 0x0f, 0x97, 0x27, 0xed, 0xd5, 0x9c, 0x60, - 0x5b, 0x0d, 0x8e, 0x69, 0x61, 0x61, 0xad, 0x5d, 0x74, 0xab, 0x60, 0xf6, 0x41, 0xa5, 0x52, 0x28, - 0x30, 0xb3, 0x52, 0xf0, 0x72, 0x0c, 0x82, 0x81, 0x5d, 0x62, 0xa5, 0x3f, 0xb3, 0xbb, 0x15, 0x43, - 0xdf, 0x7a, 0x83, 0x96, 0xf7, 0x55, 0xfc, 0x2c, 0x1d, 0x84, 0x1a, 0x0e, 0xc2, 0x2c, 0x4c, 0x94, - 0x1d, 0x3c, 0x8f, 0x05, 0x64, 0x6e, 0xef, 0xce, 0xc2, 0x3d, 0x54, 0x4d, 0x2d, 0xc2, 0xee, 0xba, - 0xb6, 0x73, 0x97, 0x5c, 0x75, 0x03, 0x24, 0x67, 0xeb, 0x55, 0x8c, 0xb0, 0xbe, 0xcb, 0xec, 0x2e, - 0xff, 0xd2, 0x64, 0x49, 0x5b, 0xeb, 0x68, 0xed, 0x8f, 0xfa, 0xd3, 0xe6, 0x77, 0x7e, 0x78, 0xa8, - 0xbc, 0xaf, 0x62, 0x3c, 0x44, 0xf3, 0xb3, 0x1f, 0xe6, 0xbd, 0xab, 0x6b, 0x16, 0x66, 0x50, 0xef, - 0x5c, 0x1b, 0x3a, 0x1b, 0x97, 0x46, 0x37, 0x7e, 0x9b, 0xc4, 0xf6, 0x5f, 0x29, 0x8a, 0xf0, 0xfa, - 0x83, 0x7f, 0x82, 0x4f, 0xab, 0xd6, 0xe7, 0xde, 0x9a, 0xb5, 0xf7, 0x9e, 0x9e, 0x9e, 0x07, 0xde, - 0xd9, 0x79, 0xe0, 0x7d, 0x3f, 0x0f, 0xbc, 0x8f, 0x17, 0x41, 0xe9, 0xec, 0x22, 0x28, 0x7d, 0xbd, - 0x08, 0x4a, 0xcf, 0x77, 0x63, 0xae, 0x87, 0xe3, 0x88, 0x30, 0x99, 0x50, 0xf7, 0xb7, 0xc0, 0x23, - 0xb6, 0x1d, 0x4b, 0x3a, 0x79, 0x48, 0x13, 0x39, 0x18, 0x8f, 0x40, 0x99, 0x53, 0x2f, 0x9c, 0xb8, - 0x7e, 0x9d, 0x82, 0x8a, 0xaa, 0xf6, 0xba, 0xef, 0xff, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x29, 0xee, - 0x20, 0x91, 0xd4, 0x04, 0x00, 0x00, + // 666 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x41, 0x6f, 0x13, 0x3b, + 0x10, 0xce, 0xbe, 0x6e, 0xf3, 0x5a, 0xe7, 0xb5, 0x7d, 0xf5, 0x7b, 0x6a, 0xb7, 0x2b, 0xb4, 0x89, + 0x22, 0x2a, 0x95, 0x94, 0xda, 0x4a, 0x11, 0x2a, 0x8a, 0x38, 0xa5, 0x12, 0x02, 0x89, 0x4a, 0x65, + 0x55, 0x2e, 0x5c, 0xaa, 0xdd, 0x8d, 0xbb, 0xb1, 0x9a, 0xb5, 0x17, 0xdb, 0x09, 0x70, 0x41, 0x88, + 0x13, 0xe2, 0xc4, 0x81, 0x1f, 0xc0, 0x91, 0x63, 0x7f, 0x46, 0x8f, 0x3d, 0x72, 0x42, 0xa8, 0x3d, + 0xf4, 0xc2, 0x8f, 0x40, 0xf6, 0x3a, 0x61, 0xe9, 0x21, 0x94, 0xcb, 0xae, 0x67, 0xe6, 0x9b, 0x6f, + 0xe6, 0x1b, 0x8f, 0x0c, 0xd6, 0x69, 0x9c, 0xe0, 0x28, 0xcf, 0x07, 0x34, 0x89, 0x14, 0xe5, 0x4c, + 0x62, 0x25, 0x22, 0x26, 0x8f, 0x88, 0xc0, 0xa3, 0x36, 0x56, 0x2f, 0x51, 0x2e, 0xb8, 0xe2, 0xf0, + 0x06, 0x8d, 0x13, 0x54, 0x86, 0xa1, 0x31, 0x0c, 0x8d, 0xda, 0xfe, 0x72, 0x94, 0x51, 0xc6, 0xb1, + 0xf9, 0x16, 0x09, 0xfe, 0xff, 0x29, 0x4f, 0xb9, 0x39, 0x62, 0x7d, 0xb2, 0xde, 0xd5, 0x84, 0xcb, + 0x8c, 0x4b, 0x9c, 0xc9, 0x54, 0xd3, 0x67, 0x32, 0xb5, 0x81, 0xc0, 0x06, 0xe2, 0x48, 0x12, 0x3c, + 0x6a, 0xc7, 0x44, 0x45, 0x6d, 0x9c, 0x70, 0xca, 0x6c, 0xbc, 0xae, 0xdb, 0x4c, 0xb8, 0x20, 0x38, + 0x19, 0x50, 0xc2, 0x94, 0xce, 0x2e, 0x4e, 0x16, 0xb0, 0x39, 0x5d, 0xc7, 0xb8, 0x59, 0x03, 0x6e, + 0x7e, 0x74, 0x41, 0x6d, 0x4f, 0xa6, 0x07, 0xd6, 0x0b, 0xeb, 0xa0, 0x26, 0xf9, 0x50, 0x24, 0xe4, + 0x30, 0xe7, 0x42, 0x79, 0x4e, 0xc3, 0xd9, 0x98, 0x0f, 0x41, 0xe1, 0xda, 0xe7, 0x42, 0xc1, 0x75, + 0xb0, 0x68, 0x01, 0x49, 0x3f, 0x62, 0x8c, 0x0c, 0xbc, 0xbf, 0x0c, 0x66, 0xa1, 0xf0, 0xee, 0x16, + 0x4e, 0xd8, 0x01, 0xb3, 0x8a, 0x1f, 0x13, 0xe6, 0xcd, 0x34, 0x9c, 0x8d, 0xda, 0xf6, 0x1a, 0x2a, + 0x54, 0x21, 0xad, 0x0a, 0x59, 0x55, 0x68, 0x97, 0x53, 0xd6, 0x9d, 0x3f, 0xfd, 0x5a, 0xaf, 0x7c, + 0xbe, 0x3c, 0x69, 0x39, 0x61, 0x91, 0x02, 0x57, 0x40, 0x55, 0x12, 0xd6, 0x23, 0xc2, 0x73, 0x0d, + 0xb5, 0xb5, 0xa0, 0x0f, 0xe6, 0x04, 0x49, 0x08, 0x1d, 0x11, 0xe1, 0xcd, 0x9a, 0xc8, 0xc4, 0x86, + 0x8f, 0xc1, 0xa2, 0xa2, 0x19, 0xe1, 0x43, 0x75, 0xd8, 0x27, 0x34, 0xed, 0x2b, 0xaf, 0x6a, 0x0a, + 0xfb, 0x48, 0x5f, 0x97, 0x1e, 0x17, 0xb2, 0x43, 0x1a, 0xb5, 0xd1, 0x43, 0x83, 0x28, 0x57, 0x5e, + 0xb0, 0xc9, 0x45, 0x04, 0x6e, 0x82, 0xe5, 0x31, 0x9b, 0xfe, 0x4b, 0x15, 0x65, 0xb9, 0xf7, 0x77, + 0xc3, 0xd9, 0x70, 0xc3, 0x7f, 0x6d, 0xe0, 0x60, 0xec, 0x87, 0x10, 0xb8, 0x19, 0xc9, 0xb8, 0x37, + 0x67, 0x5a, 0x32, 0x67, 0x78, 0x1f, 0x54, 0x8d, 0x16, 0xe9, 0xcd, 0x37, 0x66, 0xae, 0xad, 0xdf, + 0xe6, 0xc0, 0x03, 0xb0, 0x78, 0xc4, 0xc5, 0x8b, 0x48, 0xf4, 0x28, 0x4b, 0xf7, 0x23, 0xd5, 0xf7, + 0x80, 0x11, 0x73, 0x1b, 0x4d, 0xdb, 0x3d, 0xf4, 0x60, 0x92, 0xf3, 0x88, 0x1d, 0xf1, 0xf0, 0x0a, + 0x47, 0xa7, 0xf5, 0xee, 0x53, 0xbd, 0xf2, 0xf6, 0xf2, 0xa4, 0x65, 0xe7, 0xf9, 0xfe, 0xf2, 0xa4, + 0xb5, 0x52, 0xb4, 0xb5, 0x25, 0x7b, 0xc7, 0xb8, 0xb4, 0x06, 0xcd, 0x1d, 0xf0, 0x5f, 0xc9, 0x0c, + 0x89, 0xcc, 0x39, 0x93, 0x44, 0xdf, 0x80, 0x24, 0xcf, 0x87, 0x84, 0x25, 0xc4, 0xac, 0x86, 0x1b, + 0x4e, 0xec, 0x8e, 0xab, 0xe9, 0x9b, 0xaf, 0xc1, 0xd2, 0x9e, 0x4c, 0x9f, 0xe6, 0xbd, 0x48, 0x91, + 0xfd, 0x48, 0x44, 0x99, 0x34, 0xd7, 0x49, 0x53, 0x46, 0x84, 0xdd, 0x26, 0x6b, 0xc1, 0x2e, 0xa8, + 0xe6, 0x06, 0x61, 0x36, 0xa8, 0xb6, 0x7d, 0x73, 0xba, 0xba, 0x82, 0xad, 0xeb, 0xea, 0x71, 0x85, + 0x36, 0xb3, 0xb3, 0xf4, 0x53, 0x93, 0x21, 0x6d, 0xae, 0x81, 0xd5, 0x2b, 0xf5, 0xc7, 0xcd, 0x6f, + 0x7f, 0x77, 0xc0, 0xcc, 0x9e, 0x4c, 0x61, 0x1f, 0xcc, 0x4d, 0xd6, 0xfd, 0xd6, 0xf4, 0x9a, 0xa5, + 0x19, 0xf8, 0xed, 0x6b, 0x43, 0x27, 0xe3, 0x52, 0xe0, 0x9f, 0x5f, 0x26, 0xb1, 0xf5, 0x5b, 0x8a, + 0x32, 0xdc, 0xbf, 0xfb, 0x47, 0xf0, 0x71, 0x55, 0x7f, 0xf6, 0x8d, 0x5e, 0xa6, 0xee, 0x93, 0xd3, + 0xf3, 0xc0, 0x39, 0x3b, 0x0f, 0x9c, 0x6f, 0xe7, 0x81, 0xf3, 0xe1, 0x22, 0xa8, 0x9c, 0x5d, 0x04, + 0x95, 0x2f, 0x17, 0x41, 0xe5, 0xd9, 0x4e, 0x4a, 0x55, 0x7f, 0x18, 0xa3, 0x84, 0x67, 0xd8, 0x3e, + 0x36, 0x34, 0x4e, 0xb6, 0x52, 0x8e, 0x47, 0xf7, 0x70, 0xc6, 0x7b, 0xc3, 0x01, 0x91, 0xfa, 0x01, + 0x29, 0x3d, 0x1c, 0xea, 0x55, 0x4e, 0x64, 0x5c, 0x35, 0x6f, 0xc6, 0x9d, 0x1f, 0x01, 0x00, 0x00, + 0xff, 0xff, 0xfe, 0xb7, 0xbe, 0x25, 0x2a, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -406,6 +409,18 @@ func (m *MsgTransfer) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ForwardingPath != nil { + { + size, err := m.ForwardingPath.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } if len(m.Tokens) > 0 { for iNdEx := len(m.Tokens) - 1; iNdEx >= 0; iNdEx-- { { @@ -624,6 +639,10 @@ func (m *MsgTransfer) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } + if m.ForwardingPath != nil { + l = m.ForwardingPath.Size() + n += 1 + l + sovTx(uint64(l)) + } return n } @@ -977,6 +996,42 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ForwardingPath", 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 m.ForwardingPath == nil { + m.ForwardingPath = &ForwardingInfo{} + } + if err := m.ForwardingPath.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/modules/apps/transfer/types/v3/packet.pb.go b/modules/apps/transfer/types/v3/packet.pb.go index 145b51c5eb9..113d758a12d 100644 --- a/modules/apps/transfer/types/v3/packet.pb.go +++ b/modules/apps/transfer/types/v3/packet.pb.go @@ -6,6 +6,7 @@ package v3 import ( fmt "fmt" proto "github.com/cosmos/gogoproto/proto" + types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" io "io" math "math" math_bits "math/bits" @@ -34,6 +35,8 @@ type FungibleTokenPacketData struct { Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` // optional memo Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` + // optional forwardingInfo struct + ForwardingPath *types.ForwardingInfo `protobuf:"bytes,5,opt,name=forwardingPath,proto3" json:"forwardingPath,omitempty"` } func (m *FungibleTokenPacketData) Reset() { *m = FungibleTokenPacketData{} } @@ -97,6 +100,13 @@ func (m *FungibleTokenPacketData) GetMemo() string { return "" } +func (m *FungibleTokenPacketData) GetForwardingPath() *types.ForwardingInfo { + if m != nil { + return m.ForwardingPath + } + return nil +} + // Token defines a struct which represents a token to be transferred. type Token struct { // the base token denomination to be transferred @@ -171,26 +181,29 @@ func init() { } var fileDescriptor_760742a8894acdbe = []byte{ - // 301 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xc1, 0x4a, 0x33, 0x31, - 0x14, 0x85, 0x9b, 0x7f, 0xda, 0xf2, 0x1b, 0x77, 0x41, 0x74, 0x10, 0x19, 0x4a, 0xdd, 0xd4, 0x85, - 0x09, 0x38, 0x1b, 0xd1, 0x9d, 0x88, 0x1b, 0x37, 0x52, 0xba, 0x72, 0x97, 0xa4, 0xd7, 0x1a, 0xda, - 0xe4, 0x0e, 0x49, 0x66, 0xc0, 0xb7, 0xf0, 0x09, 0x7c, 0x1e, 0x97, 0x5d, 0xba, 0x94, 0xf6, 0x45, - 0x64, 0xd2, 0x56, 0xba, 0x72, 0x77, 0xbf, 0x7b, 0xcf, 0xb9, 0x07, 0x0e, 0xbd, 0x30, 0x4a, 0x0b, - 0x59, 0x55, 0x0b, 0xa3, 0x65, 0x34, 0xe8, 0x82, 0x88, 0x5e, 0xba, 0xf0, 0x02, 0x5e, 0x34, 0xa5, - 0xa8, 0xa4, 0x9e, 0x43, 0xe4, 0x95, 0xc7, 0x88, 0xec, 0xcc, 0x28, 0xcd, 0xf7, 0xa5, 0x7c, 0x27, - 0xe5, 0x4d, 0x39, 0xfc, 0x20, 0xf4, 0xe4, 0xa1, 0x76, 0x33, 0xa3, 0x16, 0x30, 0xc1, 0x39, 0xb8, - 0xa7, 0xe4, 0xbd, 0x97, 0x51, 0xb2, 0x5b, 0xda, 0x8f, 0xed, 0x2a, 0xe4, 0x64, 0x90, 0x8d, 0x0e, - 0xaf, 0xce, 0xf9, 0x5f, 0xaf, 0x78, 0xb2, 0x8f, 0xb7, 0x16, 0x76, 0x4c, 0xfb, 0x01, 0xdc, 0x14, - 0x7c, 0xfe, 0x6f, 0x40, 0x46, 0x07, 0xe3, 0x2d, 0xb1, 0x53, 0xfa, 0xdf, 0x83, 0x06, 0xd3, 0x80, - 0xcf, 0xb3, 0x74, 0xf9, 0x65, 0xc6, 0x68, 0xd7, 0x82, 0xc5, 0xbc, 0x9b, 0xf6, 0x69, 0x1e, 0x3e, - 0xd2, 0x5e, 0x7a, 0xcc, 0x8e, 0x68, 0x6f, 0x0a, 0x0e, 0x6d, 0x4e, 0xd2, 0x75, 0x03, 0x6d, 0x8c, - 0xb4, 0x58, 0xbb, 0xb8, 0x8b, 0xd9, 0x50, 0xab, 0x8e, 0x5e, 0x6a, 0xc8, 0xb3, 0x41, 0xd6, 0xaa, - 0x13, 0xdc, 0x4d, 0x3e, 0x57, 0x05, 0x59, 0xae, 0x0a, 0xf2, 0xbd, 0x2a, 0xc8, 0xfb, 0xba, 0xe8, - 0x2c, 0xd7, 0x45, 0xe7, 0x6b, 0x5d, 0x74, 0x9e, 0x6f, 0x66, 0x26, 0xbe, 0xd6, 0x8a, 0x6b, 0xb4, - 0x42, 0x63, 0xb0, 0x18, 0x84, 0x51, 0xfa, 0x72, 0x86, 0xa2, 0xb9, 0x16, 0x16, 0xa7, 0xf5, 0x02, - 0x42, 0x5b, 0xf8, 0x5e, 0xd1, 0xf1, 0xad, 0x82, 0x20, 0x9a, 0x52, 0xf5, 0x53, 0xd1, 0xe5, 0x4f, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x97, 0x4d, 0xcc, 0xde, 0x95, 0x01, 0x00, 0x00, + // 344 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0xcf, 0x4a, 0xc3, 0x30, + 0x1c, 0x5e, 0xec, 0x36, 0x34, 0x03, 0x0f, 0x41, 0xb4, 0x0c, 0x29, 0x65, 0x5e, 0x26, 0x6a, 0xc2, + 0xd6, 0x8b, 0xe8, 0x4d, 0x64, 0x20, 0x5e, 0xc6, 0xd8, 0xc9, 0x5b, 0x9a, 0x66, 0x5d, 0xd8, 0x9a, + 0x94, 0x24, 0xad, 0xf8, 0x16, 0x3e, 0x96, 0xc7, 0x1d, 0x3d, 0xca, 0xf6, 0x0a, 0x3e, 0x80, 0x34, + 0xfb, 0xc3, 0xf0, 0xb0, 0x5b, 0xbe, 0x5f, 0xbe, 0x7f, 0xf0, 0xc1, 0x6b, 0x11, 0x33, 0x42, 0xf3, + 0x7c, 0x2e, 0x18, 0xb5, 0x42, 0x49, 0x43, 0xac, 0xa6, 0xd2, 0x4c, 0xb8, 0x26, 0x65, 0x44, 0x72, + 0xca, 0x66, 0xdc, 0xe2, 0x5c, 0x2b, 0xab, 0xd0, 0xa5, 0x88, 0x19, 0xde, 0xa7, 0xe2, 0x2d, 0x15, + 0x97, 0x51, 0xfb, 0xe6, 0x80, 0x51, 0x6f, 0xf7, 0x5e, 0x5b, 0x75, 0x7e, 0x01, 0xbc, 0x18, 0x14, + 0x32, 0x15, 0xf1, 0x9c, 0x8f, 0xd5, 0x8c, 0xcb, 0xa1, 0x0b, 0x7a, 0xa6, 0x96, 0xa2, 0x47, 0xd8, + 0xb4, 0xd5, 0xc9, 0xf8, 0x20, 0xf4, 0xba, 0xad, 0xfe, 0x15, 0x3e, 0x94, 0x8b, 0x9d, 0x7c, 0xb4, + 0x91, 0xa0, 0x73, 0xd8, 0x34, 0x5c, 0x26, 0x5c, 0xfb, 0x47, 0x21, 0xe8, 0x9e, 0x8c, 0x36, 0x08, + 0xb5, 0xe1, 0xb1, 0xe6, 0x8c, 0x8b, 0x92, 0x6b, 0xdf, 0x73, 0x3f, 0x3b, 0x8c, 0x10, 0xac, 0x67, + 0x3c, 0x53, 0x7e, 0xdd, 0xdd, 0xdd, 0x1b, 0x8d, 0xe1, 0xe9, 0x44, 0xe9, 0x77, 0xaa, 0x13, 0x21, + 0xd3, 0x21, 0xb5, 0x53, 0xbf, 0x11, 0x82, 0x6e, 0xab, 0x7f, 0x7b, 0xa8, 0x4c, 0x0f, 0x0f, 0x76, + 0x9a, 0x17, 0x39, 0x51, 0xa3, 0x7f, 0x1e, 0x9d, 0x57, 0xd8, 0x70, 0x75, 0xd1, 0x19, 0x6c, 0x24, + 0x5c, 0xaa, 0xcc, 0x07, 0x2e, 0x73, 0x0d, 0xaa, 0xf2, 0x34, 0x53, 0x85, 0xb4, 0xdb, 0xf2, 0x6b, + 0x54, 0xb1, 0xad, 0xa6, 0x8c, 0xfb, 0x5e, 0xe8, 0x55, 0x6c, 0x07, 0x9e, 0xc6, 0x5f, 0xcb, 0x00, + 0x2c, 0x96, 0x01, 0xf8, 0x59, 0x06, 0xe0, 0x73, 0x15, 0xd4, 0x16, 0xab, 0xa0, 0xf6, 0xbd, 0x0a, + 0x6a, 0x6f, 0x0f, 0xa9, 0xb0, 0xd3, 0x22, 0xc6, 0x4c, 0x65, 0x84, 0x29, 0x93, 0x29, 0x43, 0x44, + 0xcc, 0xee, 0x52, 0x45, 0xca, 0x7b, 0x92, 0xa9, 0xa4, 0x98, 0x73, 0x53, 0x4d, 0xb5, 0x37, 0x91, + 0xfd, 0xc8, 0xb9, 0x21, 0x65, 0x14, 0x37, 0xdd, 0x40, 0xd1, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x1f, 0xc2, 0x4f, 0x29, 0x18, 0x02, 0x00, 0x00, } func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { @@ -213,6 +226,18 @@ func (m *FungibleTokenPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l + if m.ForwardingPath != nil { + { + size, err := m.ForwardingPath.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPacket(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } if len(m.Memo) > 0 { i -= len(m.Memo) copy(dAtA[i:], m.Memo) @@ -332,6 +357,10 @@ func (m *FungibleTokenPacketData) Size() (n int) { if l > 0 { n += 1 + l + sovPacket(uint64(l)) } + if m.ForwardingPath != nil { + l = m.ForwardingPath.Size() + n += 1 + l + sovPacket(uint64(l)) + } return n } @@ -523,6 +552,42 @@ func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { } m.Memo = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ForwardingPath", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPacket + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ForwardingPath == nil { + m.ForwardingPath = &types.ForwardingInfo{} + } + if err := m.ForwardingPath.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipPacket(dAtA[iNdEx:]) diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index 7f77237621f..ca430451f91 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -26,3 +26,13 @@ message Params { // chain. bool receive_enabled = 2; } + +message ForwardingInfo { + repeated Hop hop = 1; + string memo = 2; +} + +message Hop { + string portID = 1; + string channelId = 2; +} \ No newline at end of file diff --git a/proto/ibc/applications/transfer/v1/tx.proto b/proto/ibc/applications/transfer/v1/tx.proto index 52e5d29b7e1..b497e141b85 100644 --- a/proto/ibc/applications/transfer/v1/tx.proto +++ b/proto/ibc/applications/transfer/v1/tx.proto @@ -51,6 +51,8 @@ message MsgTransfer { string memo = 8; // tokens to be transferred repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; + + ForwardingInfo forwardingPath = 10; } // MsgTransferResponse defines the Msg/Transfer response type. @@ -78,4 +80,4 @@ message MsgUpdateParams { // MsgUpdateParamsResponse defines the response structure for executing a // MsgUpdateParams message. -message MsgUpdateParamsResponse {} \ No newline at end of file +message MsgUpdateParamsResponse {} diff --git a/proto/ibc/applications/transfer/v3/packet.proto b/proto/ibc/applications/transfer/v3/packet.proto index 963a5afc980..78a58f8dc21 100644 --- a/proto/ibc/applications/transfer/v3/packet.proto +++ b/proto/ibc/applications/transfer/v3/packet.proto @@ -4,6 +4,8 @@ package ibc.applications.transfer.v3; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3"; +import "ibc/applications/transfer/v1/transfer.proto"; + // FungibleTokenPacketData defines a struct for the packet payload // See FungibleTokenPacketData spec: // https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures @@ -17,9 +19,10 @@ message FungibleTokenPacketData { // optional memo string memo = 4; // optional forwardingInfo struct - ForwardingInfo forwardingPath = 10; + ibc.applications.transfer.v1.ForwardingInfo forwardingPath = 5; } +/* message ForwardingInfo { repeated Hop hop = 1; string memo = 2; @@ -28,7 +31,7 @@ message ForwardingInfo { message Hop { string portID = 1; string channelId = 2; -} +}*/ // Token defines a struct which represents a token to be transferred. message Token { @@ -38,15 +41,4 @@ message Token { string amount = 2; // the trace of the token repeated string trace = 3; -} - - -// Token defines a struct which represents a token to be transferred. -message Hop { - // the base token denomination to be transferred - string denom = 1; - // the token amount to be transferred - string amount = 2; - // the trace of the token - repeated string trace = 3; } \ No newline at end of file From 03cc2e542d24398f694093dfb9ac180019b27fdd Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Fri, 10 May 2024 16:20:30 +0200 Subject: [PATCH 014/141] fixes --- e2e/tests/transfer/authz_test.go | 11 +++ e2e/tests/transfer/incentivized_test.go | 4 +- e2e/tests/transfer/upgrades_test.go | 2 +- e2e/tests/upgrades/upgrade_test.go | 9 ++- e2e/testsuite/tx.go | 9 ++- .../host/keeper/relay_test.go | 9 +++ modules/apps/29-fee/keeper/events_test.go | 8 +++ modules/apps/29-fee/transfer_test.go | 11 ++- modules/apps/callbacks/ibc_middleware_test.go | 13 +++- modules/apps/callbacks/replay_test.go | 1 + modules/apps/callbacks/transfer_test.go | 8 +++ modules/apps/transfer/client/cli/tx.go | 9 ++- .../apps/transfer/internal/convert/convert.go | 11 ++- .../transfer/internal/convert/convert_test.go | 26 +++++-- .../apps/transfer/keeper/invariants_test.go | 1 + .../apps/transfer/keeper/mbt_relay_test.go | 2 + modules/apps/transfer/keeper/msg_server.go | 2 +- .../apps/transfer/keeper/msg_server_test.go | 3 + modules/apps/transfer/keeper/relay.go | 3 +- modules/apps/transfer/keeper/relay_test.go | 28 +++++--- modules/apps/transfer/transfer_test.go | 13 +++- modules/apps/transfer/types/msgs.go | 2 + modules/apps/transfer/types/msgs_test.go | 47 +++++++------ modules/apps/transfer/types/transfer.pb.go | 68 +++++++++---------- .../types/transfer_authorization_test.go | 10 ++- modules/apps/transfer/types/v3/packet.go | 10 +-- modules/apps/transfer/types/v3/packet_test.go | 35 ++++++++-- modules/apps/transfer/types/v3/token_test.go | 3 + .../applications/transfer/v1/transfer.proto | 2 +- testing/solomachine.go | 8 +++ 30 files changed, 265 insertions(+), 103 deletions(-) diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index 33297e0766d..7580a93e7f1 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -22,6 +22,13 @@ import ( ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ) +var ( + emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} + forwardingPath = &transfertypes.ForwardingInfo{ + Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line + Memo: ""} +) + func TestAuthzTransferTestSuite(t *testing.T) { testifysuite.Run(t, new(AuthzTransferTestSuite)) } @@ -113,6 +120,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.GetTimeoutHeight(ctx, chainB), 0, "", + forwardingPath, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -172,6 +180,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.GetTimeoutHeight(ctx, chainB), 0, "", + forwardingPath, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -254,6 +263,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { suite.GetTimeoutHeight(ctx, chainB), 0, "", + forwardingPath, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -313,6 +323,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { suite.GetTimeoutHeight(ctx, chainB), 0, "", + forwardingPath, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) diff --git a/e2e/tests/transfer/incentivized_test.go b/e2e/tests/transfer/incentivized_test.go index b8818a00002..e71fc7a33a7 100644 --- a/e2e/tests/transfer/incentivized_test.go +++ b/e2e/tests/transfer/incentivized_test.go @@ -197,7 +197,7 @@ func (s *IncentivizedTransferTestSuite) TestMsgPayPacketFee_InvalidReceiverAccou transferAmount := testvalues.DefaultTransferAmount(chainADenom) t.Run("send IBC transfer", func(t *testing.T) { - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), testvalues.InvalidAddress, s.GetTimeoutHeight(ctx, chainB), 0, "") + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), testvalues.InvalidAddress, s.GetTimeoutHeight(ctx, chainB), 0, "", forwardingPath) txResp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgTransfer) // this message should be successful, as receiver account is not validated on the sending chain. s.AssertTxSuccess(txResp) @@ -322,7 +322,7 @@ func (s *IncentivizedTransferTestSuite) TestMultiMsg_MsgPayPacketFeeSingleSender }) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "") + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", forwardingPath) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) diff --git a/e2e/tests/transfer/upgrades_test.go b/e2e/tests/transfer/upgrades_test.go index 74f5593d611..e69dd7e2439 100644 --- a/e2e/tests/transfer/upgrades_test.go +++ b/e2e/tests/transfer/upgrades_test.go @@ -197,7 +197,7 @@ func (s *TransferChannelUpgradesTestSuite) TestChannelUpgrade_WithFeeMiddleware_ transferAmount := testvalues.DefaultTransferAmount(chainA.Config().Denom) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "") + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", forwardingPath) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) }) diff --git a/e2e/tests/upgrades/upgrade_test.go b/e2e/tests/upgrades/upgrade_test.go index 494a73a4511..eac7655d3fe 100644 --- a/e2e/tests/upgrades/upgrade_test.go +++ b/e2e/tests/upgrades/upgrade_test.go @@ -37,6 +37,13 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) +var ( + emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} + forwardingPath = &transfertypes.ForwardingInfo{ + Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line + Memo: ""} +) + const ( haltHeight = int64(100) blocksAfterUpgrade = uint64(10) @@ -960,7 +967,7 @@ func (s *UpgradeTestSuite) TestV8ToV8_1ChainUpgrade_ChannelUpgrades() { transferAmount := testvalues.DefaultTransferAmount(chainA.Config().Denom) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "") + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", forwardingPath) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) }) diff --git a/e2e/testsuite/tx.go b/e2e/testsuite/tx.go index b0ee8ab763b..b91fb147cff 100644 --- a/e2e/testsuite/tx.go +++ b/e2e/testsuite/tx.go @@ -34,6 +34,13 @@ import ( channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ) +var ( + emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} + forwardingPath = &transfertypes.ForwardingInfo{ + Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line + Memo: ""} +) + // BroadcastMessages broadcasts the provided messages to the given chain and signs them on behalf of the provided user. // Once the broadcast response is returned, we wait for a few blocks to be created on both chain A and chain B. func (s *E2ETestSuite) BroadcastMessages(ctx context.Context, chain ibc.Chain, user ibc.Wallet, msgs ...sdk.Msg) sdk.TxResponse { @@ -265,7 +272,7 @@ func (s *E2ETestSuite) ExecuteGovV1Beta1Proposal(ctx context.Context, chain ibc. func (s *E2ETestSuite) Transfer(ctx context.Context, chain ibc.Chain, user ibc.Wallet, portID, channelID string, token sdk.Coin, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, ) sdk.TxResponse { - msg := transfertypes.NewMsgTransfer(portID, channelID, sdk.NewCoins(token), sender, receiver, timeoutHeight, timeoutTimestamp, memo) + msg := transfertypes.NewMsgTransfer(portID, channelID, sdk.NewCoins(token), sender, receiver, timeoutHeight, timeoutTimestamp, memo, forwardingPath) return s.BroadcastMessages(ctx, chain, user, msg) } diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index f49e623e939..15958aa5c80 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -24,6 +24,12 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) +var ( + forwardingPath = &transfertypes.ForwardingInfo{ + Hops: []*transfertypes.Hop{}, // Correcting this line + Memo: ""} +) + func (suite *KeeperTestSuite) TestOnRecvPacket() { testedEncodings := []string{icatypes.EncodingProtobuf, icatypes.EncodingProto3JSON} var ( @@ -351,6 +357,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.chainB.GetTimeoutHeight(), 0, "", + forwardingPath, ) data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) @@ -386,6 +393,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.chainB.GetTimeoutHeight(), 0, "", + forwardingPath, ) data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) @@ -791,6 +799,7 @@ func (suite *KeeperTestSuite) TestJSONOnRecvPacket() { "receiver": "cosmos15ulrf36d4wdtrtqzkgaan9ylwuhs7k7qz753uk", "timeout_height": { "revision_number": 1, "revision_height": 100 }, "timeout_timestamp": 0 + "forwarding_path": { "Hops": [], "Memo": "" } } ] }`) diff --git a/modules/apps/29-fee/keeper/events_test.go b/modules/apps/29-fee/keeper/events_test.go index d70b8bfd229..0af93c58f28 100644 --- a/modules/apps/29-fee/keeper/events_test.go +++ b/modules/apps/29-fee/keeper/events_test.go @@ -15,6 +15,13 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) +var ( + emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} + forwardingPath = &transfertypes.ForwardingInfo{ + Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line + Memo: ""} +) + func (suite *KeeperTestSuite) TestIncentivizePacketEvent() { var ( expRecvFees sdk.Coins @@ -115,6 +122,7 @@ func (suite *KeeperTestSuite) TestDistributeFeeEvent() { path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", + forwardingPath, ) res, err := suite.chainA.SendMsgs(msgPayPacketFee, msgTransfer) diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index f76393bfcf8..0b0528a3860 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -9,6 +9,13 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) +var ( + emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} + forwardingPath = &transfertypes.ForwardingInfo{ + Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line + Memo: ""} +) + // Integration test to ensure ics29 works with ics20 func (suite *FeeTestSuite) TestFeeTransfer() { path := ibctesting.NewPath(suite.chainA, suite.chainB) @@ -30,7 +37,7 @@ func (suite *FeeTestSuite) TestFeeTransfer() { msgs := []sdk.Msg{ types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), - transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, ""), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", forwardingPath), } res, err := suite.chainA.SendMsgs(msgs...) suite.Require().NoError(err) // message committed @@ -138,7 +145,7 @@ func (suite *FeeTestSuite) TestTransferFeeUpgrade() { fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) msgs := []sdk.Msg{ types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), - transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, ""), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", forwardingPath), } res, err := suite.chainA.SendMsgs(msgs...) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index c08f531ca3d..ba55ec61701 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -176,6 +176,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract), + *forwardingPath, ) chanCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) @@ -318,6 +319,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, simapp.SuccessContract, userGasLimit), + *forwardingPath, ) packet = channeltypes.Packet{ @@ -483,6 +485,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { sdk.NewCoins(ibctesting.TestCoin), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), // set user gas limit above panic level in mock contract keeper + forwardingPath, ) res, err := s.chainA.SendMsgs(msg) @@ -651,6 +654,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), + *forwardingPath, ) packet = channeltypes.Packet{ @@ -783,6 +787,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), + *forwardingPath, ) packet = channeltypes.Packet{ @@ -999,9 +1004,11 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { Trace: nil, }, }, - Sender: ibctesting.TestAccAddress, - Receiver: ibctesting.TestAccAddress, - Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), + Sender: ibctesting.TestAccAddress, + Receiver: ibctesting.TestAccAddress, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), + ForwardingPath: forwardingPath, + //ForwardingPath: &transferv1types.ForwardingInfo{Hops: []*transferv1types.Hop{}, Memo: ""}, } // Unmarshal ICS20 v1 packet data diff --git a/modules/apps/callbacks/replay_test.go b/modules/apps/callbacks/replay_test.go index 04a8e5900fb..95ad17bf72d 100644 --- a/modules/apps/callbacks/replay_test.go +++ b/modules/apps/callbacks/replay_test.go @@ -330,6 +330,7 @@ func (s *CallbacksTestSuite) ExecuteFailedTransfer(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, + forwardingPath, ) res, err := s.chainA.SendMsgs(msg) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 16698f074e6..4f9048e1ab4 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -14,6 +14,12 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) +var ( + forwardingPath = &transfertypes.ForwardingInfo{ + Hops: []*transfertypes.Hop{}, // Correcting this line + Memo: ""} +) + func (s *CallbacksTestSuite) TestTransferCallbacks() { testCases := []struct { name string @@ -193,6 +199,7 @@ func (s *CallbacksTestSuite) ExecuteTransfer(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, + forwardingPath, ) res, err := s.chainA.SendMsgs(msg) @@ -227,6 +234,7 @@ func (s *CallbacksTestSuite) ExecuteTransferTimeout(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), timeoutHeight, timeoutTimestamp, memo, + forwardingPath, ) res, err := s.chainA.SendMsgs(msg) diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index ccdd08af588..58965a82358 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -18,6 +18,13 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" ) +var ( + emptyHop = types.Hop{PortID: "", ChannelId: ""} + forwardingPath = &types.ForwardingInfo{ + Hops: []*types.Hop{&emptyHop}, // Correcting this line + Memo: ""} +) + const ( flagPacketTimeoutHeight = "packet-timeout-height" flagPacketTimeoutTimestamp = "packet-timeout-timestamp" @@ -107,7 +114,7 @@ Relative timeout timestamp is added to the value of the user's local system cloc } msg := types.NewMsgTransfer( - srcPort, srcChannel, sdk.NewCoins(coin), sender, receiver, timeoutHeight, timeoutTimestamp, memo, + srcPort, srcChannel, sdk.NewCoins(coin), sender, receiver, timeoutHeight, timeoutTimestamp, memo, forwardingPath, ) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go index 2665974d64c..650679d5aa2 100644 --- a/modules/apps/transfer/internal/convert/convert.go +++ b/modules/apps/transfer/internal/convert/convert.go @@ -7,6 +7,10 @@ import ( v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" ) +var forwardingPath = &types.ForwardingInfo{ + Hops: []*types.Hop{}, // Correcting this line + Memo: ""} + // PacketDataV1ToV3 converts a v1 (ICS20-V1) packet data to a v3 (ICS20-V2) packet data. func PacketDataV1ToV3(packetData types.FungibleTokenPacketData) v3types.FungibleTokenPacketData { if err := packetData.ValidateBasic(); err != nil { @@ -22,9 +26,10 @@ func PacketDataV1ToV3(packetData types.FungibleTokenPacketData) v3types.Fungible Trace: trace, }, }, - Sender: packetData.Sender, - Receiver: packetData.Receiver, - Memo: packetData.Memo, + Sender: packetData.Sender, + Receiver: packetData.Receiver, + Memo: packetData.Memo, + ForwardingPath: forwardingPath, } } diff --git a/modules/apps/transfer/internal/convert/convert_test.go b/modules/apps/transfer/internal/convert/convert_test.go index b406210ad47..2f74000ee25 100644 --- a/modules/apps/transfer/internal/convert/convert_test.go +++ b/modules/apps/transfer/internal/convert/convert_test.go @@ -11,12 +11,24 @@ import ( v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" ) +/* +var ( + //emptyHop = types.Hop{PortID: "", ChannelId: ""} + forwardingPath = &types.ForwardingInfo{ + Hops: []*types.Hop{}, // Correcting this line + Memo: ""} +)*/ + func TestConvertPacketV1ToPacketV3(t *testing.T) { const ( sender = "sender" receiver = "receiver" ) + var forwardingPath = &types.ForwardingInfo{ + Hops: []*types.Hop{}, // Correcting this line + Memo: ""} + testCases := []struct { name string v1Data types.FungibleTokenPacketData @@ -33,7 +45,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0"}, }, - }, sender, receiver, ""), + }, sender, receiver, "", *forwardingPath), nil, }, { @@ -46,7 +58,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: nil, }, - }, sender, receiver, ""), + }, sender, receiver, "", *forwardingPath), nil, }, { @@ -59,7 +71,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0"}, }, - }, sender, receiver, ""), + }, sender, receiver, "", *forwardingPath), nil, }, { @@ -72,7 +84,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0"}, }, - }, sender, receiver, ""), + }, sender, receiver, "", *forwardingPath), nil, }, { @@ -85,7 +97,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0", "transfer/channel-1"}, }, - }, sender, receiver, ""), + }, sender, receiver, "", *forwardingPath), nil, }, { @@ -98,7 +110,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0", "transfer/channel-1", "transfer-custom/channel-2"}, }, - }, sender, receiver, ""), + }, sender, receiver, "", *forwardingPath), nil, }, { @@ -111,7 +123,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0", "transfer/channel-1", "transfer-custom/channel-2"}, }, - }, sender, receiver, ""), + }, sender, receiver, "", *forwardingPath), nil, }, { diff --git a/modules/apps/transfer/keeper/invariants_test.go b/modules/apps/transfer/keeper/invariants_test.go index e150f9ef7c9..7e8ce6db554 100644 --- a/modules/apps/transfer/keeper/invariants_test.go +++ b/modules/apps/transfer/keeper/invariants_test.go @@ -51,6 +51,7 @@ func (suite *KeeperTestSuite) TestTotalEscrowPerDenomInvariant() { suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", + forwardingPath, ) res, err := suite.chainA.SendMsgs(msg) diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index d12abd8a589..4a939715727 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -162,6 +162,7 @@ func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPack AddressFromString(packet.Data.Sender), AddressFromString(packet.Data.Receiver), "", + *forwardingPath, ), } } @@ -362,6 +363,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { tc.packet.Data.Receiver, suite.chainA.GetTimeoutHeight(), 0, // only use timeout height "", + forwardingPath, ) _, err = suite.chainB.GetSimApp().TransferKeeper.Transfer(suite.chainB.GetContext(), msg) diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index aa81a9a228a..25cca768468 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. sequence, err := k.sendTransfer( ctx, msg.SourcePort, msg.SourceChannel, tokens, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, - msg.Memo) + msg.Memo, *msg.ForwardingPath) if err != nil { return nil, err } diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 355b21e5b88..1cda59fa298 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -54,6 +54,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", + forwardingPath, ) }, nil, @@ -139,6 +140,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", + forwardingPath, ) // explicitly set to ics20-1 which does not support multi-denom @@ -169,6 +171,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", + forwardingPath, ) tc.malleate() diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 0671d64fffd..6acb6a1f91e 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -64,6 +64,7 @@ func (k Keeper) sendTransfer( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, + forwardingPath types.ForwardingInfo, ) (uint64, error) { channel, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) if !found { @@ -144,7 +145,7 @@ func (k Keeper) sendTransfer( tokens = append(tokens, token) } - packetData := v3types.NewFungibleTokenPacketData(tokens, sender.String(), receiver, memo) + packetData := v3types.NewFungibleTokenPacketData(tokens, sender.String(), receiver, memo, forwardingPath) sequence, err := k.ics4Wrapper.SendPacket(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, packetData.GetBytes()) if err != nil { diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index e4ce18817fb..5eb249f6ccd 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -18,6 +18,13 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) +var ( + emptyHop = types.Hop{PortID: "", ChannelId: ""} + forwardingPath = &types.ForwardingInfo{ + Hops: []*types.Hop{&emptyHop}, // Correcting this line + Memo: ""} +) + // test sending from chainA to chainB using both coin that originate on // chainA and coin that originate on chainB func (suite *KeeperTestSuite) TestSendTransfer() { @@ -28,6 +35,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { timeoutHeight clienttypes.Height memo string expEscrowAmount sdkmath.Int // total amount in escrow for denom on receiving chain + ) testCases := []struct { @@ -128,7 +136,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { expEscrowAmount = sdkmath.ZeroInt() // create IBC token on chainA - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "") + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", forwardingPath) result, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -146,6 +154,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { sdk.NewCoins(coin), sender.String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, // only use timeout height memo, + forwardingPath, ) res, err := suite.chainA.GetSimApp().TransferKeeper.Transfer(suite.chainA.GetContext(), msg) @@ -212,6 +221,7 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, "", + forwardingPath, ) result, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -232,6 +242,7 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", + forwardingPath, ) res, err := suite.chainB.GetSimApp().TransferKeeper.Transfer(suite.chainB.GetContext(), msg) @@ -385,7 +396,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { if tc.recvIsSource { // send coin from chainB to chainA, receive them, acknowledge them, and send back to chainB coinFromBToA := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coinFromBToA), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, memo) + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coinFromBToA), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, memo, forwardingPath) res, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -405,7 +416,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // send coin from chainA to chainB coin := sdk.NewCoin(denomTrace.IBCDenom(), amount) - transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo) + transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo, forwardingPath) _, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -419,7 +430,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Amount: amount.String(), Trace: trace, }, - }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo) + }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, *forwardingPath) packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) @@ -502,7 +513,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT Amount: amount.String(), Trace: trace, }, - }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "") + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", *forwardingPath) packet := channeltypes.NewPacket( data.GetBytes(), seq, @@ -629,7 +640,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { Amount: amount.String(), Trace: trace, }, - }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "") + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", *forwardingPath) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denomTrace.IBCDenom()) @@ -726,6 +737,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", + *forwardingPath, ) packet := channeltypes.NewPacket( data.GetBytes(), @@ -845,7 +857,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { Amount: amount.String(), Trace: trace, }, - }, sender, suite.chainB.SenderAccount.GetAddress().String(), "") + }, sender, suite.chainB.SenderAccount.GetAddress().String(), "", *forwardingPath) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denomTrace.IBCDenom()) @@ -931,7 +943,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI Amount: amount.String(), Trace: trace, }, - }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "") + }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", *forwardingPath) packet := channeltypes.NewPacket( data.GetBytes(), seq, diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go index 1cb1261c0e3..9721ecd8d12 100644 --- a/modules/apps/transfer/transfer_test.go +++ b/modules/apps/transfer/transfer_test.go @@ -32,6 +32,13 @@ func (suite *TransferTestSuite) SetupTest() { suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3)) } +var ( + emptyHop = types.Hop{PortID: "", ChannelId: ""} + forwardingPath = &types.ForwardingInfo{ + Hops: []*types.Hop{&emptyHop}, // Correcting this line + Memo: ""} +) + // Constructs the following sends based on the established channels/connections // 1 - from chainA to chainB // 2 - from chainB to chainC @@ -52,7 +59,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) // send from chainA to chainB - msg := types.NewMsgTransfer(pathAtoB.EndpointA.ChannelConfig.PortID, pathAtoB.EndpointA.ChannelID, sdk.NewCoins(coinToSendToB), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") + msg := types.NewMsgTransfer(pathAtoB.EndpointA.ChannelConfig.PortID, pathAtoB.EndpointA.ChannelID, sdk.NewCoins(coinToSendToB), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", forwardingPath) res, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -82,7 +89,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { pathBtoC.Setup() // send from chainB to chainC - msg = types.NewMsgTransfer(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, sdk.NewCoins(coinSentFromAToB), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") + msg = types.NewMsgTransfer(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, sdk.NewCoins(coinSentFromAToB), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", forwardingPath) res, err = suite.chainB.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -105,7 +112,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { suite.Require().Zero(balance.Amount.Int64()) // send from chainC back to chainB - msg = types.NewMsgTransfer(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, sdk.NewCoins(coinSentFromBToC), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") + msg = types.NewMsgTransfer(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, sdk.NewCoins(coinSentFromBToC), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", forwardingPath) res, err = suite.chainC.SendMsgs(msg) suite.Require().NoError(err) // message committed diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 2994e841951..172e0c67fe0 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -48,6 +48,7 @@ func NewMsgTransfer( tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, + forwardingPath *ForwardingInfo, ) *MsgTransfer { return &MsgTransfer{ SourcePort: sourcePort, @@ -58,6 +59,7 @@ func NewMsgTransfer( TimeoutTimestamp: timeoutTimestamp, Memo: memo, Tokens: tokens, + ForwardingPath: forwardingPath, } } diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index e98400bfa45..b9fffe9363c 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -43,7 +43,10 @@ var ( invalidIBCCoins = sdk.NewCoins(sdk.NewCoin("ibc/7F1D3FCF4AE79E1554", sdkmath.NewInt(100))) invalidDenomCoins = []sdk.Coin{{Denom: "0atom", Amount: sdkmath.NewInt(100)}} zeroCoins = sdk.NewCoins(sdk.Coin{Denom: "atoms", Amount: sdkmath.NewInt(0)}) - + emptyHop = types.Hop{PortID: "", ChannelId: ""} + forwardingPath = &types.ForwardingInfo{ + Hops: []*types.Hop{&emptyHop}, // Correcting this line + Memo: ""} timeoutHeight = clienttypes.NewHeight(0, 10) ) @@ -54,26 +57,26 @@ func TestMsgTransferValidation(t *testing.T) { msg *types.MsgTransfer expPass bool }{ - {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ""), true}, - {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, timeoutHeight, 0, ""), true}, - {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, timeoutHeight, 0, ""), true}, - {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, timeoutHeight, 0, ""), false}, - {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, - {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, - {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, - {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, - {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, - {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1)), false}, - {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, timeoutHeight, 0, ""), false}, - {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, timeoutHeight, 0, ""), false}, - {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, ""), false}, - {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, timeoutHeight, 0, ""), false}, - {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", timeoutHeight, 0, ""), false}, - {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, ""), false}, - {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, timeoutHeight, 0, ""), false}, - {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, ""), false}, - {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, ""), false}, - {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, ""), false}, + {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), true}, + {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, timeoutHeight, 0, "", forwardingPath), true}, + {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, timeoutHeight, 0, "", forwardingPath), true}, + {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1), forwardingPath), false}, + {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", timeoutHeight, 0, "", forwardingPath), false}, + {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, "", forwardingPath), false}, + {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, } for i, tc := range testCases { @@ -91,7 +94,7 @@ func TestMsgTransferValidation(t *testing.T) { // TestMsgTransferGetSigners tests GetSigners for MsgTransfer func TestMsgTransferGetSigners(t *testing.T) { addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - msg := types.NewMsgTransfer(validPort, validChannel, coins, addr.String(), receiver, timeoutHeight, 0, "") + msg := types.NewMsgTransfer(validPort, validChannel, coins, addr.String(), receiver, timeoutHeight, 0, "", forwardingPath) encodingCfg := moduletestutil.MakeTestEncodingConfig(transfer.AppModuleBasic{}) signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) diff --git a/modules/apps/transfer/types/transfer.pb.go b/modules/apps/transfer/types/transfer.pb.go index fb88c9e9e2e..cc7cdff4d8b 100644 --- a/modules/apps/transfer/types/transfer.pb.go +++ b/modules/apps/transfer/types/transfer.pb.go @@ -140,7 +140,7 @@ func (m *Params) GetReceiveEnabled() bool { } type ForwardingInfo struct { - Hop []*Hop `protobuf:"bytes,1,rep,name=hop,proto3" json:"hop,omitempty"` + Hops []*Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops,omitempty"` Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` } @@ -177,9 +177,9 @@ func (m *ForwardingInfo) XXX_DiscardUnknown() { var xxx_messageInfo_ForwardingInfo proto.InternalMessageInfo -func (m *ForwardingInfo) GetHop() []*Hop { +func (m *ForwardingInfo) GetHops() []*Hop { if m != nil { - return m.Hop + return m.Hops } return nil } @@ -255,29 +255,29 @@ func init() { } var fileDescriptor_5041673e96e97901 = []byte{ - // 338 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x31, 0x4b, 0xf3, 0x40, - 0x1c, 0xc6, 0x9b, 0xf6, 0xa5, 0xbc, 0xbd, 0x4a, 0x85, 0x1b, 0xa4, 0x43, 0x0d, 0x6d, 0x16, 0x0b, - 0x62, 0x42, 0xed, 0xa0, 0xe0, 0x20, 0x48, 0x95, 0x76, 0xd3, 0xd2, 0x45, 0x97, 0x72, 0xb9, 0xfc, - 0xdb, 0x1c, 0x24, 0xf7, 0x3f, 0xee, 0xd2, 0x88, 0xdf, 0xc2, 0x8f, 0xe5, 0xd8, 0xd1, 0x51, 0xda, - 0x2f, 0x22, 0x39, 0x63, 0xe8, 0xe4, 0xf6, 0xe4, 0x97, 0xdf, 0x1d, 0xf7, 0xf0, 0x90, 0x73, 0x11, - 0xf2, 0x80, 0x29, 0x95, 0x08, 0xce, 0x32, 0x81, 0xd2, 0x04, 0x99, 0x66, 0xd2, 0xac, 0x40, 0x07, - 0xf9, 0xa8, 0xca, 0xbe, 0xd2, 0x98, 0x21, 0xed, 0x89, 0x90, 0xfb, 0x87, 0xb2, 0x5f, 0x09, 0xf9, - 0xc8, 0xbb, 0x25, 0x64, 0x02, 0x12, 0xd3, 0x85, 0x66, 0x1c, 0x28, 0x25, 0xff, 0x14, 0xcb, 0xe2, - 0xae, 0xd3, 0x77, 0x86, 0xad, 0xb9, 0xcd, 0xf4, 0x94, 0x90, 0x90, 0x19, 0x58, 0x46, 0x85, 0xd6, - 0xad, 0xdb, 0x3f, 0xad, 0x82, 0xd8, 0x73, 0xde, 0x82, 0x34, 0x1f, 0x99, 0x66, 0xa9, 0xa1, 0x03, - 0x72, 0x64, 0x40, 0x46, 0x4b, 0x90, 0x2c, 0x4c, 0x20, 0xb2, 0x97, 0xfc, 0x9f, 0xb7, 0x0b, 0x76, - 0xff, 0x83, 0xe8, 0x19, 0x39, 0xd6, 0xc0, 0x41, 0xe4, 0x50, 0x59, 0x75, 0x6b, 0x75, 0x4a, 0x5c, - 0x8a, 0xde, 0x33, 0xe9, 0x3c, 0xa0, 0x7e, 0x65, 0x3a, 0x12, 0x72, 0x3d, 0x93, 0x2b, 0xa4, 0x63, - 0xd2, 0x88, 0x51, 0x75, 0x9d, 0x7e, 0x63, 0xd8, 0xbe, 0x1c, 0xf8, 0x7f, 0x95, 0xf2, 0xa7, 0xa8, - 0xe6, 0x85, 0x5d, 0xf4, 0x49, 0x21, 0xc5, 0xf2, 0xd5, 0x36, 0x7b, 0x37, 0xa4, 0x31, 0x45, 0x45, - 0x4f, 0x48, 0x53, 0xa1, 0xce, 0x66, 0x93, 0xb2, 0x6c, 0xf9, 0x45, 0x7b, 0xa4, 0xc5, 0x63, 0x26, - 0x25, 0x24, 0xb3, 0xe8, 0xb7, 0x6d, 0x05, 0xee, 0x9e, 0x3e, 0x76, 0xae, 0xb3, 0xdd, 0xb9, 0xce, - 0xd7, 0xce, 0x75, 0xde, 0xf7, 0x6e, 0x6d, 0xbb, 0x77, 0x6b, 0x9f, 0x7b, 0xb7, 0xf6, 0x72, 0xb5, - 0x16, 0x59, 0xbc, 0x09, 0x7d, 0x8e, 0x69, 0xc0, 0xd1, 0xa4, 0x68, 0x02, 0x11, 0xf2, 0x8b, 0x35, - 0x06, 0xf9, 0x75, 0x90, 0x62, 0xb4, 0x49, 0xc0, 0x14, 0x9b, 0x1d, 0x6c, 0x95, 0xbd, 0x29, 0x30, - 0x61, 0xd3, 0xce, 0x34, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xeb, 0xfc, 0xb4, 0x1e, 0xd5, 0x01, - 0x00, 0x00, + // 340 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xc1, 0x4a, 0xeb, 0x40, + 0x18, 0x85, 0x9b, 0xb6, 0x94, 0xdb, 0xe9, 0xa5, 0x17, 0x66, 0x71, 0xe9, 0xa2, 0x86, 0x36, 0x1b, + 0x0b, 0x62, 0x42, 0x15, 0x51, 0x70, 0x21, 0x48, 0x95, 0x76, 0xa7, 0xa5, 0x2b, 0x5d, 0x94, 0xc9, + 0xe4, 0x6f, 0x33, 0x90, 0xcc, 0x3f, 0xcc, 0xa4, 0x11, 0xdf, 0xc2, 0xc7, 0x72, 0xd9, 0xa5, 0x4b, + 0x69, 0x5f, 0x44, 0x32, 0xc6, 0xd0, 0x95, 0xbb, 0x93, 0x2f, 0xdf, 0x0c, 0x73, 0x38, 0xe4, 0x44, + 0x84, 0x3c, 0x60, 0x4a, 0x25, 0x82, 0xb3, 0x4c, 0xa0, 0x34, 0x41, 0xa6, 0x99, 0x34, 0x2b, 0xd0, + 0x41, 0x3e, 0xae, 0xb2, 0xaf, 0x34, 0x66, 0x48, 0xfb, 0x22, 0xe4, 0xfe, 0xa1, 0xec, 0x57, 0x42, + 0x3e, 0xf6, 0x6e, 0x08, 0x99, 0x80, 0xc4, 0x74, 0xa1, 0x19, 0x07, 0x4a, 0x49, 0x53, 0xb1, 0x2c, + 0xee, 0x39, 0x03, 0x67, 0xd4, 0x9e, 0xdb, 0x4c, 0x8f, 0x08, 0x09, 0x99, 0x81, 0x65, 0x54, 0x68, + 0xbd, 0xba, 0xfd, 0xd3, 0x2e, 0x88, 0x3d, 0xe7, 0x2d, 0x48, 0xeb, 0x81, 0x69, 0x96, 0x1a, 0x3a, + 0x24, 0x7f, 0x0d, 0xc8, 0x68, 0x09, 0x92, 0x85, 0x09, 0x44, 0xf6, 0x92, 0x3f, 0xf3, 0x4e, 0xc1, + 0xee, 0xbe, 0x11, 0x3d, 0x26, 0xff, 0x34, 0x70, 0x10, 0x39, 0x54, 0x56, 0xdd, 0x5a, 0xdd, 0x12, + 0x97, 0xa2, 0xf7, 0x4c, 0xba, 0xf7, 0xa8, 0x5f, 0x98, 0x8e, 0x84, 0x5c, 0xcf, 0xe4, 0x0a, 0xe9, + 0x05, 0x69, 0xc6, 0xa8, 0x4c, 0xcf, 0x19, 0x34, 0x46, 0x9d, 0xb3, 0xa1, 0xff, 0x5b, 0x2b, 0x7f, + 0x8a, 0x6a, 0x6e, 0xf5, 0xa2, 0x51, 0x0a, 0x29, 0x96, 0xef, 0xb6, 0xd9, 0xbb, 0x26, 0x8d, 0x29, + 0x2a, 0xfa, 0x9f, 0xb4, 0x14, 0xea, 0x6c, 0x36, 0x29, 0xeb, 0x96, 0x5f, 0xb4, 0x4f, 0xda, 0x3c, + 0x66, 0x52, 0x42, 0x32, 0x8b, 0x7e, 0xfa, 0x56, 0xe0, 0xf6, 0xf1, 0x7d, 0xe7, 0x3a, 0xdb, 0x9d, + 0xeb, 0x7c, 0xee, 0x5c, 0xe7, 0x6d, 0xef, 0xd6, 0xb6, 0x7b, 0xb7, 0xf6, 0xb1, 0x77, 0x6b, 0x4f, + 0x97, 0x6b, 0x91, 0xc5, 0x9b, 0xd0, 0xe7, 0x98, 0x06, 0x1c, 0x4d, 0x8a, 0x26, 0x10, 0x21, 0x3f, + 0x5d, 0x63, 0x90, 0x5f, 0x05, 0x29, 0x46, 0x9b, 0x04, 0x4c, 0xb1, 0xda, 0xc1, 0x5a, 0xd9, 0xab, + 0x02, 0x13, 0xb6, 0xec, 0x50, 0xe7, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbe, 0x42, 0x60, 0x0c, + 0xd7, 0x01, 0x00, 0x00, } func (m *DenomTrace) Marshal() (dAtA []byte, err error) { @@ -387,10 +387,10 @@ func (m *ForwardingInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if len(m.Hop) > 0 { - for iNdEx := len(m.Hop) - 1; iNdEx >= 0; iNdEx-- { + if len(m.Hops) > 0 { + for iNdEx := len(m.Hops) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.Hop[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Hops[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -490,8 +490,8 @@ func (m *ForwardingInfo) Size() (n int) { } var l int _ = l - if len(m.Hop) > 0 { - for _, e := range m.Hop { + if len(m.Hops) > 0 { + for _, e := range m.Hops { l = e.Size() n += 1 + l + sovTransfer(uint64(l)) } @@ -761,7 +761,7 @@ func (m *ForwardingInfo) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Hop", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Hops", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -788,8 +788,8 @@ func (m *ForwardingInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Hop = append(m.Hop, &Hop{}) - if err := m.Hop[len(m.Hop)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Hops = append(m.Hops, &Hop{}) + if err := m.Hops[len(m.Hops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index 063200c9d92..d84d9d17f93 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -15,8 +15,12 @@ const testMemo = `{"wasm":{"contract":"osmo1c3ljch9dfw5kf52nfwpxd2zmj2ese7agnx0p func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { var ( - msgTransfer *types.MsgTransfer - transferAuthz types.TransferAuthorization + msgTransfer *types.MsgTransfer + transferAuthz types.TransferAuthorization + emptyHop = types.Hop{PortID: "", ChannelId: ""} + forwardingPath = &types.ForwardingInfo{ + Hops: []*types.Hop{&emptyHop}, // Correcting this line + Memo: ""} ) testCases := []struct { @@ -92,6 +96,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.chainB.GetTimeoutHeight(), 0, "", + forwardingPath, ) }, func(res authz.AcceptResponse, err error) { @@ -273,6 +278,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.chainB.GetTimeoutHeight(), 0, "", + forwardingPath, ) tc.malleate() diff --git a/modules/apps/transfer/types/v3/packet.go b/modules/apps/transfer/types/v3/packet.go index 510a1024cac..e8c899dfe74 100644 --- a/modules/apps/transfer/types/v3/packet.go +++ b/modules/apps/transfer/types/v3/packet.go @@ -23,12 +23,14 @@ func NewFungibleTokenPacketData( tokens []*Token, sender, receiver string, memo string, + forwardingPath types.ForwardingInfo, ) FungibleTokenPacketData { return FungibleTokenPacketData{ - Tokens: tokens, - Sender: sender, - Receiver: receiver, - Memo: memo, + Tokens: tokens, + Sender: sender, + Receiver: receiver, + Memo: memo, + ForwardingPath: &forwardingPath, } } diff --git a/modules/apps/transfer/types/v3/packet_test.go b/modules/apps/transfer/types/v3/packet_test.go index 63435d8589e..1a7a08b374e 100644 --- a/modules/apps/transfer/types/v3/packet_test.go +++ b/modules/apps/transfer/types/v3/packet_test.go @@ -22,6 +22,13 @@ const ( invalidLargeAmount = "115792089237316195423570985008687907853269984665640564039457584007913129639936" // 2^256 ) +var ( + emptyHop = types.Hop{PortID: "", ChannelId: ""} + forwardingPath = &types.ForwardingInfo{ + Hops: []*types.Hop{&emptyHop}, // Correcting this line + Memo: ""} +) + var ( sender = secp256k1.GenPrivKey().PubKey().Address().String() receiver = sdk.AccAddress("testaddr2").String() @@ -47,6 +54,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", + *forwardingPath, ), nil, }, @@ -63,6 +71,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "memo", + *forwardingPath, ), nil, }, @@ -79,6 +88,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "memo", + *forwardingPath, ), nil, }, @@ -95,6 +105,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", + *forwardingPath, ), types.ErrInvalidDenomForTransfer, }, @@ -111,6 +122,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", + *forwardingPath, ), types.ErrInvalidAmount, }, @@ -121,6 +133,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", + *forwardingPath, ), types.ErrInvalidAmount, }, @@ -137,6 +150,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", + *forwardingPath, ), types.ErrInvalidAmount, }, @@ -153,6 +167,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", + *forwardingPath, ), types.ErrInvalidAmount, }, @@ -169,6 +184,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "memo", + *forwardingPath, ), types.ErrInvalidAmount, }, @@ -185,6 +201,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { "", receiver, "memo", + *forwardingPath, ), ibcerrors.ErrInvalidAddress, }, @@ -201,6 +218,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, "", "", + *forwardingPath, ), ibcerrors.ErrInvalidAddress, }, @@ -239,6 +257,7 @@ func TestGetPacketSender(t *testing.T) { sender, receiver, "", + *forwardingPath, ), sender, }, @@ -255,6 +274,7 @@ func TestGetPacketSender(t *testing.T) { "", receiver, "abc", + *forwardingPath, ), "", }, @@ -285,7 +305,7 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver)), + fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver), *forwardingPath), map[string]interface{}{ "address": receiver, @@ -303,7 +323,7 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, receiver)), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, receiver), *forwardingPath), map[string]interface{}{ "address": receiver, "gas_limit": "200000", @@ -321,7 +341,7 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - `{"src_callback": "string"}`), + `{"src_callback": "string"}`, *forwardingPath), "string", }, { @@ -336,7 +356,7 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - fmt.Sprintf(`{"dest_callback": {"address": "%s", "min_gas": "200000"}}`, receiver)), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "min_gas": "200000"}}`, receiver), *forwardingPath), nil, }, { @@ -351,7 +371,8 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - ""), + "", + *forwardingPath), nil, }, { @@ -366,7 +387,7 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - "invalid"), + "invalid", *forwardingPath), nil, }, } @@ -398,6 +419,7 @@ func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { sender, receiver, "", + *forwardingPath, ), false, }, @@ -414,6 +436,7 @@ func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { sender, receiver, "abc", + *forwardingPath, ), true, }, diff --git a/modules/apps/transfer/types/v3/token_test.go b/modules/apps/transfer/types/v3/token_test.go index 13654cfcc1d..ddd7e33059b 100644 --- a/modules/apps/transfer/types/v3/token_test.go +++ b/modules/apps/transfer/types/v3/token_test.go @@ -28,6 +28,7 @@ func TestGetFullDenomPath(t *testing.T) { sender, receiver, "", + *forwardingPath, ), "transfer/channel-0/transfer/channel-1/atom/pool", }, @@ -44,6 +45,7 @@ func TestGetFullDenomPath(t *testing.T) { sender, receiver, "", + *forwardingPath, ), denom, }, @@ -60,6 +62,7 @@ func TestGetFullDenomPath(t *testing.T) { sender, receiver, "", + *forwardingPath, ), denom, }, diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index ca430451f91..ad6b5e9671e 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -28,7 +28,7 @@ message Params { } message ForwardingInfo { - repeated Hop hop = 1; + repeated Hop hops = 1; string memo = 2; } diff --git a/testing/solomachine.go b/testing/solomachine.go index 46151bec3ea..f9120ae64d6 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -34,6 +34,13 @@ var ( channelIDSolomachine = "channel-on-solomachine" // channelID generated on solo machine side ) +var ( + emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} + forwardingPath = &transfertypes.ForwardingInfo{ + Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line + Memo: ""} +) + // DefaultSolomachineClientID is the default solo machine client id used for testing var DefaultSolomachineClientID = "06-solomachine-0" @@ -378,6 +385,7 @@ func (solo *Solomachine) SendTransfer(chain *TestChain, portID, channelID string clienttypes.ZeroHeight(), uint64(chain.GetContext().BlockTime().Add(time.Hour).UnixNano()), "", + forwardingPath, ) for _, fn := range fns { From 65f4476cdba109f706d92078e746bed79b48ea48 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Fri, 10 May 2024 19:16:22 +0200 Subject: [PATCH 015/141] test fixes --- modules/apps/callbacks/ibc_middleware_test.go | 13 ++++++------- modules/apps/callbacks/replay_test.go | 2 +- modules/apps/callbacks/transfer_test.go | 10 ++-------- modules/apps/transfer/internal/convert/convert.go | 2 +- .../apps/transfer/internal/convert/convert_test.go | 10 +--------- modules/apps/transfer/types/v3/packet_test.go | 3 +-- testing/values.go | 9 ++++++--- 7 files changed, 18 insertions(+), 31 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index ba55ec61701..7206479f1bd 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -176,7 +176,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract), - *forwardingPath, + *ibctesting.TestEmptyForwardingPath, ) chanCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) @@ -319,7 +319,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, simapp.SuccessContract, userGasLimit), - *forwardingPath, + *ibctesting.TestEmptyForwardingPath, ) packet = channeltypes.Packet{ @@ -485,7 +485,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { sdk.NewCoins(ibctesting.TestCoin), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), // set user gas limit above panic level in mock contract keeper - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) res, err := s.chainA.SendMsgs(msg) @@ -654,7 +654,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), - *forwardingPath, + *ibctesting.TestEmptyForwardingPath, ) packet = channeltypes.Packet{ @@ -787,7 +787,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), - *forwardingPath, + *ibctesting.TestEmptyForwardingPath, ) packet = channeltypes.Packet{ @@ -1007,8 +1007,7 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { Sender: ibctesting.TestAccAddress, Receiver: ibctesting.TestAccAddress, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), - ForwardingPath: forwardingPath, - //ForwardingPath: &transferv1types.ForwardingInfo{Hops: []*transferv1types.Hop{}, Memo: ""}, + ForwardingPath: ibctesting.TestEmptyForwardingPath, } // Unmarshal ICS20 v1 packet data diff --git a/modules/apps/callbacks/replay_test.go b/modules/apps/callbacks/replay_test.go index 95ad17bf72d..b3f12b0e12d 100644 --- a/modules/apps/callbacks/replay_test.go +++ b/modules/apps/callbacks/replay_test.go @@ -330,7 +330,7 @@ func (s *CallbacksTestSuite) ExecuteFailedTransfer(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) res, err := s.chainA.SendMsgs(msg) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 4f9048e1ab4..2661703553a 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -14,12 +14,6 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) -var ( - forwardingPath = &transfertypes.ForwardingInfo{ - Hops: []*transfertypes.Hop{}, // Correcting this line - Memo: ""} -) - func (s *CallbacksTestSuite) TestTransferCallbacks() { testCases := []struct { name string @@ -199,7 +193,7 @@ func (s *CallbacksTestSuite) ExecuteTransfer(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) res, err := s.chainA.SendMsgs(msg) @@ -234,7 +228,7 @@ func (s *CallbacksTestSuite) ExecuteTransferTimeout(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), timeoutHeight, timeoutTimestamp, memo, - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) res, err := s.chainA.SendMsgs(msg) diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go index 650679d5aa2..e9f343eb58f 100644 --- a/modules/apps/transfer/internal/convert/convert.go +++ b/modules/apps/transfer/internal/convert/convert.go @@ -8,7 +8,7 @@ import ( ) var forwardingPath = &types.ForwardingInfo{ - Hops: []*types.Hop{}, // Correcting this line + Hops: nil, // Correcting this line Memo: ""} // PacketDataV1ToV3 converts a v1 (ICS20-V1) packet data to a v3 (ICS20-V2) packet data. diff --git a/modules/apps/transfer/internal/convert/convert_test.go b/modules/apps/transfer/internal/convert/convert_test.go index 2f74000ee25..5fc869f7f1b 100644 --- a/modules/apps/transfer/internal/convert/convert_test.go +++ b/modules/apps/transfer/internal/convert/convert_test.go @@ -11,14 +11,6 @@ import ( v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" ) -/* -var ( - //emptyHop = types.Hop{PortID: "", ChannelId: ""} - forwardingPath = &types.ForwardingInfo{ - Hops: []*types.Hop{}, // Correcting this line - Memo: ""} -)*/ - func TestConvertPacketV1ToPacketV3(t *testing.T) { const ( sender = "sender" @@ -26,7 +18,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { ) var forwardingPath = &types.ForwardingInfo{ - Hops: []*types.Hop{}, // Correcting this line + Hops: nil, Memo: ""} testCases := []struct { diff --git a/modules/apps/transfer/types/v3/packet_test.go b/modules/apps/transfer/types/v3/packet_test.go index 1a7a08b374e..772a7cd7ccb 100644 --- a/modules/apps/transfer/types/v3/packet_test.go +++ b/modules/apps/transfer/types/v3/packet_test.go @@ -23,9 +23,8 @@ const ( ) var ( - emptyHop = types.Hop{PortID: "", ChannelId: ""} forwardingPath = &types.ForwardingInfo{ - Hops: []*types.Hop{&emptyHop}, // Correcting this line + Hops: nil, Memo: ""} ) diff --git a/testing/values.go b/testing/values.go index 0f14f41a081..8112cbf7f9e 100644 --- a/testing/values.go +++ b/testing/values.go @@ -55,9 +55,12 @@ var ( // DefaultTrustLevel sets params variables used to create a TM client DefaultTrustLevel = ibctm.DefaultTrustLevel - TestAccAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" - TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) - TestCoins = sdk.NewCoins(TestCoin) + TestAccAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + TestEmptyForwardingPath = &ibctransfertypes.ForwardingInfo{ + Hops: nil, // Correcting this line + Memo: ""} + TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) + TestCoins = sdk.NewCoins(TestCoin) UpgradePath = []string{"upgrade", "upgradedIBCState"} From db85a29ef6650e59e14f95b2af7b959e6d55091f Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Mon, 13 May 2024 16:35:19 +0200 Subject: [PATCH 016/141] add forwardPath keys and memo check in sendTransfer --- .../host/keeper/relay_test.go | 12 ++----- .../apps/transfer/keeper/invariants_test.go | 2 +- modules/apps/transfer/keeper/keeper.go | 22 +++++++++++++ .../apps/transfer/keeper/mbt_relay_test.go | 4 +-- .../apps/transfer/keeper/msg_server_test.go | 6 ++-- modules/apps/transfer/keeper/relay.go | 17 ++++++++++ modules/apps/transfer/keeper/relay_test.go | 31 +++++++------------ modules/apps/transfer/types/errors.go | 21 +++++++------ modules/apps/transfer/types/keys.go | 12 +++++++ 9 files changed, 83 insertions(+), 44 deletions(-) diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index 15958aa5c80..364f5061bb4 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -24,12 +24,6 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) -var ( - forwardingPath = &transfertypes.ForwardingInfo{ - Hops: []*transfertypes.Hop{}, // Correcting this line - Memo: ""} -) - func (suite *KeeperTestSuite) TestOnRecvPacket() { testedEncodings := []string{icatypes.EncodingProtobuf, icatypes.EncodingProto3JSON} var ( @@ -357,7 +351,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.chainB.GetTimeoutHeight(), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) @@ -393,7 +387,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.chainB.GetTimeoutHeight(), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) @@ -916,7 +910,7 @@ func (suite *KeeperTestSuite) TestJSONOnRecvPacket() { suite.chainB.GetTimeoutHeight(), 0, ) - + // Test fails here txResponse, err := suite.chainB.GetSimApp().ICAHostKeeper.OnRecvPacket(suite.chainB.GetContext(), packet) expPass := tc.expErr == nil diff --git a/modules/apps/transfer/keeper/invariants_test.go b/modules/apps/transfer/keeper/invariants_test.go index 7e8ce6db554..928d2157959 100644 --- a/modules/apps/transfer/keeper/invariants_test.go +++ b/modules/apps/transfer/keeper/invariants_test.go @@ -51,7 +51,7 @@ func (suite *KeeperTestSuite) TestTotalEscrowPerDenomInvariant() { suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) res, err := suite.chainA.SendMsgs(msg) diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 0ec4dac6abf..3ad1dc03908 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -18,6 +18,7 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" 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" @@ -302,3 +303,24 @@ func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Cap func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { return k.scopedKeeper.ClaimCapability(ctx, cap, name) } + +// Set the forwarded packet in the private store. +func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, packet v3types.FungibleTokenPacketData) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshal(&packet) + store.Set(types.PacketForwardPath(portID, channelID), bz) +} + +// GetCounterpartyUpgrade gets the counterparty upgrade from the store. +func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string) (v3types.FungibleTokenPacketData, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.PacketForwardPath(portID, channelID)) + if bz == nil { + return v3types.FungibleTokenPacketData{}, false + } + + var upgrade v3types.FungibleTokenPacketData + k.cdc.MustUnmarshal(bz, &upgrade) + + return upgrade, true +} diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 4a939715727..101db74ceed 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -162,7 +162,7 @@ func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPack AddressFromString(packet.Data.Sender), AddressFromString(packet.Data.Receiver), "", - *forwardingPath, + *ibctesting.TestEmptyForwardingPath, ), } } @@ -363,7 +363,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { tc.packet.Data.Receiver, suite.chainA.GetTimeoutHeight(), 0, // only use timeout height "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) _, err = suite.chainB.GetSimApp().TransferKeeper.Transfer(suite.chainB.GetContext(), msg) diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 1cda59fa298..cac968618ce 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -54,7 +54,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) }, nil, @@ -140,7 +140,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) // explicitly set to ics20-1 which does not support multi-denom @@ -171,7 +171,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) tc.malleate() diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 6acb6a1f91e..93441309686 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -71,6 +71,14 @@ func (k Keeper) sendTransfer( return 0, errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", sourcePort, sourceChannel) } + // Input validation. We cannot have memo and forwarding path set at the same time. + // Note that this check could actually go inside the validate basic of v3 packet.go + // for NewFungibleTokenPacketData. Should probably go there because validateBasics is the function used for + // Input validations. For now I'll keep this check inside the relay.go function. We can decide to move them. + if forwardingPath.Hops != nil && memo != "" { + return 0, errorsmod.Wrapf(types.ErrInvalidMemoSpecification, "incorrect memo specification: %s,%s", memo, forwardingPath.Hops) + } + destinationPort := channel.Counterparty.PortId destinationChannel := channel.Counterparty.ChannelId @@ -145,6 +153,7 @@ func (k Keeper) sendTransfer( tokens = append(tokens, token) } + // If we put the memo check in the validate basic, in case this line will return an error. packetData := v3types.NewFungibleTokenPacketData(tokens, sender.String(), receiver, memo, forwardingPath) sequence, err := k.ics4Wrapper.SendPacket(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, packetData.GetBytes()) @@ -181,10 +190,16 @@ func (k Keeper) sendTransfer( // unescrowed and sent to the receiving address. func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { // validate packet data upon receiving + // same things here if we put the validate memo here this function would return an error. if err := data.ValidateBasic(); err != nil { return errorsmod.Wrapf(err, "error validating ICS-20 transfer packet data") } + // Otherwise we need to validate here + if data.ForwardingPath.Hops != nil && data.Memo != "" { + return errorsmod.Wrapf(types.ErrInvalidMemoSpecification, "incorrect memo specification: %s,%s", data.Memo, data.ForwardingPath.Hops) + } + if !k.GetParams(ctx).ReceiveEnabled { return types.ErrReceiveDisabled } @@ -195,6 +210,8 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver) } + //var receivedTokens=[]v3types.Token + for _, token := range data.Tokens { fullDenomPath := token.GetFullDenomPath() diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 5eb249f6ccd..d4fed1a9501 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -18,13 +18,6 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) -var ( - emptyHop = types.Hop{PortID: "", ChannelId: ""} - forwardingPath = &types.ForwardingInfo{ - Hops: []*types.Hop{&emptyHop}, // Correcting this line - Memo: ""} -) - // test sending from chainA to chainB using both coin that originate on // chainA and coin that originate on chainB func (suite *KeeperTestSuite) TestSendTransfer() { @@ -136,7 +129,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { expEscrowAmount = sdkmath.ZeroInt() // create IBC token on chainA - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", forwardingPath) + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", ibctesting.TestEmptyForwardingPath) result, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -154,7 +147,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { sdk.NewCoins(coin), sender.String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, // only use timeout height memo, - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) res, err := suite.chainA.GetSimApp().TransferKeeper.Transfer(suite.chainA.GetContext(), msg) @@ -221,7 +214,7 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) result, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -242,7 +235,7 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) res, err := suite.chainB.GetSimApp().TransferKeeper.Transfer(suite.chainB.GetContext(), msg) @@ -396,7 +389,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { if tc.recvIsSource { // send coin from chainB to chainA, receive them, acknowledge them, and send back to chainB coinFromBToA := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coinFromBToA), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, memo, forwardingPath) + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coinFromBToA), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, memo, ibctesting.TestEmptyForwardingPath) res, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -416,7 +409,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // send coin from chainA to chainB coin := sdk.NewCoin(denomTrace.IBCDenom(), amount) - transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo, forwardingPath) + transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo, ibctesting.TestEmptyForwardingPath) _, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -430,7 +423,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Amount: amount.String(), Trace: trace, }, - }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, *forwardingPath) + }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, *ibctesting.TestEmptyForwardingPath) packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) @@ -513,7 +506,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT Amount: amount.String(), Trace: trace, }, - }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", *forwardingPath) + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", *ibctesting.TestEmptyForwardingPath) packet := channeltypes.NewPacket( data.GetBytes(), seq, @@ -640,7 +633,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { Amount: amount.String(), Trace: trace, }, - }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", *forwardingPath) + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", *ibctesting.TestEmptyForwardingPath) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denomTrace.IBCDenom()) @@ -737,7 +730,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", - *forwardingPath, + *ibctesting.TestEmptyForwardingPath, ) packet := channeltypes.NewPacket( data.GetBytes(), @@ -857,7 +850,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { Amount: amount.String(), Trace: trace, }, - }, sender, suite.chainB.SenderAccount.GetAddress().String(), "", *forwardingPath) + }, sender, suite.chainB.SenderAccount.GetAddress().String(), "", *ibctesting.TestEmptyForwardingPath) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denomTrace.IBCDenom()) @@ -943,7 +936,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI Amount: amount.String(), Trace: trace, }, - }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", *forwardingPath) + }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", *ibctesting.TestEmptyForwardingPath) packet := channeltypes.NewPacket( data.GetBytes(), seq, diff --git a/modules/apps/transfer/types/errors.go b/modules/apps/transfer/types/errors.go index b3e45aa2ae2..4c630a25e56 100644 --- a/modules/apps/transfer/types/errors.go +++ b/modules/apps/transfer/types/errors.go @@ -6,14 +6,15 @@ import ( // IBC transfer sentinel errors var ( - ErrInvalidPacketTimeout = errorsmod.Register(ModuleName, 2, "invalid packet timeout") - ErrInvalidDenomForTransfer = errorsmod.Register(ModuleName, 3, "invalid denomination for cross-chain transfer") - ErrInvalidVersion = errorsmod.Register(ModuleName, 4, "invalid ICS20 version") - ErrInvalidAmount = errorsmod.Register(ModuleName, 5, "invalid token amount") - ErrTraceNotFound = errorsmod.Register(ModuleName, 6, "denomination trace not found") - ErrSendDisabled = errorsmod.Register(ModuleName, 7, "fungible token transfers from this chain are disabled") - ErrReceiveDisabled = errorsmod.Register(ModuleName, 8, "fungible token transfers to this chain are disabled") - ErrMaxTransferChannels = errorsmod.Register(ModuleName, 9, "max transfer channels") - ErrInvalidAuthorization = errorsmod.Register(ModuleName, 10, "invalid transfer authorization") - ErrInvalidMemo = errorsmod.Register(ModuleName, 11, "invalid memo") + ErrInvalidPacketTimeout = errorsmod.Register(ModuleName, 2, "invalid packet timeout") + ErrInvalidDenomForTransfer = errorsmod.Register(ModuleName, 3, "invalid denomination for cross-chain transfer") + ErrInvalidVersion = errorsmod.Register(ModuleName, 4, "invalid ICS20 version") + ErrInvalidAmount = errorsmod.Register(ModuleName, 5, "invalid token amount") + ErrTraceNotFound = errorsmod.Register(ModuleName, 6, "denomination trace not found") + ErrSendDisabled = errorsmod.Register(ModuleName, 7, "fungible token transfers from this chain are disabled") + ErrReceiveDisabled = errorsmod.Register(ModuleName, 8, "fungible token transfers to this chain are disabled") + ErrMaxTransferChannels = errorsmod.Register(ModuleName, 9, "max transfer channels") + ErrInvalidAuthorization = errorsmod.Register(ModuleName, 10, "invalid transfer authorization") + ErrInvalidMemo = errorsmod.Register(ModuleName, 11, "invalid memo") + ErrInvalidMemoSpecification = errorsmod.Register(ModuleName, 12, "invalid memo speicification") ) diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index d985438ab71..02412b8ae21 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -32,6 +32,8 @@ const ( KeyTotalEscrowPrefix = "totalEscrowForDenom" ParamsKey = "params" + + KeyPacketForwardPrefix = "forwardedPacket" ) const ( @@ -77,3 +79,13 @@ func GetEscrowAddress(portID, channelID string) sdk.AccAddress { func TotalEscrowForDenomKey(denom string) []byte { return []byte(fmt.Sprintf("%s/%s", KeyTotalEscrowPrefix, denom)) } + +// Packet forward key +func PacketForwardPath(portID, channelID string) []byte { + return []byte(packetForwardPath(portID, channelID)) +} + +// Packet ForwardPath to store the forwarded packets +func packetForwardPath(portID, channelID string) string { + return fmt.Sprintf("%s/%s", KeyPacketForwardPrefix, PacketForwardPath(portID, channelID)) +} From 999ed80451449e92e53b85723c63eed5b3fba30a Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Mon, 13 May 2024 20:22:19 +0200 Subject: [PATCH 017/141] wip onRecvPacket logic --- modules/apps/29-fee/transfer_test.go | 11 +-- modules/apps/transfer/keeper/relay.go | 98 ++++++++++++++++++++++++-- modules/apps/transfer/transfer_test.go | 13 +--- modules/apps/transfer/types/keys.go | 24 ++++++- 4 files changed, 120 insertions(+), 26 deletions(-) diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 0b0528a3860..68b7fea95cf 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -9,13 +9,6 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) -var ( - emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} - forwardingPath = &transfertypes.ForwardingInfo{ - Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line - Memo: ""} -) - // Integration test to ensure ics29 works with ics20 func (suite *FeeTestSuite) TestFeeTransfer() { path := ibctesting.NewPath(suite.chainA, suite.chainB) @@ -37,7 +30,7 @@ func (suite *FeeTestSuite) TestFeeTransfer() { msgs := []sdk.Msg{ types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), - transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", forwardingPath), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", ibctesting.TestEmptyForwardingPath), } res, err := suite.chainA.SendMsgs(msgs...) suite.Require().NoError(err) // message committed @@ -145,7 +138,7 @@ func (suite *FeeTestSuite) TestTransferFeeUpgrade() { fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) msgs := []sdk.Msg{ types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), - transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", forwardingPath), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", ibctesting.TestEmptyForwardingPath), } res, err := suite.chainA.SendMsgs(msgs...) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 93441309686..23cd74074f1 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -204,13 +204,39 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v return types.ErrReceiveDisabled } - // decode the receiver address - receiver, err := sdk.AccAddressFromBech32(data.Receiver) - if err != nil { - return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver) + // Receiver addresses logic: + var forwardAddress sdk.AccAddress + var finalReceiver sdk.AccAddress + var receiver sdk.AccAddress + var err error + + if len(data.ForwardingPath.Hops) > 0 { + // Transaction would abort already for previous check on Memo + forwardAddress = types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) + if forwardAddress.Empty() { + forwardAddress, err = sdk.AccAddressFromBech32("forwardAddress") // MMMM // How to set this? + if err != nil { + return errorsmod.Wrapf(err, "failed to decode forward address: %s", data.Receiver) + } + } + receiver = forwardAddress + finalReceiver, err = sdk.AccAddressFromBech32(data.Receiver) + if err != nil { + return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver) + } + } else { + receiver, err = sdk.AccAddressFromBech32(data.Receiver) + if err != nil { + return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver) + } } - //var receivedTokens=[]v3types.Token + //TODO Assertion Implementation + /*assert(packet.sender !== "") + assert(receiver !== "")*/ + + //var receivedTokens []*v3types.Token + var receivedTokens sdk.Coins for _, token := range data.Tokens { fullDenomPath := token.GetFullDenomPath() @@ -278,7 +304,17 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v ) }() - return nil + // Need to set right trace. Or we use directly coins? + //_, trace := convert.ExtractDenomAndTraceFromV1Denom(fullDenomPath) + + recvToken := sdk.Coin{ + Denom: token.Denom, // or denom? + //Trace: trace, // Which trace? + Amount: transferAmount, + } + + receivedTokens = append(receivedTokens, recvToken) + //return nil } // sender chain is the source, mint vouchers @@ -339,11 +375,61 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v ), ) }() + + // Need to set right trace. Or we use directly coins? + //_, trace := convert.ExtractDenomAndTraceFromV1Denom(fullDenomPath) + + recvToken := sdk.Coin{ + Denom: token.Denom, + // Trace: trace, // Which trace? + Amount: transferAmount, + } + + receivedTokens = append(receivedTokens, recvToken) } + // END OF FOR CYCLE + + /* If ack wasn't successfull in the implementation we would have already errored out. No need of this check: + if !ack.Success() { + return ack + } + */ + + // Adding forwarding logic + if len(data.ForwardingPath.Hops) > 0 { + memo := "" + nextForwardingPath := types.ForwardingInfo{ + Hops: data.ForwardingPath.Hops[1:], + Memo: data.ForwardingPath.Memo, + } + + if len(data.ForwardingPath.Hops) == 1 { + memo = data.ForwardingPath.Memo + nextForwardingPath = types.ForwardingInfo{ + Hops: nil, + Memo: data.ForwardingPath.Memo, + } + + } + + // Need to check if setting of timeoutHeight and timeoutTimestamp is correct + selfHeight, selfTimestamp := clienttypes.GetSelfHeight(ctx), uint64(ctx.BlockTime().UnixNano()) + // _ is nextPacketSequence + _, err := k.sendTransfer(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, receivedTokens, receiver, string(finalReceiver), selfHeight, selfTimestamp, memo, nextForwardingPath) + if err != nil { + return err + } + //return sequence, nil + return nil + } + // This should be return ack. return nil } +// return nil +//} + // OnAcknowledgementPacket responds to the success or failure of a packet // acknowledgement written on the receiving chain. If the acknowledgement // was a success then nothing occurs. If the acknowledgement failed, then diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go index 9721ecd8d12..da411cedbbe 100644 --- a/modules/apps/transfer/transfer_test.go +++ b/modules/apps/transfer/transfer_test.go @@ -32,13 +32,6 @@ func (suite *TransferTestSuite) SetupTest() { suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(3)) } -var ( - emptyHop = types.Hop{PortID: "", ChannelId: ""} - forwardingPath = &types.ForwardingInfo{ - Hops: []*types.Hop{&emptyHop}, // Correcting this line - Memo: ""} -) - // Constructs the following sends based on the established channels/connections // 1 - from chainA to chainB // 2 - from chainB to chainC @@ -59,7 +52,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) // send from chainA to chainB - msg := types.NewMsgTransfer(pathAtoB.EndpointA.ChannelConfig.PortID, pathAtoB.EndpointA.ChannelID, sdk.NewCoins(coinToSendToB), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", forwardingPath) + msg := types.NewMsgTransfer(pathAtoB.EndpointA.ChannelConfig.PortID, pathAtoB.EndpointA.ChannelID, sdk.NewCoins(coinToSendToB), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath) res, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -89,7 +82,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { pathBtoC.Setup() // send from chainB to chainC - msg = types.NewMsgTransfer(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, sdk.NewCoins(coinSentFromAToB), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", forwardingPath) + msg = types.NewMsgTransfer(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, sdk.NewCoins(coinSentFromAToB), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath) res, err = suite.chainB.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -112,7 +105,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { suite.Require().Zero(balance.Amount.Int64()) // send from chainC back to chainB - msg = types.NewMsgTransfer(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, sdk.NewCoins(coinSentFromBToC), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", forwardingPath) + msg = types.NewMsgTransfer(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, sdk.NewCoins(coinSentFromBToC), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath) res, err = suite.chainC.SendMsgs(msg) suite.Require().NoError(err) // message committed diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index 02412b8ae21..ef1eaa36027 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -29,7 +29,8 @@ const ( // AllowAllPacketDataKeys holds the string key that allows all packet data keys in authz transfer messages AllowAllPacketDataKeys = "*" - KeyTotalEscrowPrefix = "totalEscrowForDenom" + KeyTotalEscrowPrefix = "totalEscrowForDenom" + KeyTotalForwardPrefix = "totalForwardForDenom" ParamsKey = "params" @@ -46,6 +47,9 @@ const ( // escrowAddressVersion should remain as ics20-1 to avoid the address changing. escrowAddressVersion = "ics20-1" + + // this new address is introduced specifically with ics20-2. + forwardAddressVersion = "ics20-2" ) var ( @@ -74,12 +78,30 @@ func GetEscrowAddress(portID, channelID string) sdk.AccAddress { return hash[:20] } +// GetForwardAddress returns the escrow address for the specified channel. +func GetForwardAddress(portID, channelID string) sdk.AccAddress { + // a slash is used to create domain separation between port and channel identifiers to + // prevent address collisions between escrow addresses created for different channels + contents := fmt.Sprintf("%s/%s", portID, channelID) + + // ADR 028 AddressHash construction + preImage := []byte(forwardAddressVersion) + preImage = append(preImage, 0) + preImage = append(preImage, contents...) + hash := sha256.Sum256(preImage) + return hash[:20] +} + // TotalEscrowForDenomKey returns the store key of under which the total amount of // source chain tokens in escrow is stored. func TotalEscrowForDenomKey(denom string) []byte { return []byte(fmt.Sprintf("%s/%s", KeyTotalEscrowPrefix, denom)) } +func TotalForwardForDenomKey(denom string) []byte { + return []byte(fmt.Sprintf("%s/%s", KeyTotalForwardPrefix, denom)) +} + // Packet forward key func PacketForwardPath(portID, channelID string) []byte { return []byte(packetForwardPath(portID, channelID)) From be7218091de880110c708a85bfbc31bd16e8aaf1 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Mon, 13 May 2024 20:43:28 +0200 Subject: [PATCH 018/141] minor fixes --- e2e/tests/transfer/authz_test.go | 16 ++----- e2e/tests/transfer/incentivized_test.go | 5 +- e2e/tests/transfer/upgrades_test.go | 3 +- e2e/tests/upgrades/upgrade_test.go | 9 +--- e2e/testsuite/tx.go | 10 +--- modules/apps/29-fee/keeper/events_test.go | 9 +--- modules/apps/transfer/client/cli/tx.go | 3 +- modules/apps/transfer/types/msgs_test.go | 48 +++++++++---------- .../types/transfer_authorization_test.go | 12 ++--- testing/solomachine.go | 3 +- 10 files changed, 42 insertions(+), 76 deletions(-) diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index 7580a93e7f1..b282376493d 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -20,13 +20,7 @@ import ( "github.com/cosmos/ibc-go/e2e/testvalues" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" -) - -var ( - emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} - forwardingPath = &transfertypes.ForwardingInfo{ - Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line - Memo: ""} + ibctesting "github.com/cosmos/ibc-go/v8/testing" ) func TestAuthzTransferTestSuite(t *testing.T) { @@ -120,7 +114,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -180,7 +174,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -263,7 +257,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -323,7 +317,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) diff --git a/e2e/tests/transfer/incentivized_test.go b/e2e/tests/transfer/incentivized_test.go index e71fc7a33a7..13211a2a37d 100644 --- a/e2e/tests/transfer/incentivized_test.go +++ b/e2e/tests/transfer/incentivized_test.go @@ -20,6 +20,7 @@ import ( feetypes "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" + ibctesting "github.com/cosmos/ibc-go/v8/testing" ) const ( @@ -197,7 +198,7 @@ func (s *IncentivizedTransferTestSuite) TestMsgPayPacketFee_InvalidReceiverAccou transferAmount := testvalues.DefaultTransferAmount(chainADenom) t.Run("send IBC transfer", func(t *testing.T) { - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), testvalues.InvalidAddress, s.GetTimeoutHeight(ctx, chainB), 0, "", forwardingPath) + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), testvalues.InvalidAddress, s.GetTimeoutHeight(ctx, chainB), 0, "", ibctesting.TestEmptyForwardingPath) txResp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgTransfer) // this message should be successful, as receiver account is not validated on the sending chain. s.AssertTxSuccess(txResp) @@ -322,7 +323,7 @@ func (s *IncentivizedTransferTestSuite) TestMultiMsg_MsgPayPacketFeeSingleSender }) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", forwardingPath) + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", ibctesting.TestEmptyForwardingPath) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) diff --git a/e2e/tests/transfer/upgrades_test.go b/e2e/tests/transfer/upgrades_test.go index e69dd7e2439..0aad2d11170 100644 --- a/e2e/tests/transfer/upgrades_test.go +++ b/e2e/tests/transfer/upgrades_test.go @@ -20,6 +20,7 @@ import ( feetypes "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" + ibctesting "github.com/cosmos/ibc-go/v8/testing" ) func TestTransferChannelUpgradesTestSuite(t *testing.T) { @@ -197,7 +198,7 @@ func (s *TransferChannelUpgradesTestSuite) TestChannelUpgrade_WithFeeMiddleware_ transferAmount := testvalues.DefaultTransferAmount(chainA.Config().Denom) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", forwardingPath) + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", ibctesting.TestEmptyForwardingPath) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) }) diff --git a/e2e/tests/upgrades/upgrade_test.go b/e2e/tests/upgrades/upgrade_test.go index eac7655d3fe..aa6287b7d2d 100644 --- a/e2e/tests/upgrades/upgrade_test.go +++ b/e2e/tests/upgrades/upgrade_test.go @@ -37,13 +37,6 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) -var ( - emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} - forwardingPath = &transfertypes.ForwardingInfo{ - Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line - Memo: ""} -) - const ( haltHeight = int64(100) blocksAfterUpgrade = uint64(10) @@ -967,7 +960,7 @@ func (s *UpgradeTestSuite) TestV8ToV8_1ChainUpgrade_ChannelUpgrades() { transferAmount := testvalues.DefaultTransferAmount(chainA.Config().Denom) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", forwardingPath) + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", ibctesting.TestEmptyForwardingPath) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) }) diff --git a/e2e/testsuite/tx.go b/e2e/testsuite/tx.go index b91fb147cff..5f1b91da7dc 100644 --- a/e2e/testsuite/tx.go +++ b/e2e/testsuite/tx.go @@ -32,13 +32,7 @@ import ( transfertypes "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" -) - -var ( - emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} - forwardingPath = &transfertypes.ForwardingInfo{ - Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line - Memo: ""} + ibctesting "github.com/cosmos/ibc-go/v8/testing" ) // BroadcastMessages broadcasts the provided messages to the given chain and signs them on behalf of the provided user. @@ -272,7 +266,7 @@ func (s *E2ETestSuite) ExecuteGovV1Beta1Proposal(ctx context.Context, chain ibc. func (s *E2ETestSuite) Transfer(ctx context.Context, chain ibc.Chain, user ibc.Wallet, portID, channelID string, token sdk.Coin, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, ) sdk.TxResponse { - msg := transfertypes.NewMsgTransfer(portID, channelID, sdk.NewCoins(token), sender, receiver, timeoutHeight, timeoutTimestamp, memo, forwardingPath) + msg := transfertypes.NewMsgTransfer(portID, channelID, sdk.NewCoins(token), sender, receiver, timeoutHeight, timeoutTimestamp, memo, ibctesting.TestEmptyForwardingPath) return s.BroadcastMessages(ctx, chain, user, msg) } diff --git a/modules/apps/29-fee/keeper/events_test.go b/modules/apps/29-fee/keeper/events_test.go index 0af93c58f28..604be9c23b0 100644 --- a/modules/apps/29-fee/keeper/events_test.go +++ b/modules/apps/29-fee/keeper/events_test.go @@ -15,13 +15,6 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) -var ( - emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} - forwardingPath = &transfertypes.ForwardingInfo{ - Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line - Memo: ""} -) - func (suite *KeeperTestSuite) TestIncentivizePacketEvent() { var ( expRecvFees sdk.Coins @@ -122,7 +115,7 @@ func (suite *KeeperTestSuite) TestDistributeFeeEvent() { path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) res, err := suite.chainA.SendMsgs(msgPayPacketFee, msgTransfer) diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index 58965a82358..2cdd9500b57 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -19,9 +19,8 @@ import ( ) var ( - emptyHop = types.Hop{PortID: "", ChannelId: ""} forwardingPath = &types.ForwardingInfo{ - Hops: []*types.Hop{&emptyHop}, // Correcting this line + Hops: nil, // Correcting this line Memo: ""} ) diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index b9fffe9363c..0e03ed02205 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -43,11 +43,7 @@ var ( invalidIBCCoins = sdk.NewCoins(sdk.NewCoin("ibc/7F1D3FCF4AE79E1554", sdkmath.NewInt(100))) invalidDenomCoins = []sdk.Coin{{Denom: "0atom", Amount: sdkmath.NewInt(100)}} zeroCoins = sdk.NewCoins(sdk.Coin{Denom: "atoms", Amount: sdkmath.NewInt(0)}) - emptyHop = types.Hop{PortID: "", ChannelId: ""} - forwardingPath = &types.ForwardingInfo{ - Hops: []*types.Hop{&emptyHop}, // Correcting this line - Memo: ""} - timeoutHeight = clienttypes.NewHeight(0, 10) + timeoutHeight = clienttypes.NewHeight(0, 10) ) // TestMsgTransferValidation tests ValidateBasic for MsgTransfer @@ -57,26 +53,26 @@ func TestMsgTransferValidation(t *testing.T) { msg *types.MsgTransfer expPass bool }{ - {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), true}, - {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, timeoutHeight, 0, "", forwardingPath), true}, - {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, timeoutHeight, 0, "", forwardingPath), true}, - {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1), forwardingPath), false}, - {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", timeoutHeight, 0, "", forwardingPath), false}, - {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, "", forwardingPath), false}, - {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, - {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", forwardingPath), false}, + {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), true}, + {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), true}, + {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), true}, + {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1), ibctesting.TestEmptyForwardingPath), false}, + {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, } for i, tc := range testCases { @@ -94,7 +90,7 @@ func TestMsgTransferValidation(t *testing.T) { // TestMsgTransferGetSigners tests GetSigners for MsgTransfer func TestMsgTransferGetSigners(t *testing.T) { addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - msg := types.NewMsgTransfer(validPort, validChannel, coins, addr.String(), receiver, timeoutHeight, 0, "", forwardingPath) + msg := types.NewMsgTransfer(validPort, validChannel, coins, addr.String(), receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath) encodingCfg := moduletestutil.MakeTestEncodingConfig(transfer.AppModuleBasic{}) signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index d84d9d17f93..65ac18f0d12 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -15,12 +15,8 @@ const testMemo = `{"wasm":{"contract":"osmo1c3ljch9dfw5kf52nfwpxd2zmj2ese7agnx0p func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { var ( - msgTransfer *types.MsgTransfer - transferAuthz types.TransferAuthorization - emptyHop = types.Hop{PortID: "", ChannelId: ""} - forwardingPath = &types.ForwardingInfo{ - Hops: []*types.Hop{&emptyHop}, // Correcting this line - Memo: ""} + msgTransfer *types.MsgTransfer + transferAuthz types.TransferAuthorization ) testCases := []struct { @@ -96,7 +92,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.chainB.GetTimeoutHeight(), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) }, func(res authz.AcceptResponse, err error) { @@ -278,7 +274,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.chainB.GetTimeoutHeight(), 0, "", - forwardingPath, + ibctesting.TestEmptyForwardingPath, ) tc.malleate() diff --git a/testing/solomachine.go b/testing/solomachine.go index f9120ae64d6..341c4bcb53c 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -35,9 +35,8 @@ var ( ) var ( - emptyHop = transfertypes.Hop{PortID: "", ChannelId: ""} forwardingPath = &transfertypes.ForwardingInfo{ - Hops: []*transfertypes.Hop{&emptyHop}, // Correcting this line + Hops: nil, // Correcting this line Memo: ""} ) From 4c333c5b9b442187bb0f4b378f772ee54c4a6044 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 14 May 2024 10:50:56 +0200 Subject: [PATCH 019/141] changes to transfer tx CLI to support multiple denoms --- modules/apps/transfer/client/cli/tx.go | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index ccdd08af588..b0ca95fe7fe 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -34,12 +34,14 @@ var defaultRelativePacketTimeoutTimestamp = uint64((time.Duration(10) * time.Min // NewTransferTxCmd returns the command to create a NewMsgTransfer transaction func NewTransferTxCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "transfer [src-port] [src-channel] [receiver] [amount]", - Short: "Transfer a fungible token through IBC", - Long: strings.TrimSpace(`Transfer a fungible token through IBC. Timeouts can be specified as absolute using the {absolute-timeouts} flag. -Timeout height can be set by passing in the height string in the form {revision}-{height} using the {packet-timeout-height} flag. Note, relative timeout height is not supported. -Relative timeout timestamp is added to the value of the user's local system clock time using the {packet-timeout-timestamp} flag. If no timeout value is set then a default relative timeout value of 10 minutes is used.`), - Example: fmt.Sprintf("%s tx ibc-transfer transfer [src-port] [src-channel] [receiver] [amount]", version.AppName), + Use: "transfer [src-port] [src-channel] [receiver] [coins]", + Short: "Transfer one or more fungible tokens through IBC", + Long: strings.TrimSpace(`Transfer one or more fungible tokens through IBC. Multiple tokens can be transferred in a single +packet if the coins list is a comma-separated string (e.g. 100uatom,100uosmo). Timeouts can be specified as absolute using the {absolute-timeouts} flag. +Timeout height can be set by passing in the height string in the form {revision}-{height} using the {packet-timeout-height} flag. +Note, relative timeout height is not supported. Relative timeout timestamp is added to the value of the user's local system clock time +using the {packet-timeout-timestamp} flag. If no timeout value is set then a default relative timeout value of 10 minutes is used.`), + Example: fmt.Sprintf("%s tx ibc-transfer transfer [src-port] [src-channel] [receiver] [coins]", version.AppName), Args: cobra.ExactArgs(4), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) @@ -51,14 +53,16 @@ Relative timeout timestamp is added to the value of the user's local system cloc srcChannel := args[1] receiver := args[2] - coin, err := sdk.ParseCoinNormalized(args[3]) + coins, err := sdk.ParseCoinsNormalized(args[3]) if err != nil { return err } - if !strings.HasPrefix(coin.Denom, "ibc/") { - denomTrace := types.ParseDenomTrace(coin.Denom) - coin.Denom = denomTrace.IBCDenom() + for i, coin := range coins { + if !strings.HasPrefix(coin.Denom, "ibc/") { + denomTrace := types.ParseDenomTrace(coin.Denom) + coins[i].Denom = denomTrace.IBCDenom() + } } timeoutHeightStr, err := cmd.Flags().GetString(flagPacketTimeoutHeight) @@ -107,7 +111,7 @@ Relative timeout timestamp is added to the value of the user's local system cloc } msg := types.NewMsgTransfer( - srcPort, srcChannel, sdk.NewCoins(coin), sender, receiver, timeoutHeight, timeoutTimestamp, memo, + srcPort, srcChannel, coins, sender, receiver, timeoutHeight, timeoutTimestamp, memo, ) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, From 0478cb9f7457985fdc6d220142d1e23b87e62d5d Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 14 May 2024 12:06:12 +0200 Subject: [PATCH 020/141] import renaming --- modules/apps/callbacks/ibc_middleware_test.go | 14 +++++++------- modules/apps/transfer/ibc_module.go | 8 ++++---- modules/apps/transfer/ibc_module_test.go | 18 +++++++++--------- modules/apps/transfer/keeper/mbt_relay_test.go | 4 ++-- .../apps/transfer/keeper/msg_server_test.go | 2 +- modules/apps/transfer/keeper/relay.go | 4 ++-- modules/apps/transfer/keeper/relay_test.go | 14 +++++++------- modules/apps/transfer/types/keys.go | 2 +- 8 files changed, 33 insertions(+), 33 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index c08f531ca3d..83db4a1b93f 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -13,7 +13,7 @@ import ( "github.com/cosmos/ibc-go/modules/apps/callbacks/testing/simapp" "github.com/cosmos/ibc-go/modules/apps/callbacks/types" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" - transferv1types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" transferv3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper" @@ -339,7 +339,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { tc.malleate() // callbacks module is routed as top level middleware - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) s.Require().True(ok) onAcknowledgementPacket := func() error { @@ -478,7 +478,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { // succeed on timeout userGasLimit := 600_000 timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano()) - msg := transferv1types.NewMsgTransfer( + msg := transfertypes.NewMsgTransfer( s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp, @@ -502,7 +502,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { tc.malleate() // callbacks module is routed as top level middleware - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) s.Require().True(ok) onTimeoutPacket := func() error { @@ -670,7 +670,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { tc.malleate() // callbacks module is routed as top level middleware - transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName) + transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) s.Require().True(ok) onRecvPacket := func() ibcexported.Acknowledgement { @@ -977,13 +977,13 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { // We will pass the function call down the transfer stack to the transfer module // transfer stack UnmarshalPacketData call order: callbacks -> fee -> transfer - transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName) + transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName) s.Require().True(ok) unmarshalerStack, ok := transferStack.(types.CallbacksCompatibleModule) s.Require().True(ok) - expPacketDataICS20V1 := transferv1types.FungibleTokenPacketData{ + expPacketDataICS20V1 := transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: ibctesting.TestAccAddress, diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 595c014f00b..7531a9318b5 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -15,7 +15,7 @@ import ( convertinternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - multidenom "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" + v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" 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" @@ -175,7 +175,7 @@ func (IBCModule) OnChanCloseConfirm( return nil } -func (IBCModule) unmarshalPacketDataBytesToICS20V2(bz []byte) (multidenom.FungibleTokenPacketData, error) { +func (IBCModule) unmarshalPacketDataBytesToICS20V2(bz []byte) (v3types.FungibleTokenPacketData, error) { // TODO: remove support for this function parsing v1 packet data // TODO: explicit check for packet data type against app version @@ -186,14 +186,14 @@ func (IBCModule) unmarshalPacketDataBytesToICS20V2(bz []byte) (multidenom.Fungib } } - var data multidenom.FungibleTokenPacketData + var data v3types.FungibleTokenPacketData if err := json.Unmarshal(bz, &data); err == nil { if len(data.Tokens) != 0 { return data, nil } } - return multidenom.FungibleTokenPacketData{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data") + return v3types.FungibleTokenPacketData{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data") } // OnRecvPacket implements the IBCModule interface. A successful acknowledgement diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 4acb9b6501a..22b398f4d50 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -9,7 +9,7 @@ import ( 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" - multidenom "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" + v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" 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" @@ -544,8 +544,8 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { { "success: valid packet data multidenom with memo", func() { - initialPacketData = multidenom.FungibleTokenPacketData{ - Tokens: []*multidenom.Token{ + initialPacketData = v3types.FungibleTokenPacketData{ + Tokens: []*v3types.Token{ { Denom: "atom", Amount: ibctesting.TestCoin.Amount.String(), @@ -557,15 +557,15 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { Memo: "some memo", } - data = initialPacketData.(multidenom.FungibleTokenPacketData).GetBytes() + data = initialPacketData.(v3types.FungibleTokenPacketData).GetBytes() }, true, }, { "success: valid packet data multidenom without memo", func() { - initialPacketData = multidenom.FungibleTokenPacketData{ - Tokens: []*multidenom.Token{ + initialPacketData = v3types.FungibleTokenPacketData{ + Tokens: []*v3types.Token{ { Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), @@ -577,7 +577,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { Memo: "", } - data = initialPacketData.(multidenom.FungibleTokenPacketData).GetBytes() + data = initialPacketData.(v3types.FungibleTokenPacketData).GetBytes() }, true, }, @@ -600,7 +600,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { if tc.expPass { suite.Require().NoError(err) - v3PacketData, ok := packetData.(multidenom.FungibleTokenPacketData) + v3PacketData, ok := packetData.(v3types.FungibleTokenPacketData) suite.Require().True(ok) if v1PacketData, ok := initialPacketData.(types.FungibleTokenPacketData); ok { @@ -610,7 +610,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { suite.Require().Equal(v1PacketData.Receiver, v3PacketData.Receiver) suite.Require().Equal(v1PacketData.Memo, v3PacketData.Memo) } else { - suite.Require().Equal(initialPacketData.(multidenom.FungibleTokenPacketData), v3PacketData) + suite.Require().Equal(initialPacketData.(v3types.FungibleTokenPacketData), v3PacketData) } } else { suite.Require().Error(err) diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index d12abd8a589..74c74bc6343 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -19,7 +19,7 @@ import ( "github.com/cometbft/cometbft/crypto" - convert "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" + convertinternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -145,7 +145,7 @@ func BalancesFromTla(tla []TlaBalance) []Balance { } func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPacket { - denom, trace := convert.ExtractDenomAndTraceFromV1Denom(DenomFromTla(packet.Data.Denom)) + denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(DenomFromTla(packet.Data.Denom)) return FungibleTokenPacket{ SourceChannel: packet.SourceChannel, SourcePort: packet.SourcePort, diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 355b21e5b88..5ab8a03e069 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -37,7 +37,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { false, }, { - "success: multi-denom with version ics20-2", + "success: multidenom", func() { coin2 = sdk.NewCoin("bond", sdkmath.NewInt(100)) coins := sdk.NewCoins(coin1, coin2) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 0671d64fffd..fa0e9db7635 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -12,7 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" + convertinternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -135,7 +135,7 @@ func (k Keeper) sendTransfer( } } - denom, trace := convert.ExtractDenomAndTraceFromV1Denom(fullDenomPath) + denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(fullDenomPath) token := &v3types.Token{ Denom: denom, Amount: coin.Amount.String(), diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index e4ce18817fb..822cae0506a 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -10,7 +10,7 @@ import ( banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" + convertinternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -411,7 +411,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { tc.malleate() - denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -494,7 +494,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), } - denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -621,7 +621,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { tc.malleate() - denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -714,7 +714,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo ), ) - denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -837,7 +837,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { tc.malleate() - denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := v3types.NewFungibleTokenPacketData( []*v3types.Token{ { @@ -923,7 +923,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI ), ) - denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := v3types.NewFungibleTokenPacketData( []*v3types.Token{ { diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index d985438ab71..e44d521856a 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -43,7 +43,7 @@ const ( Version1 = "ics20-1" // escrowAddressVersion should remain as ics20-1 to avoid the address changing. - escrowAddressVersion = "ics20-1" + escrowAddressVersion = Version1 ) var ( From 37f5b5e829e38aa8f13fb41e5d6886e63c7effde Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Tue, 14 May 2024 16:05:39 +0200 Subject: [PATCH 021/141] onRecv logic completed --- .../host/keeper/relay_test.go | 5 +- modules/apps/transfer/keeper/keeper.go | 20 +++---- modules/apps/transfer/keeper/relay.go | 53 ++++++------------- modules/apps/transfer/types/keys.go | 11 +++- 4 files changed, 39 insertions(+), 50 deletions(-) diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index 364f5061bb4..cbee3f7ac8c 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -792,8 +792,9 @@ func (suite *KeeperTestSuite) TestJSONOnRecvPacket() { "sender": "` + icaAddress + `", "receiver": "cosmos15ulrf36d4wdtrtqzkgaan9ylwuhs7k7qz753uk", "timeout_height": { "revision_number": 1, "revision_height": 100 }, - "timeout_timestamp": 0 - "forwarding_path": { "Hops": [], "Memo": "" } + "timeout_timestamp": 0, + "memo": "" + "forwarding_path": { "Hops": nil, "Memo": "" } } ] }`) diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 3ad1dc03908..f51e325d06e 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -18,7 +18,7 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" + 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" @@ -304,23 +304,23 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability return k.scopedKeeper.ClaimCapability(ctx, cap, name) } -// Set the forwarded packet in the private store. -func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, packet v3types.FungibleTokenPacketData) { +// Set the forwarded packet in the private store. // Should the packet be v3types or +func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64, packet channeltypes.Packet) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshal(&packet) - store.Set(types.PacketForwardPath(portID, channelID), bz) + store.Set(types.PacketForwardPath(portID, channelID, nextPacketSequence), bz) } // GetCounterpartyUpgrade gets the counterparty upgrade from the store. -func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string) (v3types.FungibleTokenPacketData, bool) { +func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64) (channeltypes.Packet, bool) { store := ctx.KVStore(k.storeKey) - bz := store.Get(types.PacketForwardPath(portID, channelID)) + bz := store.Get(types.PacketForwardPath(portID, channelID, nextPacketSequence)) if bz == nil { - return v3types.FungibleTokenPacketData{}, false + return channeltypes.Packet{}, false } - var upgrade v3types.FungibleTokenPacketData - k.cdc.MustUnmarshal(bz, &upgrade) + var storedPacket channeltypes.Packet + k.cdc.MustUnmarshal(bz, &storedPacket) - return upgrade, true + return storedPacket, true } diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 23cd74074f1..8ca85729559 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -3,6 +3,7 @@ package keeper import ( "fmt" "strings" + "time" metrics "github.com/hashicorp/go-metrics" @@ -213,12 +214,12 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v if len(data.ForwardingPath.Hops) > 0 { // Transaction would abort already for previous check on Memo forwardAddress = types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) - if forwardAddress.Empty() { - forwardAddress, err = sdk.AccAddressFromBech32("forwardAddress") // MMMM // How to set this? + /*if forwardAddress.Empty() { + forwardAddress, err = sdk.AccAddressFromBech32("forwardingAddress") // MMMM // How to set this? if err != nil { return errorsmod.Wrapf(err, "failed to decode forward address: %s", data.Receiver) } - } + }*/ receiver = forwardAddress finalReceiver, err = sdk.AccAddressFromBech32(data.Receiver) if err != nil { @@ -303,18 +304,9 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v ), ) }() + // Appending token. The new denom has been computed + receivedTokens = append(receivedTokens, token) - // Need to set right trace. Or we use directly coins? - //_, trace := convert.ExtractDenomAndTraceFromV1Denom(fullDenomPath) - - recvToken := sdk.Coin{ - Denom: token.Denom, // or denom? - //Trace: trace, // Which trace? - Amount: transferAmount, - } - - receivedTokens = append(receivedTokens, recvToken) - //return nil } // sender chain is the source, mint vouchers @@ -376,19 +368,9 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v ) }() - // Need to set right trace. Or we use directly coins? - //_, trace := convert.ExtractDenomAndTraceFromV1Denom(fullDenomPath) - - recvToken := sdk.Coin{ - Denom: token.Denom, - // Trace: trace, // Which trace? - Amount: transferAmount, - } - - receivedTokens = append(receivedTokens, recvToken) - } - - // END OF FOR CYCLE + // Appending voucher. The new denom has been computed + receivedTokens = append(receivedTokens, voucher) + } // END OF FOR CYCLE /* If ack wasn't successfull in the implementation we would have already errored out. No need of this check: if !ack.Success() { @@ -412,24 +394,23 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v } } - - // Need to check if setting of timeoutHeight and timeoutTimestamp is correct - selfHeight, selfTimestamp := clienttypes.GetSelfHeight(ctx), uint64(ctx.BlockTime().UnixNano()) + // Assign to timestamp --> current + 1 h + timeoutTimestamp := uint64(ctx.BlockTime().Add(time.Hour).UnixNano()) // _ is nextPacketSequence - _, err := k.sendTransfer(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, receivedTokens, receiver, string(finalReceiver), selfHeight, selfTimestamp, memo, nextForwardingPath) + nextPacketSequence, err := k.sendTransfer(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, receivedTokens, receiver, string(finalReceiver), clienttypes.Height{}, timeoutTimestamp, memo, nextForwardingPath) if err != nil { return err } - //return sequence, nil + + //packetData := v3types.NewFungibleTokenPacketData(tokens, sender.String(), receiver, memo, forwardingPath) + + k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, nextPacketSequence, packet) return nil } - // This should be return ack. + // The ibc_module.go module will return the proper ack. return nil } -// return nil -//} - // OnAcknowledgementPacket responds to the success or failure of a packet // acknowledgement written on the receiving chain. If the acknowledgement // was a success then nothing occurs. If the acknowledgement failed, then diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index ef1eaa36027..123047259ce 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -49,7 +49,7 @@ const ( escrowAddressVersion = "ics20-1" // this new address is introduced specifically with ics20-2. - forwardAddressVersion = "ics20-2" + forwardAddressVersion = "forwardingAddress" ) var ( @@ -102,6 +102,13 @@ func TotalForwardForDenomKey(denom string) []byte { return []byte(fmt.Sprintf("%s/%s", KeyTotalForwardPrefix, denom)) } +// PacketForwardPath returns the packet forward path as a byte slice for the provided portID, channelID, and nextPacketSequence +func PacketForwardPath(portID, channelID string, nextPacketSequence uint64) []byte { + path := fmt.Sprintf("%s/%s/%s/%d", KeyPacketForwardPrefix, portID, channelID, nextPacketSequence) + return []byte(path) +} + +/* // Packet forward key func PacketForwardPath(portID, channelID string) []byte { return []byte(packetForwardPath(portID, channelID)) @@ -110,4 +117,4 @@ func PacketForwardPath(portID, channelID string) []byte { // Packet ForwardPath to store the forwarded packets func packetForwardPath(portID, channelID string) string { return fmt.Sprintf("%s/%s", KeyPacketForwardPrefix, PacketForwardPath(portID, channelID)) -} +}*/ From 3fd334536b43a1d73057e17665e7075d3bdd1126 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Tue, 14 May 2024 17:42:26 +0200 Subject: [PATCH 022/141] add revertInFlights function --- modules/apps/transfer/keeper/keeper.go | 10 ++-- modules/apps/transfer/keeper/relay.go | 72 +++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index f51e325d06e..81eaea2e406 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -18,7 +18,7 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" 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" @@ -305,21 +305,21 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability } // Set the forwarded packet in the private store. // Should the packet be v3types or -func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64, packet channeltypes.Packet) { +func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64, packet v3types.FungibleTokenPacketData) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshal(&packet) store.Set(types.PacketForwardPath(portID, channelID, nextPacketSequence), bz) } // GetCounterpartyUpgrade gets the counterparty upgrade from the store. -func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64) (channeltypes.Packet, bool) { +func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64) (v3types.FungibleTokenPacketData, bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(types.PacketForwardPath(portID, channelID, nextPacketSequence)) if bz == nil { - return channeltypes.Packet{}, false + return v3types.FungibleTokenPacketData{}, false } - var storedPacket channeltypes.Packet + var storedPacket v3types.FungibleTokenPacketData k.cdc.MustUnmarshal(bz, &storedPacket) return storedPacket, true diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 8ca85729559..3e583264d49 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -403,8 +403,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v } //packetData := v3types.NewFungibleTokenPacketData(tokens, sender.String(), receiver, memo, forwardingPath) - - k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, nextPacketSequence, packet) + k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, nextPacketSequence, data) return nil } // The ibc_module.go module will return the proper ack. @@ -438,6 +437,7 @@ func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, dat // if the sending chain was the source chain. Otherwise, the sent tokens // were burnt in the original send so new tokens are minted and sent to // the sending address. +// Probably data is not really necessary here. func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { // NOTE: packet data type already checked in handler.go @@ -481,6 +481,74 @@ func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, d return nil } +func (k Keeper) revertInFlightChanges(ctx sdk.Context, sentPacket channeltypes.Packet, receivedPacket channeltypes.Packet, sentPacketData v3types.FungibleTokenPacketData) error { + + forwardEscrow := types.GetEscrowAddress(sentPacket.SourcePort, sentPacket.SourceChannel) + reverseEscrow := types.GetEscrowAddress(receivedPacket.DestinationPort, receivedPacket.DestinationChannel) + // the token on our chain is the token in the sentPacket + + // We could unmarshall the sentPacket data and use it in the for or use sentPacketData + // Need to understand how to deal with this. The bank functions wants a coin and not a v3token type + for _, token := range sentPacketData.Tokens { + + fullDenomPath := token.GetFullDenomPath() + + // parse the denomination from the full denom path + trace := types.ParseDenomTrace(fullDenomPath) + + // parse the transfer amount + transferAmount, ok := sdkmath.NewIntFromString(token.Amount) + if !ok { + return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", transferAmount) + } + sdkToken := sdk.NewCoin(trace.IBCDenom(), transferAmount) + + // check if the packet we sent out was sending as source or not + // in this case we escrowed the outgoing tokens + if types.SenderChainIsSource(sentPacket.SourcePort, sentPacket.SourceChannel, fullDenomPath) { + // check if the packet we received was a source token for our chain + // Check if here should be ReceiverChainIsSource + if types.SenderChainIsSource(receivedPacket.DestinationPort, receivedPacket.DestinationChannel, fullDenomPath) { + // receive sent tokens from the received escrow to the forward escrow account + // so we must send the tokens back from the forward escrow to the original received escrow account + // To check if this is proper + //escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel()) + return k.unescrowToken(ctx, forwardEscrow, reverseEscrow, sdkToken) + //bank.TransferCoins(forwardEscrow, reverseEscrow, token.denom, token.amount) + } else { + // receive minted vouchers and sent to the forward escrow account + // so we must remove the vouchers from the forward escrow account and burn them + // Is this ok? + if err := k.bankKeeper.BurnCoins( + ctx, types.ModuleName, sdk.NewCoins(sdkToken), + ); err != nil { + return err + } + } + } else { + // in this case we burned the vouchers of the outgoing packets + // check if the packet we received was a source token for our chain + // in this case, the tokens were unescrowed from the reverse escrow account + if types.SenderChainIsSource(receivedPacket.DestinationPort, receivedPacket.DestinationChannel, token.Denom) { + // in this case we must mint the burned vouchers and send them back to the escrow account + // mint vouchers back to sender + // Is this ok? + if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdkToken)); err != nil { + return err + } + + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, reverseEscrow, sdk.NewCoins(sdkToken)); err != nil { + panic(fmt.Errorf("unable to send coins from module to account despite previously minting coins to module account: %v", err)) + } + } + //return nil + // if it wasn't a source token on receive, then we simply had minted vouchers and burned them in the receive. + // So no state changes were made, and thus no reversion is necessary + } + } + return nil +} + // escrowToken will send the given token from the provided sender to the escrow address. It will also // update the total escrowed amount by adding the escrowed token to the current total escrow. func (k Keeper) escrowToken(ctx sdk.Context, sender, escrowAddress sdk.AccAddress, token sdk.Coin) error { From 24e24074a21778ebb3989ff48980415dba9c6170 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Tue, 14 May 2024 20:26:54 +0200 Subject: [PATCH 023/141] add onAck && onTimeout logic --- modules/apps/transfer/keeper/keeper.go | 19 ++++-- modules/apps/transfer/keeper/relay.go | 89 ++++++++++++++++++++++---- modules/apps/transfer/types/keys.go | 16 +---- 3 files changed, 91 insertions(+), 33 deletions(-) diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 81eaea2e406..ef707161e94 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -18,7 +18,7 @@ import ( capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" + 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" @@ -305,21 +305,26 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability } // Set the forwarded packet in the private store. // Should the packet be v3types or -func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64, packet v3types.FungibleTokenPacketData) { +// func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64, packet v3types.FungibleTokenPacketData) { +func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, packet channeltypes.Packet) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshal(&packet) - store.Set(types.PacketForwardPath(portID, channelID, nextPacketSequence), bz) + // store.Set(types.PacketForwardPath(portID, channelID, nextPacketSequence), bz) + store.Set(types.PacketForwardPath(portID, channelID), bz) + } // GetCounterpartyUpgrade gets the counterparty upgrade from the store. -func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64) (v3types.FungibleTokenPacketData, bool) { +// func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64) (v3types.FungibleTokenPacketData, bool) { +func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string) (channeltypes.Packet, bool) { store := ctx.KVStore(k.storeKey) - bz := store.Get(types.PacketForwardPath(portID, channelID, nextPacketSequence)) + //bz := store.Get(types.PacketForwardPath(portID, channelID, nextPacketSequence)) + bz := store.Get(types.PacketForwardPath(portID, channelID)) if bz == nil { - return v3types.FungibleTokenPacketData{}, false + return channeltypes.Packet{}, false } - var storedPacket v3types.FungibleTokenPacketData + var storedPacket channeltypes.Packet k.cdc.MustUnmarshal(bz, &storedPacket) return storedPacket, true diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 3e583264d49..b15d39b864a 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -396,14 +396,16 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v } // Assign to timestamp --> current + 1 h timeoutTimestamp := uint64(ctx.BlockTime().Add(time.Hour).UnixNano()) - // _ is nextPacketSequence - nextPacketSequence, err := k.sendTransfer(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, receivedTokens, receiver, string(finalReceiver), clienttypes.Height{}, timeoutTimestamp, memo, nextForwardingPath) + // _ is nextPacketSequence what we do with it? + _, err := k.sendTransfer(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, receivedTokens, receiver, string(finalReceiver), clienttypes.Height{}, timeoutTimestamp, memo, nextForwardingPath) if err != nil { return err } //packetData := v3types.NewFungibleTokenPacketData(tokens, sender.String(), receiver, memo, forwardingPath) - k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, nextPacketSequence, data) + //k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, nextPacketSequence, data) + k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, packet) + return nil } // The ibc_module.go module will return the proper ack. @@ -415,22 +417,83 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v // was a success then nothing occurs. If the acknowledgement failed, then // the sender is refunded their tokens using the refundPacketToken function. func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData, ack channeltypes.Acknowledgement) error { - switch ack.Response.(type) { - case *channeltypes.Acknowledgement_Result: - // the acknowledgement succeeded on the receiving chain so nothing - // needs to be executed and no error needs to be returned - return nil - case *channeltypes.Acknowledgement_Error: - return k.refundPacketToken(ctx, packet, data) - default: - return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected one of [%T, %T], got %T", channeltypes.Acknowledgement_Result{}, channeltypes.Acknowledgement_Error{}, ack.Response) + + prevPacket, prevPacketExist := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel) + + channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) + if !ok { + errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + + if prevPacketExist { + switch ack.Response.(type) { + case *channeltypes.Acknowledgement_Result: + // the acknowledgement succeeded on the receiving chain so nothing + // needs to be executed and no error needs to be returned + // here the ibc_module.go will generate the sucss ack. + + // Figure Out how to do this + + FungibleTokenPacketAcknowledgement := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) + // Error: "forwarded packet succeeded", + // Result: true, + // } + + return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, packet, FungibleTokenPacketAcknowledgement) + + //return nil + case *channeltypes.Acknowledgement_Error: + // the forwarded packet has failed, thus the funds have been refunded to the forwarding address. + // we must revert the changes that came from successfully receiving the tokens on our chain + // before propogating the error acknowledgement back to original sender chain + + k.revertInFlightChanges(ctx, packet, prevPacket, data) + // Figure Out how to do this + //err error := "forwarded packet failed" + FungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(fmt.Errorf("forwarded packet failed")) + /* channeltypes.Acknowledgement{ + channeltypes.Acknowledgement.Response.Error: "forwarded packet failed", + channeltypes.Acknowledgement.Response.Result: false, + }*/ + // set the acknowledgement so that it can be verified on the other side + return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, packet, FungibleTokenPacketAcknowledgement) + + default: + return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected one of [%T, %T], got %T", channeltypes.Acknowledgement_Result{}, channeltypes.Acknowledgement_Error{}, ack.Response) + } + } else { + switch ack.Response.(type) { + case *channeltypes.Acknowledgement_Error: + k.refundPacketToken(ctx, packet, data) + } } + return nil } // OnTimeoutPacket refunds the sender since the original packet sent was // never received and has been timed out. func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { - return k.refundPacketToken(ctx, packet, data) + prevPacket, prevPacketExist := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel) + + channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) + if !ok { + errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + + if prevPacketExist { + k.revertInFlightChanges(ctx, packet, prevPacket, data) + + FungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(fmt.Errorf("forwarded packet failed")) + + /*FungibleTokenPacketAcknowledgement := channeltypes.Acknowledgement{ + channeltypes.Acknowledgement.Response.Error: "forwarded packet failed", + channeltypes.Acknowledgement.Response.Result: false, + }*/ + + return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, packet, FungibleTokenPacketAcknowledgement) + } else { + return k.refundPacketToken(ctx, packet, data) + } } // refundPacketToken will unescrow and send back the tokens back to sender diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index 123047259ce..d67d935ca2e 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -103,18 +103,8 @@ func TotalForwardForDenomKey(denom string) []byte { } // PacketForwardPath returns the packet forward path as a byte slice for the provided portID, channelID, and nextPacketSequence -func PacketForwardPath(portID, channelID string, nextPacketSequence uint64) []byte { - path := fmt.Sprintf("%s/%s/%s/%d", KeyPacketForwardPrefix, portID, channelID, nextPacketSequence) - return []byte(path) -} - -/* -// Packet forward key +// func PacketForwardPath(portID, channelID string, nextPacketSequence uint64) []byte { func PacketForwardPath(portID, channelID string) []byte { - return []byte(packetForwardPath(portID, channelID)) + path := fmt.Sprintf("%s/%s/%s", KeyPacketForwardPrefix, portID, channelID) //, nextPacketSequence) + return []byte(path) } - -// Packet ForwardPath to store the forwarded packets -func packetForwardPath(portID, channelID string) string { - return fmt.Sprintf("%s/%s", KeyPacketForwardPrefix, PacketForwardPath(portID, channelID)) -}*/ From 7858528f5bc8d39b4292b9d054579d4215131033 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 14 May 2024 22:44:39 +0200 Subject: [PATCH 024/141] fix interchain accounts test --- .../host/keeper/relay_test.go | 8 +- modules/apps/transfer/types/tx.pb.go | 86 +++++++++---------- modules/apps/transfer/types/v3/packet.pb.go | 48 +++++------ .../applications/transfer/v1/transfer.proto | 6 +- proto/ibc/applications/transfer/v1/tx.proto | 2 +- .../ibc/applications/transfer/v3/packet.proto | 6 +- 6 files changed, 78 insertions(+), 78 deletions(-) diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index cbee3f7ac8c..d6ef992ee12 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -788,13 +788,13 @@ func (suite *KeeperTestSuite) TestJSONOnRecvPacket() { "@type": "/ibc.applications.transfer.v1.MsgTransfer", "source_port": "transfer", "source_channel": "channel-1", - "token": { "denom": "stake", "amount": "100" }, + "tokens": [{ "denom": "stake", "amount": "100" }], "sender": "` + icaAddress + `", "receiver": "cosmos15ulrf36d4wdtrtqzkgaan9ylwuhs7k7qz753uk", "timeout_height": { "revision_number": 1, "revision_height": 100 }, - "timeout_timestamp": 0, - "memo": "" - "forwarding_path": { "Hops": nil, "Memo": "" } + "timeout_timestamp": 0, + "memo": "", + "forwarding_path": { "hops": [], "memo": "" } } ] }`) diff --git a/modules/apps/transfer/types/tx.pb.go b/modules/apps/transfer/types/tx.pb.go index 557bb6d35ed..124af2460d2 100644 --- a/modules/apps/transfer/types/tx.pb.go +++ b/modules/apps/transfer/types/tx.pb.go @@ -56,7 +56,7 @@ type MsgTransfer struct { Memo string `protobuf:"bytes,8,opt,name=memo,proto3" json:"memo,omitempty"` // tokens to be transferred Tokens []types.Coin `protobuf:"bytes,9,rep,name=tokens,proto3" json:"tokens"` - ForwardingPath *ForwardingInfo `protobuf:"bytes,10,opt,name=forwardingPath,proto3" json:"forwardingPath,omitempty"` + ForwardingPath *ForwardingInfo `protobuf:"bytes,10,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` } func (m *MsgTransfer) Reset() { *m = MsgTransfer{} } @@ -225,48 +225,48 @@ func init() { var fileDescriptor_7401ed9bed2f8e09 = []byte{ // 666 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x41, 0x6f, 0x13, 0x3b, - 0x10, 0xce, 0xbe, 0x6e, 0xf3, 0x5a, 0xe7, 0xb5, 0x7d, 0xf5, 0x7b, 0x6a, 0xb7, 0x2b, 0xb4, 0x89, - 0x22, 0x2a, 0x95, 0x94, 0xda, 0x4a, 0x11, 0x2a, 0x8a, 0x38, 0xa5, 0x12, 0x02, 0x89, 0x4a, 0x65, - 0x55, 0x2e, 0x5c, 0xaa, 0xdd, 0x8d, 0xbb, 0xb1, 0x9a, 0xb5, 0x17, 0xdb, 0x09, 0x70, 0x41, 0x88, - 0x13, 0xe2, 0xc4, 0x81, 0x1f, 0xc0, 0x91, 0x63, 0x7f, 0x46, 0x8f, 0x3d, 0x72, 0x42, 0xa8, 0x3d, - 0xf4, 0xc2, 0x8f, 0x40, 0xf6, 0x3a, 0x61, 0xe9, 0x21, 0x94, 0xcb, 0xae, 0x67, 0xe6, 0x9b, 0x6f, - 0xe6, 0x1b, 0x8f, 0x0c, 0xd6, 0x69, 0x9c, 0xe0, 0x28, 0xcf, 0x07, 0x34, 0x89, 0x14, 0xe5, 0x4c, - 0x62, 0x25, 0x22, 0x26, 0x8f, 0x88, 0xc0, 0xa3, 0x36, 0x56, 0x2f, 0x51, 0x2e, 0xb8, 0xe2, 0xf0, - 0x06, 0x8d, 0x13, 0x54, 0x86, 0xa1, 0x31, 0x0c, 0x8d, 0xda, 0xfe, 0x72, 0x94, 0x51, 0xc6, 0xb1, - 0xf9, 0x16, 0x09, 0xfe, 0xff, 0x29, 0x4f, 0xb9, 0x39, 0x62, 0x7d, 0xb2, 0xde, 0xd5, 0x84, 0xcb, - 0x8c, 0x4b, 0x9c, 0xc9, 0x54, 0xd3, 0x67, 0x32, 0xb5, 0x81, 0xc0, 0x06, 0xe2, 0x48, 0x12, 0x3c, - 0x6a, 0xc7, 0x44, 0x45, 0x6d, 0x9c, 0x70, 0xca, 0x6c, 0xbc, 0xae, 0xdb, 0x4c, 0xb8, 0x20, 0x38, - 0x19, 0x50, 0xc2, 0x94, 0xce, 0x2e, 0x4e, 0x16, 0xb0, 0x39, 0x5d, 0xc7, 0xb8, 0x59, 0x03, 0x6e, - 0x7e, 0x74, 0x41, 0x6d, 0x4f, 0xa6, 0x07, 0xd6, 0x0b, 0xeb, 0xa0, 0x26, 0xf9, 0x50, 0x24, 0xe4, - 0x30, 0xe7, 0x42, 0x79, 0x4e, 0xc3, 0xd9, 0x98, 0x0f, 0x41, 0xe1, 0xda, 0xe7, 0x42, 0xc1, 0x75, - 0xb0, 0x68, 0x01, 0x49, 0x3f, 0x62, 0x8c, 0x0c, 0xbc, 0xbf, 0x0c, 0x66, 0xa1, 0xf0, 0xee, 0x16, - 0x4e, 0xd8, 0x01, 0xb3, 0x8a, 0x1f, 0x13, 0xe6, 0xcd, 0x34, 0x9c, 0x8d, 0xda, 0xf6, 0x1a, 0x2a, - 0x54, 0x21, 0xad, 0x0a, 0x59, 0x55, 0x68, 0x97, 0x53, 0xd6, 0x9d, 0x3f, 0xfd, 0x5a, 0xaf, 0x7c, - 0xbe, 0x3c, 0x69, 0x39, 0x61, 0x91, 0x02, 0x57, 0x40, 0x55, 0x12, 0xd6, 0x23, 0xc2, 0x73, 0x0d, - 0xb5, 0xb5, 0xa0, 0x0f, 0xe6, 0x04, 0x49, 0x08, 0x1d, 0x11, 0xe1, 0xcd, 0x9a, 0xc8, 0xc4, 0x86, - 0x8f, 0xc1, 0xa2, 0xa2, 0x19, 0xe1, 0x43, 0x75, 0xd8, 0x27, 0x34, 0xed, 0x2b, 0xaf, 0x6a, 0x0a, - 0xfb, 0x48, 0x5f, 0x97, 0x1e, 0x17, 0xb2, 0x43, 0x1a, 0xb5, 0xd1, 0x43, 0x83, 0x28, 0x57, 0x5e, - 0xb0, 0xc9, 0x45, 0x04, 0x6e, 0x82, 0xe5, 0x31, 0x9b, 0xfe, 0x4b, 0x15, 0x65, 0xb9, 0xf7, 0x77, - 0xc3, 0xd9, 0x70, 0xc3, 0x7f, 0x6d, 0xe0, 0x60, 0xec, 0x87, 0x10, 0xb8, 0x19, 0xc9, 0xb8, 0x37, - 0x67, 0x5a, 0x32, 0x67, 0x78, 0x1f, 0x54, 0x8d, 0x16, 0xe9, 0xcd, 0x37, 0x66, 0xae, 0xad, 0xdf, - 0xe6, 0xc0, 0x03, 0xb0, 0x78, 0xc4, 0xc5, 0x8b, 0x48, 0xf4, 0x28, 0x4b, 0xf7, 0x23, 0xd5, 0xf7, - 0x80, 0x11, 0x73, 0x1b, 0x4d, 0xdb, 0x3d, 0xf4, 0x60, 0x92, 0xf3, 0x88, 0x1d, 0xf1, 0xf0, 0x0a, - 0x47, 0xa7, 0xf5, 0xee, 0x53, 0xbd, 0xf2, 0xf6, 0xf2, 0xa4, 0x65, 0xe7, 0xf9, 0xfe, 0xf2, 0xa4, - 0xb5, 0x52, 0xb4, 0xb5, 0x25, 0x7b, 0xc7, 0xb8, 0xb4, 0x06, 0xcd, 0x1d, 0xf0, 0x5f, 0xc9, 0x0c, - 0x89, 0xcc, 0x39, 0x93, 0x44, 0xdf, 0x80, 0x24, 0xcf, 0x87, 0x84, 0x25, 0xc4, 0xac, 0x86, 0x1b, - 0x4e, 0xec, 0x8e, 0xab, 0xe9, 0x9b, 0xaf, 0xc1, 0xd2, 0x9e, 0x4c, 0x9f, 0xe6, 0xbd, 0x48, 0x91, - 0xfd, 0x48, 0x44, 0x99, 0x34, 0xd7, 0x49, 0x53, 0x46, 0x84, 0xdd, 0x26, 0x6b, 0xc1, 0x2e, 0xa8, - 0xe6, 0x06, 0x61, 0x36, 0xa8, 0xb6, 0x7d, 0x73, 0xba, 0xba, 0x82, 0xad, 0xeb, 0xea, 0x71, 0x85, - 0x36, 0xb3, 0xb3, 0xf4, 0x53, 0x93, 0x21, 0x6d, 0xae, 0x81, 0xd5, 0x2b, 0xf5, 0xc7, 0xcd, 0x6f, - 0x7f, 0x77, 0xc0, 0xcc, 0x9e, 0x4c, 0x61, 0x1f, 0xcc, 0x4d, 0xd6, 0xfd, 0xd6, 0xf4, 0x9a, 0xa5, - 0x19, 0xf8, 0xed, 0x6b, 0x43, 0x27, 0xe3, 0x52, 0xe0, 0x9f, 0x5f, 0x26, 0xb1, 0xf5, 0x5b, 0x8a, - 0x32, 0xdc, 0xbf, 0xfb, 0x47, 0xf0, 0x71, 0x55, 0x7f, 0xf6, 0x8d, 0x5e, 0xa6, 0xee, 0x93, 0xd3, - 0xf3, 0xc0, 0x39, 0x3b, 0x0f, 0x9c, 0x6f, 0xe7, 0x81, 0xf3, 0xe1, 0x22, 0xa8, 0x9c, 0x5d, 0x04, - 0x95, 0x2f, 0x17, 0x41, 0xe5, 0xd9, 0x4e, 0x4a, 0x55, 0x7f, 0x18, 0xa3, 0x84, 0x67, 0xd8, 0x3e, - 0x36, 0x34, 0x4e, 0xb6, 0x52, 0x8e, 0x47, 0xf7, 0x70, 0xc6, 0x7b, 0xc3, 0x01, 0x91, 0xfa, 0x01, - 0x29, 0x3d, 0x1c, 0xea, 0x55, 0x4e, 0x64, 0x5c, 0x35, 0x6f, 0xc6, 0x9d, 0x1f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xfe, 0xb7, 0xbe, 0x25, 0x2a, 0x05, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x31, 0x6f, 0x13, 0x31, + 0x14, 0xce, 0xd1, 0x34, 0xb4, 0x0e, 0x6d, 0xa9, 0x41, 0xed, 0x35, 0x42, 0x97, 0x28, 0xa2, 0x52, + 0x49, 0xa9, 0xad, 0x14, 0xa1, 0xa2, 0x88, 0x29, 0x95, 0x10, 0x48, 0x54, 0x2a, 0xa7, 0x76, 0x61, + 0xa9, 0x7c, 0x17, 0xf7, 0xce, 0x6a, 0xce, 0x3e, 0x6c, 0x27, 0xc0, 0x82, 0x10, 0x13, 0x62, 0x62, + 0x61, 0x67, 0x64, 0xec, 0xcf, 0xe8, 0xd8, 0x91, 0x09, 0xa1, 0x76, 0xe8, 0xc2, 0x8f, 0x40, 0xe7, + 0x73, 0xd2, 0x83, 0x21, 0x94, 0xe5, 0xce, 0xef, 0xbd, 0xef, 0x7d, 0xef, 0x7d, 0xcf, 0x4f, 0x06, + 0xab, 0x2c, 0x08, 0x31, 0x49, 0xd3, 0x3e, 0x0b, 0x89, 0x66, 0x82, 0x2b, 0xac, 0x25, 0xe1, 0xea, + 0x90, 0x4a, 0x3c, 0x6c, 0x63, 0xfd, 0x06, 0xa5, 0x52, 0x68, 0x01, 0xef, 0xb0, 0x20, 0x44, 0x45, + 0x18, 0x1a, 0xc1, 0xd0, 0xb0, 0x5d, 0x5b, 0x24, 0x09, 0xe3, 0x02, 0x9b, 0x6f, 0x9e, 0x50, 0xbb, + 0x1d, 0x89, 0x48, 0x98, 0x23, 0xce, 0x4e, 0xd6, 0xbb, 0x1c, 0x0a, 0x95, 0x08, 0x85, 0x13, 0x15, + 0x65, 0xf4, 0x89, 0x8a, 0x6c, 0xc0, 0xb3, 0x81, 0x80, 0x28, 0x8a, 0x87, 0xed, 0x80, 0x6a, 0xd2, + 0xc6, 0xa1, 0x60, 0xdc, 0xc6, 0xeb, 0x59, 0x9b, 0xa1, 0x90, 0x14, 0x87, 0x7d, 0x46, 0xb9, 0xce, + 0xb2, 0xf3, 0x93, 0x05, 0xac, 0x4f, 0xd6, 0x31, 0x6a, 0xd6, 0x80, 0x9b, 0x5f, 0xca, 0xa0, 0xba, + 0xa3, 0xa2, 0x3d, 0xeb, 0x85, 0x75, 0x50, 0x55, 0x62, 0x20, 0x43, 0x7a, 0x90, 0x0a, 0xa9, 0x5d, + 0xa7, 0xe1, 0xac, 0xcd, 0xfa, 0x20, 0x77, 0xed, 0x0a, 0xa9, 0xe1, 0x2a, 0x98, 0xb7, 0x80, 0x30, + 0x26, 0x9c, 0xd3, 0xbe, 0x7b, 0xcd, 0x60, 0xe6, 0x72, 0xef, 0x76, 0xee, 0x84, 0x1d, 0x30, 0xad, + 0xc5, 0x11, 0xe5, 0xee, 0x54, 0xc3, 0x59, 0xab, 0x6e, 0xae, 0xa0, 0x5c, 0x15, 0xca, 0x54, 0x21, + 0xab, 0x0a, 0x6d, 0x0b, 0xc6, 0xbb, 0xb3, 0x27, 0x3f, 0xea, 0xa5, 0x6f, 0x17, 0xc7, 0x2d, 0xc7, + 0xcf, 0x53, 0xe0, 0x12, 0xa8, 0x28, 0xca, 0x7b, 0x54, 0xba, 0x65, 0x43, 0x6d, 0x2d, 0x58, 0x03, + 0x33, 0x92, 0x86, 0x94, 0x0d, 0xa9, 0x74, 0xa7, 0x4d, 0x64, 0x6c, 0xc3, 0xe7, 0x60, 0x5e, 0xb3, + 0x84, 0x8a, 0x81, 0x3e, 0x88, 0x29, 0x8b, 0x62, 0xed, 0x56, 0x4c, 0xe1, 0x1a, 0xca, 0xae, 0x2b, + 0x1b, 0x17, 0xb2, 0x43, 0x1a, 0xb6, 0xd1, 0x53, 0x83, 0x28, 0x56, 0x9e, 0xb3, 0xc9, 0x79, 0x04, + 0xae, 0x83, 0xc5, 0x11, 0x5b, 0xf6, 0x57, 0x9a, 0x24, 0xa9, 0x7b, 0xbd, 0xe1, 0xac, 0x95, 0xfd, + 0x9b, 0x36, 0xb0, 0x37, 0xf2, 0x43, 0x08, 0xca, 0x09, 0x4d, 0x84, 0x3b, 0x63, 0x5a, 0x32, 0x67, + 0xf8, 0x18, 0x54, 0x8c, 0x16, 0xe5, 0xce, 0x36, 0xa6, 0xae, 0xac, 0xdf, 0xe6, 0xc0, 0x7d, 0xb0, + 0x70, 0x28, 0xe4, 0x6b, 0x22, 0x7b, 0x8c, 0x47, 0x07, 0x29, 0xd1, 0xb1, 0x0b, 0x8c, 0x9a, 0xfb, + 0x68, 0xd2, 0xf2, 0xa1, 0x27, 0xe3, 0xa4, 0x67, 0xfc, 0x50, 0xf8, 0xf3, 0x97, 0x24, 0xbb, 0x44, + 0xc7, 0x9d, 0xd6, 0xc7, 0xaf, 0xf5, 0xd2, 0x87, 0x8b, 0xe3, 0x96, 0x1d, 0xe8, 0xa7, 0x8b, 0xe3, + 0xd6, 0x52, 0xde, 0xd7, 0x86, 0xea, 0x1d, 0xe1, 0xc2, 0x1e, 0x34, 0xb7, 0xc0, 0xad, 0x82, 0xe9, + 0x53, 0x95, 0x0a, 0xae, 0x68, 0x76, 0x05, 0x8a, 0xbe, 0x1a, 0x50, 0x1e, 0x52, 0xb3, 0x1b, 0x65, + 0x7f, 0x6c, 0x77, 0xca, 0x19, 0x7d, 0xf3, 0x1d, 0x58, 0xd8, 0x51, 0xd1, 0x7e, 0xda, 0x23, 0x9a, + 0xee, 0x12, 0x49, 0x12, 0x65, 0xee, 0x93, 0x45, 0x9c, 0x4a, 0xbb, 0x4e, 0xd6, 0x82, 0x5d, 0x50, + 0x49, 0x0d, 0xc2, 0xac, 0x50, 0x75, 0xf3, 0xee, 0x64, 0x75, 0x39, 0x5b, 0xb7, 0x9c, 0xcd, 0xcb, + 0xb7, 0x99, 0x9d, 0x85, 0x4b, 0x4d, 0x86, 0xb4, 0xb9, 0x02, 0x96, 0xff, 0xaa, 0x3f, 0x6a, 0x7e, + 0xf3, 0x97, 0x03, 0xa6, 0x76, 0x54, 0x04, 0x63, 0x30, 0x33, 0xde, 0xf7, 0x7b, 0x93, 0x6b, 0x16, + 0x66, 0x50, 0x6b, 0x5f, 0x19, 0x3a, 0x1e, 0x97, 0x06, 0x37, 0xfe, 0x98, 0xc4, 0xc6, 0x3f, 0x29, + 0x8a, 0xf0, 0xda, 0xc3, 0xff, 0x82, 0x8f, 0xaa, 0xd6, 0xa6, 0xdf, 0x67, 0xdb, 0xd4, 0x7d, 0x71, + 0x72, 0xe6, 0x39, 0xa7, 0x67, 0x9e, 0xf3, 0xf3, 0xcc, 0x73, 0x3e, 0x9f, 0x7b, 0xa5, 0xd3, 0x73, + 0xaf, 0xf4, 0xfd, 0xdc, 0x2b, 0xbd, 0xdc, 0x8a, 0x98, 0x8e, 0x07, 0x01, 0x0a, 0x45, 0x82, 0xed, + 0x6b, 0xc3, 0x82, 0x70, 0x23, 0x12, 0x78, 0xf8, 0x08, 0x27, 0xa2, 0x37, 0xe8, 0x53, 0x95, 0xbd, + 0x20, 0x85, 0x97, 0x43, 0xbf, 0x4d, 0xa9, 0x0a, 0x2a, 0xe6, 0xd1, 0x78, 0xf0, 0x3b, 0x00, 0x00, + 0xff, 0xff, 0xd4, 0x59, 0xa7, 0xd2, 0x2b, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/modules/apps/transfer/types/v3/packet.pb.go b/modules/apps/transfer/types/v3/packet.pb.go index 113d758a12d..098f87f9c2d 100644 --- a/modules/apps/transfer/types/v3/packet.pb.go +++ b/modules/apps/transfer/types/v3/packet.pb.go @@ -36,7 +36,7 @@ type FungibleTokenPacketData struct { // optional memo Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` // optional forwardingInfo struct - ForwardingPath *types.ForwardingInfo `protobuf:"bytes,5,opt,name=forwardingPath,proto3" json:"forwardingPath,omitempty"` + ForwardingPath *types.ForwardingInfo `protobuf:"bytes,5,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` } func (m *FungibleTokenPacketData) Reset() { *m = FungibleTokenPacketData{} } @@ -181,29 +181,29 @@ func init() { } var fileDescriptor_760742a8894acdbe = []byte{ - // 344 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0xcf, 0x4a, 0xc3, 0x30, - 0x1c, 0x5e, 0xec, 0x36, 0x34, 0x03, 0x0f, 0x41, 0xb4, 0x0c, 0x29, 0x65, 0x5e, 0x26, 0x6a, 0xc2, - 0xd6, 0x8b, 0xe8, 0x4d, 0x64, 0x20, 0x5e, 0xc6, 0xd8, 0xc9, 0x5b, 0x9a, 0x66, 0x5d, 0xd8, 0x9a, - 0x94, 0x24, 0xad, 0xf8, 0x16, 0x3e, 0x96, 0xc7, 0x1d, 0x3d, 0xca, 0xf6, 0x0a, 0x3e, 0x80, 0x34, - 0xfb, 0xc3, 0xf0, 0xb0, 0x5b, 0xbe, 0x5f, 0xbe, 0x7f, 0xf0, 0xc1, 0x6b, 0x11, 0x33, 0x42, 0xf3, - 0x7c, 0x2e, 0x18, 0xb5, 0x42, 0x49, 0x43, 0xac, 0xa6, 0xd2, 0x4c, 0xb8, 0x26, 0x65, 0x44, 0x72, - 0xca, 0x66, 0xdc, 0xe2, 0x5c, 0x2b, 0xab, 0xd0, 0xa5, 0x88, 0x19, 0xde, 0xa7, 0xe2, 0x2d, 0x15, - 0x97, 0x51, 0xfb, 0xe6, 0x80, 0x51, 0x6f, 0xf7, 0x5e, 0x5b, 0x75, 0x7e, 0x01, 0xbc, 0x18, 0x14, - 0x32, 0x15, 0xf1, 0x9c, 0x8f, 0xd5, 0x8c, 0xcb, 0xa1, 0x0b, 0x7a, 0xa6, 0x96, 0xa2, 0x47, 0xd8, - 0xb4, 0xd5, 0xc9, 0xf8, 0x20, 0xf4, 0xba, 0xad, 0xfe, 0x15, 0x3e, 0x94, 0x8b, 0x9d, 0x7c, 0xb4, - 0x91, 0xa0, 0x73, 0xd8, 0x34, 0x5c, 0x26, 0x5c, 0xfb, 0x47, 0x21, 0xe8, 0x9e, 0x8c, 0x36, 0x08, - 0xb5, 0xe1, 0xb1, 0xe6, 0x8c, 0x8b, 0x92, 0x6b, 0xdf, 0x73, 0x3f, 0x3b, 0x8c, 0x10, 0xac, 0x67, - 0x3c, 0x53, 0x7e, 0xdd, 0xdd, 0xdd, 0x1b, 0x8d, 0xe1, 0xe9, 0x44, 0xe9, 0x77, 0xaa, 0x13, 0x21, - 0xd3, 0x21, 0xb5, 0x53, 0xbf, 0x11, 0x82, 0x6e, 0xab, 0x7f, 0x7b, 0xa8, 0x4c, 0x0f, 0x0f, 0x76, - 0x9a, 0x17, 0x39, 0x51, 0xa3, 0x7f, 0x1e, 0x9d, 0x57, 0xd8, 0x70, 0x75, 0xd1, 0x19, 0x6c, 0x24, - 0x5c, 0xaa, 0xcc, 0x07, 0x2e, 0x73, 0x0d, 0xaa, 0xf2, 0x34, 0x53, 0x85, 0xb4, 0xdb, 0xf2, 0x6b, - 0x54, 0xb1, 0xad, 0xa6, 0x8c, 0xfb, 0x5e, 0xe8, 0x55, 0x6c, 0x07, 0x9e, 0xc6, 0x5f, 0xcb, 0x00, - 0x2c, 0x96, 0x01, 0xf8, 0x59, 0x06, 0xe0, 0x73, 0x15, 0xd4, 0x16, 0xab, 0xa0, 0xf6, 0xbd, 0x0a, - 0x6a, 0x6f, 0x0f, 0xa9, 0xb0, 0xd3, 0x22, 0xc6, 0x4c, 0x65, 0x84, 0x29, 0x93, 0x29, 0x43, 0x44, - 0xcc, 0xee, 0x52, 0x45, 0xca, 0x7b, 0x92, 0xa9, 0xa4, 0x98, 0x73, 0x53, 0x4d, 0xb5, 0x37, 0x91, - 0xfd, 0xc8, 0xb9, 0x21, 0x65, 0x14, 0x37, 0xdd, 0x40, 0xd1, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x1f, 0xc2, 0x4f, 0x29, 0x18, 0x02, 0x00, 0x00, + // 352 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0xcf, 0x4a, 0x23, 0x31, + 0x1c, 0x6e, 0x76, 0xda, 0xb2, 0x9b, 0xc2, 0x2e, 0x84, 0x45, 0x87, 0x22, 0xc3, 0x50, 0x2f, 0x15, + 0x35, 0xa1, 0x9d, 0x8b, 0xe8, 0x4d, 0xa4, 0x20, 0x5e, 0x4a, 0xa9, 0x17, 0x2f, 0x92, 0xc9, 0xa4, + 0xd3, 0xd0, 0x4e, 0x32, 0x24, 0x99, 0x11, 0xdf, 0xc2, 0xc7, 0xf2, 0xd8, 0xa3, 0x47, 0x69, 0x9f, + 0xc1, 0xbb, 0x4c, 0xfa, 0xc7, 0x9e, 0x7a, 0xcb, 0xf7, 0xcb, 0xf7, 0x0f, 0x3e, 0x78, 0x26, 0x62, + 0x46, 0x68, 0x9e, 0xcf, 0x05, 0xa3, 0x56, 0x28, 0x69, 0x88, 0xd5, 0x54, 0x9a, 0x09, 0xd7, 0xa4, + 0x8c, 0x48, 0x4e, 0xd9, 0x8c, 0x5b, 0x9c, 0x6b, 0x65, 0x15, 0x3a, 0x11, 0x31, 0xc3, 0xfb, 0x54, + 0xbc, 0xa5, 0xe2, 0x32, 0x6a, 0x9f, 0x1f, 0x30, 0xea, 0xed, 0xde, 0x6b, 0xab, 0xce, 0x17, 0x80, + 0xc7, 0x83, 0x42, 0xa6, 0x22, 0x9e, 0xf3, 0xb1, 0x9a, 0x71, 0x39, 0x74, 0x41, 0x77, 0xd4, 0x52, + 0x74, 0x03, 0x9b, 0xb6, 0x3a, 0x19, 0x1f, 0x84, 0x5e, 0xb7, 0xd5, 0x3f, 0xc5, 0x87, 0x72, 0xb1, + 0x93, 0x8f, 0x36, 0x12, 0x74, 0x04, 0x9b, 0x86, 0xcb, 0x84, 0x6b, 0xff, 0x57, 0x08, 0xba, 0x7f, + 0x46, 0x1b, 0x84, 0xda, 0xf0, 0xb7, 0xe6, 0x8c, 0x8b, 0x92, 0x6b, 0xdf, 0x73, 0x3f, 0x3b, 0x8c, + 0x10, 0xac, 0x67, 0x3c, 0x53, 0x7e, 0xdd, 0xdd, 0xdd, 0x1b, 0x3d, 0xc2, 0x7f, 0x13, 0xa5, 0x5f, + 0xa8, 0x4e, 0x84, 0x4c, 0x9f, 0x73, 0x6a, 0xa7, 0x7e, 0x23, 0x04, 0xdd, 0x56, 0xff, 0xe2, 0x50, + 0x9b, 0x1e, 0x1e, 0xec, 0x44, 0xf7, 0x72, 0xa2, 0x46, 0x7f, 0x7f, 0x4c, 0x86, 0xd4, 0x4e, 0x3b, + 0x0f, 0xb0, 0xe1, 0xfa, 0xa2, 0xff, 0xb0, 0x91, 0x70, 0xa9, 0x32, 0x1f, 0xb8, 0xd0, 0x35, 0xa8, + 0xda, 0xd3, 0x4c, 0x15, 0xd2, 0x6e, 0xdb, 0xaf, 0x51, 0xc5, 0xb6, 0x9a, 0x32, 0xee, 0x7b, 0xa1, + 0x57, 0xb1, 0x1d, 0xb8, 0x1d, 0xbf, 0x2f, 0x03, 0xb0, 0x58, 0x06, 0xe0, 0x73, 0x19, 0x80, 0xb7, + 0x55, 0x50, 0x5b, 0xac, 0x82, 0xda, 0xc7, 0x2a, 0xa8, 0x3d, 0x5d, 0xa7, 0xc2, 0x4e, 0x8b, 0x18, + 0x33, 0x95, 0x11, 0xa6, 0x4c, 0xa6, 0x0c, 0x11, 0x31, 0xbb, 0x4c, 0x15, 0x29, 0xaf, 0x48, 0xa6, + 0x92, 0x62, 0xce, 0x4d, 0xb5, 0xd5, 0xde, 0x46, 0xf6, 0x35, 0xe7, 0x86, 0x94, 0x51, 0xdc, 0x74, + 0x0b, 0x45, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x94, 0x9a, 0x68, 0x66, 0x19, 0x02, 0x00, 0x00, } func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index ad6b5e9671e..36172d0f7bf 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -28,11 +28,11 @@ message Params { } message ForwardingInfo { - repeated Hop hops = 1; - string memo = 2; + repeated Hop hops = 1; + string memo = 2; } message Hop { - string portID = 1; + string portID = 1; string channelId = 2; } \ No newline at end of file diff --git a/proto/ibc/applications/transfer/v1/tx.proto b/proto/ibc/applications/transfer/v1/tx.proto index b497e141b85..116a8b26662 100644 --- a/proto/ibc/applications/transfer/v1/tx.proto +++ b/proto/ibc/applications/transfer/v1/tx.proto @@ -52,7 +52,7 @@ message MsgTransfer { // tokens to be transferred repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; - ForwardingInfo forwardingPath = 10; + ForwardingInfo forwarding_path = 10; } // MsgTransferResponse defines the Msg/Transfer response type. diff --git a/proto/ibc/applications/transfer/v3/packet.proto b/proto/ibc/applications/transfer/v3/packet.proto index 78a58f8dc21..4ddfb97a8d9 100644 --- a/proto/ibc/applications/transfer/v3/packet.proto +++ b/proto/ibc/applications/transfer/v3/packet.proto @@ -18,13 +18,13 @@ message FungibleTokenPacketData { string receiver = 3; // optional memo string memo = 4; - // optional forwardingInfo struct - ibc.applications.transfer.v1.ForwardingInfo forwardingPath = 5; + // optional forwardingInfo struct + ibc.applications.transfer.v1.ForwardingInfo forwarding_path = 5; } /* message ForwardingInfo { - repeated Hop hop = 1; + repeated Hop hop = 1; string memo = 2; } From 55d7bf97f19cd115a013f700c5c5075c4090d5e1 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 15 May 2024 00:05:41 +0200 Subject: [PATCH 025/141] basic unit test for path forwarding --- modules/apps/transfer/keeper/relay_test.go | 54 ++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index d4fed1a9501..5033f02e5aa 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -450,6 +450,60 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { } } +func (suite *KeeperTestSuite) TestPathForwarding() { + amount := sdkmath.NewInt(100) + + // setup + // 2 transfer channels between chain A and chain B + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path2.Setup() + + coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainA.SenderAccounts[1].SenderAccount + forwardingPath := types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortID: path2.EndpointA.ChannelConfig.PortID, + ChannelId: path2.EndpointA.ChannelID, + }, + }, + Memo: "", + } + + transferMsg := types.NewMsgTransfer( + path1.EndpointA.ChannelConfig.PortID, + path1.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + &forwardingPath, + ) + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(packet, forwardedPacket) +} + func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCToken() { /* Given the following flow of tokens: From 1a95262f1e97cae71ffd7036da9e3509857a56a6 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Wed, 15 May 2024 16:29:02 +0200 Subject: [PATCH 026/141] fix test unsuccessful refund from source --- modules/apps/transfer/keeper/relay.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index b15d39b864a..05a99389e70 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -434,7 +434,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // Figure Out how to do this - FungibleTokenPacketAcknowledgement := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) + FungibleTokenPacketAcknowledgement := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) //[]byte{byte(1)}) // Error: "forwarded packet succeeded", // Result: true, // } @@ -464,7 +464,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac } else { switch ack.Response.(type) { case *channeltypes.Acknowledgement_Error: - k.refundPacketToken(ctx, packet, data) + return k.refundPacketToken(ctx, packet, data) } } return nil From 44e15cb5ca0c5670169d1252e18767aee63884cc Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Wed, 15 May 2024 20:24:54 +0200 Subject: [PATCH 027/141] wip test fix --- modules/apps/transfer/ibc_module.go | 7 ++++++- modules/apps/transfer/keeper/mbt_relay_test.go | 4 +++- modules/apps/transfer/keeper/relay.go | 5 +++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 595c014f00b..afb4e656c0e 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -254,7 +254,12 @@ func (im IBCModule) OnRecvPacket( ctx.EventManager().EmitEvents(events) // NOTE: acknowledgement will be written synchronously during IBC handler execution. - return ack + if ack.Success() { + return channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + } else { + return ack + } + } // OnAcknowledgementPacket implements the IBCModule interface diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 101db74ceed..ce1e73ac7c1 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -155,8 +155,8 @@ func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPack []*v3types.Token{ { Denom: denom, - Amount: packet.Data.Amount, Trace: trace, + Amount: packet.Data.Amount, }, }, AddressFromString(packet.Data.Sender), @@ -355,6 +355,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { if !ok { panic(errors.New("MBT failed to parse amount from string")) } + msg := types.NewMsgTransfer( tc.packet.SourcePort, tc.packet.SourceChannel, @@ -374,6 +375,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { case "OnTimeoutPacket": registerDenomFn() err = suite.chainB.GetSimApp().TransferKeeper.OnTimeoutPacket(suite.chainB.GetContext(), packet, tc.packet.Data) + case "OnRecvAcknowledgementResult": err = suite.chainB.GetSimApp().TransferKeeper.OnAcknowledgementPacket( suite.chainB.GetContext(), packet, tc.packet.Data, diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 05a99389e70..22bd9c78190 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -206,14 +206,14 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v } // Receiver addresses logic: - var forwardAddress sdk.AccAddress + //var forwardAddress sdk.AccAddress var finalReceiver sdk.AccAddress var receiver sdk.AccAddress var err error if len(data.ForwardingPath.Hops) > 0 { // Transaction would abort already for previous check on Memo - forwardAddress = types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) + forwardAddress := types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) /*if forwardAddress.Empty() { forwardAddress, err = sdk.AccAddressFromBech32("forwardingAddress") // MMMM // How to set this? if err != nil { @@ -447,6 +447,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // we must revert the changes that came from successfully receiving the tokens on our chain // before propogating the error acknowledgement back to original sender chain + // Should Check return value k.revertInFlightChanges(ctx, packet, prevPacket, data) // Figure Out how to do this //err error := "forwarded packet failed" From 334d5a909dc3b49d5556f8100fd4add6a987c9de Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Thu, 16 May 2024 12:54:21 +0200 Subject: [PATCH 028/141] fix mbt test - need more investigation --- .../transfer/keeper/model_based_tests/TestUnescrowTokens.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json b/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json index b4ebe81c70d..f61886b2805 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json @@ -300,6 +300,6 @@ "amount": 2 } ], - "error": false + "error": true } ] From 7466b19eb541943842b0570a6e34e540305e765b Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Thu, 16 May 2024 16:13:28 +0200 Subject: [PATCH 029/141] revert test fix --- .../transfer/keeper/model_based_tests/TestUnescrowTokens.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json b/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json index f61886b2805..b4ebe81c70d 100644 --- a/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json +++ b/modules/apps/transfer/keeper/model_based_tests/TestUnescrowTokens.json @@ -300,6 +300,6 @@ "amount": 2 } ], - "error": true + "error": false } ] From 5c46d7945a8a0b7a09af1f1c1f1d8443a2af8231 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Thu, 16 May 2024 17:17:05 +0200 Subject: [PATCH 030/141] add assertions --- modules/apps/transfer/keeper/relay.go | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 22bd9c78190..f60cd8fefc3 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -214,12 +214,6 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v if len(data.ForwardingPath.Hops) > 0 { // Transaction would abort already for previous check on Memo forwardAddress := types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) - /*if forwardAddress.Empty() { - forwardAddress, err = sdk.AccAddressFromBech32("forwardingAddress") // MMMM // How to set this? - if err != nil { - return errorsmod.Wrapf(err, "failed to decode forward address: %s", data.Receiver) - } - }*/ receiver = forwardAddress finalReceiver, err = sdk.AccAddressFromBech32(data.Receiver) if err != nil { @@ -232,11 +226,14 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v } } - //TODO Assertion Implementation - /*assert(packet.sender !== "") - assert(receiver !== "")*/ + if string(data.Sender) == "" { + return errorsmod.Wrapf(err, "empty sender address: %s", data.Sender) + } + + if string(receiver) == "" { + return errorsmod.Wrapf(err, "empty receiver address: %s", receiver) + } - //var receivedTokens []*v3types.Token var receivedTokens sdk.Coins for _, token := range data.Tokens { From 99e6b0a1d116d42f4446caee8fc1d3fb2889363e Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Thu, 16 May 2024 19:36:12 +0200 Subject: [PATCH 031/141] add support for async ack --- modules/apps/transfer/ibc_module.go | 11 +++-- .../apps/transfer/keeper/mbt_relay_test.go | 5 ++- modules/apps/transfer/keeper/relay.go | 45 ++++++++++++------- modules/apps/transfer/keeper/relay_test.go | 9 ++-- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index afb4e656c0e..d904bb90e0e 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -216,7 +216,10 @@ func (im IBCModule) OnRecvPacket( // only attempt the application logic if the packet data // was successfully decoded if ack.Success() { - err := im.keeper.OnRecvPacket(ctx, packet, data) + err, async := im.keeper.OnRecvPacket(ctx, packet, data) + if async { + return nil // Ok if we do this, which guaranteee we have that we can return the proper ack later on? + } if err != nil { ack = channeltypes.NewErrorAcknowledgement(err) ackErr = err @@ -254,11 +257,7 @@ func (im IBCModule) OnRecvPacket( ctx.EventManager().EmitEvents(events) // NOTE: acknowledgement will be written synchronously during IBC handler execution. - if ack.Success() { - return channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - } else { - return ack - } + return ack } diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index ce1e73ac7c1..f4bf0078faf 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -371,7 +371,10 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { } case "OnRecvPacket": - err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, tc.packet.Data) + var async bool + err, async = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, tc.packet.Data) + suite.Require().False(async) + case "OnTimeoutPacket": registerDenomFn() err = suite.chainB.GetSimApp().TransferKeeper.OnTimeoutPacket(suite.chainB.GetContext(), packet, tc.packet.Data) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index f60cd8fefc3..7c424799721 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -189,20 +189,21 @@ func (k Keeper) sendTransfer( // and sent to the receiving address. Otherwise if the sender chain is sending // back tokens this chain originally transferred to it, the tokens are // unescrowed and sent to the receiving address. -func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { +func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) (error, bool) { // validate packet data upon receiving // same things here if we put the validate memo here this function would return an error. + if err := data.ValidateBasic(); err != nil { - return errorsmod.Wrapf(err, "error validating ICS-20 transfer packet data") + return errorsmod.Wrapf(err, "error validating ICS-20 transfer packet data"), false } // Otherwise we need to validate here if data.ForwardingPath.Hops != nil && data.Memo != "" { - return errorsmod.Wrapf(types.ErrInvalidMemoSpecification, "incorrect memo specification: %s,%s", data.Memo, data.ForwardingPath.Hops) + return errorsmod.Wrapf(types.ErrInvalidMemoSpecification, "incorrect memo specification: %s,%s", data.Memo, data.ForwardingPath.Hops), false } if !k.GetParams(ctx).ReceiveEnabled { - return types.ErrReceiveDisabled + return types.ErrReceiveDisabled, false } // Receiver addresses logic: @@ -217,21 +218,21 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v receiver = forwardAddress finalReceiver, err = sdk.AccAddressFromBech32(data.Receiver) if err != nil { - return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver) + return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver), false } } else { receiver, err = sdk.AccAddressFromBech32(data.Receiver) if err != nil { - return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver) + return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver), false } } if string(data.Sender) == "" { - return errorsmod.Wrapf(err, "empty sender address: %s", data.Sender) + return errorsmod.Wrapf(err, "empty sender address: %s", data.Sender), false } if string(receiver) == "" { - return errorsmod.Wrapf(err, "empty receiver address: %s", receiver) + return errorsmod.Wrapf(err, "empty receiver address: %s", receiver), false } var receivedTokens sdk.Coins @@ -247,7 +248,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v // parse the transfer amount transferAmount, ok := sdkmath.NewIntFromString(token.Amount) if !ok { - return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount: %s", token.Amount) + return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount: %s", token.Amount), false } // This is the prefix that would have been prefixed to the denomination @@ -276,12 +277,12 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v token := sdk.NewCoin(denom, transferAmount) if k.bankKeeper.BlockedAddr(receiver) { - return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) + return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver), false } escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) if err := k.unescrowToken(ctx, escrowAddress, receiver, token); err != nil { - return err + return err, false } defer func() { @@ -337,14 +338,14 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v if err := k.bankKeeper.MintCoins( ctx, types.ModuleName, sdk.NewCoins(voucher), ); err != nil { - return errorsmod.Wrap(err, "failed to mint IBC tokens") + return errorsmod.Wrap(err, "failed to mint IBC tokens"), false } // send to receiver if err := k.bankKeeper.SendCoinsFromModuleToAccount( ctx, types.ModuleName, receiver, sdk.NewCoins(voucher), ); err != nil { - return errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()) + return errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()), false } defer func() { @@ -396,17 +397,27 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v // _ is nextPacketSequence what we do with it? _, err := k.sendTransfer(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, receivedTokens, receiver, string(finalReceiver), clienttypes.Height{}, timeoutTimestamp, memo, nextForwardingPath) if err != nil { - return err + return err, false } - //packetData := v3types.NewFungibleTokenPacketData(tokens, sender.String(), receiver, memo, forwardingPath) //k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, nextPacketSequence, data) k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, packet) - return nil + // The return value will be used by the onRecvPacket in the ibc_module.go + // If we return nil here, then we will write a successfull sinc ack. + // If we reutrn an error, then we will write a sinc error ack + // The onRecvPacket in the ibc_module.go has as return value ibcexported.Acknowledgement + // and it will return either an error ack or succesfull ack. + // Thus to achieve the correct behaviour, we should be able to return a nil value in the ibc_module.go + // onRecvPacket function. + // return nil + // Instead of returning simply nil, we will return a sentinel value that can be used to return nil in the ibc_module.go + // onRecvPacket function. + return nil, true + } // The ibc_module.go module will return the proper ack. - return nil + return nil, false } // OnAcknowledgementPacket responds to the success or failure of a packet diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 5033f02e5aa..2ab263108d9 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -426,8 +426,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, *ibctesting.TestEmptyForwardingPath) packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) - + var async bool + err, async = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) + suite.Require().False(async) // check total amount in escrow of received token denom on receiving chain totalEscrow := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), sdk.DefaultBondDenom) suite.Require().Equal(expEscrowAmount, totalEscrow.Amount) @@ -593,7 +594,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) // execute onRecvPacket, when chaninB receives the source token the escrow amount should decrease - err := suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) + var async bool + err, async := suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) + suite.Require().False(async) suite.Require().NoError(err) // check total amount in escrow of sent token on receiving chain From a114af636c80f357041868ce43aaf5a1d8f503dd Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Thu, 16 May 2024 21:40:29 +0200 Subject: [PATCH 032/141] wip test forwarding happy path --- modules/apps/transfer/keeper/relay_test.go | 120 +++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 2ab263108d9..cd364fe9c63 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -1015,3 +1015,123 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI totalEscrowChainB = suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) suite.Require().Equal(sdkmath.ZeroInt(), totalEscrowChainB.Amount) } + +func (suite *KeeperTestSuite) TestHappyPathForwarding() { + amount := sdkmath.NewInt(100) + + // setup A -> B -> A + // 2 transfer channels between chain A <-> B <-> C + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) + path2.Setup() + + //path3 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) + //path3.Setup() + + coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainC.SenderAccounts[0].SenderAccount + forwardingPath := types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortID: path2.EndpointA.ChannelConfig.PortID, + ChannelId: path2.EndpointA.ChannelID, + }, + }, + Memo: "", + } + + preCoinA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress(), sdk.DefaultBondDenom) + + transferMsg := types.NewMsgTransfer( + path1.EndpointA.ChannelConfig.PortID, + path1.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + &forwardingPath, + ) + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) + + postCoinA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress(), sdk.DefaultBondDenom) + + packet2, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet2) + + result, err = path2.EndpointB.RecvPacketWithResult(packet2) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID) + suite.Require().True(found) + suite.Require().Equal(packet, forwardedPacket) + + totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) + + denomTraceAB := types.DenomTrace{ + BaseDenom: sdk.DefaultBondDenom, + Path: fmt.Sprintf("%s/%s/", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + } + + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), denomTraceAB.IBCDenom()) + suite.Require().Equal(sdkmath.ZeroInt(), totalEscrowChainB.Amount) + + // Since we're sending out from A to C + // The delta amount is computed as preSend - postSend : e.g. if preSend=100 and postSend=0 --> delta = 100 + deltaAmountA := preCoinA.Amount.Sub(postCoinA.Amount) + suite.Require().Equal(amount.Int64(), deltaAmountA.Int64(), "token successfully deduced from A balance") + + // WIP + /* Random things + + denomTraceABC := types.DenomTrace{ + BaseDenom: sdk.DefaultBondDenom, + Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + } + + //preCoinC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), denomTraceABC.IBCDenom()) + + // Check sender's balance on chain A to ensure it has reduced by the sent amount + //balanceA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress(), sdk.DefaultBondDenom) + //suite.Require().Equal(sdkmath.NewInt(0), balanceA.Amount) + + denomTrace = types.DenomTrace{ + BaseDenom: sdk.DefaultBondDenom, + Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + } + balanceC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), denomTrace.IBCDenom()) + suite.Require().Equal(denomTrace.IBCDenom(), balanceC.Denom) + suite.Require().NoError(err)*/ + + //suite.Require().Equal(sdkmath.NewInt(100), balanceC.Amount) + /* + // Additional checks: Verify that there is no unexpected remaining balance or state + // Check that the escrow amount on chain B is zero after forwarding + + balanceC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), denomTrace.IBCDenom()) + suite.Require().Equal(denomTrace.IBCDenom(), balanceC.Denom) + //suite.Require().Equal(sdkmath.NewInt(10), balanceC.Amount) + */ +} From d800caa9d796489e20862a784ec16fe83245c3d4 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 17 May 2024 12:39:39 +0200 Subject: [PATCH 033/141] icsv20(path forwarding): use nil as default forwarding path when not set, use sequence in key to store forwarded packet (#6325) * use nil forwarding path as default when not set, use sequence in key to store forwarded packet * lint --- e2e/tests/transfer/authz_test.go | 9 ++-- e2e/tests/transfer/incentivized_test.go | 5 +- e2e/tests/transfer/upgrades_test.go | 3 +- e2e/tests/upgrades/upgrade_test.go | 2 +- e2e/testsuite/tx.go | 3 +- .../host/keeper/relay_test.go | 4 +- modules/apps/29-fee/keeper/events_test.go | 2 +- modules/apps/29-fee/transfer_test.go | 4 +- modules/apps/callbacks/ibc_middleware_test.go | 12 ++--- modules/apps/callbacks/replay_test.go | 2 +- modules/apps/callbacks/transfer_test.go | 4 +- modules/apps/transfer/client/cli/tx.go | 8 +-- modules/apps/transfer/ibc_module.go | 1 - .../apps/transfer/internal/convert/convert.go | 6 +-- .../transfer/internal/convert/convert_test.go | 18 +++---- .../apps/transfer/keeper/invariants_test.go | 2 +- modules/apps/transfer/keeper/keeper.go | 17 +++--- .../apps/transfer/keeper/mbt_relay_test.go | 4 +- modules/apps/transfer/keeper/msg_server.go | 2 +- .../apps/transfer/keeper/msg_server_test.go | 6 +-- modules/apps/transfer/keeper/relay.go | 54 ++++++------------- modules/apps/transfer/keeper/relay_test.go | 33 ++++++------ modules/apps/transfer/transfer_test.go | 6 +-- modules/apps/transfer/types/errors.go | 21 ++++---- modules/apps/transfer/types/keys.go | 9 ++-- modules/apps/transfer/types/msgs_test.go | 42 +++++++-------- .../types/transfer_authorization_test.go | 4 +- modules/apps/transfer/types/v3/packet.go | 9 +++- modules/apps/transfer/types/v3/packet_test.go | 49 ++++++++--------- modules/apps/transfer/types/v3/token_test.go | 6 +-- testing/solomachine.go | 8 +-- testing/values.go | 9 ++-- 32 files changed, 153 insertions(+), 211 deletions(-) diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index b282376493d..2f665d533dd 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -20,7 +20,6 @@ import ( "github.com/cosmos/ibc-go/e2e/testvalues" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" - ibctesting "github.com/cosmos/ibc-go/v8/testing" ) func TestAuthzTransferTestSuite(t *testing.T) { @@ -114,7 +113,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -174,7 +173,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -257,7 +256,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -317,7 +316,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) diff --git a/e2e/tests/transfer/incentivized_test.go b/e2e/tests/transfer/incentivized_test.go index 13211a2a37d..573bc142f85 100644 --- a/e2e/tests/transfer/incentivized_test.go +++ b/e2e/tests/transfer/incentivized_test.go @@ -20,7 +20,6 @@ import ( feetypes "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" - ibctesting "github.com/cosmos/ibc-go/v8/testing" ) const ( @@ -198,7 +197,7 @@ func (s *IncentivizedTransferTestSuite) TestMsgPayPacketFee_InvalidReceiverAccou transferAmount := testvalues.DefaultTransferAmount(chainADenom) t.Run("send IBC transfer", func(t *testing.T) { - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), testvalues.InvalidAddress, s.GetTimeoutHeight(ctx, chainB), 0, "", ibctesting.TestEmptyForwardingPath) + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), testvalues.InvalidAddress, s.GetTimeoutHeight(ctx, chainB), 0, "", nil) txResp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgTransfer) // this message should be successful, as receiver account is not validated on the sending chain. s.AssertTxSuccess(txResp) @@ -323,7 +322,7 @@ func (s *IncentivizedTransferTestSuite) TestMultiMsg_MsgPayPacketFeeSingleSender }) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", ibctesting.TestEmptyForwardingPath) + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", nil) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) diff --git a/e2e/tests/transfer/upgrades_test.go b/e2e/tests/transfer/upgrades_test.go index 0aad2d11170..3a92bdc648d 100644 --- a/e2e/tests/transfer/upgrades_test.go +++ b/e2e/tests/transfer/upgrades_test.go @@ -20,7 +20,6 @@ import ( feetypes "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" - ibctesting "github.com/cosmos/ibc-go/v8/testing" ) func TestTransferChannelUpgradesTestSuite(t *testing.T) { @@ -198,7 +197,7 @@ func (s *TransferChannelUpgradesTestSuite) TestChannelUpgrade_WithFeeMiddleware_ transferAmount := testvalues.DefaultTransferAmount(chainA.Config().Denom) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", ibctesting.TestEmptyForwardingPath) + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", nil) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) }) diff --git a/e2e/tests/upgrades/upgrade_test.go b/e2e/tests/upgrades/upgrade_test.go index aa6287b7d2d..7b9fa90d97a 100644 --- a/e2e/tests/upgrades/upgrade_test.go +++ b/e2e/tests/upgrades/upgrade_test.go @@ -960,7 +960,7 @@ func (s *UpgradeTestSuite) TestV8ToV8_1ChainUpgrade_ChannelUpgrades() { transferAmount := testvalues.DefaultTransferAmount(chainA.Config().Denom) msgPayPacketFee := feetypes.NewMsgPayPacketFee(testFee, channelA.PortID, channelA.ChannelID, chainAWallet.FormattedAddress(), nil) - msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", ibctesting.TestEmptyForwardingPath) + msgTransfer := transfertypes.NewMsgTransfer(channelA.PortID, channelA.ChannelID, sdk.NewCoins(transferAmount), chainAWallet.FormattedAddress(), chainBWallet.FormattedAddress(), s.GetTimeoutHeight(ctx, chainB), 0, "", nil) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) }) diff --git a/e2e/testsuite/tx.go b/e2e/testsuite/tx.go index 5f1b91da7dc..038b31ad650 100644 --- a/e2e/testsuite/tx.go +++ b/e2e/testsuite/tx.go @@ -32,7 +32,6 @@ import ( transfertypes "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" - ibctesting "github.com/cosmos/ibc-go/v8/testing" ) // BroadcastMessages broadcasts the provided messages to the given chain and signs them on behalf of the provided user. @@ -266,7 +265,7 @@ func (s *E2ETestSuite) ExecuteGovV1Beta1Proposal(ctx context.Context, chain ibc. func (s *E2ETestSuite) Transfer(ctx context.Context, chain ibc.Chain, user ibc.Wallet, portID, channelID string, token sdk.Coin, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, ) sdk.TxResponse { - msg := transfertypes.NewMsgTransfer(portID, channelID, sdk.NewCoins(token), sender, receiver, timeoutHeight, timeoutTimestamp, memo, ibctesting.TestEmptyForwardingPath) + msg := transfertypes.NewMsgTransfer(portID, channelID, sdk.NewCoins(token), sender, receiver, timeoutHeight, timeoutTimestamp, memo, nil) return s.BroadcastMessages(ctx, chain, user, msg) } diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index d6ef992ee12..ada479ef691 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -351,7 +351,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.chainB.GetTimeoutHeight(), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) @@ -387,7 +387,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.chainB.GetTimeoutHeight(), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) diff --git a/modules/apps/29-fee/keeper/events_test.go b/modules/apps/29-fee/keeper/events_test.go index 604be9c23b0..97abffbd54e 100644 --- a/modules/apps/29-fee/keeper/events_test.go +++ b/modules/apps/29-fee/keeper/events_test.go @@ -115,7 +115,7 @@ func (suite *KeeperTestSuite) TestDistributeFeeEvent() { path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) res, err := suite.chainA.SendMsgs(msgPayPacketFee, msgTransfer) diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 68b7fea95cf..ce44f4a32c6 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -30,7 +30,7 @@ func (suite *FeeTestSuite) TestFeeTransfer() { msgs := []sdk.Msg{ types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), - transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", ibctesting.TestEmptyForwardingPath), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", nil), } res, err := suite.chainA.SendMsgs(msgs...) suite.Require().NoError(err) // message committed @@ -138,7 +138,7 @@ func (suite *FeeTestSuite) TestTransferFeeUpgrade() { fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) msgs := []sdk.Msg{ types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), - transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", ibctesting.TestEmptyForwardingPath), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", nil), } res, err := suite.chainA.SendMsgs(msgs...) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 7206479f1bd..0f494e679fb 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -176,7 +176,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract), - *ibctesting.TestEmptyForwardingPath, + nil, ) chanCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) @@ -319,7 +319,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, simapp.SuccessContract, userGasLimit), - *ibctesting.TestEmptyForwardingPath, + nil, ) packet = channeltypes.Packet{ @@ -485,7 +485,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { sdk.NewCoins(ibctesting.TestCoin), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), // set user gas limit above panic level in mock contract keeper - ibctesting.TestEmptyForwardingPath, + nil, ) res, err := s.chainA.SendMsgs(msg) @@ -654,7 +654,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), - *ibctesting.TestEmptyForwardingPath, + nil, ) packet = channeltypes.Packet{ @@ -787,7 +787,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), - *ibctesting.TestEmptyForwardingPath, + nil, ) packet = channeltypes.Packet{ @@ -1007,7 +1007,7 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { Sender: ibctesting.TestAccAddress, Receiver: ibctesting.TestAccAddress, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), - ForwardingPath: ibctesting.TestEmptyForwardingPath, + ForwardingPath: nil, } // Unmarshal ICS20 v1 packet data diff --git a/modules/apps/callbacks/replay_test.go b/modules/apps/callbacks/replay_test.go index b3f12b0e12d..86df3bacde4 100644 --- a/modules/apps/callbacks/replay_test.go +++ b/modules/apps/callbacks/replay_test.go @@ -330,7 +330,7 @@ func (s *CallbacksTestSuite) ExecuteFailedTransfer(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, - ibctesting.TestEmptyForwardingPath, + nil, ) res, err := s.chainA.SendMsgs(msg) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 2661703553a..c2d09046448 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -193,7 +193,7 @@ func (s *CallbacksTestSuite) ExecuteTransfer(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, - ibctesting.TestEmptyForwardingPath, + nil, ) res, err := s.chainA.SendMsgs(msg) @@ -228,7 +228,7 @@ func (s *CallbacksTestSuite) ExecuteTransferTimeout(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), timeoutHeight, timeoutTimestamp, memo, - ibctesting.TestEmptyForwardingPath, + nil, ) res, err := s.chainA.SendMsgs(msg) diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index 2cdd9500b57..b2c41011745 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -18,12 +18,6 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" ) -var ( - forwardingPath = &types.ForwardingInfo{ - Hops: nil, // Correcting this line - Memo: ""} -) - const ( flagPacketTimeoutHeight = "packet-timeout-height" flagPacketTimeoutTimestamp = "packet-timeout-timestamp" @@ -113,7 +107,7 @@ Relative timeout timestamp is added to the value of the user's local system cloc } msg := types.NewMsgTransfer( - srcPort, srcChannel, sdk.NewCoins(coin), sender, receiver, timeoutHeight, timeoutTimestamp, memo, forwardingPath, + srcPort, srcChannel, sdk.NewCoins(coin), sender, receiver, timeoutHeight, timeoutTimestamp, memo, nil, ) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index d904bb90e0e..9b5a9e92712 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -258,7 +258,6 @@ func (im IBCModule) OnRecvPacket( // NOTE: acknowledgement will be written synchronously during IBC handler execution. return ack - } // OnAcknowledgementPacket implements the IBCModule interface diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go index e9f343eb58f..56b8f77b5c6 100644 --- a/modules/apps/transfer/internal/convert/convert.go +++ b/modules/apps/transfer/internal/convert/convert.go @@ -7,10 +7,6 @@ import ( v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" ) -var forwardingPath = &types.ForwardingInfo{ - Hops: nil, // Correcting this line - Memo: ""} - // PacketDataV1ToV3 converts a v1 (ICS20-V1) packet data to a v3 (ICS20-V2) packet data. func PacketDataV1ToV3(packetData types.FungibleTokenPacketData) v3types.FungibleTokenPacketData { if err := packetData.ValidateBasic(); err != nil { @@ -29,7 +25,7 @@ func PacketDataV1ToV3(packetData types.FungibleTokenPacketData) v3types.Fungible Sender: packetData.Sender, Receiver: packetData.Receiver, Memo: packetData.Memo, - ForwardingPath: forwardingPath, + ForwardingPath: nil, } } diff --git a/modules/apps/transfer/internal/convert/convert_test.go b/modules/apps/transfer/internal/convert/convert_test.go index 5fc869f7f1b..a2fab25052c 100644 --- a/modules/apps/transfer/internal/convert/convert_test.go +++ b/modules/apps/transfer/internal/convert/convert_test.go @@ -17,10 +17,6 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { receiver = "receiver" ) - var forwardingPath = &types.ForwardingInfo{ - Hops: nil, - Memo: ""} - testCases := []struct { name string v1Data types.FungibleTokenPacketData @@ -37,7 +33,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0"}, }, - }, sender, receiver, "", *forwardingPath), + }, sender, receiver, "", nil), nil, }, { @@ -50,7 +46,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: nil, }, - }, sender, receiver, "", *forwardingPath), + }, sender, receiver, "", nil), nil, }, { @@ -63,7 +59,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0"}, }, - }, sender, receiver, "", *forwardingPath), + }, sender, receiver, "", nil), nil, }, { @@ -76,7 +72,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0"}, }, - }, sender, receiver, "", *forwardingPath), + }, sender, receiver, "", nil), nil, }, { @@ -89,7 +85,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0", "transfer/channel-1"}, }, - }, sender, receiver, "", *forwardingPath), + }, sender, receiver, "", nil), nil, }, { @@ -102,7 +98,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0", "transfer/channel-1", "transfer-custom/channel-2"}, }, - }, sender, receiver, "", *forwardingPath), + }, sender, receiver, "", nil), nil, }, { @@ -115,7 +111,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { Amount: "1000", Trace: []string{"transfer/channel-0", "transfer/channel-1", "transfer-custom/channel-2"}, }, - }, sender, receiver, "", *forwardingPath), + }, sender, receiver, "", nil), nil, }, { diff --git a/modules/apps/transfer/keeper/invariants_test.go b/modules/apps/transfer/keeper/invariants_test.go index 928d2157959..d606549f0d4 100644 --- a/modules/apps/transfer/keeper/invariants_test.go +++ b/modules/apps/transfer/keeper/invariants_test.go @@ -51,7 +51,7 @@ func (suite *KeeperTestSuite) TestTotalEscrowPerDenomInvariant() { suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) res, err := suite.chainA.SendMsgs(msg) diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index ef707161e94..dd7097a7451 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -304,22 +304,17 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability return k.scopedKeeper.ClaimCapability(ctx, cap, name) } -// Set the forwarded packet in the private store. // Should the packet be v3types or -// func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64, packet v3types.FungibleTokenPacketData) { -func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, packet channeltypes.Packet) { +// SetForwardedPacket sets the forwarded packet in the private store. +func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, sequence uint64, packet channeltypes.Packet) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshal(&packet) - // store.Set(types.PacketForwardPath(portID, channelID, nextPacketSequence), bz) - store.Set(types.PacketForwardPath(portID, channelID), bz) - + store.Set(types.PacketForwardKey(portID, channelID, sequence), bz) } -// GetCounterpartyUpgrade gets the counterparty upgrade from the store. -// func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, nextPacketSequence uint64) (v3types.FungibleTokenPacketData, bool) { -func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string) (channeltypes.Packet, bool) { +// GetForwardedPacket gets the forwarded packet from the store. +func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, sequence uint64) (channeltypes.Packet, bool) { store := ctx.KVStore(k.storeKey) - //bz := store.Get(types.PacketForwardPath(portID, channelID, nextPacketSequence)) - bz := store.Get(types.PacketForwardPath(portID, channelID)) + bz := store.Get(types.PacketForwardKey(portID, channelID, sequence)) if bz == nil { return channeltypes.Packet{}, false } diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index f4bf0078faf..b81374831ba 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -162,7 +162,7 @@ func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPack AddressFromString(packet.Data.Sender), AddressFromString(packet.Data.Receiver), "", - *ibctesting.TestEmptyForwardingPath, + nil, ), } } @@ -364,7 +364,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { tc.packet.Data.Receiver, suite.chainA.GetTimeoutHeight(), 0, // only use timeout height "", - ibctesting.TestEmptyForwardingPath, + nil, ) _, err = suite.chainB.GetSimApp().TransferKeeper.Transfer(suite.chainB.GetContext(), msg) diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 25cca768468..cd1aea16081 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. sequence, err := k.sendTransfer( ctx, msg.SourcePort, msg.SourceChannel, tokens, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, - msg.Memo, *msg.ForwardingPath) + msg.Memo, msg.ForwardingPath) if err != nil { return nil, err } diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index cac968618ce..c447dce75cc 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -54,7 +54,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", - ibctesting.TestEmptyForwardingPath, + nil, ) }, nil, @@ -140,7 +140,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", - ibctesting.TestEmptyForwardingPath, + nil, ) // explicitly set to ics20-1 which does not support multi-denom @@ -171,7 +171,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", - ibctesting.TestEmptyForwardingPath, + nil, ) tc.malleate() diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 7c424799721..17b1c73e439 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -65,21 +65,13 @@ func (k Keeper) sendTransfer( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, - forwardingPath types.ForwardingInfo, + forwardingPath *types.ForwardingInfo, ) (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) } - // Input validation. We cannot have memo and forwarding path set at the same time. - // Note that this check could actually go inside the validate basic of v3 packet.go - // for NewFungibleTokenPacketData. Should probably go there because validateBasics is the function used for - // Input validations. For now I'll keep this check inside the relay.go function. We can decide to move them. - if forwardingPath.Hops != nil && memo != "" { - return 0, errorsmod.Wrapf(types.ErrInvalidMemoSpecification, "incorrect memo specification: %s,%s", memo, forwardingPath.Hops) - } - destinationPort := channel.Counterparty.PortId destinationChannel := channel.Counterparty.ChannelId @@ -197,22 +189,17 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v return errorsmod.Wrapf(err, "error validating ICS-20 transfer packet data"), false } - // Otherwise we need to validate here - if data.ForwardingPath.Hops != nil && data.Memo != "" { - return errorsmod.Wrapf(types.ErrInvalidMemoSpecification, "incorrect memo specification: %s,%s", data.Memo, data.ForwardingPath.Hops), false - } - if !k.GetParams(ctx).ReceiveEnabled { return types.ErrReceiveDisabled, false } // Receiver addresses logic: - //var forwardAddress sdk.AccAddress + var finalReceiver sdk.AccAddress var receiver sdk.AccAddress var err error - if len(data.ForwardingPath.Hops) > 0 { + if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { // Transaction would abort already for previous check on Memo forwardAddress := types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) receiver = forwardAddress @@ -370,14 +357,14 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v receivedTokens = append(receivedTokens, voucher) } // END OF FOR CYCLE - /* If ack wasn't successfull in the implementation we would have already errored out. No need of this check: + /* If ack wasn't successful in the implementation we would have already errored out. No need of this check: if !ack.Success() { return ack } */ // Adding forwarding logic - if len(data.ForwardingPath.Hops) > 0 { + if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { memo := "" nextForwardingPath := types.ForwardingInfo{ Hops: data.ForwardingPath.Hops[1:], @@ -390,21 +377,18 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v Hops: nil, Memo: data.ForwardingPath.Memo, } - } // Assign to timestamp --> current + 1 h timeoutTimestamp := uint64(ctx.BlockTime().Add(time.Hour).UnixNano()) - // _ is nextPacketSequence what we do with it? - _, err := k.sendTransfer(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, receivedTokens, receiver, string(finalReceiver), clienttypes.Height{}, timeoutTimestamp, memo, nextForwardingPath) + sequence, err := k.sendTransfer(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, receivedTokens, receiver, string(finalReceiver), clienttypes.Height{}, timeoutTimestamp, memo, &nextForwardingPath) if err != nil { return err, false } - //k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, nextPacketSequence, data) - k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, packet) + k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, sequence, packet) // The return value will be used by the onRecvPacket in the ibc_module.go - // If we return nil here, then we will write a successfull sinc ack. + // If we return nil here, then we will write a successful sinc ack. // If we reutrn an error, then we will write a sinc error ack // The onRecvPacket in the ibc_module.go has as return value ibcexported.Acknowledgement // and it will return either an error ack or succesfull ack. @@ -425,15 +409,13 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v // was a success then nothing occurs. If the acknowledgement failed, then // the sender is refunded their tokens using the refundPacketToken function. func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData, ack channeltypes.Acknowledgement) error { - - prevPacket, prevPacketExist := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel) - channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) if !ok { errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } - if prevPacketExist { + prevPacket, found := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) + if found { switch ack.Response.(type) { case *channeltypes.Acknowledgement_Result: // the acknowledgement succeeded on the receiving chain so nothing @@ -442,14 +424,13 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // Figure Out how to do this - FungibleTokenPacketAcknowledgement := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) //[]byte{byte(1)}) + FungibleTokenPacketAcknowledgement := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) // []byte{byte(1)}) // Error: "forwarded packet succeeded", // Result: true, // } return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, packet, FungibleTokenPacketAcknowledgement) - //return nil case *channeltypes.Acknowledgement_Error: // the forwarded packet has failed, thus the funds have been refunded to the forwarding address. // we must revert the changes that came from successfully receiving the tokens on our chain @@ -458,7 +439,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // Should Check return value k.revertInFlightChanges(ctx, packet, prevPacket, data) // Figure Out how to do this - //err error := "forwarded packet failed" + FungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(fmt.Errorf("forwarded packet failed")) /* channeltypes.Acknowledgement{ channeltypes.Acknowledgement.Response.Error: "forwarded packet failed", @@ -482,14 +463,13 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // OnTimeoutPacket refunds the sender since the original packet sent was // never received and has been timed out. func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { - prevPacket, prevPacketExist := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel) - channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) if !ok { errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } - if prevPacketExist { + prevPacket, found := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) + if found { k.revertInFlightChanges(ctx, packet, prevPacket, data) FungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(fmt.Errorf("forwarded packet failed")) @@ -554,7 +534,6 @@ func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, d } func (k Keeper) revertInFlightChanges(ctx sdk.Context, sentPacket channeltypes.Packet, receivedPacket channeltypes.Packet, sentPacketData v3types.FungibleTokenPacketData) error { - forwardEscrow := types.GetEscrowAddress(sentPacket.SourcePort, sentPacket.SourceChannel) reverseEscrow := types.GetEscrowAddress(receivedPacket.DestinationPort, receivedPacket.DestinationChannel) // the token on our chain is the token in the sentPacket @@ -584,9 +563,8 @@ func (k Keeper) revertInFlightChanges(ctx sdk.Context, sentPacket channeltypes.P // receive sent tokens from the received escrow to the forward escrow account // so we must send the tokens back from the forward escrow to the original received escrow account // To check if this is proper - //escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel()) + return k.unescrowToken(ctx, forwardEscrow, reverseEscrow, sdkToken) - //bank.TransferCoins(forwardEscrow, reverseEscrow, token.denom, token.amount) } else { // receive minted vouchers and sent to the forward escrow account // so we must remove the vouchers from the forward escrow account and burn them @@ -613,7 +591,7 @@ func (k Keeper) revertInFlightChanges(ctx sdk.Context, sentPacket channeltypes.P panic(fmt.Errorf("unable to send coins from module to account despite previously minting coins to module account: %v", err)) } } - //return nil + // if it wasn't a source token on receive, then we simply had minted vouchers and burned them in the receive. // So no state changes were made, and thus no reversion is necessary } diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index cd364fe9c63..cb9fd2a5658 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -129,7 +129,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { expEscrowAmount = sdkmath.ZeroInt() // create IBC token on chainA - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", ibctesting.TestEmptyForwardingPath) + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", nil) result, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -147,7 +147,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { sdk.NewCoins(coin), sender.String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, // only use timeout height memo, - ibctesting.TestEmptyForwardingPath, + nil, ) res, err := suite.chainA.GetSimApp().TransferKeeper.Transfer(suite.chainA.GetContext(), msg) @@ -214,7 +214,7 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) result, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -235,7 +235,7 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) res, err := suite.chainB.GetSimApp().TransferKeeper.Transfer(suite.chainB.GetContext(), msg) @@ -389,7 +389,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { if tc.recvIsSource { // send coin from chainB to chainA, receive them, acknowledge them, and send back to chainB coinFromBToA := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coinFromBToA), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, memo, ibctesting.TestEmptyForwardingPath) + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coinFromBToA), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, memo, nil) res, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -409,7 +409,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // send coin from chainA to chainB coin := sdk.NewCoin(denomTrace.IBCDenom(), amount) - transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo, ibctesting.TestEmptyForwardingPath) + transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo, nil) _, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -423,7 +423,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { Amount: amount.String(), Trace: trace, }, - }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, *ibctesting.TestEmptyForwardingPath) + }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, nil) packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) var async bool @@ -500,7 +500,7 @@ func (suite *KeeperTestSuite) TestPathForwarding() { suite.Require().NoError(err) suite.Require().NotNil(result) - forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID) + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, packet.Sequence) suite.Require().True(found) suite.Require().Equal(packet, forwardedPacket) } @@ -561,7 +561,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT Amount: amount.String(), Trace: trace, }, - }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", *ibctesting.TestEmptyForwardingPath) + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", nil) packet := channeltypes.NewPacket( data.GetBytes(), seq, @@ -690,7 +690,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { Amount: amount.String(), Trace: trace, }, - }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", *ibctesting.TestEmptyForwardingPath) + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", nil) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denomTrace.IBCDenom()) @@ -787,7 +787,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", - *ibctesting.TestEmptyForwardingPath, + nil, ) packet := channeltypes.NewPacket( data.GetBytes(), @@ -907,7 +907,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { Amount: amount.String(), Trace: trace, }, - }, sender, suite.chainB.SenderAccount.GetAddress().String(), "", *ibctesting.TestEmptyForwardingPath) + }, sender, suite.chainB.SenderAccount.GetAddress().String(), "", nil) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preCoin := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denomTrace.IBCDenom()) @@ -993,7 +993,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI Amount: amount.String(), Trace: trace, }, - }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", *ibctesting.TestEmptyForwardingPath) + }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", nil) packet := channeltypes.NewPacket( data.GetBytes(), seq, @@ -1027,8 +1027,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) path2.Setup() - //path3 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) - //path3.Setup() + coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount @@ -1083,7 +1082,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { suite.Require().NoError(err) suite.Require().NotNil(result) - forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID) + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, packet2.Sequence) suite.Require().True(found) suite.Require().Equal(packet, forwardedPacket) @@ -1125,7 +1124,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { suite.Require().Equal(denomTrace.IBCDenom(), balanceC.Denom) suite.Require().NoError(err)*/ - //suite.Require().Equal(sdkmath.NewInt(100), balanceC.Amount) + // suite.Require().Equal(sdkmath.NewInt(100), balanceC.Amount) /* // Additional checks: Verify that there is no unexpected remaining balance or state // Check that the escrow amount on chain B is zero after forwarding diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go index da411cedbbe..51cc2370604 100644 --- a/modules/apps/transfer/transfer_test.go +++ b/modules/apps/transfer/transfer_test.go @@ -52,7 +52,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, amount) // send from chainA to chainB - msg := types.NewMsgTransfer(pathAtoB.EndpointA.ChannelConfig.PortID, pathAtoB.EndpointA.ChannelID, sdk.NewCoins(coinToSendToB), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath) + msg := types.NewMsgTransfer(pathAtoB.EndpointA.ChannelConfig.PortID, pathAtoB.EndpointA.ChannelID, sdk.NewCoins(coinToSendToB), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", nil) res, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -82,7 +82,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { pathBtoC.Setup() // send from chainB to chainC - msg = types.NewMsgTransfer(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, sdk.NewCoins(coinSentFromAToB), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath) + msg = types.NewMsgTransfer(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, sdk.NewCoins(coinSentFromAToB), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", nil) res, err = suite.chainB.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -105,7 +105,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { suite.Require().Zero(balance.Amount.Int64()) // send from chainC back to chainB - msg = types.NewMsgTransfer(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, sdk.NewCoins(coinSentFromBToC), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath) + msg = types.NewMsgTransfer(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID, sdk.NewCoins(coinSentFromBToC), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", nil) res, err = suite.chainC.SendMsgs(msg) suite.Require().NoError(err) // message committed diff --git a/modules/apps/transfer/types/errors.go b/modules/apps/transfer/types/errors.go index 4c630a25e56..b3e45aa2ae2 100644 --- a/modules/apps/transfer/types/errors.go +++ b/modules/apps/transfer/types/errors.go @@ -6,15 +6,14 @@ import ( // IBC transfer sentinel errors var ( - ErrInvalidPacketTimeout = errorsmod.Register(ModuleName, 2, "invalid packet timeout") - ErrInvalidDenomForTransfer = errorsmod.Register(ModuleName, 3, "invalid denomination for cross-chain transfer") - ErrInvalidVersion = errorsmod.Register(ModuleName, 4, "invalid ICS20 version") - ErrInvalidAmount = errorsmod.Register(ModuleName, 5, "invalid token amount") - ErrTraceNotFound = errorsmod.Register(ModuleName, 6, "denomination trace not found") - ErrSendDisabled = errorsmod.Register(ModuleName, 7, "fungible token transfers from this chain are disabled") - ErrReceiveDisabled = errorsmod.Register(ModuleName, 8, "fungible token transfers to this chain are disabled") - ErrMaxTransferChannels = errorsmod.Register(ModuleName, 9, "max transfer channels") - ErrInvalidAuthorization = errorsmod.Register(ModuleName, 10, "invalid transfer authorization") - ErrInvalidMemo = errorsmod.Register(ModuleName, 11, "invalid memo") - ErrInvalidMemoSpecification = errorsmod.Register(ModuleName, 12, "invalid memo speicification") + ErrInvalidPacketTimeout = errorsmod.Register(ModuleName, 2, "invalid packet timeout") + ErrInvalidDenomForTransfer = errorsmod.Register(ModuleName, 3, "invalid denomination for cross-chain transfer") + ErrInvalidVersion = errorsmod.Register(ModuleName, 4, "invalid ICS20 version") + ErrInvalidAmount = errorsmod.Register(ModuleName, 5, "invalid token amount") + ErrTraceNotFound = errorsmod.Register(ModuleName, 6, "denomination trace not found") + ErrSendDisabled = errorsmod.Register(ModuleName, 7, "fungible token transfers from this chain are disabled") + ErrReceiveDisabled = errorsmod.Register(ModuleName, 8, "fungible token transfers to this chain are disabled") + ErrMaxTransferChannels = errorsmod.Register(ModuleName, 9, "max transfer channels") + ErrInvalidAuthorization = errorsmod.Register(ModuleName, 10, "invalid transfer authorization") + ErrInvalidMemo = errorsmod.Register(ModuleName, 11, "invalid memo") ) diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index d67d935ca2e..46d5a9cddf6 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -102,9 +102,8 @@ func TotalForwardForDenomKey(denom string) []byte { return []byte(fmt.Sprintf("%s/%s", KeyTotalForwardPrefix, denom)) } -// PacketForwardPath returns the packet forward path as a byte slice for the provided portID, channelID, and nextPacketSequence -// func PacketForwardPath(portID, channelID string, nextPacketSequence uint64) []byte { -func PacketForwardPath(portID, channelID string) []byte { - path := fmt.Sprintf("%s/%s/%s", KeyPacketForwardPrefix, portID, channelID) //, nextPacketSequence) - return []byte(path) +// PacketForwardKey returns the store key under which the forwarded packet is stored +// for the provided portID, channelID, and packet sequence. +func PacketForwardKey(portID, channelID string, sequence uint64) []byte { + return []byte(fmt.Sprintf("%s/%s/%s/%d", KeyPacketForwardPrefix, portID, channelID, sequence)) } diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index 0e03ed02205..eabd5e64c9a 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -53,26 +53,26 @@ func TestMsgTransferValidation(t *testing.T) { msg *types.MsgTransfer expPass bool }{ - {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), true}, - {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), true}, - {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), true}, - {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1), ibctesting.TestEmptyForwardingPath), false}, - {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, - {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath), false}, + {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), true}, + {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, timeoutHeight, 0, "", nil), true}, + {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, timeoutHeight, 0, "", nil), true}, + {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, timeoutHeight, 0, "", nil), false}, + {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), false}, + {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), false}, + {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), false}, + {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), false}, + {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), false}, + {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1), nil), false}, + {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), false}, + {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, timeoutHeight, 0, "", nil), false}, + {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", nil), false}, + {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, timeoutHeight, 0, "", nil), false}, + {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", timeoutHeight, 0, "", nil), false}, + {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, "", nil), false}, + {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, timeoutHeight, 0, "", nil), false}, + {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, "", nil), false}, + {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, "", nil), false}, + {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", nil), false}, } for i, tc := range testCases { @@ -90,7 +90,7 @@ func TestMsgTransferValidation(t *testing.T) { // TestMsgTransferGetSigners tests GetSigners for MsgTransfer func TestMsgTransferGetSigners(t *testing.T) { addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - msg := types.NewMsgTransfer(validPort, validChannel, coins, addr.String(), receiver, timeoutHeight, 0, "", ibctesting.TestEmptyForwardingPath) + msg := types.NewMsgTransfer(validPort, validChannel, coins, addr.String(), receiver, timeoutHeight, 0, "", nil) encodingCfg := moduletestutil.MakeTestEncodingConfig(transfer.AppModuleBasic{}) signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index 65ac18f0d12..1b1e31b0568 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -92,7 +92,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.chainB.GetTimeoutHeight(), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) }, func(res authz.AcceptResponse, err error) { @@ -274,7 +274,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.chainB.GetTimeoutHeight(), 0, "", - ibctesting.TestEmptyForwardingPath, + nil, ) tc.malleate() diff --git a/modules/apps/transfer/types/v3/packet.go b/modules/apps/transfer/types/v3/packet.go index e8c899dfe74..4ed8cf8cd68 100644 --- a/modules/apps/transfer/types/v3/packet.go +++ b/modules/apps/transfer/types/v3/packet.go @@ -23,14 +23,14 @@ func NewFungibleTokenPacketData( tokens []*Token, sender, receiver string, memo string, - forwardingPath types.ForwardingInfo, + forwardingPath *types.ForwardingInfo, ) FungibleTokenPacketData { return FungibleTokenPacketData{ Tokens: tokens, Sender: sender, Receiver: receiver, Memo: memo, - ForwardingPath: &forwardingPath, + ForwardingPath: forwardingPath, } } @@ -69,6 +69,11 @@ func (ftpd FungibleTokenPacketData) ValidateBasic() error { return errorsmod.Wrapf(types.ErrInvalidMemo, "memo must not exceed %d bytes", types.MaximumMemoLength) } + // We cannot have non-empty memo and non-empty forwarding path hops at the same time. + if ftpd.ForwardingPath != nil && len(ftpd.ForwardingPath.Hops) > 0 && ftpd.Memo != "" { + return errorsmod.Wrapf(types.ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", ftpd.Memo, ftpd.ForwardingPath.Hops) + } + return nil } diff --git a/modules/apps/transfer/types/v3/packet_test.go b/modules/apps/transfer/types/v3/packet_test.go index 772a7cd7ccb..4cfc70a6ae3 100644 --- a/modules/apps/transfer/types/v3/packet_test.go +++ b/modules/apps/transfer/types/v3/packet_test.go @@ -22,12 +22,6 @@ const ( invalidLargeAmount = "115792089237316195423570985008687907853269984665640564039457584007913129639936" // 2^256 ) -var ( - forwardingPath = &types.ForwardingInfo{ - Hops: nil, - Memo: ""} -) - var ( sender = secp256k1.GenPrivKey().PubKey().Address().String() receiver = sdk.AccAddress("testaddr2").String() @@ -53,7 +47,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), nil, }, @@ -70,7 +64,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "memo", - *forwardingPath, + nil, ), nil, }, @@ -87,7 +81,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "memo", - *forwardingPath, + nil, ), nil, }, @@ -104,7 +98,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), types.ErrInvalidDenomForTransfer, }, @@ -121,7 +115,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), types.ErrInvalidAmount, }, @@ -132,7 +126,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), types.ErrInvalidAmount, }, @@ -149,7 +143,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), types.ErrInvalidAmount, }, @@ -166,7 +160,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), types.ErrInvalidAmount, }, @@ -183,7 +177,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, receiver, "memo", - *forwardingPath, + nil, ), types.ErrInvalidAmount, }, @@ -200,7 +194,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { "", receiver, "memo", - *forwardingPath, + nil, ), ibcerrors.ErrInvalidAddress, }, @@ -217,7 +211,7 @@ func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { sender, "", "", - *forwardingPath, + nil, ), ibcerrors.ErrInvalidAddress, }, @@ -256,7 +250,7 @@ func TestGetPacketSender(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), sender, }, @@ -273,7 +267,7 @@ func TestGetPacketSender(t *testing.T) { "", receiver, "abc", - *forwardingPath, + nil, ), "", }, @@ -304,7 +298,7 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver), *forwardingPath), + fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver), nil), map[string]interface{}{ "address": receiver, @@ -322,7 +316,7 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, receiver), *forwardingPath), + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, receiver), nil), map[string]interface{}{ "address": receiver, "gas_limit": "200000", @@ -340,7 +334,7 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - `{"src_callback": "string"}`, *forwardingPath), + `{"src_callback": "string"}`, nil), "string", }, { @@ -355,7 +349,7 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - fmt.Sprintf(`{"dest_callback": {"address": "%s", "min_gas": "200000"}}`, receiver), *forwardingPath), + fmt.Sprintf(`{"dest_callback": {"address": "%s", "min_gas": "200000"}}`, receiver), nil), nil, }, { @@ -371,7 +365,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, "", - *forwardingPath), + nil), nil, }, { @@ -386,7 +380,8 @@ func TestPacketDataProvider(t *testing.T) { }, sender, receiver, - "invalid", *forwardingPath), + "invalid", + nil), nil, }, } @@ -418,7 +413,7 @@ func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), false, }, @@ -435,7 +430,7 @@ func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { sender, receiver, "abc", - *forwardingPath, + nil, ), true, }, diff --git a/modules/apps/transfer/types/v3/token_test.go b/modules/apps/transfer/types/v3/token_test.go index ddd7e33059b..6268e1b353f 100644 --- a/modules/apps/transfer/types/v3/token_test.go +++ b/modules/apps/transfer/types/v3/token_test.go @@ -28,7 +28,7 @@ func TestGetFullDenomPath(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), "transfer/channel-0/transfer/channel-1/atom/pool", }, @@ -45,7 +45,7 @@ func TestGetFullDenomPath(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), denom, }, @@ -62,7 +62,7 @@ func TestGetFullDenomPath(t *testing.T) { sender, receiver, "", - *forwardingPath, + nil, ), denom, }, diff --git a/testing/solomachine.go b/testing/solomachine.go index 341c4bcb53c..f8ce1f45a63 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -34,12 +34,6 @@ var ( channelIDSolomachine = "channel-on-solomachine" // channelID generated on solo machine side ) -var ( - forwardingPath = &transfertypes.ForwardingInfo{ - Hops: nil, // Correcting this line - Memo: ""} -) - // DefaultSolomachineClientID is the default solo machine client id used for testing var DefaultSolomachineClientID = "06-solomachine-0" @@ -384,7 +378,7 @@ func (solo *Solomachine) SendTransfer(chain *TestChain, portID, channelID string clienttypes.ZeroHeight(), uint64(chain.GetContext().BlockTime().Add(time.Hour).UnixNano()), "", - forwardingPath, + nil, ) for _, fn := range fns { diff --git a/testing/values.go b/testing/values.go index 8112cbf7f9e..0f14f41a081 100644 --- a/testing/values.go +++ b/testing/values.go @@ -55,12 +55,9 @@ var ( // DefaultTrustLevel sets params variables used to create a TM client DefaultTrustLevel = ibctm.DefaultTrustLevel - TestAccAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" - TestEmptyForwardingPath = &ibctransfertypes.ForwardingInfo{ - Hops: nil, // Correcting this line - Memo: ""} - TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) - TestCoins = sdk.NewCoins(TestCoin) + TestAccAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" + TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) + TestCoins = sdk.NewCoins(TestCoin) UpgradePath = []string{"upgrade", "upgradedIBCState"} From dd873a1140d10c56915bc13c433e98faf2517eaa Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Fri, 17 May 2024 19:58:16 +0200 Subject: [PATCH 034/141] add forwarding happy path tests --- modules/apps/transfer/keeper/relay_test.go | 218 +++++++++++++++------ 1 file changed, 161 insertions(+), 57 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index cb9fd2a5658..79e6675ee13 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -1016,34 +1016,41 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI suite.Require().Equal(sdkmath.ZeroInt(), totalEscrowChainB.Amount) } -func (suite *KeeperTestSuite) TestHappyPathForwarding() { +func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { amount := sdkmath.NewInt(100) + /* + Given the following topolgy: - // setup A -> B -> A - // 2 transfer channels between chain A <-> B <-> C - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A + stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake - path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) - path2.Setup() + We want to trigger: + 1. A sends B over channel0. + 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions + At this point we want to assert: + A: escrowA = amount,denom + B: escrowB = amount,transfer/channel-0/denom + */ + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path2.Setup() coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainC.SenderAccounts[0].SenderAccount + receiver := suite.chainA.SenderAccounts[1].SenderAccount forwardingPath := types.ForwardingInfo{ Hops: []*types.Hop{ { - PortID: path2.EndpointA.ChannelConfig.PortID, - ChannelId: path2.EndpointA.ChannelID, + PortID: path2.EndpointB.ChannelConfig.PortID, + ChannelId: path2.EndpointB.ChannelID, }, }, Memo: "", } - preCoinA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress(), sdk.DefaultBondDenom) - transferMsg := types.NewMsgTransfer( path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, @@ -1054,6 +1061,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { 0, "", &forwardingPath, ) + result, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -1069,68 +1077,164 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { suite.Require().NoError(err) suite.Require().NotNil(result) - err = path2.EndpointB.UpdateClient() - suite.Require().NoError(err) + totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) - postCoinA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress(), sdk.DefaultBondDenom) + // denomTrace path: transfer/channel-0 + denomTrace := types.DenomTrace{ + BaseDenom: sdk.DefaultBondDenom, + Path: fmt.Sprintf("%s/%s", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + } - packet2, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet2) + // Check that Escrow B has amount + coin = sdk.NewCoin(denomTrace.IBCDenom(), amount) + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - result, err = path2.EndpointB.RecvPacketWithResult(packet2) - suite.Require().NoError(err) - suite.Require().NotNil(result) +} - forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, packet2.Sequence) - suite.Require().True(found) - suite.Require().Equal(packet, forwardedPacket) +// This test is probably overcomplicated. Could have used RecvPacketWithResult directly. +func (suite *KeeperTestSuite) TestHappyPathForwarding() { + amount := sdkmath.NewInt(100) + /* + Given the following topolgy: - totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A + stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake + + We want to trigger: + 1. A sends B over channel0. + 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions + At this point we want to assert: + A: escrowA = amount,denom + B: escrowB = amount,transfer/channel-0/denom + 3. A OnRecv + At this point we want to assert: + C: finalReceiver = amount,transfer/channel-1/transfer/channel-0/denom + */ + + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() - denomTraceAB := types.DenomTrace{ + path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path2.Setup() + + // transfer/channel-1/transfer/channel-0/denom + denomTraceABA := types.DenomTrace{ BaseDenom: sdk.DefaultBondDenom, - Path: fmt.Sprintf("%s/%s/", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), } - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), denomTraceAB.IBCDenom()) - suite.Require().Equal(sdkmath.ZeroInt(), totalEscrowChainB.Amount) + // Check that initially the final receiver address has 0 ABA coins + coin := sdk.NewCoin(denomTraceABA.IBCDenom(), amount) + preCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), preCoinOnA.Amount, "final receiver has not zero balance") + + coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainA.SenderAccounts[1].SenderAccount + forwardingPath := types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortID: path2.EndpointB.ChannelConfig.PortID, + ChannelId: path2.EndpointB.ChannelID, + }, + }, + Memo: "", + } - // Since we're sending out from A to C - // The delta amount is computed as preSend - postSend : e.g. if preSend=100 and postSend=0 --> delta = 100 - deltaAmountA := preCoinA.Amount.Sub(postCoinA.Amount) - suite.Require().Equal(amount.Int64(), deltaAmountA.Int64(), "token successfully deduced from A balance") + transferMsg := types.NewMsgTransfer( + path1.EndpointA.ChannelConfig.PortID, + path1.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + &forwardingPath, + ) - // WIP - /* Random things + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed - denomTraceABC := types.DenomTrace{ + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + denomTrace := types.ParseDenomTrace(sdk.DefaultBondDenom) + + denom, trace := convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + data := v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: denom, + Amount: amount.String(), + Trace: trace, + }, + }, sender.GetAddress().String(), receiver.GetAddress().String(), "", &forwardingPath) + packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) + + var async bool + err, async = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) + // If forwarding has been triggered then the async must be true. + suite.Require().True(async) + suite.Require().Nil(err) + + // denomTrace path: transfer/channel-0 + denomTrace = types.DenomTrace{ BaseDenom: sdk.DefaultBondDenom, - Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + Path: fmt.Sprintf("%s/%s", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), } - //preCoinC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), denomTraceABC.IBCDenom()) + // Check that Escrow B has amount + coin = sdk.NewCoin(denomTrace.IBCDenom(), amount) + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(amount, totalEscrowChainB.Amount, "escrow account on B is different than amount") - // Check sender's balance on chain A to ensure it has reduced by the sent amount - //balanceA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress(), sdk.DefaultBondDenom) - //suite.Require().Equal(sdkmath.NewInt(0), balanceA.Amount) + // Check that Escrow A has amount + coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) + totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(amount, totalEscrowChainA.Amount, "escrow account on A is different than amount") - denomTrace = types.DenomTrace{ - BaseDenom: sdk.DefaultBondDenom, - Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), - } - balanceC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), denomTrace.IBCDenom()) - suite.Require().Equal(denomTrace.IBCDenom(), balanceC.Denom) - suite.Require().NoError(err)*/ + // Now during the onRecvPacket above a new msgTransfer has been sent + // We need to receive the packet on the final hand - // suite.Require().Equal(sdkmath.NewInt(100), balanceC.Amount) - /* - // Additional checks: Verify that there is no unexpected remaining balance or state - // Check that the escrow amount on chain B is zero after forwarding + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) - balanceC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), denomTrace.IBCDenom()) - suite.Require().Equal(denomTrace.IBCDenom(), balanceC.Denom) - //suite.Require().Equal(sdkmath.NewInt(10), balanceC.Amount) - */ + denom, trace = convert.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) + data = v3types.NewFungibleTokenPacketData( + []*v3types.Token{ + { + Denom: denom, + Amount: amount.String(), + Trace: trace, + }, + }, types.GetForwardAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID).String(), receiver.GetAddress().String(), "", nil) + packetRecv = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) + + // execute onRecvPacket, when chaninA receives the tokens the escrow amount on B should increase to amount + err, async = suite.chainA.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainA.GetContext(), packetRecv, data) + suite.Require().False(async) + suite.Require().NoError(err) + + // Check that the final receiver has received the expected tokens. + coin = sdk.NewCoin(denomTraceABA.IBCDenom(), amount) + postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") } + +/* +// TODO + Test scenarios for failures ack +Check out the notion page: https://www.notion.so/interchain/ICS20-v2-path-forwarding-091f1ac788e84a538261c5a247cb5924 + +// TODO +Test async ack is properly relayed to middle hop after forwarding transfer completition + +// TODO +Tiemout during forwarding after middle hop execution reverts properly the state changes + +*/ From e25ba0cb3eaf538a4490a72db2d03056ca8e911d Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Mon, 20 May 2024 19:05:50 +0200 Subject: [PATCH 035/141] fix merge --- modules/apps/transfer/client/cli/tx.go | 2 +- modules/apps/transfer/keeper/relay_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index 9ccf4758469..4126ab79676 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -111,7 +111,7 @@ using the {packet-timeout-timestamp} flag. If no timeout value is set then a def } msg := types.NewMsgTransfer( - srcPort, srcChannel, sdk.NewCoins(coin), sender, receiver, timeoutHeight, timeoutTimestamp, memo, nil, + srcPort, srcChannel, coins, sender, receiver, timeoutHeight, timeoutTimestamp, memo, nil, ) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 9a1e708a905..bce1114aee2 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -10,6 +10,7 @@ import ( banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" convertinternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" From f39d173f8405f97c1c05338cc61246f1392ddb92 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 21 May 2024 11:43:05 +0100 Subject: [PATCH 036/141] Use type with V2 suffix for package data (#6330) --- modules/apps/callbacks/ibc_middleware_test.go | 31 +- modules/apps/transfer/ibc_module.go | 9 +- modules/apps/transfer/ibc_module_test.go | 25 +- .../apps/transfer/internal/convert/convert.go | 9 +- .../transfer/internal/convert/convert_test.go | 41 +- .../apps/transfer/keeper/mbt_relay_test.go | 7 +- modules/apps/transfer/keeper/relay.go | 15 +- modules/apps/transfer/keeper/relay_test.go | 25 +- modules/apps/transfer/types/packet.go | 95 +++ modules/apps/transfer/types/packet.pb.go | 660 ++++++++++++++- modules/apps/transfer/types/packet_test.go | 409 +++++++++ modules/apps/transfer/types/{v3 => }/token.go | 7 +- .../transfer/types/{v3 => }/token_test.go | 25 +- modules/apps/transfer/types/v3/packet.go | 114 --- modules/apps/transfer/types/v3/packet.pb.go | 776 ------------------ modules/apps/transfer/types/v3/packet_test.go | 436 ---------- .../ibc/applications/transfer/v2/packet.proto | 24 + .../ibc/applications/transfer/v3/packet.proto | 29 - 18 files changed, 1269 insertions(+), 1468 deletions(-) rename modules/apps/transfer/types/{v3 => }/token.go (79%) rename modules/apps/transfer/types/{v3 => }/token_test.go (83%) delete mode 100644 modules/apps/transfer/types/v3/packet.go delete mode 100644 modules/apps/transfer/types/v3/packet.pb.go delete mode 100644 modules/apps/transfer/types/v3/packet_test.go delete mode 100644 proto/ibc/applications/transfer/v3/packet.proto diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 83db4a1b93f..441512d7469 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -14,7 +14,6 @@ import ( "github.com/cosmos/ibc-go/modules/apps/callbacks/types" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - transferv3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/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" @@ -94,7 +93,7 @@ func (s *CallbacksTestSuite) TestWithICS4Wrapper() { } func (s *CallbacksTestSuite) TestSendPacket() { - var packetData transferv3types.FungibleTokenPacketData + var packetData transfertypes.FungibleTokenPacketDataV2 testCases := []struct { name string @@ -165,8 +164,8 @@ func (s *CallbacksTestSuite) TestSendPacket() { transferICS4Wrapper := GetSimApp(s.chainA).TransferKeeper.GetICS4Wrapper() - packetData = transferv3types.NewFungibleTokenPacketData( - []*transferv3types.Token{ + packetData = transfertypes.NewFungibleTokenPacketDataV2( + []*transfertypes.Token{ { Denom: ibctesting.TestCoin.GetDenom(), Amount: ibctesting.TestCoin.Amount.String(), @@ -231,7 +230,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { ) var ( - packetData transferv3types.FungibleTokenPacketData + packetData transfertypes.FungibleTokenPacketDataV2 packet channeltypes.Packet ack []byte ctx sdk.Context @@ -307,8 +306,8 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { s.SetupTransferTest() userGasLimit = 600000 - packetData = transferv3types.NewFungibleTokenPacketData( - []*transferv3types.Token{ + packetData = transfertypes.NewFungibleTokenPacketDataV2( + []*transfertypes.Token{ { Denom: ibctesting.TestCoin.GetDenom(), Amount: ibctesting.TestCoin.Amount.String(), @@ -401,7 +400,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { ) var ( - packetData transferv3types.FungibleTokenPacketData + packetData transfertypes.FungibleTokenPacketDataV2 packet channeltypes.Packet ctx sdk.Context ) @@ -563,7 +562,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { ) var ( - packetData transferv3types.FungibleTokenPacketData + packetData transfertypes.FungibleTokenPacketDataV2 packet channeltypes.Packet ctx sdk.Context userGasLimit uint64 @@ -640,8 +639,8 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { // set user gas limit above panic level in mock contract keeper userGasLimit = 600_000 - packetData = transferv3types.NewFungibleTokenPacketData( - []*transferv3types.Token{ + packetData = transfertypes.NewFungibleTokenPacketDataV2( + []*transfertypes.Token{ { Denom: ibctesting.TestCoin.GetDenom(), Amount: ibctesting.TestCoin.Amount.String(), @@ -725,7 +724,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { func (s *CallbacksTestSuite) TestWriteAcknowledgement() { var ( - packetData transferv3types.FungibleTokenPacketData + packetData transfertypes.FungibleTokenPacketDataV2 packet channeltypes.Packet ctx sdk.Context ack ibcexported.Acknowledgement @@ -772,8 +771,8 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { s.SetupTransferTest() // set user gas limit above panic level in mock contract keeper - packetData = transferv3types.NewFungibleTokenPacketData( - []*transferv3types.Token{ + packetData = transfertypes.NewFungibleTokenPacketDataV2( + []*transfertypes.Token{ { Denom: ibctesting.TestCoin.GetDenom(), Amount: ibctesting.TestCoin.Amount.String(), @@ -991,8 +990,8 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), } - expPacketDataICS20V2 := transferv3types.FungibleTokenPacketData{ - Tokens: []*transferv3types.Token{ + expPacketDataICS20V2 := transfertypes.FungibleTokenPacketDataV2{ + Tokens: []*transfertypes.Token{ { Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 7531a9318b5..ddfc4f0a9dd 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -15,7 +15,6 @@ import ( convertinternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" 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" @@ -175,25 +174,25 @@ func (IBCModule) OnChanCloseConfirm( return nil } -func (IBCModule) unmarshalPacketDataBytesToICS20V2(bz []byte) (v3types.FungibleTokenPacketData, error) { +func (IBCModule) unmarshalPacketDataBytesToICS20V2(bz []byte) (types.FungibleTokenPacketDataV2, error) { // TODO: remove support for this function parsing v1 packet data // TODO: explicit check for packet data type against app version var datav1 types.FungibleTokenPacketData if err := json.Unmarshal(bz, &datav1); err == nil { if len(datav1.Denom) != 0 { - return convertinternal.PacketDataV1ToV3(datav1), nil + return convertinternal.PacketDataV1ToV2(datav1), nil } } - var data v3types.FungibleTokenPacketData + var data types.FungibleTokenPacketDataV2 if err := json.Unmarshal(bz, &data); err == nil { if len(data.Tokens) != 0 { return data, nil } } - return v3types.FungibleTokenPacketData{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data") + return types.FungibleTokenPacketDataV2{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data") } // OnRecvPacket implements the IBCModule interface. A successful acknowledgement diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 22b398f4d50..12e6f4c661d 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -9,7 +9,6 @@ import ( 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" - v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" 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" @@ -544,8 +543,8 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { { "success: valid packet data multidenom with memo", func() { - initialPacketData = v3types.FungibleTokenPacketData{ - Tokens: []*v3types.Token{ + initialPacketData = types.FungibleTokenPacketDataV2{ + Tokens: []*types.Token{ { Denom: "atom", Amount: ibctesting.TestCoin.Amount.String(), @@ -557,15 +556,15 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { Memo: "some memo", } - data = initialPacketData.(v3types.FungibleTokenPacketData).GetBytes() + data = initialPacketData.(types.FungibleTokenPacketDataV2).GetBytes() }, true, }, { "success: valid packet data multidenom without memo", func() { - initialPacketData = v3types.FungibleTokenPacketData{ - Tokens: []*v3types.Token{ + initialPacketData = types.FungibleTokenPacketDataV2{ + Tokens: []*types.Token{ { Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), @@ -577,7 +576,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { Memo: "", } - data = initialPacketData.(v3types.FungibleTokenPacketData).GetBytes() + data = initialPacketData.(types.FungibleTokenPacketDataV2).GetBytes() }, true, }, @@ -600,17 +599,17 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { if tc.expPass { suite.Require().NoError(err) - v3PacketData, ok := packetData.(v3types.FungibleTokenPacketData) + v2PacketData, ok := packetData.(types.FungibleTokenPacketDataV2) suite.Require().True(ok) if v1PacketData, ok := initialPacketData.(types.FungibleTokenPacketData); ok { // Note: testing of the denom trace parsing/conversion should be done as part of testing internal conversion functions - suite.Require().Equal(v1PacketData.Amount, v3PacketData.Tokens[0].Amount) - suite.Require().Equal(v1PacketData.Sender, v3PacketData.Sender) - suite.Require().Equal(v1PacketData.Receiver, v3PacketData.Receiver) - suite.Require().Equal(v1PacketData.Memo, v3PacketData.Memo) + suite.Require().Equal(v1PacketData.Amount, v2PacketData.Tokens[0].Amount) + suite.Require().Equal(v1PacketData.Sender, v2PacketData.Sender) + suite.Require().Equal(v1PacketData.Receiver, v2PacketData.Receiver) + suite.Require().Equal(v1PacketData.Memo, v2PacketData.Memo) } else { - suite.Require().Equal(initialPacketData.(v3types.FungibleTokenPacketData), v3PacketData) + suite.Require().Equal(initialPacketData.(types.FungibleTokenPacketDataV2), v2PacketData) } } else { suite.Require().Error(err) diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go index 2665974d64c..3c39bdeb20b 100644 --- a/modules/apps/transfer/internal/convert/convert.go +++ b/modules/apps/transfer/internal/convert/convert.go @@ -4,18 +4,17 @@ import ( "strings" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" ) -// PacketDataV1ToV3 converts a v1 (ICS20-V1) packet data to a v3 (ICS20-V2) packet data. -func PacketDataV1ToV3(packetData types.FungibleTokenPacketData) v3types.FungibleTokenPacketData { +// PacketDataV1ToV2 converts a v1 packet data to a v2 packet data. +func PacketDataV1ToV2(packetData types.FungibleTokenPacketData) types.FungibleTokenPacketDataV2 { if err := packetData.ValidateBasic(); err != nil { panic(err) } v2Denom, trace := ExtractDenomAndTraceFromV1Denom(packetData.Denom) - return v3types.FungibleTokenPacketData{ - Tokens: []*v3types.Token{ + return types.FungibleTokenPacketDataV2{ + Tokens: []*types.Token{ { Denom: v2Denom, Amount: packetData.Amount, diff --git a/modules/apps/transfer/internal/convert/convert_test.go b/modules/apps/transfer/internal/convert/convert_test.go index b406210ad47..5860f328e8c 100644 --- a/modules/apps/transfer/internal/convert/convert_test.go +++ b/modules/apps/transfer/internal/convert/convert_test.go @@ -8,10 +8,9 @@ import ( errorsmod "cosmossdk.io/errors" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" ) -func TestConvertPacketV1ToPacketV3(t *testing.T) { +func TestConvertPacketV1ToPacketV2(t *testing.T) { const ( sender = "sender" receiver = "receiver" @@ -20,14 +19,14 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { testCases := []struct { name string v1Data types.FungibleTokenPacketData - v3Data v3types.FungibleTokenPacketData + v2Data types.FungibleTokenPacketDataV2 expPanic error }{ { "success", types.NewFungibleTokenPacketData("transfer/channel-0/atom", "1000", sender, receiver, ""), - v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: "atom", Amount: "1000", @@ -39,8 +38,8 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { { "success with empty trace", types.NewFungibleTokenPacketData("atom", "1000", sender, receiver, ""), - v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: "atom", Amount: "1000", @@ -52,8 +51,8 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { { "success: base denom with '/'", types.NewFungibleTokenPacketData("transfer/channel-0/atom/withslash", "1000", sender, receiver, ""), - v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: "atom/withslash", Amount: "1000", @@ -65,8 +64,8 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { { "success: base denom with '/' at the end", types.NewFungibleTokenPacketData("transfer/channel-0/atom/", "1000", sender, receiver, ""), - v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: "atom/", Amount: "1000", @@ -78,8 +77,8 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { { "success: longer trace base denom with '/'", types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/atom/pool", "1000", sender, receiver, ""), - v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: "atom/pool", Amount: "1000", @@ -91,8 +90,8 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { { "success: longer trace with non transfer port", types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/transfer-custom/channel-2/atom", "1000", sender, receiver, ""), - v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: "atom", Amount: "1000", @@ -104,8 +103,8 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { { "success: base denom with slash, trace with non transfer port", types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/transfer-custom/channel-2/atom/pool", "1000", sender, receiver, ""), - v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: "atom/pool", Amount: "1000", @@ -117,7 +116,7 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { { "failure: panics with empty denom", types.NewFungibleTokenPacketData("", "1000", sender, receiver, ""), - v3types.FungibleTokenPacketData{}, + types.FungibleTokenPacketDataV2{}, errorsmod.Wrap(types.ErrInvalidDenomForTransfer, "base denomination cannot be blank"), }, } @@ -125,11 +124,11 @@ func TestConvertPacketV1ToPacketV3(t *testing.T) { for _, tc := range testCases { expPass := tc.expPanic == nil if expPass { - v3Data := PacketDataV1ToV3(tc.v1Data) - require.Equal(t, tc.v3Data, v3Data, "test case: %s", tc.name) + actualV2Data := PacketDataV1ToV2(tc.v1Data) + require.Equal(t, tc.v2Data, actualV2Data, "test case: %s", tc.name) } else { require.PanicsWithError(t, tc.expPanic.Error(), func() { - PacketDataV1ToV3(tc.v1Data) + PacketDataV1ToV2(tc.v1Data) }, "test case: %s", tc.name) } } diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 74c74bc6343..86ad87c3a91 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -21,7 +21,6 @@ import ( convertinternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" @@ -67,7 +66,7 @@ type FungibleTokenPacket struct { SourcePort string DestChannel string DestPort string - Data v3types.FungibleTokenPacketData + Data types.FungibleTokenPacketDataV2 } type OnRecvPacketTestCase = struct { @@ -151,8 +150,8 @@ func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPack SourcePort: packet.SourcePort, DestChannel: packet.DestChannel, DestPort: packet.DestPort, - Data: v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + Data: types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: denom, Amount: packet.Data.Amount, diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index fa0e9db7635..bc5c39e5b3a 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -14,7 +14,6 @@ import ( convertinternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" 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" @@ -85,7 +84,7 @@ func (k Keeper) sendTransfer( return 0, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } - var tokens []*v3types.Token + var tokens []*types.Token for _, coin := range coins { // NOTE: denomination and hex hash correctness checked during msg.ValidateBasic @@ -136,7 +135,7 @@ func (k Keeper) sendTransfer( } denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(fullDenomPath) - token := &v3types.Token{ + token := &types.Token{ Denom: denom, Amount: coin.Amount.String(), Trace: trace, @@ -144,7 +143,7 @@ func (k Keeper) sendTransfer( tokens = append(tokens, token) } - packetData := v3types.NewFungibleTokenPacketData(tokens, sender.String(), receiver, memo) + packetData := types.NewFungibleTokenPacketDataV2(tokens, sender.String(), receiver, memo) sequence, err := k.ics4Wrapper.SendPacket(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, packetData.GetBytes()) if err != nil { @@ -178,7 +177,7 @@ func (k Keeper) sendTransfer( // and sent to the receiving address. Otherwise if the sender chain is sending // back tokens this chain originally transferred to it, the tokens are // unescrowed and sent to the receiving address. -func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { +func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) error { // validate packet data upon receiving if err := data.ValidateBasic(); err != nil { return errorsmod.Wrapf(err, "error validating ICS-20 transfer packet data") @@ -330,7 +329,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data v // acknowledgement written on the receiving chain. If the acknowledgement // was a success then nothing occurs. If the acknowledgement failed, then // the sender is refunded their tokens using the refundPacketToken function. -func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData, ack channeltypes.Acknowledgement) error { +func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) error { switch ack.Response.(type) { case *channeltypes.Acknowledgement_Result: // the acknowledgement succeeded on the receiving chain so nothing @@ -345,7 +344,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // OnTimeoutPacket refunds the sender since the original packet sent was // never received and has been timed out. -func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { +func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) error { return k.refundPacketToken(ctx, packet, data) } @@ -353,7 +352,7 @@ func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, dat // if the sending chain was the source chain. Otherwise, the sent tokens // were burnt in the original send so new tokens are minted and sent to // the sending address. -func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, data v3types.FungibleTokenPacketData) error { +func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) error { // NOTE: packet data type already checked in handler.go for _, token := range data.Tokens { diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 822cae0506a..5ed95db4bab 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -12,7 +12,6 @@ import ( convertinternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/convert" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - v3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -412,8 +411,8 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { tc.malleate() denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) - data := v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + data := types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: denom, Amount: amount.String(), @@ -495,8 +494,8 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT } denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) - data := v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + data := types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: denom, Amount: amount.String(), @@ -622,8 +621,8 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { tc.malleate() denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) - data := v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + data := types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: denom, Amount: amount.String(), @@ -715,8 +714,8 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo ) denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) - data := v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + data := types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: denom, Amount: amount.String(), @@ -838,8 +837,8 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { tc.malleate() denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) - data := v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + data := types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: denom, Amount: amount.String(), @@ -924,8 +923,8 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI ) denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) - data := v3types.NewFungibleTokenPacketData( - []*v3types.Token{ + data := types.NewFungibleTokenPacketDataV2( + []*types.Token{ { Denom: denom, Amount: amount.String(), diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 351500abfe1..6ddf67cdbb5 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -96,3 +96,98 @@ func (ftpd FungibleTokenPacketData) GetCustomPacketData(key string) interface{} return memoData } + +// NewFungibleTokenPacketDataV2 constructs a new NewFungibleTokenPacketDataV2 instance +func NewFungibleTokenPacketDataV2( + tokens []*Token, + sender, receiver string, + memo string, +) FungibleTokenPacketDataV2 { + return FungibleTokenPacketDataV2{ + Tokens: tokens, + Sender: sender, + Receiver: receiver, + Memo: memo, + } +} + +// ValidateBasic is used for validating the token transfer. +// NOTE: The addresses formats are not validated as the sender and recipient can have different +// formats defined by their corresponding chains that are not known to IBC. +func (ftpd FungibleTokenPacketDataV2) ValidateBasic() error { + if strings.TrimSpace(ftpd.Sender) == "" { + return errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "sender address cannot be blank") + } + + if strings.TrimSpace(ftpd.Receiver) == "" { + return errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "receiver address cannot be blank") + } + + if len(ftpd.Tokens) == 0 { + return errorsmod.Wrap(ErrInvalidAmount, "tokens cannot be empty") + } + + for _, token := range ftpd.Tokens { + amount, ok := sdkmath.NewIntFromString(token.Amount) + if !ok { + return errorsmod.Wrapf(ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", token.Amount) + } + + if !amount.IsPositive() { + return errorsmod.Wrapf(ErrInvalidAmount, "amount must be strictly positive: got %d", amount) + } + + if err := token.Validate(); err != nil { + return err + } + } + + if len(ftpd.Memo) > MaximumMemoLength { + return errorsmod.Wrapf(ErrInvalidMemo, "memo must not exceed %d bytes", MaximumMemoLength) + } + + return nil +} + +// GetBytes is a helper for serialising +func (ftpd FungibleTokenPacketDataV2) GetBytes() []byte { + bz, err := json.Marshal(&ftpd) + if err != nil { + panic(errors.New("cannot marshal FungibleTokenPacketDataV2 into bytes")) + } + + return bz +} + +// GetCustomPacketData interprets the memo field of the packet data as a JSON object +// and returns the value associated with the given key. +// If the key is missing or the memo is not properly formatted, then nil is returned. +func (ftpd FungibleTokenPacketDataV2) GetCustomPacketData(key string) interface{} { + if len(ftpd.Memo) == 0 { + return nil + } + + jsonObject := make(map[string]interface{}) + err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) + if err != nil { + return nil + } + + memoData, found := jsonObject[key] + if !found { + return nil + } + + return memoData +} + +// GetPacketSender returns the sender address embedded in the packet data. +// +// NOTE: +// - The sender address is set by the module which requested the packet to be sent, +// and this module may not have validated the sender address by a signature check. +// - The sender address must only be used by modules on the sending chain. +// - sourcePortID is not used in this implementation. +func (ftpd FungibleTokenPacketDataV2) GetPacketSender(sourcePortID string) string { + return ftpd.Sender +} diff --git a/modules/apps/transfer/types/packet.pb.go b/modules/apps/transfer/types/packet.pb.go index 5b0c659e69c..020e16b93ef 100644 --- a/modules/apps/transfer/types/packet.pb.go +++ b/modules/apps/transfer/types/packet.pb.go @@ -106,8 +106,149 @@ func (m *FungibleTokenPacketData) GetMemo() string { return "" } +// FungibleTokenPacketDataV2 defines a struct for the packet payload +// See FungibleTokenPacketDataV2 spec: +// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures +type FungibleTokenPacketDataV2 struct { + // the tokens to be transferred + Tokens []*Token `protobuf:"bytes,1,rep,name=tokens,proto3" json:"tokens,omitempty"` + // the sender address + Sender string `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` + // the recipient address on the destination chain + Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` + // optional memo + Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` +} + +func (m *FungibleTokenPacketDataV2) Reset() { *m = FungibleTokenPacketDataV2{} } +func (m *FungibleTokenPacketDataV2) String() string { return proto.CompactTextString(m) } +func (*FungibleTokenPacketDataV2) ProtoMessage() {} +func (*FungibleTokenPacketDataV2) Descriptor() ([]byte, []int) { + return fileDescriptor_653ca2ce9a5ca313, []int{1} +} +func (m *FungibleTokenPacketDataV2) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FungibleTokenPacketDataV2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FungibleTokenPacketDataV2.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 *FungibleTokenPacketDataV2) XXX_Merge(src proto.Message) { + xxx_messageInfo_FungibleTokenPacketDataV2.Merge(m, src) +} +func (m *FungibleTokenPacketDataV2) XXX_Size() int { + return m.Size() +} +func (m *FungibleTokenPacketDataV2) XXX_DiscardUnknown() { + xxx_messageInfo_FungibleTokenPacketDataV2.DiscardUnknown(m) +} + +var xxx_messageInfo_FungibleTokenPacketDataV2 proto.InternalMessageInfo + +func (m *FungibleTokenPacketDataV2) GetTokens() []*Token { + if m != nil { + return m.Tokens + } + return nil +} + +func (m *FungibleTokenPacketDataV2) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *FungibleTokenPacketDataV2) GetReceiver() string { + if m != nil { + return m.Receiver + } + return "" +} + +func (m *FungibleTokenPacketDataV2) GetMemo() string { + if m != nil { + return m.Memo + } + return "" +} + +// Token defines a struct which represents a token to be transferred. +type Token struct { + // the base token denomination to be transferred + Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` + // the token amount to be transferred + Amount string `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"` + // the trace of the token + Trace []string `protobuf:"bytes,3,rep,name=trace,proto3" json:"trace,omitempty"` +} + +func (m *Token) Reset() { *m = Token{} } +func (m *Token) String() string { return proto.CompactTextString(m) } +func (*Token) ProtoMessage() {} +func (*Token) Descriptor() ([]byte, []int) { + return fileDescriptor_653ca2ce9a5ca313, []int{2} +} +func (m *Token) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Token) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Token.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 *Token) XXX_Merge(src proto.Message) { + xxx_messageInfo_Token.Merge(m, src) +} +func (m *Token) XXX_Size() int { + return m.Size() +} +func (m *Token) XXX_DiscardUnknown() { + xxx_messageInfo_Token.DiscardUnknown(m) +} + +var xxx_messageInfo_Token proto.InternalMessageInfo + +func (m *Token) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *Token) GetAmount() string { + if m != nil { + return m.Amount + } + return "" +} + +func (m *Token) GetTrace() []string { + if m != nil { + return m.Trace + } + return nil +} + func init() { proto.RegisterType((*FungibleTokenPacketData)(nil), "ibc.applications.transfer.v2.FungibleTokenPacketData") + proto.RegisterType((*FungibleTokenPacketDataV2)(nil), "ibc.applications.transfer.v2.FungibleTokenPacketDataV2") + proto.RegisterType((*Token)(nil), "ibc.applications.transfer.v2.Token") } func init() { @@ -115,23 +256,28 @@ func init() { } var fileDescriptor_653ca2ce9a5ca313 = []byte{ - // 254 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0x90, 0xb1, 0x4a, 0x34, 0x31, - 0x14, 0x46, 0x27, 0xff, 0xbf, 0xbb, 0x68, 0xca, 0x20, 0x3a, 0x88, 0x04, 0xb1, 0xd2, 0xc2, 0x09, - 0xac, 0x85, 0xd6, 0x22, 0xd6, 0x2a, 0x56, 0x76, 0x49, 0xe6, 0x3a, 0x86, 0x9d, 0xe4, 0x86, 0x24, - 0x33, 0xe0, 0x53, 0xe8, 0x63, 0x59, 0x6e, 0x69, 0x29, 0x33, 0x2f, 0x22, 0x9b, 0x51, 0xd9, 0x2e, - 0xe7, 0xe4, 0xbb, 0xcd, 0xa1, 0x67, 0x46, 0x69, 0x21, 0xbd, 0x6f, 0x8d, 0x96, 0xc9, 0xa0, 0x8b, - 0x22, 0x05, 0xe9, 0xe2, 0x33, 0x04, 0xd1, 0x2f, 0x85, 0x97, 0x7a, 0x05, 0xa9, 0xf2, 0x01, 0x13, - 0xb2, 0x23, 0xa3, 0x74, 0xb5, 0x3d, 0xad, 0x7e, 0xa7, 0x55, 0xbf, 0x3c, 0x79, 0x23, 0xf4, 0xe0, - 0xb6, 0x73, 0x8d, 0x51, 0x2d, 0x3c, 0xe2, 0x0a, 0xdc, 0x5d, 0xbe, 0xbd, 0x91, 0x49, 0xb2, 0x3d, - 0x3a, 0xaf, 0xc1, 0xa1, 0x2d, 0xc9, 0x31, 0x39, 0xdd, 0x7d, 0x98, 0x80, 0xed, 0xd3, 0x85, 0xb4, - 0xd8, 0xb9, 0x54, 0xfe, 0xcb, 0xfa, 0x87, 0x36, 0x3e, 0x82, 0xab, 0x21, 0x94, 0xff, 0x27, 0x3f, - 0x11, 0x3b, 0xa4, 0x3b, 0x01, 0x34, 0x98, 0x1e, 0x42, 0x39, 0xcb, 0x3f, 0x7f, 0xcc, 0x18, 0x9d, - 0x59, 0xb0, 0x58, 0xce, 0xb3, 0xcf, 0xef, 0xeb, 0xfb, 0x8f, 0x81, 0x93, 0xf5, 0xc0, 0xc9, 0xd7, - 0xc0, 0xc9, 0xfb, 0xc8, 0x8b, 0xf5, 0xc8, 0x8b, 0xcf, 0x91, 0x17, 0x4f, 0x97, 0x8d, 0x49, 0x2f, - 0x9d, 0xaa, 0x34, 0x5a, 0xa1, 0x31, 0x5a, 0x8c, 0xc2, 0x28, 0x7d, 0xde, 0xa0, 0xe8, 0xaf, 0x84, - 0xc5, 0xba, 0x6b, 0x21, 0x6e, 0xa2, 0x6c, 0xc5, 0x48, 0xaf, 0x1e, 0xa2, 0x5a, 0xe4, 0x12, 0x17, - 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x93, 0x3d, 0xc6, 0x36, 0x36, 0x01, 0x00, 0x00, + // 325 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0x31, 0x4b, 0x03, 0x31, + 0x14, 0xc7, 0x9b, 0x5e, 0xaf, 0x68, 0xdc, 0x8e, 0xa2, 0x51, 0xe4, 0x28, 0x75, 0xa9, 0x83, 0x09, + 0x9c, 0x83, 0x82, 0x9b, 0x88, 0x8b, 0x8b, 0x16, 0x71, 0x70, 0xcb, 0xa5, 0xcf, 0x1a, 0xda, 0x24, + 0x47, 0x92, 0x3b, 0xf0, 0x53, 0xe8, 0x47, 0xf0, 0xe3, 0x38, 0x76, 0x74, 0x94, 0xf6, 0x8b, 0xc8, + 0xa5, 0x55, 0x6e, 0xa9, 0xe0, 0x96, 0xff, 0x3f, 0xff, 0xf7, 0xf8, 0x25, 0xef, 0xe1, 0x63, 0x99, + 0x0b, 0xc6, 0x8b, 0x62, 0x26, 0x05, 0xf7, 0xd2, 0x68, 0xc7, 0xbc, 0xe5, 0xda, 0x3d, 0x81, 0x65, + 0x55, 0xc6, 0x0a, 0x2e, 0xa6, 0xe0, 0x69, 0x61, 0x8d, 0x37, 0xc9, 0xa1, 0xcc, 0x05, 0x6d, 0x46, + 0xe9, 0x4f, 0x94, 0x56, 0xd9, 0xe0, 0x15, 0xe1, 0xbd, 0xeb, 0x52, 0x4f, 0x64, 0x3e, 0x83, 0x7b, + 0x33, 0x05, 0x7d, 0x1b, 0x6a, 0xaf, 0xb8, 0xe7, 0x49, 0x0f, 0xc7, 0x63, 0xd0, 0x46, 0x11, 0xd4, + 0x47, 0xc3, 0xed, 0xd1, 0x4a, 0x24, 0xbb, 0xb8, 0xcb, 0x95, 0x29, 0xb5, 0x27, 0xed, 0x60, 0xaf, + 0x55, 0xed, 0x3b, 0xd0, 0x63, 0xb0, 0x24, 0x5a, 0xf9, 0x2b, 0x95, 0x1c, 0xe0, 0x2d, 0x0b, 0x02, + 0x64, 0x05, 0x96, 0x74, 0xc2, 0xcd, 0xaf, 0x4e, 0x12, 0xdc, 0x51, 0xa0, 0x0c, 0x89, 0x83, 0x1f, + 0xce, 0x83, 0x77, 0x84, 0xf7, 0x37, 0x10, 0x3d, 0x64, 0xc9, 0x05, 0xee, 0xfa, 0xda, 0x74, 0x04, + 0xf5, 0xa3, 0xe1, 0x4e, 0x76, 0x44, 0xff, 0x7a, 0x1e, 0x0d, 0x0d, 0x46, 0xeb, 0x92, 0x06, 0x62, + 0x7b, 0x23, 0x62, 0xb4, 0x01, 0xb1, 0xd3, 0x40, 0xbc, 0xc1, 0x71, 0x68, 0xfc, 0xcf, 0x1f, 0xea, + 0xe1, 0xd8, 0x5b, 0x2e, 0x80, 0x44, 0xfd, 0xa8, 0x4e, 0x07, 0x71, 0x79, 0xf7, 0xb1, 0x48, 0xd1, + 0x7c, 0x91, 0xa2, 0xaf, 0x45, 0x8a, 0xde, 0x96, 0x69, 0x6b, 0xbe, 0x4c, 0x5b, 0x9f, 0xcb, 0xb4, + 0xf5, 0x78, 0x36, 0x91, 0xfe, 0xb9, 0xcc, 0xa9, 0x30, 0x8a, 0x09, 0xe3, 0x94, 0x71, 0x4c, 0xe6, + 0xe2, 0x64, 0x62, 0x58, 0x75, 0xce, 0x94, 0x19, 0x97, 0x33, 0x70, 0xf5, 0x12, 0x34, 0x86, 0xef, + 0x5f, 0x0a, 0x70, 0x79, 0x37, 0x4c, 0xfe, 0xf4, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x65, 0x55, 0xb8, + 0x16, 0x26, 0x02, 0x00, 0x00, } func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { @@ -192,6 +338,110 @@ func (m *FungibleTokenPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *FungibleTokenPacketDataV2) 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 *FungibleTokenPacketDataV2) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FungibleTokenPacketDataV2) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Memo) > 0 { + i -= len(m.Memo) + copy(dAtA[i:], m.Memo) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Memo))) + i-- + dAtA[i] = 0x22 + } + if len(m.Receiver) > 0 { + i -= len(m.Receiver) + copy(dAtA[i:], m.Receiver) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Receiver))) + i-- + dAtA[i] = 0x1a + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0x12 + } + if len(m.Tokens) > 0 { + for iNdEx := len(m.Tokens) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Tokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPacket(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *Token) 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 *Token) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Token) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Trace) > 0 { + for iNdEx := len(m.Trace) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Trace[iNdEx]) + copy(dAtA[i:], m.Trace[iNdEx]) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Trace[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.Amount) > 0 { + i -= len(m.Amount) + copy(dAtA[i:], m.Amount) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Amount))) + i-- + dAtA[i] = 0x12 + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintPacket(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintPacket(dAtA []byte, offset int, v uint64) int { offset -= sovPacket(v) base := offset @@ -232,6 +482,56 @@ func (m *FungibleTokenPacketData) Size() (n int) { return n } +func (m *FungibleTokenPacketDataV2) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Tokens) > 0 { + for _, e := range m.Tokens { + l = e.Size() + n += 1 + l + sovPacket(uint64(l)) + } + } + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + l = len(m.Receiver) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + l = len(m.Memo) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + return n +} + +func (m *Token) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + l = len(m.Amount) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + if len(m.Trace) > 0 { + for _, s := range m.Trace { + l = len(s) + n += 1 + l + sovPacket(uint64(l)) + } + } + return n +} + func sovPacket(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -448,6 +748,332 @@ func (m *FungibleTokenPacketData) Unmarshal(dAtA []byte) error { } return nil } +func (m *FungibleTokenPacketDataV2) 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 ErrIntOverflowPacket + } + 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: FungibleTokenPacketDataV2: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FungibleTokenPacketDataV2: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tokens", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPacket + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tokens = append(m.Tokens, &Token{}) + if err := m.Tokens[len(m.Tokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Memo", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Memo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPacket(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPacket + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Token) 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 ErrIntOverflowPacket + } + 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: Token: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Token: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Trace = append(m.Trace, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPacket(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPacket + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipPacket(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index d06d0774c7d..759253ccfec 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ) const ( @@ -159,3 +160,411 @@ func (suite *TypesTestSuite) TestFungibleTokenPacketDataOmitEmpty() { // check that the memo field is present in the marshalled bytes suite.Require().Contains(string(bz), "memo") } + +// TestFungibleTokenPacketDataValidateBasic tests ValidateBasic for FungibleTokenPacketData +func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { + testCases := []struct { + name string + packetData types.FungibleTokenPacketDataV2 + expErr error + }{ + { + "success: valid packet", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + nil, + }, + { + "success: valid packet with memo", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "memo", + ), + nil, + }, + { + "success: valid packet with large amount", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: largeAmount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "memo", + ), + nil, + }, + { + "failure: invalid denom", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: "", + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + types.ErrInvalidDenomForTransfer, + }, + { + "failure: invalid empty amount", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: "", + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + types.ErrInvalidAmount, + }, + { + "failure: invalid empty token array", + types.NewFungibleTokenPacketDataV2( + []*types.Token{}, + sender, + receiver, + "", + ), + types.ErrInvalidAmount, + }, + { + "failure: invalid zero amount", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: "0", + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + types.ErrInvalidAmount, + }, + { + "failure: invalid negative amount", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: "-100", + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + types.ErrInvalidAmount, + }, + { + "failure: invalid large amount", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: invalidLargeAmount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "memo", + ), + types.ErrInvalidAmount, + }, + { + "failure: missing sender address", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + "", + receiver, + "memo", + ), + ibcerrors.ErrInvalidAddress, + }, + { + "failure: missing recipient address", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + "", + "", + ), + ibcerrors.ErrInvalidAddress, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.packetData.ValidateBasic() + + expPass := tc.expErr == nil + if expPass { + require.NoError(t, err, tc.name) + } else { + require.ErrorContains(t, err, tc.expErr.Error(), tc.name) + } + }) + } +} + +func TestGetPacketSender(t *testing.T) { + testCases := []struct { + name string + packetData types.FungibleTokenPacketDataV2 + expSender string + }{ + { + "non-empty sender field", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + sender, + }, + { + "empty sender field", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + "", + receiver, + "abc", + ), + "", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + require.Equal(t, tc.expSender, tc.packetData.GetPacketSender(types.PortID)) + }) + } +} + +func TestPacketDataProvider(t *testing.T) { + testCases := []struct { + name string + packetData types.FungibleTokenPacketDataV2 + expCustomData interface{} + }{ + { + "success: src_callback key in memo", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver)), + + map[string]interface{}{ + "address": receiver, + }, + }, + { + "success: src_callback key in memo with additional fields", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, receiver)), + map[string]interface{}{ + "address": receiver, + "gas_limit": "200000", + }, + }, + { + "success: src_callback has string value", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + `{"src_callback": "string"}`), + "string", + }, + { + "failure: src_callback key not found memo", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + fmt.Sprintf(`{"dest_callback": {"address": "%s", "min_gas": "200000"}}`, receiver)), + nil, + }, + { + "failure: empty memo", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + ""), + nil, + }, + { + "failure: non-json memo", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "invalid"), + nil, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + customData := tc.packetData.GetCustomPacketData("src_callback") + require.Equal(t, tc.expCustomData, customData) + }) + } +} + +func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { + testCases := []struct { + name string + packetData types.FungibleTokenPacketDataV2 + expMemo bool + }{ + { + "empty memo field, resulting marshalled bytes should not contain the memo field", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + ), + false, + }, + { + "non-empty memo field, resulting marshalled bytes should contain the memo field", + types.NewFungibleTokenPacketDataV2( + []*types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "abc", + ), + true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + bz, err := json.Marshal(tc.packetData) + if tc.expMemo { + require.NoError(t, err, tc.name) + // check that the memo field is present in the marshalled bytes + require.Contains(t, string(bz), "memo") + } else { + require.NoError(t, err, tc.name) + // check that the memo field is not present in the marshalled bytes + require.NotContains(t, string(bz), "memo") + } + }) + } +} diff --git a/modules/apps/transfer/types/v3/token.go b/modules/apps/transfer/types/token.go similarity index 79% rename from modules/apps/transfer/types/v3/token.go rename to modules/apps/transfer/types/token.go index 8eea4eab756..bdfb7880577 100644 --- a/modules/apps/transfer/types/v3/token.go +++ b/modules/apps/transfer/types/token.go @@ -1,4 +1,4 @@ -package v3 +package types import ( "strings" @@ -8,13 +8,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" denominternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/denom" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ) -// ValidateToken validates a token denomination and trace identifiers. +// Validate validates a token denomination and trace identifiers. func (t Token) Validate() error { if err := sdk.ValidateDenom(t.Denom); err != nil { - return errorsmod.Wrap(types.ErrInvalidDenomForTransfer, err.Error()) + return errorsmod.Wrap(ErrInvalidDenomForTransfer, err.Error()) } if len(t.Trace) == 0 { diff --git a/modules/apps/transfer/types/v3/token_test.go b/modules/apps/transfer/types/token_test.go similarity index 83% rename from modules/apps/transfer/types/v3/token_test.go rename to modules/apps/transfer/types/token_test.go index 13654cfcc1d..efbee444478 100644 --- a/modules/apps/transfer/types/v3/token_test.go +++ b/modules/apps/transfer/types/token_test.go @@ -1,4 +1,4 @@ -package v3 +package types import ( fmt "fmt" @@ -6,18 +6,29 @@ import ( "github.com/stretchr/testify/require" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + denom = "atom/pool" + amount = "100" +) + +var ( + sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver = sdk.AccAddress("testaddr2").String() ) func TestGetFullDenomPath(t *testing.T) { testCases := []struct { name string - packetData FungibleTokenPacketData + packetData FungibleTokenPacketDataV2 expPath string }{ { "denom path with trace", - NewFungibleTokenPacketData( + NewFungibleTokenPacketDataV2( []*Token{ { Denom: denom, @@ -33,7 +44,7 @@ func TestGetFullDenomPath(t *testing.T) { }, { "nil trace", - NewFungibleTokenPacketData( + NewFungibleTokenPacketDataV2( []*Token{ { Denom: denom, @@ -49,7 +60,7 @@ func TestGetFullDenomPath(t *testing.T) { }, { "empty string trace", - NewFungibleTokenPacketData( + NewFungibleTokenPacketDataV2( []*Token{ { Denom: denom, @@ -113,7 +124,7 @@ func TestValidate(t *testing.T) { Amount: amount, Trace: nil, }, - types.ErrInvalidDenomForTransfer, + ErrInvalidDenomForTransfer, }, { "failure: invalid identifier in trace", diff --git a/modules/apps/transfer/types/v3/packet.go b/modules/apps/transfer/types/v3/packet.go deleted file mode 100644 index 510a1024cac..00000000000 --- a/modules/apps/transfer/types/v3/packet.go +++ /dev/null @@ -1,114 +0,0 @@ -package v3 - -import ( - "encoding/json" - "errors" - "strings" - - errorsmod "cosmossdk.io/errors" - sdkmath "cosmossdk.io/math" - - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" - ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" -) - -var ( - _ ibcexported.PacketData = (*FungibleTokenPacketData)(nil) - _ ibcexported.PacketDataProvider = (*FungibleTokenPacketData)(nil) -) - -// NewFungibleTokenPacketData constructs a new NewFungibleTokenPacketData instance -func NewFungibleTokenPacketData( - tokens []*Token, - sender, receiver string, - memo string, -) FungibleTokenPacketData { - return FungibleTokenPacketData{ - Tokens: tokens, - Sender: sender, - Receiver: receiver, - Memo: memo, - } -} - -// ValidateBasic is used for validating the token transfer. -// NOTE: The addresses formats are not validated as the sender and recipient can have different -// formats defined by their corresponding chains that are not known to IBC. -func (ftpd FungibleTokenPacketData) ValidateBasic() error { - if strings.TrimSpace(ftpd.Sender) == "" { - return errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "sender address cannot be blank") - } - - if strings.TrimSpace(ftpd.Receiver) == "" { - return errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "receiver address cannot be blank") - } - - if len(ftpd.Tokens) == 0 { - return errorsmod.Wrap(types.ErrInvalidAmount, "tokens cannot be empty") - } - - for _, token := range ftpd.Tokens { - amount, ok := sdkmath.NewIntFromString(token.Amount) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", token.Amount) - } - - if !amount.IsPositive() { - return errorsmod.Wrapf(types.ErrInvalidAmount, "amount must be strictly positive: got %d", amount) - } - - if err := token.Validate(); err != nil { - return err - } - } - - if len(ftpd.Memo) > types.MaximumMemoLength { - return errorsmod.Wrapf(types.ErrInvalidMemo, "memo must not exceed %d bytes", types.MaximumMemoLength) - } - - return nil -} - -// GetBytes is a helper for serialising -func (ftpd FungibleTokenPacketData) GetBytes() []byte { - bz, err := json.Marshal(&ftpd) - if err != nil { - panic(errors.New("cannot marshal v3 FungibleTokenPacketData into bytes")) - } - - return bz -} - -// GetCustomPacketData interprets the memo field of the packet data as a JSON object -// and returns the value associated with the given key. -// If the key is missing or the memo is not properly formatted, then nil is returned. -func (ftpd FungibleTokenPacketData) GetCustomPacketData(key string) interface{} { - if len(ftpd.Memo) == 0 { - return nil - } - - jsonObject := make(map[string]interface{}) - err := json.Unmarshal([]byte(ftpd.Memo), &jsonObject) - if err != nil { - return nil - } - - memoData, found := jsonObject[key] - if !found { - return nil - } - - return memoData -} - -// GetPacketSender returns the sender address embedded in the packet data. -// -// NOTE: -// - The sender address is set by the module which requested the packet to be sent, -// and this module may not have validated the sender address by a signature check. -// - The sender address must only be used by modules on the sending chain. -// - sourcePortID is not used in this implementation. -func (ftpd FungibleTokenPacketData) GetPacketSender(sourcePortID string) string { - return ftpd.Sender -} diff --git a/modules/apps/transfer/types/v3/packet.pb.go b/modules/apps/transfer/types/v3/packet.pb.go deleted file mode 100644 index 145b51c5eb9..00000000000 --- a/modules/apps/transfer/types/v3/packet.pb.go +++ /dev/null @@ -1,776 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: ibc/applications/transfer/v3/packet.proto - -package v3 - -import ( - fmt "fmt" - proto "github.com/cosmos/gogoproto/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// FungibleTokenPacketData defines a struct for the packet payload -// See FungibleTokenPacketData spec: -// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures -type FungibleTokenPacketData struct { - // the tokens to be transferred - Tokens []*Token `protobuf:"bytes,1,rep,name=tokens,proto3" json:"tokens,omitempty"` - // the sender address - Sender string `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` - // the recipient address on the destination chain - Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` - // optional memo - Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` -} - -func (m *FungibleTokenPacketData) Reset() { *m = FungibleTokenPacketData{} } -func (m *FungibleTokenPacketData) String() string { return proto.CompactTextString(m) } -func (*FungibleTokenPacketData) ProtoMessage() {} -func (*FungibleTokenPacketData) Descriptor() ([]byte, []int) { - return fileDescriptor_760742a8894acdbe, []int{0} -} -func (m *FungibleTokenPacketData) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *FungibleTokenPacketData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_FungibleTokenPacketData.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 *FungibleTokenPacketData) XXX_Merge(src proto.Message) { - xxx_messageInfo_FungibleTokenPacketData.Merge(m, src) -} -func (m *FungibleTokenPacketData) XXX_Size() int { - return m.Size() -} -func (m *FungibleTokenPacketData) XXX_DiscardUnknown() { - xxx_messageInfo_FungibleTokenPacketData.DiscardUnknown(m) -} - -var xxx_messageInfo_FungibleTokenPacketData proto.InternalMessageInfo - -func (m *FungibleTokenPacketData) GetTokens() []*Token { - if m != nil { - return m.Tokens - } - return nil -} - -func (m *FungibleTokenPacketData) GetSender() string { - if m != nil { - return m.Sender - } - return "" -} - -func (m *FungibleTokenPacketData) GetReceiver() string { - if m != nil { - return m.Receiver - } - return "" -} - -func (m *FungibleTokenPacketData) GetMemo() string { - if m != nil { - return m.Memo - } - return "" -} - -// Token defines a struct which represents a token to be transferred. -type Token struct { - // the base token denomination to be transferred - Denom string `protobuf:"bytes,1,opt,name=denom,proto3" json:"denom,omitempty"` - // the token amount to be transferred - Amount string `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"` - // the trace of the token - Trace []string `protobuf:"bytes,3,rep,name=trace,proto3" json:"trace,omitempty"` -} - -func (m *Token) Reset() { *m = Token{} } -func (m *Token) String() string { return proto.CompactTextString(m) } -func (*Token) ProtoMessage() {} -func (*Token) Descriptor() ([]byte, []int) { - return fileDescriptor_760742a8894acdbe, []int{1} -} -func (m *Token) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Token) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Token.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 *Token) XXX_Merge(src proto.Message) { - xxx_messageInfo_Token.Merge(m, src) -} -func (m *Token) XXX_Size() int { - return m.Size() -} -func (m *Token) XXX_DiscardUnknown() { - xxx_messageInfo_Token.DiscardUnknown(m) -} - -var xxx_messageInfo_Token proto.InternalMessageInfo - -func (m *Token) GetDenom() string { - if m != nil { - return m.Denom - } - return "" -} - -func (m *Token) GetAmount() string { - if m != nil { - return m.Amount - } - return "" -} - -func (m *Token) GetTrace() []string { - if m != nil { - return m.Trace - } - return nil -} - -func init() { - proto.RegisterType((*FungibleTokenPacketData)(nil), "ibc.applications.transfer.v3.FungibleTokenPacketData") - proto.RegisterType((*Token)(nil), "ibc.applications.transfer.v3.Token") -} - -func init() { - proto.RegisterFile("ibc/applications/transfer/v3/packet.proto", fileDescriptor_760742a8894acdbe) -} - -var fileDescriptor_760742a8894acdbe = []byte{ - // 301 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xc1, 0x4a, 0x33, 0x31, - 0x14, 0x85, 0x9b, 0x7f, 0xda, 0xf2, 0x1b, 0x77, 0x41, 0x74, 0x10, 0x19, 0x4a, 0xdd, 0xd4, 0x85, - 0x09, 0x38, 0x1b, 0xd1, 0x9d, 0x88, 0x1b, 0x37, 0x52, 0xba, 0x72, 0x97, 0xa4, 0xd7, 0x1a, 0xda, - 0xe4, 0x0e, 0x49, 0x66, 0xc0, 0xb7, 0xf0, 0x09, 0x7c, 0x1e, 0x97, 0x5d, 0xba, 0x94, 0xf6, 0x45, - 0x64, 0xd2, 0x56, 0xba, 0x72, 0x77, 0xbf, 0x7b, 0xcf, 0xb9, 0x07, 0x0e, 0xbd, 0x30, 0x4a, 0x0b, - 0x59, 0x55, 0x0b, 0xa3, 0x65, 0x34, 0xe8, 0x82, 0x88, 0x5e, 0xba, 0xf0, 0x02, 0x5e, 0x34, 0xa5, - 0xa8, 0xa4, 0x9e, 0x43, 0xe4, 0x95, 0xc7, 0x88, 0xec, 0xcc, 0x28, 0xcd, 0xf7, 0xa5, 0x7c, 0x27, - 0xe5, 0x4d, 0x39, 0xfc, 0x20, 0xf4, 0xe4, 0xa1, 0x76, 0x33, 0xa3, 0x16, 0x30, 0xc1, 0x39, 0xb8, - 0xa7, 0xe4, 0xbd, 0x97, 0x51, 0xb2, 0x5b, 0xda, 0x8f, 0xed, 0x2a, 0xe4, 0x64, 0x90, 0x8d, 0x0e, - 0xaf, 0xce, 0xf9, 0x5f, 0xaf, 0x78, 0xb2, 0x8f, 0xb7, 0x16, 0x76, 0x4c, 0xfb, 0x01, 0xdc, 0x14, - 0x7c, 0xfe, 0x6f, 0x40, 0x46, 0x07, 0xe3, 0x2d, 0xb1, 0x53, 0xfa, 0xdf, 0x83, 0x06, 0xd3, 0x80, - 0xcf, 0xb3, 0x74, 0xf9, 0x65, 0xc6, 0x68, 0xd7, 0x82, 0xc5, 0xbc, 0x9b, 0xf6, 0x69, 0x1e, 0x3e, - 0xd2, 0x5e, 0x7a, 0xcc, 0x8e, 0x68, 0x6f, 0x0a, 0x0e, 0x6d, 0x4e, 0xd2, 0x75, 0x03, 0x6d, 0x8c, - 0xb4, 0x58, 0xbb, 0xb8, 0x8b, 0xd9, 0x50, 0xab, 0x8e, 0x5e, 0x6a, 0xc8, 0xb3, 0x41, 0xd6, 0xaa, - 0x13, 0xdc, 0x4d, 0x3e, 0x57, 0x05, 0x59, 0xae, 0x0a, 0xf2, 0xbd, 0x2a, 0xc8, 0xfb, 0xba, 0xe8, - 0x2c, 0xd7, 0x45, 0xe7, 0x6b, 0x5d, 0x74, 0x9e, 0x6f, 0x66, 0x26, 0xbe, 0xd6, 0x8a, 0x6b, 0xb4, - 0x42, 0x63, 0xb0, 0x18, 0x84, 0x51, 0xfa, 0x72, 0x86, 0xa2, 0xb9, 0x16, 0x16, 0xa7, 0xf5, 0x02, - 0x42, 0x5b, 0xf8, 0x5e, 0xd1, 0xf1, 0xad, 0x82, 0x20, 0x9a, 0x52, 0xf5, 0x53, 0xd1, 0xe5, 0x4f, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x97, 0x4d, 0xcc, 0xde, 0x95, 0x01, 0x00, 0x00, -} - -func (m *FungibleTokenPacketData) 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 *FungibleTokenPacketData) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *FungibleTokenPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Memo) > 0 { - i -= len(m.Memo) - copy(dAtA[i:], m.Memo) - i = encodeVarintPacket(dAtA, i, uint64(len(m.Memo))) - i-- - dAtA[i] = 0x22 - } - if len(m.Receiver) > 0 { - i -= len(m.Receiver) - copy(dAtA[i:], m.Receiver) - i = encodeVarintPacket(dAtA, i, uint64(len(m.Receiver))) - i-- - dAtA[i] = 0x1a - } - if len(m.Sender) > 0 { - i -= len(m.Sender) - copy(dAtA[i:], m.Sender) - i = encodeVarintPacket(dAtA, i, uint64(len(m.Sender))) - i-- - dAtA[i] = 0x12 - } - if len(m.Tokens) > 0 { - for iNdEx := len(m.Tokens) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Tokens[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintPacket(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *Token) 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 *Token) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Token) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Trace) > 0 { - for iNdEx := len(m.Trace) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Trace[iNdEx]) - copy(dAtA[i:], m.Trace[iNdEx]) - i = encodeVarintPacket(dAtA, i, uint64(len(m.Trace[iNdEx]))) - i-- - dAtA[i] = 0x1a - } - } - if len(m.Amount) > 0 { - i -= len(m.Amount) - copy(dAtA[i:], m.Amount) - i = encodeVarintPacket(dAtA, i, uint64(len(m.Amount))) - i-- - dAtA[i] = 0x12 - } - if len(m.Denom) > 0 { - i -= len(m.Denom) - copy(dAtA[i:], m.Denom) - i = encodeVarintPacket(dAtA, i, uint64(len(m.Denom))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintPacket(dAtA []byte, offset int, v uint64) int { - offset -= sovPacket(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *FungibleTokenPacketData) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Tokens) > 0 { - for _, e := range m.Tokens { - l = e.Size() - n += 1 + l + sovPacket(uint64(l)) - } - } - l = len(m.Sender) - if l > 0 { - n += 1 + l + sovPacket(uint64(l)) - } - l = len(m.Receiver) - if l > 0 { - n += 1 + l + sovPacket(uint64(l)) - } - l = len(m.Memo) - if l > 0 { - n += 1 + l + sovPacket(uint64(l)) - } - return n -} - -func (m *Token) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Denom) - if l > 0 { - n += 1 + l + sovPacket(uint64(l)) - } - l = len(m.Amount) - if l > 0 { - n += 1 + l + sovPacket(uint64(l)) - } - if len(m.Trace) > 0 { - for _, s := range m.Trace { - l = len(s) - n += 1 + l + sovPacket(uint64(l)) - } - } - return n -} - -func sovPacket(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozPacket(x uint64) (n int) { - return sovPacket(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *FungibleTokenPacketData) 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 ErrIntOverflowPacket - } - 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: FungibleTokenPacketData: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: FungibleTokenPacketData: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Tokens", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPacket - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthPacket - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthPacket - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Tokens = append(m.Tokens, &Token{}) - if err := m.Tokens[len(m.Tokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPacket - } - 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 ErrInvalidLengthPacket - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPacket - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Sender = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPacket - } - 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 ErrInvalidLengthPacket - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPacket - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Receiver = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Memo", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPacket - } - 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 ErrInvalidLengthPacket - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPacket - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Memo = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipPacket(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthPacket - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Token) 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 ErrIntOverflowPacket - } - 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: Token: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Token: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPacket - } - 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 ErrInvalidLengthPacket - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPacket - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Denom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPacket - } - 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 ErrInvalidLengthPacket - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPacket - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Amount = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Trace", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPacket - } - 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 ErrInvalidLengthPacket - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthPacket - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Trace = append(m.Trace, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipPacket(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthPacket - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipPacket(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowPacket - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowPacket - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowPacket - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthPacket - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupPacket - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthPacket - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthPacket = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowPacket = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupPacket = fmt.Errorf("proto: unexpected end of group") -) diff --git a/modules/apps/transfer/types/v3/packet_test.go b/modules/apps/transfer/types/v3/packet_test.go deleted file mode 100644 index 63435d8589e..00000000000 --- a/modules/apps/transfer/types/v3/packet_test.go +++ /dev/null @@ -1,436 +0,0 @@ -package v3 - -import ( - "encoding/json" - "fmt" - "testing" - - "github.com/stretchr/testify/require" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/cometbft/cometbft/crypto/secp256k1" - - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" -) - -const ( - denom = "atom/pool" - amount = "1000" - largeAmount = "18446744073709551616" // one greater than largest uint64 (^uint64(0)) - invalidLargeAmount = "115792089237316195423570985008687907853269984665640564039457584007913129639936" // 2^256 -) - -var ( - sender = secp256k1.GenPrivKey().PubKey().Address().String() - receiver = sdk.AccAddress("testaddr2").String() -) - -// TestFungibleTokenPacketDataValidateBasic tests ValidateBasic for FungibleTokenPacketData -func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { - testCases := []struct { - name string - packetData FungibleTokenPacketData - expErr error - }{ - { - "success: valid packet", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "", - ), - nil, - }, - { - "success: valid packet with memo", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "memo", - ), - nil, - }, - { - "success: valid packet with large amount", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: largeAmount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "memo", - ), - nil, - }, - { - "failure: invalid denom", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: "", - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "", - ), - types.ErrInvalidDenomForTransfer, - }, - { - "failure: invalid empty amount", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: "", - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "", - ), - types.ErrInvalidAmount, - }, - { - "failure: invalid empty token array", - NewFungibleTokenPacketData( - []*Token{}, - sender, - receiver, - "", - ), - types.ErrInvalidAmount, - }, - { - "failure: invalid zero amount", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: "0", - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "", - ), - types.ErrInvalidAmount, - }, - { - "failure: invalid negative amount", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: "-100", - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "", - ), - types.ErrInvalidAmount, - }, - { - "failure: invalid large amount", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: invalidLargeAmount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "memo", - ), - types.ErrInvalidAmount, - }, - { - "failure: missing sender address", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - "", - receiver, - "memo", - ), - ibcerrors.ErrInvalidAddress, - }, - { - "failure: missing recipient address", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - "", - "", - ), - ibcerrors.ErrInvalidAddress, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - err := tc.packetData.ValidateBasic() - - expPass := tc.expErr == nil - if expPass { - require.NoError(t, err, tc.name) - } else { - require.ErrorContains(t, err, tc.expErr.Error(), tc.name) - } - }) - } -} - -func TestGetPacketSender(t *testing.T) { - testCases := []struct { - name string - packetData FungibleTokenPacketData - expSender string - }{ - { - "non-empty sender field", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "", - ), - sender, - }, - { - "empty sender field", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - "", - receiver, - "abc", - ), - "", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - require.Equal(t, tc.expSender, tc.packetData.GetPacketSender(types.PortID)) - }) - } -} - -func TestPacketDataProvider(t *testing.T) { - testCases := []struct { - name string - packetData FungibleTokenPacketData - expCustomData interface{} - }{ - { - "success: src_callback key in memo", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver)), - - map[string]interface{}{ - "address": receiver, - }, - }, - { - "success: src_callback key in memo with additional fields", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, receiver)), - map[string]interface{}{ - "address": receiver, - "gas_limit": "200000", - }, - }, - { - "success: src_callback has string value", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - `{"src_callback": "string"}`), - "string", - }, - { - "failure: src_callback key not found memo", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - fmt.Sprintf(`{"dest_callback": {"address": "%s", "min_gas": "200000"}}`, receiver)), - nil, - }, - { - "failure: empty memo", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - ""), - nil, - }, - { - "failure: non-json memo", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "invalid"), - nil, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - customData := tc.packetData.GetCustomPacketData("src_callback") - require.Equal(t, tc.expCustomData, customData) - }) - } -} - -func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { - testCases := []struct { - name string - packetData FungibleTokenPacketData - expMemo bool - }{ - { - "empty memo field, resulting marshalled bytes should not contain the memo field", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "", - ), - false, - }, - { - "non-empty memo field, resulting marshalled bytes should contain the memo field", - NewFungibleTokenPacketData( - []*Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{"transfer/channel-0", "transfer/channel-1"}, - }, - }, - sender, - receiver, - "abc", - ), - true, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - bz, err := json.Marshal(tc.packetData) - if tc.expMemo { - require.NoError(t, err, tc.name) - // check that the memo field is present in the marshalled bytes - require.Contains(t, string(bz), "memo") - } else { - require.NoError(t, err, tc.name) - // check that the memo field is not present in the marshalled bytes - require.NotContains(t, string(bz), "memo") - } - }) - } -} diff --git a/proto/ibc/applications/transfer/v2/packet.proto b/proto/ibc/applications/transfer/v2/packet.proto index bff35bdd6d3..4dfaf107062 100644 --- a/proto/ibc/applications/transfer/v2/packet.proto +++ b/proto/ibc/applications/transfer/v2/packet.proto @@ -19,3 +19,27 @@ message FungibleTokenPacketData { // optional memo string memo = 5; } + +// FungibleTokenPacketDataV2 defines a struct for the packet payload +// See FungibleTokenPacketDataV2 spec: +// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures +message FungibleTokenPacketDataV2 { + // the tokens to be transferred + repeated Token tokens = 1; + // the sender address + string sender = 2; + // the recipient address on the destination chain + string receiver = 3; + // optional memo + string memo = 4; +} + +// Token defines a struct which represents a token to be transferred. +message Token { + // the base token denomination to be transferred + string denom = 1; + // the token amount to be transferred + string amount = 2; + // the trace of the token + repeated string trace = 3; +} diff --git a/proto/ibc/applications/transfer/v3/packet.proto b/proto/ibc/applications/transfer/v3/packet.proto deleted file mode 100644 index 8971472c69d..00000000000 --- a/proto/ibc/applications/transfer/v3/packet.proto +++ /dev/null @@ -1,29 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.transfer.v3; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3"; - -// FungibleTokenPacketData defines a struct for the packet payload -// See FungibleTokenPacketData spec: -// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures -message FungibleTokenPacketData { - // the tokens to be transferred - repeated Token tokens = 1; - // the sender address - string sender = 2; - // the recipient address on the destination chain - string receiver = 3; - // optional memo - string memo = 4; -} - -// Token defines a struct which represents a token to be transferred. -message Token { - // the base token denomination to be transferred - string denom = 1; - // the token amount to be transferred - string amount = 2; - // the trace of the token - repeated string trace = 3; -} From 9b399449acafda46655d4ac8802f888b24fd7047 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Tue, 21 May 2024 14:00:35 +0100 Subject: [PATCH 037/141] Adding additional comments and changing version variable names (#6345) --- e2e/tests/transfer/localhost_test.go | 8 +++--- e2e/tests/transfer/upgrades_test.go | 4 +-- e2e/testsuite/testsuite.go | 6 ++-- modules/apps/29-fee/keeper/events_test.go | 2 +- modules/apps/29-fee/transfer_test.go | 8 +++--- modules/apps/callbacks/callbacks_test.go | 6 ++-- modules/apps/transfer/ibc_module.go | 6 ++-- modules/apps/transfer/ibc_module_test.go | 28 +++++++++---------- .../apps/transfer/keeper/mbt_relay_test.go | 2 +- modules/apps/transfer/keeper/msg_server.go | 2 +- .../apps/transfer/keeper/msg_server_test.go | 2 +- modules/apps/transfer/types/keys.go | 16 ++++++----- testing/path.go | 4 +-- testing/solomachine.go | 10 +++---- 14 files changed, 53 insertions(+), 51 deletions(-) diff --git a/e2e/tests/transfer/localhost_test.go b/e2e/tests/transfer/localhost_test.go index a8909fa9675..246fa201553 100644 --- a/e2e/tests/transfer/localhost_test.go +++ b/e2e/tests/transfer/localhost_test.go @@ -68,7 +68,7 @@ func (s *LocalhostTransferTestSuite) TestMsgTransfer_Localhost() { t.Run("channel open init localhost", func(t *testing.T) { msgChanOpenInit := channeltypes.NewMsgChannelOpenInit( - transfertypes.PortID, transfertypes.Version, + transfertypes.PortID, transfertypes.V2, channeltypes.UNORDERED, []string{exported.LocalhostConnectionID}, transfertypes.PortID, rlyWallet.FormattedAddress(), ) @@ -83,10 +83,10 @@ func (s *LocalhostTransferTestSuite) TestMsgTransfer_Localhost() { t.Run("channel open try localhost", func(t *testing.T) { msgChanOpenTry := channeltypes.NewMsgChannelOpenTry( - transfertypes.PortID, transfertypes.Version, + transfertypes.PortID, transfertypes.V2, channeltypes.UNORDERED, []string{exported.LocalhostConnectionID}, transfertypes.PortID, msgChanOpenInitRes.ChannelId, - transfertypes.Version, localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress(), + transfertypes.V2, localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress(), ) txResp := s.BroadcastMessages(ctx, chainA, rlyWallet, msgChanOpenTry) @@ -98,7 +98,7 @@ func (s *LocalhostTransferTestSuite) TestMsgTransfer_Localhost() { t.Run("channel open ack localhost", func(t *testing.T) { msgChanOpenAck := channeltypes.NewMsgChannelOpenAck( transfertypes.PortID, msgChanOpenInitRes.ChannelId, - msgChanOpenTryRes.ChannelId, transfertypes.Version, + msgChanOpenTryRes.ChannelId, transfertypes.V2, localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress(), ) diff --git a/e2e/tests/transfer/upgrades_test.go b/e2e/tests/transfer/upgrades_test.go index 74f5593d611..11a2d1a84e4 100644 --- a/e2e/tests/transfer/upgrades_test.go +++ b/e2e/tests/transfer/upgrades_test.go @@ -361,7 +361,7 @@ func (s *TransferChannelUpgradesTestSuite) TestChannelUpgrade_WithFeeMiddleware_ s.Require().NoError(err) s.Require().Equal(channeltypes.OPEN, channel.State, "the channel state is not OPEN") - s.Require().Equal(transfertypes.Version, channel.Version, "the channel version is not ics20-1") + s.Require().Equal(transfertypes.V2, channel.Version, "the channel version is not ics20-2") errorReceipt, err := s.QueryUpgradeError(ctx, chainA, channelA.PortID, channelA.ChannelID) s.Require().NoError(err) @@ -374,7 +374,7 @@ func (s *TransferChannelUpgradesTestSuite) TestChannelUpgrade_WithFeeMiddleware_ s.Require().NoError(err) s.Require().Equal(channeltypes.OPEN, channel.State, "the channel state is not OPEN") - s.Require().Equal(transfertypes.Version, channel.Version, "the channel version is not ics20-1") + s.Require().Equal(transfertypes.V2, channel.Version, "the channel version is not ics20-2") errorReceipt, err := s.QueryUpgradeError(ctx, chainB, channelB.PortID, channelB.ChannelID) s.Require().NoError(err) diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index dc188180aa1..990cbf06fc1 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -111,7 +111,7 @@ func (s *E2ETestSuite) ConfigureRelayer(ctx context.Context, chainA, chainB ibc. channelOptions := ibc.DefaultChannelOpts() // TODO: better way to do this. // For now, set the version to the latest transfer module version - channelOptions.Version = transfertypes.Version + channelOptions.Version = transfertypes.V2 if channelOpts != nil { channelOpts(&channelOptions) @@ -401,7 +401,7 @@ func (s *E2ETestSuite) GetRelayerExecReporter() *testreporter.RelayerExecReporte // TransferChannelOptions configures both of the chains to have non-incentivized transfer channels. func (*E2ETestSuite) TransferChannelOptions() func(options *ibc.CreateChannelOptions) { return func(opts *ibc.CreateChannelOptions) { - opts.Version = transfertypes.Version + opts.Version = transfertypes.V2 opts.SourcePortName = transfertypes.PortID opts.DestPortName = transfertypes.PortID } @@ -411,7 +411,7 @@ func (*E2ETestSuite) TransferChannelOptions() func(options *ibc.CreateChannelOpt func (s *E2ETestSuite) FeeMiddlewareChannelOptions() func(options *ibc.CreateChannelOptions) { versionMetadata := feetypes.Metadata{ FeeVersion: feetypes.Version, - AppVersion: transfertypes.Version, + AppVersion: transfertypes.V2, } versionBytes, err := feetypes.ModuleCdc.MarshalJSON(&versionMetadata) s.Require().NoError(err) diff --git a/modules/apps/29-fee/keeper/events_test.go b/modules/apps/29-fee/keeper/events_test.go index d70b8bfd229..38b64cadd80 100644 --- a/modules/apps/29-fee/keeper/events_test.go +++ b/modules/apps/29-fee/keeper/events_test.go @@ -93,7 +93,7 @@ func (suite *KeeperTestSuite) TestIncentivizePacketEvent() { func (suite *KeeperTestSuite) TestDistributeFeeEvent() { // create an incentivized transfer path path := ibctesting.NewPath(suite.chainA, suite.chainB) - feeTransferVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.Version})) + feeTransferVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.V2})) path.EndpointA.ChannelConfig.Version = feeTransferVersion path.EndpointB.ChannelConfig.Version = feeTransferVersion path.EndpointA.ChannelConfig.PortID = transfertypes.PortID diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index f76393bfcf8..11145598d4b 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -12,7 +12,7 @@ import ( // Integration test to ensure ics29 works with ics20 func (suite *FeeTestSuite) TestFeeTransfer() { path := ibctesting.NewPath(suite.chainA, suite.chainB) - feeTransferVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.Version})) + feeTransferVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.V2})) path.EndpointA.ChannelConfig.Version = feeTransferVersion path.EndpointB.ChannelConfig.Version = feeTransferVersion path.EndpointA.ChannelConfig.PortID = transfertypes.PortID @@ -94,13 +94,13 @@ func (suite *FeeTestSuite) TestTransferFeeUpgrade() { // configure the initial path to create a regular transfer channel path.EndpointA.ChannelConfig.PortID = transfertypes.PortID path.EndpointB.ChannelConfig.PortID = transfertypes.PortID - path.EndpointA.ChannelConfig.Version = transfertypes.Version - path.EndpointB.ChannelConfig.Version = transfertypes.Version + path.EndpointA.ChannelConfig.Version = transfertypes.V2 + path.EndpointB.ChannelConfig.Version = transfertypes.V2 path.Setup() // configure the channel upgrade to upgrade to an incentivized fee enabled transfer channel - upgradeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.Version})) + upgradeVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.V2})) path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = upgradeVersion diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 3b337b7bd24..6c76deb5795 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -78,8 +78,8 @@ func (s *CallbacksTestSuite) SetupTransferTest() { s.path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort s.path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort - s.path.EndpointA.ChannelConfig.Version = transfertypes.Version - s.path.EndpointB.ChannelConfig.Version = transfertypes.Version + s.path.EndpointA.ChannelConfig.Version = transfertypes.V2 + s.path.EndpointB.ChannelConfig.Version = transfertypes.V2 s.path.Setup() } @@ -88,7 +88,7 @@ func (s *CallbacksTestSuite) SetupTransferTest() { func (s *CallbacksTestSuite) SetupFeeTransferTest() { s.setupChains() - feeTransferVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feetypes.Metadata{FeeVersion: feetypes.Version, AppVersion: transfertypes.Version})) + feeTransferVersion := string(feetypes.ModuleCdc.MustMarshalJSON(&feetypes.Metadata{FeeVersion: feetypes.Version, AppVersion: transfertypes.V2})) s.path.EndpointA.ChannelConfig.Version = feeTransferVersion s.path.EndpointB.ChannelConfig.Version = feeTransferVersion s.path.EndpointA.ChannelConfig.PortID = transfertypes.PortID diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index ddfc4f0a9dd..90cc379258d 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -89,7 +89,7 @@ func (im IBCModule) OnChanOpenInit( // default to latest supported version if strings.TrimSpace(version) == "" { - version = types.Version + version = types.V2 } if !slices.Contains(types.SupportedVersions, version) { @@ -120,7 +120,7 @@ func (im IBCModule) OnChanOpenTry( } if !slices.Contains(types.SupportedVersions, counterpartyVersion) { - return types.Version, nil + return types.V2, nil } // OpenTry must claim the channelCapability that IBC passes into the callback @@ -375,7 +375,7 @@ func (im IBCModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, } if !slices.Contains(types.SupportedVersions, counterpartyVersion) { - return types.Version, nil + return types.V2, nil } return counterpartyVersion, nil diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 12e6f4c661d..2fd36dbe422 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -31,24 +31,24 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { expVersion string }{ { - "success", func() {}, true, types.Version, + "success", func() {}, true, types.V2, }, { // connection hops is not used in the transfer application callback, // it is already validated in the core OnChanUpgradeInit. "success: invalid connection hops", func() { path.EndpointA.ConnectionID = "invalid-connection-id" - }, true, types.Version, + }, true, types.V2, }, { "success: empty version string", func() { channel.Version = "" - }, true, types.Version, + }, true, types.V2, }, { "success: ics20-1 legacy", func() { - channel.Version = types.Version1 - }, true, types.Version1, + channel.Version = types.V1 + }, true, types.V1, }, { "max channels reached", func() { @@ -93,7 +93,7 @@ func (suite *TransferTestSuite) TestOnChanOpenInit() { Ordering: channeltypes.UNORDERED, Counterparty: counterparty, ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: types.Version, + Version: types.V2, } var err error @@ -134,17 +134,17 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { expVersion string }{ { - "success", func() {}, true, types.Version, + "success", func() {}, true, types.V2, }, { "success: counterparty version is legacy ics20-1", func() { - counterpartyVersion = types.Version1 - }, true, types.Version1, + counterpartyVersion = types.V1 + }, true, types.V1, }, { "success: invalid counterparty version, we use our proposed version", func() { counterpartyVersion = "version" - }, true, types.Version, + }, true, types.V2, }, { "max channels reached", func() { @@ -185,9 +185,9 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { Ordering: channeltypes.UNORDERED, Counterparty: counterparty, ConnectionHops: []string{path.EndpointA.ConnectionID}, - Version: types.Version, + Version: types.V2, } - counterpartyVersion = types.Version + counterpartyVersion = types.V2 module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) suite.Require().NoError(err) @@ -242,7 +242,7 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { path := ibctesting.NewTransferPath(suite.chainA, suite.chainB) path.SetupConnections() path.EndpointA.ChannelID = ibctesting.FirstChannelID - counterpartyVersion = types.Version + counterpartyVersion = types.V2 module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) suite.Require().NoError(err) @@ -405,7 +405,7 @@ func (suite *TransferTestSuite) TestOnChanUpgradeTry() { expPass := tc.expError == nil if expPass { suite.Require().NoError(err) - suite.Require().Equal(types.Version, version) + suite.Require().Equal(types.V2, version) } else { suite.Require().Error(err) suite.Require().Contains(err.Error(), tc.expError.Error()) diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 86ad87c3a91..6c0752e6b5f 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -109,7 +109,7 @@ func AddressFromTla(addr []string) string { s = addr[2] } else if len(addr[2]) == 0 { // escrow address: ics20-1\x00port/channel - s = fmt.Sprintf("%s\x00%s/%s", types.Version1, addr[0], addr[1]) + s = fmt.Sprintf("%s\x00%s/%s", types.V1, addr[0], addr[1]) } else { panic(errors.New("failed to convert from TLA+ address: neither simple nor escrow address")) } diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index aa81a9a228a..74bb202f521 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -36,7 +36,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. } // ics20-1 only supports a single token, so if that is the current version, we must only process a single token. - if appVersion == types.Version1 && len(tokens) > 1 { + if appVersion == types.V1 && len(tokens) > 1 { return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "cannot transfer multiple tokens with ics20-1") } diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 5ab8a03e069..ae4aaef3107 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -143,7 +143,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { // explicitly set to ics20-1 which does not support multi-denom path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { - channel.Version = types.Version1 + channel.Version = types.V1 }) }, ibcerrors.ErrInvalidRequest, diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index e44d521856a..3321243ae84 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -35,15 +35,17 @@ const ( ) const ( - // Version defines the current version the IBC transfer - // module supports - Version = "ics20-2" + // V1 defines first version of the IBC transfer module + V1 = "ics20-1" - // Version1 defines first version of the IBC transfer module - Version1 = "ics20-1" + // V2 defines the current version the IBC transfer + // module supports + V2 = "ics20-2" // escrowAddressVersion should remain as ics20-1 to avoid the address changing. - escrowAddressVersion = Version1 + // this address has been reasoned about to avoid collisions with other addresses + // https://github.com/cosmos/cosmos-sdk/issues/7737#issuecomment-735671951 + escrowAddressVersion = V1 ) var ( @@ -53,7 +55,7 @@ var ( DenomTraceKey = []byte{0x02} // SupportedVersions defines all versions that are supported by the module - SupportedVersions = []string{Version, Version1} + SupportedVersions = []string{V2, V1} ) // GetEscrowAddress returns the escrow address for the specified channel. diff --git a/testing/path.go b/testing/path.go index cb1c968952a..0a101c4739e 100644 --- a/testing/path.go +++ b/testing/path.go @@ -47,8 +47,8 @@ func NewTransferPath(chainA, chainB *TestChain) *Path { path := NewPath(chainA, chainB) path.EndpointA.ChannelConfig.PortID = TransferPort path.EndpointB.ChannelConfig.PortID = TransferPort - path.EndpointA.ChannelConfig.Version = transfertypes.Version - path.EndpointB.ChannelConfig.Version = transfertypes.Version + path.EndpointA.ChannelConfig.Version = transfertypes.V2 + path.EndpointB.ChannelConfig.Version = transfertypes.V2 return path } diff --git a/testing/solomachine.go b/testing/solomachine.go index 46151bec3ea..2a10fc50107 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -312,7 +312,7 @@ func (solo *Solomachine) ConnOpenAck(chain *TestChain, clientID, connectionID st func (solo *Solomachine) ChanOpenInit(chain *TestChain, connectionID string) string { msgChanOpenInit := channeltypes.NewMsgChannelOpenInit( transfertypes.PortID, - transfertypes.Version, + transfertypes.V2, channeltypes.UNORDERED, []string{connectionID}, transfertypes.PortID, @@ -332,12 +332,12 @@ func (solo *Solomachine) ChanOpenInit(chain *TestChain, connectionID string) str // ChanOpenAck performs the channel open ack handshake step on the tendermint chain for the associated // solo machine client. func (solo *Solomachine) ChanOpenAck(chain *TestChain, channelID string) { - tryProof := solo.GenerateChanOpenTryProof(transfertypes.PortID, transfertypes.Version, channelID) + tryProof := solo.GenerateChanOpenTryProof(transfertypes.PortID, transfertypes.V2, channelID) msgChanOpenAck := channeltypes.NewMsgChannelOpenAck( transfertypes.PortID, channelID, channelIDSolomachine, - transfertypes.Version, + transfertypes.V2, tryProof, clienttypes.ZeroHeight(), chain.SenderAccount.GetAddress().String(), @@ -351,7 +351,7 @@ func (solo *Solomachine) ChanOpenAck(chain *TestChain, channelID string) { // ChanCloseConfirm performs the channel close confirm handshake step on the tendermint chain for the associated // solo machine client. func (solo *Solomachine) ChanCloseConfirm(chain *TestChain, portID, channelID string) { - initProof := solo.GenerateChanClosedProof(portID, transfertypes.Version, channelID) + initProof := solo.GenerateChanClosedProof(portID, transfertypes.V2, channelID) msgChanCloseConfirm := channeltypes.NewMsgChannelCloseConfirm( portID, channelID, @@ -442,7 +442,7 @@ func (solo *Solomachine) TimeoutPacket(chain *TestChain, packet channeltypes.Pac // TimeoutPacketOnClose creates a channel closed and unreceived packet proof and broadcasts a MsgTimeoutOnClose. func (solo *Solomachine) TimeoutPacketOnClose(chain *TestChain, packet channeltypes.Packet, channelID string) { - closedProof := solo.GenerateChanClosedProof(transfertypes.PortID, transfertypes.Version, channelID) + closedProof := solo.GenerateChanClosedProof(transfertypes.PortID, transfertypes.V2, channelID) unreceivedProof := solo.GenerateReceiptAbsenceProof(packet) msgTimeout := channeltypes.NewMsgTimeoutOnClose( packet, From 7897ef360da23cd8026dbbc6b61c288566fa431d Mon Sep 17 00:00:00 2001 From: chatton Date: Tue, 21 May 2024 15:41:08 +0100 Subject: [PATCH 038/141] chore: correctly claim capability --- modules/apps/29-fee/transfer_test.go | 31 ++++++++++++++-------------- modules/apps/transfer/ibc_module.go | 8 +++---- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 9f8492dcdb1..dcfa344ab87 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -164,19 +164,18 @@ func (suite *FeeTestSuite) TestTransferFeeUpgrade() { } } -// TODO: fix this test -//func (suite *FeeTestSuite) TestOnesidedFeeMiddlewareTransferHandshake() { -// RemoveFeeMiddleware(suite.chainB) // remove fee middleware from chainB -// -// path := ibctesting.NewPath(suite.chainA, suite.chainB) -// feeTransferVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.V1})) -// path.EndpointA.ChannelConfig.Version = feeTransferVersion // this will be renegotiated by the Try step -// path.EndpointB.ChannelConfig.Version = "" // this will be overwritten by the Try step -// path.EndpointA.ChannelConfig.PortID = transfertypes.PortID -// path.EndpointB.ChannelConfig.PortID = transfertypes.PortID -// -// path.Setup() -// -// suite.Require().Equal(path.EndpointA.ChannelConfig.Version, transfertypes.V1) -// suite.Require().Equal(path.EndpointB.ChannelConfig.Version, transfertypes.V1) -//} +func (suite *FeeTestSuite) TestOnesidedFeeMiddlewareTransferHandshake() { + RemoveFeeMiddleware(suite.chainB) // remove fee middleware from chainB + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + feeTransferVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.V2})) + path.EndpointA.ChannelConfig.Version = feeTransferVersion // this will be renegotiated by the Try step + path.EndpointB.ChannelConfig.Version = "" // this will be overwritten by the Try step + path.EndpointA.ChannelConfig.PortID = transfertypes.PortID + path.EndpointB.ChannelConfig.PortID = transfertypes.PortID + + path.Setup() + + suite.Require().Equal(path.EndpointA.ChannelConfig.Version, transfertypes.V2) + suite.Require().Equal(path.EndpointB.ChannelConfig.Version, transfertypes.V2) +} diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 52e75eb51b7..62a5b975506 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -119,15 +119,15 @@ func (im IBCModule) OnChanOpenTry( return "", err } - if !slices.Contains(types.SupportedVersions, counterpartyVersion) { - return types.V2, nil - } - // 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) { + return types.V2, nil + } + return counterpartyVersion, nil } From 786a4f1c86acc3bad5afeff26bf3bdf1976a9240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 21 May 2024 17:20:33 +0200 Subject: [PATCH 039/141] lint --- modules/apps/transfer/types/token_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/types/token_test.go b/modules/apps/transfer/types/token_test.go index efbee444478..deb468e7066 100644 --- a/modules/apps/transfer/types/token_test.go +++ b/modules/apps/transfer/types/token_test.go @@ -1,7 +1,7 @@ package types import ( - fmt "fmt" + "fmt" "testing" "github.com/stretchr/testify/require" From a84b0e713c56e15e977f5e446a036c524be6df0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 22 May 2024 10:38:16 +0200 Subject: [PATCH 040/141] imp: change ics20 events to emit token set (#6348) * refactor: quick change to tokens event attribute * fix: various tests * lint * lint:fixeroni * imp: remove events variable in favour of direct event emission --------- Co-authored-by: DimitrisJim --- modules/apps/callbacks/ibc_middleware_test.go | 10 +-- modules/apps/transfer/ibc_module.go | 86 ++++++++----------- modules/apps/transfer/ibc_module_test.go | 4 +- .../apps/transfer/internal/convert/convert.go | 2 +- .../transfer/internal/convert/convert_test.go | 14 +-- .../apps/transfer/keeper/mbt_relay_test.go | 2 +- modules/apps/transfer/keeper/msg_server.go | 24 +++--- .../apps/transfer/keeper/msg_server_test.go | 13 +-- modules/apps/transfer/keeper/relay.go | 4 +- modules/apps/transfer/keeper/relay_test.go | 12 +-- modules/apps/transfer/types/events.go | 2 +- modules/apps/transfer/types/msgs.go | 2 +- modules/apps/transfer/types/packet.go | 2 +- modules/apps/transfer/types/packet.pb.go | 52 +++++------ modules/apps/transfer/types/packet_test.go | 42 ++++----- modules/apps/transfer/types/token.go | 22 +++++ modules/apps/transfer/types/token_test.go | 6 +- .../ibc/applications/transfer/v2/packet.proto | 4 +- 18 files changed, 151 insertions(+), 152 deletions(-) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 553f2fd4631..fa8ee5794ab 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -165,7 +165,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { transferICS4Wrapper := GetSimApp(s.chainA).TransferKeeper.GetICS4Wrapper() packetData = transfertypes.NewFungibleTokenPacketDataV2( - []*transfertypes.Token{ + []transfertypes.Token{ { Denom: ibctesting.TestCoin.GetDenom(), Amount: ibctesting.TestCoin.Amount.String(), @@ -307,7 +307,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { userGasLimit = 600000 packetData = transfertypes.NewFungibleTokenPacketDataV2( - []*transfertypes.Token{ + []transfertypes.Token{ { Denom: ibctesting.TestCoin.GetDenom(), Amount: ibctesting.TestCoin.Amount.String(), @@ -640,7 +640,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { // set user gas limit above panic level in mock contract keeper userGasLimit = 600_000 packetData = transfertypes.NewFungibleTokenPacketDataV2( - []*transfertypes.Token{ + []transfertypes.Token{ { Denom: ibctesting.TestCoin.GetDenom(), Amount: ibctesting.TestCoin.Amount.String(), @@ -772,7 +772,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { // set user gas limit above panic level in mock contract keeper packetData = transfertypes.NewFungibleTokenPacketDataV2( - []*transfertypes.Token{ + []transfertypes.Token{ { Denom: ibctesting.TestCoin.GetDenom(), Amount: ibctesting.TestCoin.Amount.String(), @@ -991,7 +991,7 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { } expPacketDataICS20V2 := transfertypes.FungibleTokenPacketDataV2{ - Tokens: []*transfertypes.Token{ + Tokens: []transfertypes.Token{ { Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 62a5b975506..21d3dd45160 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -224,17 +224,13 @@ func (im IBCModule) OnRecvPacket( } } - events := make([]sdk.Event, 0, len(data.Tokens)+1) - for _, token := range data.Tokens { - events = append(events, sdk.NewEvent( - types.EventTypePacket, - sdk.NewAttribute(types.AttributeKeySender, data.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), - sdk.NewAttribute(types.AttributeKeyDenom, token.GetFullDenomPath()), - sdk.NewAttribute(types.AttributeKeyAmount, token.Amount), - sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), - )) - } + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePacket, + sdk.NewAttribute(types.AttributeKeySender, data.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), + sdk.NewAttribute(types.AttributeKeyTokens, types.Tokens(data.Tokens).String()), + sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), + )) eventAttributes := []sdk.Attribute{ sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), @@ -244,13 +240,11 @@ func (im IBCModule) OnRecvPacket( eventAttributes = append(eventAttributes, sdk.NewAttribute(types.AttributeKeyAckError, ackErr.Error())) } - events = append(events, sdk.NewEvent( + ctx.EventManager().EmitEvent(sdk.NewEvent( sdk.EventTypeMessage, eventAttributes..., )) - ctx.EventManager().EmitEvents(events) - // NOTE: acknowledgement will be written synchronously during IBC handler execution. return ack } @@ -276,25 +270,20 @@ func (im IBCModule) OnAcknowledgementPacket( return err } - events := make([]sdk.Event, 0, len(data.Tokens)+1) - for _, token := range data.Tokens { - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypePacket, - sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), - sdk.NewAttribute(types.AttributeKeyDenom, token.GetFullDenomPath()), - sdk.NewAttribute(types.AttributeKeyAmount, token.Amount), - sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), - ), - ) - } - events = append(events, sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(types.AttributeKeyAck, ack.String()), - )) - ctx.EventManager().EmitEvents(events) + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypePacket, + sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), + sdk.NewAttribute(types.AttributeKeyTokens, types.Tokens(data.Tokens).String()), + sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeyAck, ack.String()), + ), + }) switch resp := ack.Response.(type) { case *channeltypes.Acknowledgement_Result: @@ -332,24 +321,19 @@ func (im IBCModule) OnTimeoutPacket( return err } - events := make([]sdk.Event, 0, len(data.Tokens)+1) - for _, token := range data.Tokens { - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeTimeout, - sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), - sdk.NewAttribute(types.AttributeKeyDenom, token.GetFullDenomPath()), - sdk.NewAttribute(types.AttributeKeyAmount, token.Amount), - sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), - ), - ) - } - events = append(events, sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - )) - ctx.EventManager().EmitEvents(events) + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeTimeout, + sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), + sdk.NewAttribute(types.AttributeKeyTokens, types.Tokens(data.Tokens).String()), + sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }) return nil } diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index a67b31bf255..ddb2dd5b238 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -554,7 +554,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { "success: valid packet data multidenom with memo", func() { initialPacketData = types.FungibleTokenPacketDataV2{ - Tokens: []*types.Token{ + Tokens: []types.Token{ { Denom: "atom", Amount: ibctesting.TestCoin.Amount.String(), @@ -574,7 +574,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { "success: valid packet data multidenom without memo", func() { initialPacketData = types.FungibleTokenPacketDataV2{ - Tokens: []*types.Token{ + Tokens: []types.Token{ { Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go index 3c39bdeb20b..686ae6119b8 100644 --- a/modules/apps/transfer/internal/convert/convert.go +++ b/modules/apps/transfer/internal/convert/convert.go @@ -14,7 +14,7 @@ func PacketDataV1ToV2(packetData types.FungibleTokenPacketData) types.FungibleTo v2Denom, trace := ExtractDenomAndTraceFromV1Denom(packetData.Denom) return types.FungibleTokenPacketDataV2{ - Tokens: []*types.Token{ + Tokens: []types.Token{ { Denom: v2Denom, Amount: packetData.Amount, diff --git a/modules/apps/transfer/internal/convert/convert_test.go b/modules/apps/transfer/internal/convert/convert_test.go index 5860f328e8c..10aecb3c33d 100644 --- a/modules/apps/transfer/internal/convert/convert_test.go +++ b/modules/apps/transfer/internal/convert/convert_test.go @@ -26,7 +26,7 @@ func TestConvertPacketV1ToPacketV2(t *testing.T) { "success", types.NewFungibleTokenPacketData("transfer/channel-0/atom", "1000", sender, receiver, ""), types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: "atom", Amount: "1000", @@ -39,7 +39,7 @@ func TestConvertPacketV1ToPacketV2(t *testing.T) { "success with empty trace", types.NewFungibleTokenPacketData("atom", "1000", sender, receiver, ""), types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: "atom", Amount: "1000", @@ -52,7 +52,7 @@ func TestConvertPacketV1ToPacketV2(t *testing.T) { "success: base denom with '/'", types.NewFungibleTokenPacketData("transfer/channel-0/atom/withslash", "1000", sender, receiver, ""), types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: "atom/withslash", Amount: "1000", @@ -65,7 +65,7 @@ func TestConvertPacketV1ToPacketV2(t *testing.T) { "success: base denom with '/' at the end", types.NewFungibleTokenPacketData("transfer/channel-0/atom/", "1000", sender, receiver, ""), types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: "atom/", Amount: "1000", @@ -78,7 +78,7 @@ func TestConvertPacketV1ToPacketV2(t *testing.T) { "success: longer trace base denom with '/'", types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/atom/pool", "1000", sender, receiver, ""), types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: "atom/pool", Amount: "1000", @@ -91,7 +91,7 @@ func TestConvertPacketV1ToPacketV2(t *testing.T) { "success: longer trace with non transfer port", types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/transfer-custom/channel-2/atom", "1000", sender, receiver, ""), types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: "atom", Amount: "1000", @@ -104,7 +104,7 @@ func TestConvertPacketV1ToPacketV2(t *testing.T) { "success: base denom with slash, trace with non transfer port", types.NewFungibleTokenPacketData("transfer/channel-0/transfer/channel-1/transfer-custom/channel-2/atom/pool", "1000", sender, receiver, ""), types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: "atom/pool", Amount: "1000", diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 6c0752e6b5f..d306643079a 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -151,7 +151,7 @@ func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPack DestChannel: packet.DestChannel, DestPort: packet.DestPort, Data: types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: packet.Data.Amount, diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 74bb202f521..e23672facb3 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -57,23 +57,21 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. return nil, err } - events := make([]sdk.Event, 0, len(tokens)+1) - for _, token := range tokens { - k.Logger(ctx).Info("IBC fungible token transfer", "token", token.Denom, "amount", token.Amount.String(), "sender", msg.Sender, "receiver", msg.Receiver) - events = append(events, sdk.NewEvent( + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( types.EventTypeTransfer, sdk.NewAttribute(types.AttributeKeySender, msg.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), - sdk.NewAttribute(types.AttributeKeyDenom, token.Denom), - sdk.NewAttribute(types.AttributeKeyAmount, token.Amount.String()), + sdk.NewAttribute(types.AttributeKeyTokens, tokens.String()), sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), - )) - } - events = append(events, sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - )) - ctx.EventManager().EmitEvents(events) + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }) + + k.Logger(ctx).Info("IBC fungible token transfer", "tokens", tokens, "sender", msg.Sender, "receiver", msg.Receiver) return &types.MsgTransferResponse{Sequence: sequence}, nil } diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index ae4aaef3107..e6d04001c4f 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -186,15 +186,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { sdk.NewAttribute(types.AttributeKeySender, msg.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), - sdk.NewAttribute(types.AttributeKeyDenom, coin1.Denom), - sdk.NewAttribute(types.AttributeKeyAmount, coin1.Amount.String()), - ), - sdk.NewEvent(types.EventTypeTransfer, - sdk.NewAttribute(types.AttributeKeySender, msg.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), - sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), - sdk.NewAttribute(types.AttributeKeyDenom, coin2.Denom), - sdk.NewAttribute(types.AttributeKeyAmount, coin2.Amount.String()), + sdk.NewAttribute(types.AttributeKeyTokens, sdk.NewCoins(coin1, coin2).String()), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -207,8 +199,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { sdk.NewAttribute(types.AttributeKeySender, msg.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), - sdk.NewAttribute(types.AttributeKeyDenom, coin1.Denom), - sdk.NewAttribute(types.AttributeKeyAmount, coin1.Amount.String()), + sdk.NewAttribute(types.AttributeKeyTokens, coin1.String()), ), sdk.NewEvent( sdk.EventTypeMessage, diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index bc5c39e5b3a..2c6dc104fbc 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -84,7 +84,7 @@ func (k Keeper) sendTransfer( return 0, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } - var tokens []*types.Token + var tokens []types.Token for _, coin := range coins { // NOTE: denomination and hex hash correctness checked during msg.ValidateBasic @@ -135,7 +135,7 @@ func (k Keeper) sendTransfer( } denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(fullDenomPath) - token := &types.Token{ + token := types.Token{ Denom: denom, Amount: coin.Amount.String(), Trace: trace, diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 5ed95db4bab..168a165cb6a 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -412,7 +412,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount.String(), @@ -495,7 +495,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount.String(), @@ -622,7 +622,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount.String(), @@ -715,7 +715,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount.String(), @@ -838,7 +838,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount.String(), @@ -924,7 +924,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTrace.GetFullDenomPath()) data := types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount.String(), diff --git a/modules/apps/transfer/types/events.go b/modules/apps/transfer/types/events.go index 20165a5e576..7a4bfaf2a04 100644 --- a/modules/apps/transfer/types/events.go +++ b/modules/apps/transfer/types/events.go @@ -11,7 +11,7 @@ const ( AttributeKeySender = "sender" AttributeKeyReceiver = "receiver" AttributeKeyDenom = "denom" - AttributeKeyAmount = "amount" + AttributeKeyTokens = "tokens" AttributeKeyRefundReceiver = "refund_receiver" AttributeKeyRefundDenom = "refund_denom" AttributeKeyRefundAmount = "refund_amount" diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 2994e841951..29bfff3e9bd 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -108,7 +108,7 @@ func (msg MsgTransfer) ValidateBasic() error { } // GetTokens returns the tokens which will be transferred. -func (msg MsgTransfer) GetTokens() []sdk.Coin { +func (msg MsgTransfer) GetTokens() sdk.Coins { tokens := msg.Tokens if isValidToken(msg.Token) { tokens = []sdk.Coin{msg.Token} diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 6ddf67cdbb5..81e46c72a53 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -99,7 +99,7 @@ func (ftpd FungibleTokenPacketData) GetCustomPacketData(key string) interface{} // NewFungibleTokenPacketDataV2 constructs a new NewFungibleTokenPacketDataV2 instance func NewFungibleTokenPacketDataV2( - tokens []*Token, + tokens []Token, sender, receiver string, memo string, ) FungibleTokenPacketDataV2 { diff --git a/modules/apps/transfer/types/packet.pb.go b/modules/apps/transfer/types/packet.pb.go index 020e16b93ef..94ef3c4a5a5 100644 --- a/modules/apps/transfer/types/packet.pb.go +++ b/modules/apps/transfer/types/packet.pb.go @@ -5,6 +5,7 @@ package types import ( fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" math "math" @@ -111,7 +112,7 @@ func (m *FungibleTokenPacketData) GetMemo() string { // https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures type FungibleTokenPacketDataV2 struct { // the tokens to be transferred - Tokens []*Token `protobuf:"bytes,1,rep,name=tokens,proto3" json:"tokens,omitempty"` + Tokens []Token `protobuf:"bytes,1,rep,name=tokens,proto3" json:"tokens"` // the sender address Sender string `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` // the recipient address on the destination chain @@ -153,7 +154,7 @@ func (m *FungibleTokenPacketDataV2) XXX_DiscardUnknown() { var xxx_messageInfo_FungibleTokenPacketDataV2 proto.InternalMessageInfo -func (m *FungibleTokenPacketDataV2) GetTokens() []*Token { +func (m *FungibleTokenPacketDataV2) GetTokens() []Token { if m != nil { return m.Tokens } @@ -256,28 +257,29 @@ func init() { } var fileDescriptor_653ca2ce9a5ca313 = []byte{ - // 325 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0x31, 0x4b, 0x03, 0x31, - 0x14, 0xc7, 0x9b, 0x5e, 0xaf, 0x68, 0xdc, 0x8e, 0xa2, 0x51, 0xe4, 0x28, 0x75, 0xa9, 0x83, 0x09, - 0x9c, 0x83, 0x82, 0x9b, 0x88, 0x8b, 0x8b, 0x16, 0x71, 0x70, 0xcb, 0xa5, 0xcf, 0x1a, 0xda, 0x24, - 0x47, 0x92, 0x3b, 0xf0, 0x53, 0xe8, 0x47, 0xf0, 0xe3, 0x38, 0x76, 0x74, 0x94, 0xf6, 0x8b, 0xc8, - 0xa5, 0x55, 0x6e, 0xa9, 0xe0, 0x96, 0xff, 0x3f, 0xff, 0xf7, 0xf8, 0x25, 0xef, 0xe1, 0x63, 0x99, - 0x0b, 0xc6, 0x8b, 0x62, 0x26, 0x05, 0xf7, 0xd2, 0x68, 0xc7, 0xbc, 0xe5, 0xda, 0x3d, 0x81, 0x65, - 0x55, 0xc6, 0x0a, 0x2e, 0xa6, 0xe0, 0x69, 0x61, 0x8d, 0x37, 0xc9, 0xa1, 0xcc, 0x05, 0x6d, 0x46, - 0xe9, 0x4f, 0x94, 0x56, 0xd9, 0xe0, 0x15, 0xe1, 0xbd, 0xeb, 0x52, 0x4f, 0x64, 0x3e, 0x83, 0x7b, - 0x33, 0x05, 0x7d, 0x1b, 0x6a, 0xaf, 0xb8, 0xe7, 0x49, 0x0f, 0xc7, 0x63, 0xd0, 0x46, 0x11, 0xd4, - 0x47, 0xc3, 0xed, 0xd1, 0x4a, 0x24, 0xbb, 0xb8, 0xcb, 0x95, 0x29, 0xb5, 0x27, 0xed, 0x60, 0xaf, - 0x55, 0xed, 0x3b, 0xd0, 0x63, 0xb0, 0x24, 0x5a, 0xf9, 0x2b, 0x95, 0x1c, 0xe0, 0x2d, 0x0b, 0x02, - 0x64, 0x05, 0x96, 0x74, 0xc2, 0xcd, 0xaf, 0x4e, 0x12, 0xdc, 0x51, 0xa0, 0x0c, 0x89, 0x83, 0x1f, - 0xce, 0x83, 0x77, 0x84, 0xf7, 0x37, 0x10, 0x3d, 0x64, 0xc9, 0x05, 0xee, 0xfa, 0xda, 0x74, 0x04, - 0xf5, 0xa3, 0xe1, 0x4e, 0x76, 0x44, 0xff, 0x7a, 0x1e, 0x0d, 0x0d, 0x46, 0xeb, 0x92, 0x06, 0x62, - 0x7b, 0x23, 0x62, 0xb4, 0x01, 0xb1, 0xd3, 0x40, 0xbc, 0xc1, 0x71, 0x68, 0xfc, 0xcf, 0x1f, 0xea, - 0xe1, 0xd8, 0x5b, 0x2e, 0x80, 0x44, 0xfd, 0xa8, 0x4e, 0x07, 0x71, 0x79, 0xf7, 0xb1, 0x48, 0xd1, - 0x7c, 0x91, 0xa2, 0xaf, 0x45, 0x8a, 0xde, 0x96, 0x69, 0x6b, 0xbe, 0x4c, 0x5b, 0x9f, 0xcb, 0xb4, - 0xf5, 0x78, 0x36, 0x91, 0xfe, 0xb9, 0xcc, 0xa9, 0x30, 0x8a, 0x09, 0xe3, 0x94, 0x71, 0x4c, 0xe6, - 0xe2, 0x64, 0x62, 0x58, 0x75, 0xce, 0x94, 0x19, 0x97, 0x33, 0x70, 0xf5, 0x12, 0x34, 0x86, 0xef, - 0x5f, 0x0a, 0x70, 0x79, 0x37, 0x4c, 0xfe, 0xf4, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x65, 0x55, 0xb8, - 0x16, 0x26, 0x02, 0x00, 0x00, + // 344 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xb1, 0x4e, 0xfb, 0x30, + 0x10, 0xc6, 0xe3, 0x26, 0xa9, 0xfe, 0x7f, 0xb3, 0x45, 0x15, 0x84, 0x0a, 0x85, 0xaa, 0x2c, 0x65, + 0x20, 0x96, 0xc2, 0x00, 0x2b, 0x15, 0x62, 0x61, 0x81, 0x0a, 0x31, 0xb0, 0x39, 0xee, 0x11, 0xac, + 0x36, 0xb9, 0x28, 0x76, 0x22, 0xf1, 0x14, 0xf0, 0x14, 0x3c, 0x4b, 0xc7, 0x8e, 0x4c, 0x08, 0xb5, + 0x2f, 0x82, 0xe2, 0x14, 0x94, 0xa5, 0x48, 0x6c, 0xf7, 0x7d, 0xfe, 0xee, 0xf4, 0xb3, 0x7d, 0xf4, + 0x58, 0xc6, 0x82, 0xf1, 0x3c, 0x9f, 0x4b, 0xc1, 0xb5, 0xc4, 0x4c, 0x31, 0x5d, 0xf0, 0x4c, 0x3d, + 0x42, 0xc1, 0xaa, 0x88, 0xe5, 0x5c, 0xcc, 0x40, 0x87, 0x79, 0x81, 0x1a, 0xbd, 0x03, 0x19, 0x8b, + 0xb0, 0x1d, 0x0d, 0xbf, 0xa3, 0x61, 0x15, 0xf5, 0x7b, 0x09, 0x26, 0x68, 0x82, 0xac, 0xae, 0x9a, + 0x9e, 0xe1, 0x0b, 0xa1, 0x7b, 0x57, 0x65, 0x96, 0xc8, 0x78, 0x0e, 0x77, 0x38, 0x83, 0xec, 0xc6, + 0x4c, 0xbc, 0xe4, 0x9a, 0x7b, 0x3d, 0xea, 0x4e, 0x21, 0xc3, 0xd4, 0x27, 0x03, 0x32, 0xfa, 0x3f, + 0x69, 0x84, 0xb7, 0x4b, 0xbb, 0x3c, 0xc5, 0x32, 0xd3, 0x7e, 0xc7, 0xd8, 0x1b, 0x55, 0xfb, 0x0a, + 0xb2, 0x29, 0x14, 0xbe, 0xdd, 0xf8, 0x8d, 0xf2, 0xfa, 0xf4, 0x5f, 0x01, 0x02, 0x64, 0x05, 0x85, + 0xef, 0x98, 0x93, 0x1f, 0xed, 0x79, 0xd4, 0x49, 0x21, 0x45, 0xdf, 0x35, 0xbe, 0xa9, 0x87, 0x6f, + 0x84, 0xee, 0x6f, 0x21, 0xba, 0x8f, 0xbc, 0x0b, 0xda, 0xd5, 0xb5, 0xa9, 0x7c, 0x32, 0xb0, 0x47, + 0x3b, 0xd1, 0x51, 0xf8, 0xdb, 0xa5, 0x43, 0x33, 0x60, 0xec, 0x2c, 0x3e, 0x0e, 0xad, 0xc9, 0xa6, + 0xb1, 0x05, 0xda, 0xd9, 0x0a, 0x6a, 0x6f, 0x01, 0x75, 0x5a, 0xa0, 0xd7, 0xd4, 0x35, 0xe3, 0xff, + 0xf8, 0x4e, 0x3d, 0xea, 0xea, 0x82, 0x0b, 0xf0, 0xed, 0x81, 0x5d, 0xa7, 0x8d, 0x18, 0xdf, 0x2e, + 0x56, 0x01, 0x59, 0xae, 0x02, 0xf2, 0xb9, 0x0a, 0xc8, 0xeb, 0x3a, 0xb0, 0x96, 0xeb, 0xc0, 0x7a, + 0x5f, 0x07, 0xd6, 0xc3, 0x59, 0x22, 0xf5, 0x53, 0x19, 0x87, 0x02, 0x53, 0x26, 0x50, 0xa5, 0xa8, + 0x98, 0x8c, 0xc5, 0x49, 0x82, 0xac, 0x3a, 0x67, 0x29, 0x4e, 0xcb, 0x39, 0xa8, 0x7a, 0x41, 0x5a, + 0x8b, 0xa1, 0x9f, 0x73, 0x50, 0x71, 0xd7, 0xfc, 0xf0, 0xe9, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xe1, 0x0d, 0x6c, 0x28, 0x42, 0x02, 0x00, 0x00, } func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { @@ -806,7 +808,7 @@ func (m *FungibleTokenPacketDataV2) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Tokens = append(m.Tokens, &Token{}) + m.Tokens = append(m.Tokens, Token{}) if err := m.Tokens[len(m.Tokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 759253ccfec..9292f207f7f 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -171,7 +171,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "success: valid packet", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -187,7 +187,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "success: valid packet with memo", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -203,7 +203,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "success: valid packet with large amount", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: largeAmount, @@ -219,7 +219,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "failure: invalid denom", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: "", Amount: amount, @@ -235,7 +235,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "failure: invalid empty amount", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: "", @@ -251,7 +251,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "failure: invalid empty token array", types.NewFungibleTokenPacketDataV2( - []*types.Token{}, + []types.Token{}, sender, receiver, "", @@ -261,7 +261,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "failure: invalid zero amount", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: "0", @@ -277,7 +277,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "failure: invalid negative amount", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: "-100", @@ -293,7 +293,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "failure: invalid large amount", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: invalidLargeAmount, @@ -309,7 +309,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "failure: missing sender address", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -325,7 +325,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { { "failure: missing recipient address", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -363,7 +363,7 @@ func TestGetPacketSender(t *testing.T) { { "non-empty sender field", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -379,7 +379,7 @@ func TestGetPacketSender(t *testing.T) { { "empty sender field", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -410,7 +410,7 @@ func TestPacketDataProvider(t *testing.T) { { "success: src_callback key in memo", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -428,7 +428,7 @@ func TestPacketDataProvider(t *testing.T) { { "success: src_callback key in memo with additional fields", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -446,7 +446,7 @@ func TestPacketDataProvider(t *testing.T) { { "success: src_callback has string value", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -461,7 +461,7 @@ func TestPacketDataProvider(t *testing.T) { { "failure: src_callback key not found memo", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -476,7 +476,7 @@ func TestPacketDataProvider(t *testing.T) { { "failure: empty memo", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -491,7 +491,7 @@ func TestPacketDataProvider(t *testing.T) { { "failure: non-json memo", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -522,7 +522,7 @@ func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { { "empty memo field, resulting marshalled bytes should not contain the memo field", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, @@ -538,7 +538,7 @@ func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { { "non-empty memo field, resulting marshalled bytes should contain the memo field", types.NewFungibleTokenPacketDataV2( - []*types.Token{ + []types.Token{ { Denom: denom, Amount: amount, diff --git a/modules/apps/transfer/types/token.go b/modules/apps/transfer/types/token.go index bdfb7880577..a91dbb97792 100644 --- a/modules/apps/transfer/types/token.go +++ b/modules/apps/transfer/types/token.go @@ -37,3 +37,25 @@ func (t Token) GetFullDenomPath() string { return strings.Join(append(t.Trace, t.Denom), "/") } + +// Tokens is a set of Token +type Tokens []Token + +// String prints out the tokens array as a string. +// If the array is empty, an empty string is returned +func (tokens Tokens) String() string { + if len(tokens) == 0 { + return "" + } else if len(tokens) == 1 { + return tokens[0].String() + } + + var out strings.Builder + for _, token := range tokens[:len(tokens)-1] { + out.WriteString(token.String()) // nolint:revive // no error returned by WriteString + out.WriteByte(',') //nolint:revive // no error returned by WriteByte + + } + out.WriteString(tokens[len(tokens)-1].String()) //nolint:revive + return out.String() +} diff --git a/modules/apps/transfer/types/token_test.go b/modules/apps/transfer/types/token_test.go index deb468e7066..afc008b6ed1 100644 --- a/modules/apps/transfer/types/token_test.go +++ b/modules/apps/transfer/types/token_test.go @@ -29,7 +29,7 @@ func TestGetFullDenomPath(t *testing.T) { { "denom path with trace", NewFungibleTokenPacketDataV2( - []*Token{ + []Token{ { Denom: denom, Amount: amount, @@ -45,7 +45,7 @@ func TestGetFullDenomPath(t *testing.T) { { "nil trace", NewFungibleTokenPacketDataV2( - []*Token{ + []Token{ { Denom: denom, Amount: amount, @@ -61,7 +61,7 @@ func TestGetFullDenomPath(t *testing.T) { { "empty string trace", NewFungibleTokenPacketDataV2( - []*Token{ + []Token{ { Denom: denom, Amount: amount, diff --git a/proto/ibc/applications/transfer/v2/packet.proto b/proto/ibc/applications/transfer/v2/packet.proto index 4dfaf107062..3614bcb85ed 100644 --- a/proto/ibc/applications/transfer/v2/packet.proto +++ b/proto/ibc/applications/transfer/v2/packet.proto @@ -4,6 +4,8 @@ package ibc.applications.transfer.v2; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; +import "gogoproto/gogo.proto"; + // FungibleTokenPacketData defines a struct for the packet payload // See FungibleTokenPacketData spec: // https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures @@ -25,7 +27,7 @@ message FungibleTokenPacketData { // https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures message FungibleTokenPacketDataV2 { // the tokens to be transferred - repeated Token tokens = 1; + repeated Token tokens = 1 [(gogoproto.nullable) = false]; // the sender address string sender = 2; // the recipient address on the destination chain From 43877df24f1f4f9c79d85ef1481e01d4cfc67a92 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 22 May 2024 11:23:50 +0200 Subject: [PATCH 041/141] imp: check length tokens array against maximum allowed (#6349) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * check length of tokens array against maximum allowed * chore: add note on arbitrary selection --------- Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> --- modules/apps/transfer/types/msgs.go | 5 +++++ modules/apps/transfer/types/msgs_test.go | 1 + 2 files changed, 6 insertions(+) diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 29bfff3e9bd..85e10c4db31 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -15,6 +15,7 @@ import ( const ( MaximumReceiverLength = 2048 // maximum length of the receiver address in bytes (value chosen arbitrarily) MaximumMemoLength = 32768 // maximum length of the memo in bytes (value chosen arbitrarily) + MaximumTokensLength = 100 // maximum number of tokens that can be transferred in a single message (value chosen arbitrarily) ) var ( @@ -81,6 +82,10 @@ func (msg MsgTransfer) ValidateBasic() error { return errorsmod.Wrap(ErrInvalidAmount, "cannot fill both token and token array") } + if len(msg.Tokens) > MaximumTokensLength { + return errorsmod.Wrapf(ibcerrors.ErrInvalidCoins, "number of tokens must not exceed %d", MaximumTokensLength) + } + _, err := sdk.AccAddressFromBech32(msg.Sender) if err != nil { return errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "string could not be parsed as address: %v", err) diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index e98400bfa45..602551980c6 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -74,6 +74,7 @@ func TestMsgTransferValidation(t *testing.T) { {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, ""), false}, {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, ""), false}, {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, ""), false}, + {"multidenom: too many coins", types.NewMsgTransfer(validPort, validChannel, make([]sdk.Coin, types.MaximumTokensLength+1), sender, receiver, timeoutHeight, 0, ""), false}, } for i, tc := range testCases { From 8eae033732183be839b3d368a6b97720768e7b3b Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Wed, 22 May 2024 13:29:10 +0300 Subject: [PATCH 042/141] Modify UnmarshalPacketData interface to allow additional args (#6341) * api(port)!: Allow passing of context, port and channel identifier to unmarshal packet data interface as disussed. This allows us to grab the app version in transfer and unmarshal the packet based on that instead of a hacky unmarshal v2 then v1 and whatever happens. * lint: as we do * callbacks: fix signature of UnmarshalPacketData as per changes, make refactors to hopefully simplify signatures. * chore: lint and remove some todos. * review: address feedback. --- .../controller/ibc_middleware.go | 2 +- .../controller/ibc_middleware_test.go | 6 ++-- .../27-interchain-accounts/host/ibc_module.go | 2 +- .../host/ibc_module_test.go | 6 ++-- modules/apps/29-fee/ibc_middleware.go | 4 +-- modules/apps/29-fee/ibc_middleware_test.go | 6 ++-- modules/apps/callbacks/callbacks_test.go | 15 ++++++-- modules/apps/callbacks/ibc_middleware.go | 22 ++++++++---- modules/apps/callbacks/ibc_middleware_test.go | 17 +++++---- modules/apps/callbacks/types/callbacks.go | 35 ++++++++++++------- .../apps/callbacks/types/callbacks_test.go | 33 +++++++++++++++-- modules/apps/callbacks/types/export_test.go | 13 ------- modules/apps/transfer/ibc_module.go | 2 +- modules/apps/transfer/ibc_module_test.go | 2 +- modules/core/05-port/types/module.go | 2 +- testing/mock/ibc_module.go | 2 +- 16 files changed, 110 insertions(+), 59 deletions(-) diff --git a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go index fe9ef65a026..dc27eeda2d8 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware.go @@ -340,7 +340,7 @@ func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) // UnmarshalPacketData attempts to unmarshal the provided packet data bytes // into an InterchainAccountPacketData. This function implements the optional // PacketDataUnmarshaler interface required for ADR 008 support. -func (IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { +func (IBCMiddleware) UnmarshalPacketData(_ sdk.Context, _, _ string, bz []byte) (interface{}, error) { var data icatypes.InterchainAccountPacketData err := data.UnmarshalJSON(bz) if err != 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 95a25ac65a9..e9ab95cc1b9 100644 --- a/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go +++ b/modules/apps/27-interchain-accounts/controller/ibc_middleware_test.go @@ -1276,13 +1276,15 @@ func (suite *InterchainAccountsTestSuite) TestPacketDataUnmarshalerInterface() { Memo: "", } - packetData, err := controller.IBCMiddleware{}.UnmarshalPacketData(expPacketData.GetBytes()) + // Context, port identifier and channel identifier are unused for controller. + packetData, err := controller.IBCMiddleware{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", expPacketData.GetBytes()) suite.Require().NoError(err) suite.Require().Equal(expPacketData, packetData) // test invalid packet data invalidPacketData := []byte("invalid packet data") - packetData, err = controller.IBCMiddleware{}.UnmarshalPacketData(invalidPacketData) + // Context, port identifier and channel identifier are not used for controller. + packetData, err = controller.IBCMiddleware{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", invalidPacketData) suite.Require().Error(err) suite.Require().Nil(packetData) } diff --git a/modules/apps/27-interchain-accounts/host/ibc_module.go b/modules/apps/27-interchain-accounts/host/ibc_module.go index 3829a4c9acd..099e51e92cd 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module.go @@ -183,7 +183,7 @@ func (IBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, pr // UnmarshalPacketData attempts to unmarshal the provided packet data bytes // into an InterchainAccountPacketData. This function implements the optional // PacketDataUnmarshaler interface required for ADR 008 support. -func (IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { +func (IBCModule) UnmarshalPacketData(_ sdk.Context, _, _ string, bz []byte) (interface{}, error) { var data icatypes.InterchainAccountPacketData err := data.UnmarshalJSON(bz) if err != nil { 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 98dbb2b36a0..9ffb67a8f4d 100644 --- a/modules/apps/27-interchain-accounts/host/ibc_module_test.go +++ b/modules/apps/27-interchain-accounts/host/ibc_module_test.go @@ -883,13 +883,15 @@ func (suite *InterchainAccountsTestSuite) TestPacketDataUnmarshalerInterface() { Memo: "", } - packetData, err := icahost.IBCModule{}.UnmarshalPacketData(expPacketData.GetBytes()) + // Context, port identifier and channel identifier are unused for host. + packetData, err := icahost.IBCModule{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", expPacketData.GetBytes()) suite.Require().NoError(err) suite.Require().Equal(expPacketData, packetData) // test invalid packet data invalidPacketData := []byte("invalid packet data") - packetData, err = icahost.IBCModule{}.UnmarshalPacketData(invalidPacketData) + // Context, port identifier and channel identifier are unused for host. + packetData, err = icahost.IBCModule{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", invalidPacketData) suite.Require().Error(err) suite.Require().Nil(packetData) } diff --git a/modules/apps/29-fee/ibc_middleware.go b/modules/apps/29-fee/ibc_middleware.go index 218efb08882..671206eab8f 100644 --- a/modules/apps/29-fee/ibc_middleware.go +++ b/modules/apps/29-fee/ibc_middleware.go @@ -472,11 +472,11 @@ func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) // UnmarshalPacketData attempts to use the underlying app to unmarshal the packet data. // If the underlying app does not support the PacketDataUnmarshaler interface, an error is returned. // This function implements the optional PacketDataUnmarshaler interface required for ADR 008 support. -func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { +func (im IBCMiddleware) UnmarshalPacketData(ctx sdk.Context, portID, channelID string, bz []byte) (interface{}, error) { unmarshaler, ok := im.app.(porttypes.PacketDataUnmarshaler) if !ok { return nil, errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketDataUnmarshaler)(nil)) } - return unmarshaler.UnmarshalPacketData(bz) + return unmarshaler.UnmarshalPacketData(ctx, portID, channelID, bz) } diff --git a/modules/apps/29-fee/ibc_middleware_test.go b/modules/apps/29-fee/ibc_middleware_test.go index fc16fd900fc..dc59f277d3f 100644 --- a/modules/apps/29-fee/ibc_middleware_test.go +++ b/modules/apps/29-fee/ibc_middleware_test.go @@ -1573,7 +1573,8 @@ func (suite *FeeTestSuite) TestPacketDataUnmarshalerInterface() { feeModule, ok := cbs.(porttypes.PacketDataUnmarshaler) suite.Require().True(ok) - packetData, err := feeModule.UnmarshalPacketData(ibcmock.MockPacketData) + // Context, port identifier, channel identifier are not used in current wiring of fee. + packetData, err := feeModule.UnmarshalPacketData(suite.chainA.GetContext(), "", "", ibcmock.MockPacketData) suite.Require().NoError(err) suite.Require().Equal(ibcmock.MockPacketData, packetData) } @@ -1582,7 +1583,8 @@ func (suite *FeeTestSuite) TestPacketDataUnmarshalerInterfaceError() { // test the case when the underlying application cannot be casted to a PacketDataUnmarshaler mockFeeMiddleware := ibcfee.NewIBCMiddleware(nil, feekeeper.Keeper{}) - _, err := mockFeeMiddleware.UnmarshalPacketData(ibcmock.MockPacketData) + // Context, port identifier, channel identifier are not used in mockFeeMiddleware. + _, err := mockFeeMiddleware.UnmarshalPacketData(suite.chainA.GetContext(), "", "", ibcmock.MockPacketData) expError := errorsmod.Wrapf(types.ErrUnsupportedAction, "underlying app does not implement %T", (*porttypes.PacketDataUnmarshaler)(nil)) suite.Require().ErrorIs(err, expError) } diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index 5c8ba271a9f..ef88db93483 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -11,6 +11,7 @@ import ( "cosmossdk.io/log" sdkmath "cosmossdk.io/math" + storetypes "cosmossdk.io/store/types" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" @@ -24,6 +25,7 @@ import ( icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" transfertypes "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" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -291,17 +293,24 @@ func (s *CallbacksTestSuite) AssertHasExecutedExpectedCallbackWithFee( // GetExpectedEvent returns the expected event for a callback. func GetExpectedEvent( - packetDataUnmarshaler porttypes.PacketDataUnmarshaler, remainingGas uint64, data []byte, srcPortID, + ctx sdk.Context, packetDataUnmarshaler porttypes.PacketDataUnmarshaler, remainingGas uint64, data []byte, srcPortID, eventPortID, eventChannelID string, seq uint64, callbackType types.CallbackType, expError error, ) (abci.Event, bool) { var ( callbackData types.CallbackData err error ) + + // Set up gas meter with remainingGas. + gasMeter := storetypes.NewGasMeter(remainingGas) + ctx = ctx.WithGasMeter(gasMeter) + + // Mock packet. + packet := channeltypes.NewPacket(data, 0, srcPortID, "", "", "", clienttypes.ZeroHeight(), 0) if callbackType == types.CallbackTypeReceivePacket { - callbackData, err = types.GetDestCallbackData(packetDataUnmarshaler, data, srcPortID, remainingGas, maxCallbackGas) + callbackData, err = types.GetDestCallbackData(ctx, packetDataUnmarshaler, packet, maxCallbackGas) } else { - callbackData, err = types.GetSourceCallbackData(packetDataUnmarshaler, data, srcPortID, remainingGas, maxCallbackGas) + callbackData, err = types.GetSourceCallbackData(ctx, packetDataUnmarshaler, packet, maxCallbackGas) } if err != nil { return abci.Event{}, false diff --git a/modules/apps/callbacks/ibc_middleware.go b/modules/apps/callbacks/ibc_middleware.go index 0ab1f5f9887..816305913d8 100644 --- a/modules/apps/callbacks/ibc_middleware.go +++ b/modules/apps/callbacks/ibc_middleware.go @@ -99,7 +99,10 @@ func (im IBCMiddleware) SendPacket( return 0, err } - callbackData, err := types.GetSourceCallbackData(im.app, data, sourcePort, ctx.GasMeter().GasRemaining(), im.maxCallbackGas) + // packet is created withouth destination information present, GetSourceCallbackData does not use these. + packet := channeltypes.NewPacket(data, seq, sourcePort, sourceChannel, "", "", timeoutHeight, timeoutTimestamp) + + callbackData, err := types.GetSourceCallbackData(ctx, im.app, packet, im.maxCallbackGas) // SendPacket is not blocked if the packet does not opt-in to callbacks if err != nil { return seq, nil @@ -138,7 +141,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket( } callbackData, err := types.GetSourceCallbackData( - im.app, packet.GetData(), packet.GetSourcePort(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas, + ctx, im.app, packet, im.maxCallbackGas, ) // OnAcknowledgementPacket is not blocked if the packet does not opt-in to callbacks if err != nil { @@ -172,7 +175,7 @@ func (im IBCMiddleware) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Pac } callbackData, err := types.GetSourceCallbackData( - im.app, packet.GetData(), packet.GetSourcePort(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas, + ctx, im.app, packet, im.maxCallbackGas, ) // OnTimeoutPacket is not blocked if the packet does not opt-in to callbacks if err != nil { @@ -208,7 +211,7 @@ func (im IBCMiddleware) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet } callbackData, err := types.GetDestCallbackData( - im.app, packet.GetData(), packet.GetSourcePort(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas, + ctx, im.app, packet, im.maxCallbackGas, ) // OnRecvPacket is not blocked if the packet does not opt-in to callbacks if err != nil { @@ -245,8 +248,13 @@ func (im IBCMiddleware) WriteAcknowledgement( return err } + chanPacket, ok := packet.(channeltypes.Packet) + if !ok { + panic(fmt.Errorf("expected type %T, got %T", &channeltypes.Packet{}, packet)) + } + callbackData, err := types.GetDestCallbackData( - im.app, packet.GetData(), packet.GetSourcePort(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas, + ctx, im.app, chanPacket, im.maxCallbackGas, ) // WriteAcknowledgement is not blocked if the packet does not opt-in to callbacks if err != nil { @@ -417,6 +425,6 @@ func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) // UnmarshalPacketData defers to the underlying app to unmarshal the packet data. // This function implements the optional PacketDataUnmarshaler interface. -func (im IBCMiddleware) UnmarshalPacketData(bz []byte) (interface{}, error) { - return im.app.UnmarshalPacketData(bz) +func (im IBCMiddleware) UnmarshalPacketData(ctx sdk.Context, portID, channelID string, bz []byte) (interface{}, error) { + return im.app.UnmarshalPacketData(ctx, portID, channelID, bz) } diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index fa8ee5794ab..0b487d93611 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -200,7 +200,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { s.Require().Equal(uint64(1), seq) expEvent, exists := GetExpectedEvent( - transferICS4Wrapper.(porttypes.PacketDataUnmarshaler), gasLimit, packetData.GetBytes(), s.path.EndpointA.ChannelConfig.PortID, + ctx, transferICS4Wrapper.(porttypes.PacketDataUnmarshaler), gasLimit, packetData.GetBytes(), s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID, seq, types.CallbackTypeSendPacket, nil, ) if exists { @@ -381,7 +381,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { s.Require().Equal(uint8(1), sourceStatefulCounter) expEvent, exists := GetExpectedEvent( - transferStack.(porttypes.PacketDataUnmarshaler), gasLimit, packet.Data, packet.SourcePort, + ctx, transferStack.(porttypes.PacketDataUnmarshaler), gasLimit, packet.Data, packet.SourcePort, packet.SourcePort, packet.SourceChannel, packet.Sequence, types.CallbackTypeAcknowledgementPacket, nil, ) s.Require().True(exists) @@ -543,7 +543,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { s.Require().Equal(uint8(2), sourceStatefulCounter) expEvent, exists := GetExpectedEvent( - transferStack.(porttypes.PacketDataUnmarshaler), gasLimit, packet.Data, packet.SourcePort, + ctx, transferStack.(porttypes.PacketDataUnmarshaler), gasLimit, packet.Data, packet.SourcePort, packet.SourcePort, packet.SourceChannel, packet.Sequence, types.CallbackTypeTimeoutPacket, nil, ) s.Require().True(exists) @@ -712,7 +712,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { s.Require().Equal(uint8(1), destStatefulCounter) expEvent, exists := GetExpectedEvent( - transferStack.(porttypes.PacketDataUnmarshaler), gasLimit, packet.Data, packet.SourcePort, + ctx, transferStack.(porttypes.PacketDataUnmarshaler), gasLimit, packet.Data, packet.SourcePort, packet.DestinationPort, packet.DestinationChannel, packet.Sequence, types.CallbackTypeReceivePacket, nil, ) s.Require().True(exists) @@ -814,7 +814,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { s.Require().NoError(err) expEvent, exists := GetExpectedEvent( - transferICS4Wrapper.(porttypes.PacketDataUnmarshaler), gasLimit, packet.Data, packet.SourcePort, + ctx, transferICS4Wrapper.(porttypes.PacketDataUnmarshaler), gasLimit, packet.Data, packet.SourcePort, packet.DestinationPort, packet.DestinationChannel, packet.Sequence, types.CallbackTypeReceivePacket, nil, ) if exists { @@ -1003,15 +1003,18 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), } + portID := s.path.EndpointA.ChannelConfig.PortID + channelID := s.path.EndpointA.ChannelID + // Unmarshal ICS20 v1 packet data data := expPacketDataICS20V1.GetBytes() - packetData, err := unmarshalerStack.UnmarshalPacketData(data) + packetData, err := unmarshalerStack.UnmarshalPacketData(s.chainA.GetContext(), portID, channelID, data) s.Require().NoError(err) s.Require().Equal(expPacketDataICS20V2, packetData) // Unmarshal ICS20 v1 packet data data = expPacketDataICS20V2.GetBytes() - packetData, err = unmarshalerStack.UnmarshalPacketData(data) + packetData, err = unmarshalerStack.UnmarshalPacketData(s.chainA.GetContext(), portID, channelID, data) s.Require().NoError(err) s.Require().Equal(expPacketDataICS20V2, packetData) } diff --git a/modules/apps/callbacks/types/callbacks.go b/modules/apps/callbacks/types/callbacks.go index 03c4128fb31..b7eaabec93b 100644 --- a/modules/apps/callbacks/types/callbacks.go +++ b/modules/apps/callbacks/types/callbacks.go @@ -6,6 +6,9 @@ import ( errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/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" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -67,18 +70,31 @@ type CallbackData struct { // GetSourceCallbackData parses the packet data and returns the source callback data. func GetSourceCallbackData( + ctx sdk.Context, packetDataUnmarshaler porttypes.PacketDataUnmarshaler, - data []byte, srcPortID string, remainingGas uint64, maxGas uint64, + packet channeltypes.Packet, + maxGas uint64, ) (CallbackData, error) { - return getCallbackData(packetDataUnmarshaler, data, srcPortID, remainingGas, maxGas, SourceCallbackKey) + packetData, err := packetDataUnmarshaler.UnmarshalPacketData(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetData()) + if err != nil { + return CallbackData{}, errorsmod.Wrap(ErrCannotUnmarshalPacketData, err.Error()) + } + + return getCallbackData(packetData, packet.GetSourcePort(), ctx.GasMeter().GasRemaining(), maxGas, SourceCallbackKey) } // GetDestCallbackData parses the packet data and returns the destination callback data. func GetDestCallbackData( + ctx sdk.Context, packetDataUnmarshaler porttypes.PacketDataUnmarshaler, - data []byte, srcPortID string, remainingGas, maxGas uint64, + packet channeltypes.Packet, maxGas uint64, ) (CallbackData, error) { - return getCallbackData(packetDataUnmarshaler, data, srcPortID, remainingGas, maxGas, DestinationCallbackKey) + packetData, err := packetDataUnmarshaler.UnmarshalPacketData(ctx, packet.GetDestPort(), packet.GetDestChannel(), packet.GetData()) + if err != nil { + return CallbackData{}, errorsmod.Wrap(ErrCannotUnmarshalPacketData, err.Error()) + } + + return getCallbackData(packetData, packet.GetSourcePort(), ctx.GasMeter().GasRemaining(), maxGas, DestinationCallbackKey) } // getCallbackData parses the packet data and returns the callback data. @@ -86,16 +102,11 @@ func GetDestCallbackData( // The addressGetter and gasLimitGetter functions are used to retrieve the callback // address and gas limit from the callback data. func getCallbackData( - packetDataUnmarshaler porttypes.PacketDataUnmarshaler, - data []byte, srcPortID string, remainingGas, + packetData interface{}, + srcPortID string, + remainingGas, maxGas uint64, callbackKey string, ) (CallbackData, error) { - // unmarshal packet data - packetData, err := packetDataUnmarshaler.UnmarshalPacketData(data) - if err != nil { - return CallbackData{}, errorsmod.Wrap(ErrCannotUnmarshalPacketData, err.Error()) - } - packetDataProvider, ok := packetData.(ibcexported.PacketDataProvider) if !ok { return CallbackData{}, ErrNotPacketDataProvider diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 4521afc0a41..754118dda90 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -3,6 +3,8 @@ package types_test import ( "fmt" + storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cometbft/cometbft/crypto/secp256k1" @@ -10,6 +12,8 @@ import ( "github.com/cosmos/ibc-go/modules/apps/callbacks/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer" transfertypes "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" ibctesting "github.com/cosmos/ibc-go/v8/testing" ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" @@ -277,7 +281,21 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { tc.malleate() - callbackData, err := types.GetCallbackData(packetDataUnmarshaler, packetData, ibcmock.PortID, remainingGas, uint64(1_000_000), callbackKey) + // Set up gas meter for context. + gasMeter := storetypes.NewGasMeter(remainingGas) + ctx := s.chain.GetContext().WithGasMeter(gasMeter) + + packet := channeltypes.NewPacket(packetData, 0, ibcmock.PortID, "", "", "", clienttypes.ZeroHeight(), 0) + + var ( + callbackData types.CallbackData + err error + ) + if callbackKey == types.DestinationCallbackKey { + callbackData, err = types.GetDestCallbackData(ctx, packetDataUnmarshaler, packet, uint64(1_000_000)) + } else { + callbackData, err = types.GetSourceCallbackData(ctx, packetDataUnmarshaler, packet, uint64(1_000_000)) + } expPass := tc.expError == nil if expPass { @@ -315,7 +333,12 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { packetUnmarshaler := transfer.IBCModule{} - callbackData, err := types.GetSourceCallbackData(packetUnmarshaler, packetDataBytes, ibcmock.PortID, 2_000_000, 1_000_000) + // Set up gas meter for context. + gasMeter := storetypes.NewGasMeter(2_000_000) + ctx := s.chain.GetContext().WithGasMeter(gasMeter) + + packet := channeltypes.NewPacket(packetDataBytes, 0, ibcmock.PortID, "", "", "", clienttypes.ZeroHeight(), 0) + callbackData, err := types.GetSourceCallbackData(ctx, packetUnmarshaler, packet, 1_000_000) s.Require().NoError(err) s.Require().Equal(expCallbackData, callbackData) } @@ -342,7 +365,11 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { packetUnmarshaler := transfer.IBCModule{} - callbackData, err := types.GetDestCallbackData(packetUnmarshaler, packetDataBytes, ibcmock.PortID, 2_000_000, 1_000_000) + gasMeter := storetypes.NewGasMeter(2_000_000) + ctx := s.chain.GetContext().WithGasMeter(gasMeter) + + packet := channeltypes.NewPacket(packetDataBytes, 0, ibcmock.PortID, "", "", "", clienttypes.ZeroHeight(), 0) + callbackData, err := types.GetDestCallbackData(ctx, packetUnmarshaler, packet, 1_000_000) s.Require().NoError(err) s.Require().Equal(expCallbackData, callbackData) } diff --git a/modules/apps/callbacks/types/export_test.go b/modules/apps/callbacks/types/export_test.go index 5ba59bed4ca..5b0a32508e3 100644 --- a/modules/apps/callbacks/types/export_test.go +++ b/modules/apps/callbacks/types/export_test.go @@ -1,22 +1,9 @@ package types -import ( - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" -) - /* This file is to allow for unexported functions to be accessible to the testing package. */ -// GetCallbackData is a wrapper around getCallbackData to allow the function to be directly called in tests. -func GetCallbackData( - packetDataUnmarshaler porttypes.PacketDataUnmarshaler, - packetData []byte, srcPortID string, remainingGas, - maxGas uint64, callbackKey string, -) (CallbackData, error) { - return getCallbackData(packetDataUnmarshaler, packetData, srcPortID, remainingGas, maxGas, callbackKey) -} - // GetCallbackAddress is a wrapper around getCallbackAddress to allow the function to be directly called in tests. func GetCallbackAddress(callbackData map[string]interface{}) string { return getCallbackAddress(callbackData) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 21d3dd45160..a58e777a3e8 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -380,7 +380,7 @@ func (IBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, pr // 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 (im IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { +func (im IBCModule) UnmarshalPacketData(_ sdk.Context, _, _ string, bz []byte) (interface{}, error) { ftpd, err := im.unmarshalPacketDataBytesToICS20V2(bz) if err != nil { return nil, err diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index ddb2dd5b238..46a2302ff8e 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -604,7 +604,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { suite.Run(tc.name, func() { tc.malleate() - packetData, err := transfer.IBCModule{}.UnmarshalPacketData(data) + packetData, err := transfer.IBCModule{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", data) expPass := tc.expError == nil if expPass { diff --git a/modules/core/05-port/types/module.go b/modules/core/05-port/types/module.go index 23fc5705233..994a90fa17b 100644 --- a/modules/core/05-port/types/module.go +++ b/modules/core/05-port/types/module.go @@ -194,5 +194,5 @@ type Middleware interface { // request the packet data to be unmarshaled by the base application. type PacketDataUnmarshaler interface { // UnmarshalPacketData unmarshals the packet data into a concrete type - UnmarshalPacketData([]byte) (interface{}, error) + UnmarshalPacketData(ctx sdk.Context, portID, channelID string, bz []byte) (interface{}, error) } diff --git a/testing/mock/ibc_module.go b/testing/mock/ibc_module.go index b3bd2432de3..963945f5330 100644 --- a/testing/mock/ibc_module.go +++ b/testing/mock/ibc_module.go @@ -219,7 +219,7 @@ func (im IBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, // UnmarshalPacketData returns the MockPacketData. This function implements the optional // PacketDataUnmarshaler interface required for ADR 008 support. -func (IBCModule) UnmarshalPacketData(bz []byte) (interface{}, error) { +func (IBCModule) UnmarshalPacketData(_ sdk.Context, _, _ string, bz []byte) (interface{}, error) { if reflect.DeepEqual(bz, MockPacketData) { return MockPacketData, nil } From dbcff45015337d734591dc33c0b4886c687b5af8 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Thu, 23 May 2024 09:28:04 +0100 Subject: [PATCH 043/141] Refactor packet data unmarshalling to use specific version (#6354) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: specifically unmarshal v1 or v2 without brute force * chore: fix TestPacketDataUnmarshalerInterface test in transfer module * Pass dest values OnRecv, refactor GetExpectedEvents * chore: fixing TestGetCallbackData test * chore: fixed remaining tests in callbacks module * test: simplify callbacks test, revert back to previous behaviour * chore: fix test case name * chore: addressing PR feedback * chore: added docstring for unmarshalPacketDataBytesToICS20V2 --------- Co-authored-by: DimitrisJim Co-authored-by: Colin Axnér <25233464+colin-axner@users.noreply.github.com> --- modules/apps/callbacks/callbacks_test.go | 4 +- modules/apps/callbacks/ibc_middleware_test.go | 43 ++++++- .../apps/callbacks/types/callbacks_test.go | 117 ++++++++---------- modules/apps/callbacks/types/export_test.go | 8 ++ modules/apps/callbacks/types/types_test.go | 11 +- modules/apps/transfer/ibc_module.go | 71 ++++++++--- modules/apps/transfer/ibc_module_test.go | 44 ++++++- 7 files changed, 202 insertions(+), 96 deletions(-) diff --git a/modules/apps/callbacks/callbacks_test.go b/modules/apps/callbacks/callbacks_test.go index ef88db93483..f9874896a22 100644 --- a/modules/apps/callbacks/callbacks_test.go +++ b/modules/apps/callbacks/callbacks_test.go @@ -305,11 +305,11 @@ func GetExpectedEvent( gasMeter := storetypes.NewGasMeter(remainingGas) ctx = ctx.WithGasMeter(gasMeter) - // Mock packet. - packet := channeltypes.NewPacket(data, 0, srcPortID, "", "", "", clienttypes.ZeroHeight(), 0) if callbackType == types.CallbackTypeReceivePacket { + packet := channeltypes.NewPacket(data, seq, "", "", eventPortID, eventChannelID, clienttypes.ZeroHeight(), 0) callbackData, err = types.GetDestCallbackData(ctx, packetDataUnmarshaler, packet, maxCallbackGas) } else { + packet := channeltypes.NewPacket(data, seq, eventPortID, eventChannelID, "", "", clienttypes.ZeroHeight(), 0) callbackData, err = types.GetSourceCallbackData(ctx, packetDataUnmarshaler, packet, maxCallbackGas) } if err != nil { diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 0b487d93611..7c394bcaa9f 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -971,8 +971,13 @@ func (s *CallbacksTestSuite) TestProcessCallback() { } } -func (s *CallbacksTestSuite) TestUnmarshalPacketData() { +func (s *CallbacksTestSuite) TestUnmarshalPacketDataV1() { s.setupChains() + s.path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort + s.path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort + s.path.EndpointA.ChannelConfig.Version = transfertypes.V1 + s.path.EndpointB.ChannelConfig.Version = transfertypes.V1 + s.path.Setup() // We will pass the function call down the transfer stack to the transfer module // transfer stack UnmarshalPacketData call order: callbacks -> fee -> transfer @@ -1006,15 +1011,43 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() { portID := s.path.EndpointA.ChannelConfig.PortID channelID := s.path.EndpointA.ChannelID - // Unmarshal ICS20 v1 packet data + // Unmarshal ICS20 v1 packet data into v2 packet data data := expPacketDataICS20V1.GetBytes() packetData, err := unmarshalerStack.UnmarshalPacketData(s.chainA.GetContext(), portID, channelID, data) s.Require().NoError(err) s.Require().Equal(expPacketDataICS20V2, packetData) +} + +func (s *CallbacksTestSuite) TestUnmarshalPacketDataV2() { + s.SetupTransferTest() + + // We will pass the function call down the transfer stack to the transfer module + // transfer stack UnmarshalPacketData call order: callbacks -> fee -> transfer + transferStack, ok := s.chainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) + s.Require().True(ok) - // Unmarshal ICS20 v1 packet data - data = expPacketDataICS20V2.GetBytes() - packetData, err = unmarshalerStack.UnmarshalPacketData(s.chainA.GetContext(), portID, channelID, data) + unmarshalerStack, ok := transferStack.(types.CallbacksCompatibleModule) + s.Require().True(ok) + + expPacketDataICS20V2 := transfertypes.FungibleTokenPacketDataV2{ + Tokens: []transfertypes.Token{ + { + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Trace: nil, + }, + }, + Sender: ibctesting.TestAccAddress, + Receiver: ibctesting.TestAccAddress, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), + } + + portID := s.path.EndpointA.ChannelConfig.PortID + channelID := s.path.EndpointA.ChannelID + + // Unmarshal ICS20 v2 packet data + data := expPacketDataICS20V2.GetBytes() + packetData, err := unmarshalerStack.UnmarshalPacketData(s.chainA.GetContext(), portID, channelID, data) s.Require().NoError(err) s.Require().Equal(expPacketDataICS20V2, packetData) } diff --git a/modules/apps/callbacks/types/callbacks_test.go b/modules/apps/callbacks/types/callbacks_test.go index 754118dda90..be4098f9bc9 100644 --- a/modules/apps/callbacks/types/callbacks_test.go +++ b/modules/apps/callbacks/types/callbacks_test.go @@ -10,23 +10,20 @@ import ( "github.com/cometbft/cometbft/crypto/secp256k1" "github.com/cosmos/ibc-go/modules/apps/callbacks/types" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer" transfertypes "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" ibctesting "github.com/cosmos/ibc-go/v8/testing" ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) func (s *CallbacksTypesTestSuite) TestGetCallbackData() { var ( - sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() - packetDataUnmarshaler porttypes.PacketDataUnmarshaler - packetData []byte - remainingGas uint64 - callbackKey string + sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + packetData interface{} + remainingGas uint64 + callbackKey string ) // max gas is 1_000_000 @@ -40,14 +37,13 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { "success: source callback", func() { remainingGas = 2_000_000 - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, sender), } - packetData = expPacketData.GetBytes() }, types.CallbackData{ CallbackAddress: sender, @@ -61,15 +57,15 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { "success: destination callback", func() { callbackKey = types.DestinationCallbackKey + remainingGas = 2_000_000 - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s"}}`, sender), } - packetData = expPacketData.GetBytes() }, types.CallbackData{ CallbackAddress: sender, @@ -83,15 +79,15 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { "success: destination callback with 0 user defined gas limit", func() { callbackKey = types.DestinationCallbackKey + remainingGas = 2_000_000 - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit":"0"}}`, sender), } - packetData = expPacketData.GetBytes() }, types.CallbackData{ CallbackAddress: sender, @@ -104,14 +100,13 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { { "success: source callback with gas limit < remaining gas < max gas", func() { - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "50000"}}`, sender), } - packetData = expPacketData.GetBytes() remainingGas = 100_000 }, @@ -127,14 +122,13 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { "success: source callback with remaining gas < gas limit < max gas", func() { remainingGas = 100_000 - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, sender), } - packetData = expPacketData.GetBytes() }, types.CallbackData{ CallbackAddress: sender, @@ -148,14 +142,13 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { "success: source callback with remaining gas < max gas < gas limit", func() { remainingGas = 100_000 - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "2000000"}}`, sender), } - packetData = expPacketData.GetBytes() }, types.CallbackData{ CallbackAddress: sender, @@ -169,15 +162,15 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { "success: destination callback with remaining gas < max gas < gas limit", func() { callbackKey = types.DestinationCallbackKey + remainingGas = 100_000 - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: fmt.Sprintf(`{"dest_callback": {"address": "%s", "gas_limit": "2000000"}}`, sender), } - packetData = expPacketData.GetBytes() }, types.CallbackData{ CallbackAddress: sender, @@ -191,14 +184,13 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { "success: source callback with max gas < remaining gas < gas limit", func() { remainingGas = 2_000_000 - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "3000000"}}`, sender), } - packetData = expPacketData.GetBytes() }, types.CallbackData{ CallbackAddress: sender, @@ -208,19 +200,10 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { }, nil, }, - { - "failure: invalid packet data", - func() { - packetData = []byte("invalid packet data") - }, - types.CallbackData{}, - types.ErrCannotUnmarshalPacketData, - }, { "failure: packet data does not implement PacketDataProvider", func() { packetData = ibcmock.MockPacketData - packetDataUnmarshaler = ibcmock.IBCModule{} }, types.CallbackData{}, types.ErrNotPacketDataProvider, @@ -228,14 +211,13 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { { "failure: empty memo", func() { - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: "", } - packetData = expPacketData.GetBytes() }, types.CallbackData{}, types.ErrCallbackKeyNotFound, @@ -243,14 +225,13 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { { "failure: empty address", func() { - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: `{"src_callback": {"address": ""}}`, } - packetData = expPacketData.GetBytes() }, types.CallbackData{}, types.ErrCallbackAddressNotFound, @@ -258,14 +239,13 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { { "failure: space address", func() { - expPacketData := transfertypes.FungibleTokenPacketData{ + packetData = transfertypes.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), Sender: sender, Receiver: receiver, Memo: `{"src_callback": {"address": " "}}`, } - packetData = expPacketData.GetBytes() }, types.CallbackData{}, types.ErrCallbackAddressNotFound, @@ -275,27 +255,13 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { for _, tc := range testCases { tc := tc s.Run(tc.name, func() { - callbackKey = types.SourceCallbackKey + s.SetupTest() - packetDataUnmarshaler = transfer.IBCModule{} + callbackKey = types.SourceCallbackKey tc.malleate() - // Set up gas meter for context. - gasMeter := storetypes.NewGasMeter(remainingGas) - ctx := s.chain.GetContext().WithGasMeter(gasMeter) - - packet := channeltypes.NewPacket(packetData, 0, ibcmock.PortID, "", "", "", clienttypes.ZeroHeight(), 0) - - var ( - callbackData types.CallbackData - err error - ) - if callbackKey == types.DestinationCallbackKey { - callbackData, err = types.GetDestCallbackData(ctx, packetDataUnmarshaler, packet, uint64(1_000_000)) - } else { - callbackData, err = types.GetSourceCallbackData(ctx, packetDataUnmarshaler, packet, uint64(1_000_000)) - } + callbackData, err := types.GetCallbackData(packetData, transfertypes.PortID, remainingGas, uint64(1_000_000), callbackKey) expPass := tc.expError == nil if expPass { @@ -312,6 +278,8 @@ func (s *CallbacksTypesTestSuite) TestGetCallbackData() { } func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { + s.SetupTest() + sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() @@ -331,19 +299,32 @@ func (s *CallbacksTypesTestSuite) TestGetSourceCallbackDataTransfer() { CommitGasLimit: 1_000_000, } - packetUnmarshaler := transfer.IBCModule{} + s.path.EndpointA.ChannelConfig.Version = transfertypes.V1 + s.path.EndpointA.ChannelConfig.PortID = transfertypes.ModuleName + s.path.EndpointB.ChannelConfig.Version = transfertypes.V1 + s.path.EndpointB.ChannelConfig.PortID = transfertypes.ModuleName + + transferStack, ok := s.chainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) + s.Require().True(ok) + + packetUnmarshaler, ok := transferStack.(types.CallbacksCompatibleModule) + s.Require().True(ok) + + s.path.Setup() // Set up gas meter for context. gasMeter := storetypes.NewGasMeter(2_000_000) - ctx := s.chain.GetContext().WithGasMeter(gasMeter) + ctx := s.chainA.GetContext().WithGasMeter(gasMeter) - packet := channeltypes.NewPacket(packetDataBytes, 0, ibcmock.PortID, "", "", "", clienttypes.ZeroHeight(), 0) + packet := channeltypes.NewPacket(packetDataBytes, 0, transfertypes.PortID, s.path.EndpointA.ChannelID, transfertypes.PortID, s.path.EndpointB.ChannelID, clienttypes.ZeroHeight(), 0) callbackData, err := types.GetSourceCallbackData(ctx, packetUnmarshaler, packet, 1_000_000) s.Require().NoError(err) s.Require().Equal(expCallbackData, callbackData) } func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { + s.SetupTest() + sender := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() @@ -363,12 +344,22 @@ func (s *CallbacksTypesTestSuite) TestGetDestCallbackDataTransfer() { CommitGasLimit: 1_000_000, } - packetUnmarshaler := transfer.IBCModule{} + s.path.EndpointA.ChannelConfig.Version = transfertypes.V1 + s.path.EndpointA.ChannelConfig.PortID = transfertypes.ModuleName + s.path.EndpointB.ChannelConfig.Version = transfertypes.V1 + s.path.EndpointB.ChannelConfig.PortID = transfertypes.ModuleName - gasMeter := storetypes.NewGasMeter(2_000_000) - ctx := s.chain.GetContext().WithGasMeter(gasMeter) + transferStack, ok := s.chainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) + s.Require().True(ok) + + packetUnmarshaler, ok := transferStack.(types.CallbacksCompatibleModule) + s.Require().True(ok) - packet := channeltypes.NewPacket(packetDataBytes, 0, ibcmock.PortID, "", "", "", clienttypes.ZeroHeight(), 0) + s.path.Setup() + + gasMeter := storetypes.NewGasMeter(2_000_000) + ctx := s.chainA.GetContext().WithGasMeter(gasMeter) + packet := channeltypes.NewPacket(packetDataBytes, 0, transfertypes.PortID, s.path.EndpointA.ChannelID, transfertypes.PortID, s.path.EndpointB.ChannelID, clienttypes.ZeroHeight(), 0) callbackData, err := types.GetDestCallbackData(ctx, packetUnmarshaler, packet, 1_000_000) s.Require().NoError(err) s.Require().Equal(expCallbackData, callbackData) diff --git a/modules/apps/callbacks/types/export_test.go b/modules/apps/callbacks/types/export_test.go index 5b0a32508e3..4cc85624827 100644 --- a/modules/apps/callbacks/types/export_test.go +++ b/modules/apps/callbacks/types/export_test.go @@ -4,6 +4,14 @@ package types This file is to allow for unexported functions to be accessible to the testing package. */ +// GetCallbackData is a wrapper around getCallbackData to allow the function to be directly called in tests. +func GetCallbackData( + packetData interface{}, srcPortID string, remainingGas, + maxGas uint64, callbackKey string, +) (CallbackData, error) { + return getCallbackData(packetData, srcPortID, remainingGas, maxGas, callbackKey) +} + // GetCallbackAddress is a wrapper around getCallbackAddress to allow the function to be directly called in tests. func GetCallbackAddress(callbackData map[string]interface{}) string { return getCallbackAddress(callbackData) diff --git a/modules/apps/callbacks/types/types_test.go b/modules/apps/callbacks/types/types_test.go index 7bb61f95162..5843f972249 100644 --- a/modules/apps/callbacks/types/types_test.go +++ b/modules/apps/callbacks/types/types_test.go @@ -15,12 +15,19 @@ type CallbacksTypesTestSuite struct { coord *ibctesting.Coordinator chain *ibctesting.TestChain + + chainA, chainB *ibctesting.TestChain + + path *ibctesting.Path } // SetupTest creates a coordinator with 1 test chain. -func (s *CallbacksTypesTestSuite) SetupSuite() { - s.coord = ibctesting.NewCoordinator(s.T(), 1) +func (s *CallbacksTypesTestSuite) SetupTest() { + s.coord = ibctesting.NewCoordinator(s.T(), 3) s.chain = s.coord.GetChain(ibctesting.GetChainID(1)) + s.chainA = s.coord.GetChain(ibctesting.GetChainID(2)) + s.chainB = s.coord.GetChain(ibctesting.GetChainID(3)) + s.path = ibctesting.NewPath(s.chainA, s.chainB) } func TestCallbacksTypesTestSuite(t *testing.T) { diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index a58e777a3e8..c87591e6c9f 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -174,25 +174,35 @@ func (IBCModule) OnChanCloseConfirm( return nil } -func (IBCModule) unmarshalPacketDataBytesToICS20V2(bz []byte) (types.FungibleTokenPacketDataV2, error) { - // TODO: remove support for this function parsing v1 packet data - // TODO: explicit check for packet data type against app version - - var datav1 types.FungibleTokenPacketData - if err := json.Unmarshal(bz, &datav1); err == nil { - if len(datav1.Denom) != 0 { - return convertinternal.PacketDataV1ToV2(datav1), nil +// unmarshalPacketDataBytesToICS20V2 attempts to unmarshal the provided packet data bytes into a FungibleTokenPacketDataV2. +// The version of ics20 should be provided and should be either ics20-1 or ics20-2. +func (IBCModule) unmarshalPacketDataBytesToICS20V2(bz []byte, ics20Version string) (types.FungibleTokenPacketDataV2, error) { + switch ics20Version { + case types.V1: + var datav1 types.FungibleTokenPacketData + if err := json.Unmarshal(bz, &datav1); err != nil { + return types.FungibleTokenPacketDataV2{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS20-V2 transfer packet data: %s", err.Error()) } - } - var data types.FungibleTokenPacketDataV2 - if err := json.Unmarshal(bz, &data); err == nil { - if len(data.Tokens) != 0 { - return data, nil + if err := datav1.ValidateBasic(); err != nil { + return types.FungibleTokenPacketDataV2{}, err + } + + return convertinternal.PacketDataV1ToV2(datav1), nil + case types.V2: + var datav2 types.FungibleTokenPacketDataV2 + if err := json.Unmarshal(bz, &datav2); err != nil { + return types.FungibleTokenPacketDataV2{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS20-V2 transfer packet data: %s", err.Error()) } - } - return types.FungibleTokenPacketDataV2{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data") + if err := datav2.ValidateBasic(); err != nil { + return types.FungibleTokenPacketDataV2{}, err + } + + return datav2, nil + default: + return types.FungibleTokenPacketDataV2{}, errorsmod.Wrap(types.ErrInvalidVersion, ics20Version) + } } // OnRecvPacket implements the IBCModule interface. A successful acknowledgement @@ -205,8 +215,14 @@ func (im IBCModule) OnRecvPacket( ) ibcexported.Acknowledgement { ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - data, ackErr := im.unmarshalPacketDataBytesToICS20V2(packet.GetData()) + ics20Version, found := im.keeper.GetICS4Wrapper().GetAppVersion(ctx, packet.DestinationPort, packet.DestinationChannel) + if !found { + return channeltypes.NewErrorAcknowledgement(errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", packet.DestinationPort, packet.DestinationChannel)) + } + + data, ackErr := im.unmarshalPacketDataBytesToICS20V2(packet.GetData(), ics20Version) if ackErr != nil { + ackErr = errorsmod.Wrapf(ibcerrors.ErrInvalidType, ackErr.Error()) im.keeper.Logger(ctx).Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence)) ack = channeltypes.NewErrorAcknowledgement(ackErr) } @@ -261,7 +277,12 @@ func (im IBCModule) OnAcknowledgementPacket( return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err) } - data, err := im.unmarshalPacketDataBytesToICS20V2(packet.GetData()) + ics20Version, found := im.keeper.GetICS4Wrapper().GetAppVersion(ctx, packet.SourcePort, packet.SourceChannel) + if !found { + return errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", packet.SourcePort, packet.SourceChannel) + } + + data, err := im.unmarshalPacketDataBytesToICS20V2(packet.GetData(), ics20Version) if err != nil { return err } @@ -311,7 +332,12 @@ func (im IBCModule) OnTimeoutPacket( packet channeltypes.Packet, relayer sdk.AccAddress, ) error { - data, err := im.unmarshalPacketDataBytesToICS20V2(packet.GetData()) + ics20Version, found := im.keeper.GetICS4Wrapper().GetAppVersion(ctx, packet.SourcePort, packet.SourceChannel) + if !found { + return errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", packet.SourcePort, packet.SourceChannel) + } + + data, err := im.unmarshalPacketDataBytesToICS20V2(packet.GetData(), ics20Version) if err != nil { return err } @@ -380,8 +406,13 @@ func (IBCModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, pr // 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 (im IBCModule) UnmarshalPacketData(_ sdk.Context, _, _ string, bz []byte) (interface{}, error) { - ftpd, err := im.unmarshalPacketDataBytesToICS20V2(bz) +func (im IBCModule) UnmarshalPacketData(ctx sdk.Context, portID, channelID string, bz []byte) (interface{}, error) { + ics20Version, found := im.keeper.GetICS4Wrapper().GetAppVersion(ctx, portID, channelID) + if !found { + return nil, errorsmod.Wrapf(ibcerrors.ErrNotFound, "app version not found for port %s and channel %s", portID, channelID) + } + + ftpd, err := im.unmarshalPacketDataBytesToICS20V2(bz, ics20Version) if err != nil { return nil, err } diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 46a2302ff8e..e52b04fc7da 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -496,6 +496,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() receiver = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String() + path *ibctesting.Path data []byte initialPacketData interface{} ) @@ -508,6 +509,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { { "success: valid packet data single denom -> multidenom conversion with memo", func() { + path.EndpointA.ChannelConfig.Version = types.V1 initialPacketData = types.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), @@ -523,6 +525,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { { "success: valid packet data single denom -> multidenom conversion without memo", func() { + path.EndpointA.ChannelConfig.Version = types.V1 initialPacketData = types.FungibleTokenPacketData{ Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), @@ -538,6 +541,7 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { { "success: valid packet data single denom with trace -> multidenom conversion with trace", func() { + path.EndpointA.ChannelConfig.Version = types.V1 initialPacketData = types.FungibleTokenPacketData{ Denom: "transfer/channel-0/atom", Amount: ibctesting.TestCoin.Amount.String(), @@ -571,14 +575,15 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { nil, }, { - "success: valid packet data multidenom without memo", + "success: valid packet data multidenom nil trace", func() { + path.EndpointA.ChannelConfig.Version = types.V2 initialPacketData = types.FungibleTokenPacketDataV2{ Tokens: []types.Token{ { Denom: ibctesting.TestCoin.Denom, Amount: ibctesting.TestCoin.Amount.String(), - Trace: []string{""}, + Trace: nil, }, }, Sender: sender, @@ -590,21 +595,52 @@ func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() { }, nil, }, + { + "failure: invalid token trace", + func() { + path.EndpointA.ChannelConfig.Version = types.V2 + initialPacketData = types.FungibleTokenPacketDataV2{ + Tokens: []types.Token{ + { + Denom: ibctesting.TestCoin.Denom, + Amount: ibctesting.TestCoin.Amount.String(), + Trace: []string{""}, + }, + }, + Sender: sender, + Receiver: receiver, + Memo: "", + } + + data = initialPacketData.(types.FungibleTokenPacketDataV2).GetBytes() + }, + errors.New("trace info must come in pairs of port and channel identifiers"), + }, { "failure: invalid packet data", func() { data = []byte("invalid packet data") }, - errors.New("cannot unmarshal ICS-20 transfer packet data"), + errors.New("cannot unmarshal ICS20-V2 transfer packet data"), }, } for _, tc := range testCases { tc := tc suite.Run(tc.name, func() { + path = ibctesting.NewTransferPath(suite.chainA, suite.chainB) + tc.malleate() - packetData, err := transfer.IBCModule{}.UnmarshalPacketData(suite.chainA.GetContext(), "", "", data) + path.Setup() + + transferStack, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Route(types.ModuleName) + suite.Require().True(ok) + + unmarshalerStack, ok := transferStack.(porttypes.PacketDataUnmarshaler) + suite.Require().True(ok) + + packetData, err := unmarshalerStack.UnmarshalPacketData(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, data) expPass := tc.expError == nil if expPass { From f19a1458d766ec7947f940cb8518d6251dfbcf44 Mon Sep 17 00:00:00 2001 From: chatton Date: Thu, 23 May 2024 09:59:23 +0100 Subject: [PATCH 044/141] chore: fixing tests --- modules/apps/transfer/keeper/relay_test.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index c9359fee456..0f7e8a70997 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -996,7 +996,7 @@ func (suite *KeeperTestSuite) TestPacketForwardsCompatibility() { func() { packetData = []byte("invalid packet data") }, - ibcerrors.ErrUnknownRequest, + ibcerrors.ErrInvalidType, }, { "failure: missing field", @@ -1004,7 +1004,7 @@ func (suite *KeeperTestSuite) TestPacketForwardsCompatibility() { jsonString := fmt.Sprintf(`{"amount":"100","sender":%s","receiver":"%s"}`, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String()) packetData = []byte(jsonString) }, - ibcerrors.ErrUnknownRequest, + ibcerrors.ErrInvalidType, }, } @@ -1015,6 +1015,8 @@ func (suite *KeeperTestSuite) TestPacketForwardsCompatibility() { packetData = nil path := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path.EndpointA.ChannelConfig.Version = types.V1 + path.EndpointB.ChannelConfig.Version = types.V1 path.Setup() tc.malleate() From d4b06c8d6aa2352e1adbd90aae9a868276469916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 23 May 2024 13:04:48 +0200 Subject: [PATCH 045/141] imp: self review comments for ics20-v2 (#6360) * refactor: address various self review comments * revert: unnecessary change * lint --- CHANGELOG.md | 1 + docs/docs/05-migrations/13-v8-to-v9.md | 1 + e2e/testsuite/testsuite.go | 2 +- modules/apps/transfer/types/keys.go | 4 +- modules/apps/transfer/types/token_test.go | 82 +++++++++++++++++++++++ 5 files changed, 87 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9299281e19..00a5a5ba760 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (core) [\#6138](https://github.com/cosmos/ibc-go/pull/6138) Remove `Router` reference from IBC core keeper and use instead the router on the existing `PortKeeper` reference. * (core/04-channel) [\#6023](https://github.com/cosmos/ibc-go/pull/6023) Remove emission of non-hexlified event attributes `packet_data` and `packet_ack`. * (core) [\#6320](https://github.com/cosmos/ibc-go/pull/6320) Remove unnecessary `Proof` interface from `exported` package. +* (core/05-port) [\#6341](https://github.com/cosmos/ibc-go/pull/6341) Modify `UnmarshalPacketData` interface to take in the context, portID, and channelID. This allows for packet data's to be unmarshaled based on the channel version. ### State Machine Breaking diff --git a/docs/docs/05-migrations/13-v8-to-v9.md b/docs/docs/05-migrations/13-v8-to-v9.md index afbf6a0e98c..bd67a09515d 100644 --- a/docs/docs/05-migrations/13-v8-to-v9.md +++ b/docs/docs/05-migrations/13-v8-to-v9.md @@ -66,6 +66,7 @@ func AssertEvents( ### IBC core +- `UnmarshalPacketData` now takes in the context, portID, and channelID. This allows the packet data to be unmarshaled based on the channel version. - `Router` reference has been removed from IBC core keeper: [#6138](https://github.com/cosmos/ibc-go/pull/6138) ### ICS27 - Interchain Accounts diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index 221c523f186..4552dea20ee 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -154,8 +154,8 @@ func (s *E2ETestSuite) ConfigureRelayer(ctx context.Context, chainA, chainB ibc. pathName := s.generatePathName() channelOptions := ibc.DefaultChannelOpts() - // TODO: better way to do this. // For now, set the version to the latest transfer module version + // DefaultChannelOpts uses V1 at the moment channelOptions.Version = transfertypes.V2 if channelOpts != nil { diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index 5e1fa0d70e6..f8faa1336fe 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -38,8 +38,8 @@ const ( // V1 defines first version of the IBC transfer module V1 = "ics20-1" - // V2 defines the current version the IBC transfer - // module supports + // V2 defines the transfer version which introduces multidenom support + // through the FungibleTokenPacketDataV2. It is the latest version. V2 = "ics20-2" // escrowAddressVersion should remain as ics20-1 to avoid the address changing. diff --git a/modules/apps/transfer/types/token_test.go b/modules/apps/transfer/types/token_test.go index afc008b6ed1..027405b582e 100644 --- a/modules/apps/transfer/types/token_test.go +++ b/modules/apps/transfer/types/token_test.go @@ -149,3 +149,85 @@ func TestValidate(t *testing.T) { }) } } + +func TestTokens_String(t *testing.T) { + cases := []struct { + name string + input Tokens + expected string + }{ + { + "empty tokens", + Tokens{}, + "", + }, + { + "single token, no trace", + Tokens{ + Token{ + Denom: "tree", + Amount: "1", + Trace: []string{}, + }, + }, + `denom:"tree" amount:"1" `, + }, + { + "single token with trace", + Tokens{ + Token{ + Denom: "tree", + Amount: "1", + Trace: []string{"portid/channelid"}, + }, + }, + `denom:"tree" amount:"1" trace:"portid/channelid" `, + }, + { + "multiple tokens, no trace", + Tokens{ + Token{ + Denom: "tree", + Amount: "1", + Trace: []string{}, + }, + Token{ + Denom: "gas", + Amount: "2", + Trace: []string{}, + }, + Token{ + Denom: "mineral", + Amount: "3", + Trace: []string{}, + }, + }, + `denom:"tree" amount:"1" ,denom:"gas" amount:"2" ,denom:"mineral" amount:"3" `, + }, + { + "multiple tokens, trace and no trace", + Tokens{ + Token{ + Denom: "tree", + Amount: "1", + Trace: []string{}, + }, + Token{ + Denom: "gas", + Amount: "2", + Trace: []string{"portid/channelid"}, + }, + Token{ + Denom: "mineral", + Amount: "3", + Trace: []string{"portid/channelid", "transfer/channel-52"}, + }, + }, + `denom:"tree" amount:"1" ,denom:"gas" amount:"2" trace:"portid/channelid" ,denom:"mineral" amount:"3" trace:"portid/channelid" trace:"transfer/channel-52" `, + }, + } + + for _, tt := range cases { + require.Equal(t, tt.expected, tt.input.String()) + } +} From a9391a4fcf1b6b644835d86c50399addbbe0d117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 23 May 2024 16:12:29 +0200 Subject: [PATCH 046/141] imp: self review on ics20-v2 part 2 (#6364) * refactor: apply review suggestions * imp: additional updates * refactor: make ValidateIBCDenom private * Update modules/apps/transfer/types/msgs.go Co-authored-by: Cian Hatton * apply review suggestions --------- Co-authored-by: Cian Hatton --- modules/apps/transfer/keeper/msg_server.go | 22 +++---- modules/apps/transfer/types/export_test.go | 6 ++ modules/apps/transfer/types/msgs.go | 62 +++++++++---------- modules/apps/transfer/types/packet.go | 9 --- modules/apps/transfer/types/token.go | 19 ++++-- modules/apps/transfer/types/token_test.go | 25 +++----- modules/apps/transfer/types/trace.go | 4 +- .../transfer/types/transfer_authorization.go | 8 +-- 8 files changed, 74 insertions(+), 81 deletions(-) create mode 100644 modules/apps/transfer/types/export_test.go diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index e23672facb3..eaac2fb3ae9 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -26,23 +26,21 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. return nil, err } - // tokens will always be an array, but may contain a single element - // if the ics20-1 token field is populated, and the ics20-2 array is empty. - tokens := msg.GetTokens() + coins := msg.GetCoins() 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) } - // ics20-1 only supports a single token, so if that is the current version, we must only process a single token. - if appVersion == types.V1 && len(tokens) > 1 { - return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "cannot transfer multiple tokens with ics20-1") + // ics20-1 only supports a single coin, so if that is the current version, we must only process a single coin. + if appVersion == types.V1 && len(coins) > 1 { + return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "cannot transfer multiple coins with ics20-1") } - for _, token := range tokens { - if !k.bankKeeper.IsSendEnabledCoin(ctx, token) { - return nil, errorsmod.Wrapf(types.ErrSendDisabled, "transfers are currently disabled for %s", token.Denom) + for _, coin := range coins { + if !k.bankKeeper.IsSendEnabledCoin(ctx, coin) { + return nil, errorsmod.Wrapf(types.ErrSendDisabled, "transfers are currently disabled for %s", coin.Denom) } } @@ -51,7 +49,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. } sequence, err := k.sendTransfer( - ctx, msg.SourcePort, msg.SourceChannel, tokens, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, + ctx, msg.SourcePort, msg.SourceChannel, coins, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Memo) if err != nil { return nil, err @@ -62,7 +60,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. types.EventTypeTransfer, sdk.NewAttribute(types.AttributeKeySender, msg.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), - sdk.NewAttribute(types.AttributeKeyTokens, tokens.String()), + sdk.NewAttribute(types.AttributeKeyTokens, coins.String()), sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), ), sdk.NewEvent( @@ -71,7 +69,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. ), }) - k.Logger(ctx).Info("IBC fungible token transfer", "tokens", tokens, "sender", msg.Sender, "receiver", msg.Receiver) + k.Logger(ctx).Info("IBC fungible token transfer", "tokens", coins, "sender", msg.Sender, "receiver", msg.Receiver) return &types.MsgTransferResponse{Sequence: sequence}, nil } diff --git a/modules/apps/transfer/types/export_test.go b/modules/apps/transfer/types/export_test.go new file mode 100644 index 00000000000..65e136757fe --- /dev/null +++ b/modules/apps/transfer/types/export_test.go @@ -0,0 +1,6 @@ +package types + +// ValidateIBCDenom is a wrapper around validateIBCDenom for testing purposes. +func ValidateIBCDenom(denom string) error { + return validateIBCDenom(denom) +} diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 85e10c4db31..fd28b8778e5 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -74,12 +74,12 @@ func (msg MsgTransfer) ValidateBasic() error { return errorsmod.Wrap(err, "invalid source channel ID") } - if len(msg.Tokens) == 0 && !isValidToken(msg.Token) { - return errorsmod.Wrap(ErrInvalidAmount, "either token or token array must be filled") + if len(msg.Tokens) == 0 && !isValidIBCCoin(msg.Token) { + return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, "either token or token array must be filled") } - if len(msg.Tokens) != 0 && isValidToken(msg.Token) { - return errorsmod.Wrap(ErrInvalidAmount, "cannot fill both token and token array") + if len(msg.Tokens) != 0 && isValidIBCCoin(msg.Token) { + return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, "cannot fill both token and token array") } if len(msg.Tokens) > MaximumTokensLength { @@ -100,47 +100,45 @@ func (msg MsgTransfer) ValidateBasic() error { return errorsmod.Wrapf(ErrInvalidMemo, "memo must not exceed %d bytes", MaximumMemoLength) } - for _, token := range msg.GetTokens() { - if !isValidToken(token) { - return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, token.String()) - } - if err := ValidateIBCDenom(token.GetDenom()); err != nil { - return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, token.Denom) + for _, coin := range msg.GetCoins() { + if err := validateIBCCoin(coin); err != nil { + return errorsmod.Wrap(err, coin.String()) } } return nil } -// GetTokens returns the tokens which will be transferred. -func (msg MsgTransfer) GetTokens() sdk.Coins { - tokens := msg.Tokens - if isValidToken(msg.Token) { - tokens = []sdk.Coin{msg.Token} +// GetCoins returns the tokens which will be transferred. +// If MsgTransfer is populated in the Token field, only that field +// will be returned in the coin array. +func (msg MsgTransfer) GetCoins() sdk.Coins { + coins := msg.Tokens + if isValidIBCCoin(msg.Token) { + coins = []sdk.Coin{msg.Token} } - return tokens + return coins } -// isValidToken returns true if the token provided is valid, +// isValidIBCCoin returns true if the token provided is valid, // and should be used to transfer tokens. -// this function is used in case the user constructs a sdk.Coin literal -// instead of using the construction function. -func isValidToken(coin sdk.Coin) bool { - if coin.IsNil() { - return false - } +func isValidIBCCoin(coin sdk.Coin) bool { + return validateIBCCoin(coin) == nil +} - if strings.TrimSpace(coin.Denom) == "" { - return false +// isValidIBCCoin returns true if the token provided is valid, +// and should be used to transfer tokens. The token must +// have a positive amount. +func validateIBCCoin(coin sdk.Coin) error { + if err := coin.Validate(); err != nil { + return err } - - if coin.Amount.IsZero() { - return false + if !coin.IsPositive() { + return errorsmod.Wrap(ErrInvalidAmount, "amount must be positive") } - - if coin.Amount.IsNegative() { - return false + if err := validateIBCDenom(coin.GetDenom()); err != nil { + return err } - return true + return nil } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 81e46c72a53..649bc7cddad 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -128,15 +128,6 @@ func (ftpd FungibleTokenPacketDataV2) ValidateBasic() error { } for _, token := range ftpd.Tokens { - amount, ok := sdkmath.NewIntFromString(token.Amount) - if !ok { - return errorsmod.Wrapf(ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", token.Amount) - } - - if !amount.IsPositive() { - return errorsmod.Wrapf(ErrInvalidAmount, "amount must be strictly positive: got %d", amount) - } - if err := token.Validate(); err != nil { return err } diff --git a/modules/apps/transfer/types/token.go b/modules/apps/transfer/types/token.go index a91dbb97792..a9d822d58e5 100644 --- a/modules/apps/transfer/types/token.go +++ b/modules/apps/transfer/types/token.go @@ -4,16 +4,24 @@ import ( "strings" errorsmod "cosmossdk.io/errors" - - sdk "github.com/cosmos/cosmos-sdk/types" + sdkmath "cosmossdk.io/math" denominternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/denom" ) // Validate validates a token denomination and trace identifiers. func (t Token) Validate() error { - if err := sdk.ValidateDenom(t.Denom); err != nil { - return errorsmod.Wrap(ErrInvalidDenomForTransfer, err.Error()) + if strings.TrimSpace(t.Denom) == "" { + return errorsmod.Wrap(ErrInvalidDenomForTransfer, "denom cannot be empty") + } + + amount, ok := sdkmath.NewIntFromString(t.Amount) + if !ok { + return errorsmod.Wrapf(ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", t.Amount) + } + + if !amount.IsPositive() { + return errorsmod.Wrapf(ErrInvalidAmount, "amount must be strictly positive: got %d", amount) } if len(t.Trace) == 0 { @@ -30,8 +38,7 @@ func (t Token) Validate() error { // tracePath + "/" + baseDenom // If there exists no trace then the base denomination is returned. func (t Token) GetFullDenomPath() string { - trace := strings.Join(t.Trace, "/") - if len(trace) == 0 { + if len(t.Trace) == 0 { return t.Denom } diff --git a/modules/apps/transfer/types/token_test.go b/modules/apps/transfer/types/token_test.go index 027405b582e..7ae88757b90 100644 --- a/modules/apps/transfer/types/token_test.go +++ b/modules/apps/transfer/types/token_test.go @@ -58,22 +58,6 @@ func TestGetFullDenomPath(t *testing.T) { ), denom, }, - { - "empty string trace", - NewFungibleTokenPacketDataV2( - []Token{ - { - Denom: denom, - Amount: amount, - Trace: []string{""}, - }, - }, - sender, - receiver, - "", - ), - denom, - }, } for _, tc := range testCases { @@ -135,6 +119,15 @@ func TestValidate(t *testing.T) { }, fmt.Errorf("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}', got the identifiers: [transfer channel-1 randomport]"), }, + { + "failure: empty identifier in trace", + Token{ + Denom: "uatom", + Amount: amount, + Trace: []string{""}, + }, + fmt.Errorf("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}', got the identifiers: "), + }, } for _, tc := range testCases { diff --git a/modules/apps/transfer/types/trace.go b/modules/apps/transfer/types/trace.go index ab4e7bbce72..0ac37b56645 100644 --- a/modules/apps/transfer/types/trace.go +++ b/modules/apps/transfer/types/trace.go @@ -163,11 +163,11 @@ func ValidatePrefixedDenom(denom string) error { return denominternal.ValidateTraceIdentifiers(identifiers) } -// ValidateIBCDenom validates that the given denomination is either: +// validateIBCDenom validates that the given denomination is either: // // - A valid base denomination (eg: 'uatom' or 'gamm/pool/1' as in https://github.com/cosmos/ibc-go/issues/894) // - A valid fungible token representation (i.e 'ibc/{hash}') per ADR 001 https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-001-coin-source-tracing.md -func ValidateIBCDenom(denom string) error { +func validateIBCDenom(denom string) error { if err := sdk.ValidateDenom(denom); err != nil { return err } diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index ea3c42a9994..333519a86a2 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -68,16 +68,16 @@ func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) allocationModified := false // update spend limit for each token in the MsgTransfer - for _, token := range msgTransfer.GetTokens() { + for _, coin := range msgTransfer.GetCoins() { // If the spend limit is set to the MaxUint256 sentinel value, do not subtract the amount from the spend limit. // if there is no unlimited spend, then we need to subtract the amount from the spend limit to get the limit left - if allocation.SpendLimit.AmountOf(token.Denom).Equal(UnboundedSpendLimit()) { + if allocation.SpendLimit.AmountOf(coin.Denom).Equal(UnboundedSpendLimit()) { continue } - limitLeft, isNegative := a.Allocations[index].SpendLimit.SafeSub(token) + limitLeft, isNegative := a.Allocations[index].SpendLimit.SafeSub(coin) if isNegative { - return authz.AcceptResponse{}, errorsmod.Wrapf(ibcerrors.ErrInsufficientFunds, "requested amount of token %s is more than spend limit", token.Denom) + return authz.AcceptResponse{}, errorsmod.Wrapf(ibcerrors.ErrInsufficientFunds, "requested amount of token %s is more than spend limit", coin.Denom) } allocationModified = true From 575403ec8d45fdaeb02e60b973201c2f078f6f59 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 23 May 2024 17:49:03 +0300 Subject: [PATCH 047/141] chore: move functions from internal/denom back to trace.go (#6368) * chore: move functions from internal/denom to trace.go * lint * lint: the comeback --- modules/apps/transfer/internal/denom/denom.go | 61 ------------------- modules/apps/transfer/types/token.go | 4 +- modules/apps/transfer/types/trace.go | 61 +++++++++++++++++-- 3 files changed, 57 insertions(+), 69 deletions(-) delete mode 100644 modules/apps/transfer/internal/denom/denom.go diff --git a/modules/apps/transfer/internal/denom/denom.go b/modules/apps/transfer/internal/denom/denom.go deleted file mode 100644 index e6b9d7b7680..00000000000 --- a/modules/apps/transfer/internal/denom/denom.go +++ /dev/null @@ -1,61 +0,0 @@ -package denom - -import ( - "fmt" - "strings" - - errorsmod "cosmossdk.io/errors" - - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" -) - -// ExtractPathAndBaseFromFullDenom returns the trace path and the base denom from -// the elements that constitute the complete denom. -func ExtractPathAndBaseFromFullDenom(fullDenomItems []string) ([]string, string) { - var ( - pathSlice []string - baseDenomSlice []string - ) - - length := len(fullDenomItems) - for i := 0; i < length; i += 2 { - // The IBC specification does not guarantee the expected format of the - // destination port or destination channel identifier. A short term solution - // to determine base denomination is to expect the channel identifier to be the - // one ibc-go specifies. A longer term solution is to separate the path and base - // denomination in the ICS20 packet. If an intermediate hop prefixes the full denom - // with a channel identifier format different from our own, the base denomination - // will be incorrectly parsed, but the token will continue to be treated correctly - // as an IBC denomination. The hash used to store the token internally on our chain - // will be the same value as the base denomination being correctly parsed. - if i < length-1 && length > 2 && channeltypes.IsValidChannelID(fullDenomItems[i+1]) { - pathSlice = append(pathSlice, fullDenomItems[i], fullDenomItems[i+1]) - } else { - baseDenomSlice = fullDenomItems[i:] - break - } - } - - baseDenom := strings.Join(baseDenomSlice, "/") - - return pathSlice, baseDenom -} - -// ValidateTraceIdentifiers validates the correctness of the trace associated with a particular base denom. -func ValidateTraceIdentifiers(identifiers []string) error { - if len(identifiers) == 0 || len(identifiers)%2 != 0 { - return fmt.Errorf("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}', got the identifiers: %s", identifiers) - } - - // validate correctness of port and channel identifiers - for i := 0; i < len(identifiers); i += 2 { - if err := host.PortIdentifierValidator(identifiers[i]); err != nil { - return errorsmod.Wrapf(err, "invalid port ID at position %d", i) - } - if err := host.ChannelIdentifierValidator(identifiers[i+1]); err != nil { - return errorsmod.Wrapf(err, "invalid channel ID at position %d", i) - } - } - return nil -} diff --git a/modules/apps/transfer/types/token.go b/modules/apps/transfer/types/token.go index a9d822d58e5..4fe2928489d 100644 --- a/modules/apps/transfer/types/token.go +++ b/modules/apps/transfer/types/token.go @@ -5,8 +5,6 @@ import ( errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" - - denominternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/denom" ) // Validate validates a token denomination and trace identifiers. @@ -31,7 +29,7 @@ func (t Token) Validate() error { trace := strings.Join(t.Trace, "/") identifiers := strings.Split(trace, "/") - return denominternal.ValidateTraceIdentifiers(identifiers) + return validateTraceIdentifiers(identifiers) } // GetFullDenomPath returns the full denomination according to the ICS20 specification: diff --git a/modules/apps/transfer/types/trace.go b/modules/apps/transfer/types/trace.go index 0ac37b56645..3287ffc1796 100644 --- a/modules/apps/transfer/types/trace.go +++ b/modules/apps/transfer/types/trace.go @@ -14,7 +14,8 @@ import ( cmtbytes "github.com/cometbft/cometbft/libs/bytes" cmttypes "github.com/cometbft/cometbft/types" - denominternal "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/denom" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) // ParseDenomTrace parses a string with the ibc prefix (denom trace) and the base denomination @@ -37,7 +38,7 @@ func ParseDenomTrace(rawDenom string) DenomTrace { } } - pathSlice, baseDenom := denominternal.ExtractPathAndBaseFromFullDenom(denomSplit) + pathSlice, baseDenom := extractPathAndBaseFromFullDenom(denomSplit) return DenomTrace{ Path: strings.Join(pathSlice, "/"), BaseDenom: baseDenom, @@ -81,6 +82,56 @@ func (dt DenomTrace) IsNativeDenom() bool { return dt.Path == "" } +// extractPathAndBaseFromFullDenom returns the trace path and the base denom from +// the elements that constitute the complete denom. +func extractPathAndBaseFromFullDenom(fullDenomItems []string) ([]string, string) { + var ( + pathSlice []string + baseDenomSlice []string + ) + + length := len(fullDenomItems) + for i := 0; i < length; i += 2 { + // The IBC specification does not guarantee the expected format of the + // destination port or destination channel identifier. A short term solution + // to determine base denomination is to expect the channel identifier to be the + // one ibc-go specifies. A longer term solution is to separate the path and base + // denomination in the ICS20 packet. If an intermediate hop prefixes the full denom + // with a channel identifier format different from our own, the base denomination + // will be incorrectly parsed, but the token will continue to be treated correctly + // as an IBC denomination. The hash used to store the token internally on our chain + // will be the same value as the base denomination being correctly parsed. + if i < length-1 && length > 2 && channeltypes.IsValidChannelID(fullDenomItems[i+1]) { + pathSlice = append(pathSlice, fullDenomItems[i], fullDenomItems[i+1]) + } else { + baseDenomSlice = fullDenomItems[i:] + break + } + } + + baseDenom := strings.Join(baseDenomSlice, "/") + + return pathSlice, baseDenom +} + +// validateTraceIdentifiers validates the correctness of the trace associated with a particular base denom. +func validateTraceIdentifiers(identifiers []string) error { + if len(identifiers) == 0 || len(identifiers)%2 != 0 { + return fmt.Errorf("trace info must come in pairs of port and channel identifiers '{portID}/{channelID}', got the identifiers: %s", identifiers) + } + + // validate correctness of port and channel identifiers + for i := 0; i < len(identifiers); i += 2 { + if err := host.PortIdentifierValidator(identifiers[i]); err != nil { + return errorsmod.Wrapf(err, "invalid port ID at position %d", i) + } + if err := host.ChannelIdentifierValidator(identifiers[i+1]); err != nil { + return errorsmod.Wrapf(err, "invalid channel ID at position %d", i) + } + } + return nil +} + // Validate performs a basic validation of the DenomTrace fields. func (dt DenomTrace) Validate() error { // empty trace is accepted when token lives on the original chain @@ -94,7 +145,7 @@ func (dt DenomTrace) Validate() error { // NOTE: no base denomination validation identifiers := strings.Split(dt.Path, "/") - return denominternal.ValidateTraceIdentifiers(identifiers) + return validateTraceIdentifiers(identifiers) } // Traces defines a wrapper type for a slice of DenomTrace. @@ -148,7 +199,7 @@ func ValidatePrefixedDenom(denom string) error { return nil } - pathSlice, baseDenom := denominternal.ExtractPathAndBaseFromFullDenom(denomSplit) + pathSlice, baseDenom := extractPathAndBaseFromFullDenom(denomSplit) if strings.TrimSpace(baseDenom) == "" { return errorsmod.Wrap(ErrInvalidDenomForTransfer, "base denomination cannot be blank") } @@ -160,7 +211,7 @@ func ValidatePrefixedDenom(denom string) error { } identifiers := strings.Split(path, "/") - return denominternal.ValidateTraceIdentifiers(identifiers) + return validateTraceIdentifiers(identifiers) } // validateIBCDenom validates that the given denomination is either: From 50ccd94580757a81dd6742ad8377b2c8377f7282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 23 May 2024 17:42:15 +0200 Subject: [PATCH 048/141] imp: ics20 v2 self review part 3 (#6373) * imp: self review items * apply jim's suggestion * Update modules/apps/transfer/keeper/msg_server_test.go * Update modules/apps/transfer/ibc_module.go * Update modules/apps/transfer/ibc_module.go --- modules/apps/transfer/ibc_module.go | 31 ++++++++++--------- modules/apps/transfer/keeper/msg_server.go | 6 ++-- .../apps/transfer/keeper/msg_server_test.go | 30 ++++++++++++++++++ modules/apps/transfer/types/events.go | 3 +- .../apps/transfer/types/expected_keepers.go | 2 +- modules/apps/transfer/types/msgs.go | 2 +- modules/apps/transfer/types/token.go | 14 +++++---- modules/apps/transfer/types/token_test.go | 27 ++++++++++++++++ 8 files changed, 86 insertions(+), 29 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index c87591e6c9f..f8435946c47 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -181,7 +181,7 @@ func (IBCModule) unmarshalPacketDataBytesToICS20V2(bz []byte, ics20Version strin case types.V1: var datav1 types.FungibleTokenPacketData if err := json.Unmarshal(bz, &datav1); err != nil { - return types.FungibleTokenPacketDataV2{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS20-V2 transfer packet data: %s", err.Error()) + return types.FungibleTokenPacketDataV2{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS20-V1 transfer packet data: %s", err.Error()) } if err := datav1.ValidateBasic(); err != nil { @@ -240,26 +240,28 @@ func (im IBCModule) OnRecvPacket( } } - ctx.EventManager().EmitEvent(sdk.NewEvent( - types.EventTypePacket, + eventAttributes := []sdk.Attribute{ sdk.NewAttribute(types.AttributeKeySender, data.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), sdk.NewAttribute(types.AttributeKeyTokens, types.Tokens(data.Tokens).String()), sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), - )) - - eventAttributes := []sdk.Attribute{ - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())), } + if ackErr != nil { eventAttributes = append(eventAttributes, sdk.NewAttribute(types.AttributeKeyAckError, ackErr.Error())) } - ctx.EventManager().EmitEvent(sdk.NewEvent( - sdk.EventTypeMessage, - eventAttributes..., - )) + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypePacket, + eventAttributes..., + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + }) // NOTE: acknowledgement will be written synchronously during IBC handler execution. return ack @@ -298,11 +300,11 @@ func (im IBCModule) OnAcknowledgementPacket( sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), sdk.NewAttribute(types.AttributeKeyTokens, types.Tokens(data.Tokens).String()), sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), + sdk.NewAttribute(types.AttributeKeyAck, ack.String()), ), sdk.NewEvent( sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(types.AttributeKeyAck, ack.String()), ), }) @@ -350,9 +352,8 @@ func (im IBCModule) OnTimeoutPacket( ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeTimeout, - sdk.NewAttribute(sdk.AttributeKeySender, data.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver), - sdk.NewAttribute(types.AttributeKeyTokens, types.Tokens(data.Tokens).String()), + sdk.NewAttribute(types.AttributeKeyReceiver, data.Sender), + sdk.NewAttribute(types.AttributeKeyRefundTokens, types.Tokens(data.Tokens).String()), sdk.NewAttribute(types.AttributeKeyMemo, data.Memo), ), sdk.NewEvent( diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index eaac2fb3ae9..f6a04ab4b81 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -38,10 +38,8 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "cannot transfer multiple coins with ics20-1") } - for _, coin := range coins { - if !k.bankKeeper.IsSendEnabledCoin(ctx, coin) { - return nil, errorsmod.Wrapf(types.ErrSendDisabled, "transfers are currently disabled for %s", coin.Denom) - } + if err := k.bankKeeper.IsSendEnabledCoins(ctx, coins...); err != nil { + return nil, errorsmod.Wrapf(types.ErrSendDisabled, err.Error()) } if k.bankKeeper.BlockedAddr(sender) { diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index e6d04001c4f..4806fc23f5d 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -113,6 +113,36 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { types.ErrSendDisabled, false, }, + { + "failure: bank send disabled for coin in multi coin transfer", + func() { + coin2 = sdk.NewCoin("bond", sdkmath.NewInt(100)) + coins := sdk.NewCoins(coin1, coin2) + + // send some coins of the second denom from bank module to the sender account as well + suite.Require().NoError(suite.chainA.GetSimApp().BankKeeper.MintCoins(suite.chainA.GetContext(), types.ModuleName, sdk.NewCoins(coin2))) + suite.Require().NoError(suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, suite.chainA.SenderAccount.GetAddress(), sdk.NewCoins(coin2))) + + msg = types.NewMsgTransfer( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + coins, + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + suite.chainB.GetTimeoutHeight(), 0, // only use timeout height + "memo", + ) + + err := suite.chainA.GetSimApp().BankKeeper.SetParams(suite.chainA.GetContext(), + banktypes.Params{ + SendEnabled: []*banktypes.SendEnabled{{Denom: coin2.Denom, Enabled: false}}, + }, + ) + suite.Require().NoError(err) + }, + types.ErrSendDisabled, + true, + }, { "failure: channel does not exist", func() { diff --git a/modules/apps/transfer/types/events.go b/modules/apps/transfer/types/events.go index 7a4bfaf2a04..f310ba5d0d9 100644 --- a/modules/apps/transfer/types/events.go +++ b/modules/apps/transfer/types/events.go @@ -13,8 +13,7 @@ const ( AttributeKeyDenom = "denom" AttributeKeyTokens = "tokens" AttributeKeyRefundReceiver = "refund_receiver" - AttributeKeyRefundDenom = "refund_denom" - AttributeKeyRefundAmount = "refund_amount" + AttributeKeyRefundTokens = "refund_tokens" AttributeKeyAckSuccess = "success" AttributeKeyAck = "acknowledgement" AttributeKeyAckError = "error" diff --git a/modules/apps/transfer/types/expected_keepers.go b/modules/apps/transfer/types/expected_keepers.go index e639a84606f..9ed02474405 100644 --- a/modules/apps/transfer/types/expected_keepers.go +++ b/modules/apps/transfer/types/expected_keepers.go @@ -27,7 +27,7 @@ type BankKeeper interface { SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error SendCoinsFromAccountToModule(ctx context.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error BlockedAddr(addr sdk.AccAddress) bool - IsSendEnabledCoin(ctx context.Context, coin sdk.Coin) bool + IsSendEnabledCoins(ctx context.Context, coins ...sdk.Coin) error HasDenomMetaData(ctx context.Context, denom string) bool SetDenomMetaData(ctx context.Context, denomMetaData banktypes.Metadata) GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index fd28b8778e5..3fdfcfefe85 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -126,7 +126,7 @@ func isValidIBCCoin(coin sdk.Coin) bool { return validateIBCCoin(coin) == nil } -// isValidIBCCoin returns true if the token provided is valid, +// validateIBCCoin returns true if the token provided is valid, // and should be used to transfer tokens. The token must // have a positive amount. func validateIBCCoin(coin sdk.Coin) error { diff --git a/modules/apps/transfer/types/token.go b/modules/apps/transfer/types/token.go index 4fe2928489d..68fd3383b75 100644 --- a/modules/apps/transfer/types/token.go +++ b/modules/apps/transfer/types/token.go @@ -22,14 +22,16 @@ func (t Token) Validate() error { return errorsmod.Wrapf(ErrInvalidAmount, "amount must be strictly positive: got %d", amount) } - if len(t.Trace) == 0 { - return nil - } + if len(t.Trace) != 0 { + trace := strings.Join(t.Trace, "/") + identifiers := strings.Split(trace, "/") - trace := strings.Join(t.Trace, "/") - identifiers := strings.Split(trace, "/") + if err := validateTraceIdentifiers(identifiers); err != nil { + return err + } + } - return validateTraceIdentifiers(identifiers) + return nil } // GetFullDenomPath returns the full denomination according to the ICS20 specification: diff --git a/modules/apps/transfer/types/token_test.go b/modules/apps/transfer/types/token_test.go index 7ae88757b90..c80fb975ec9 100644 --- a/modules/apps/transfer/types/token_test.go +++ b/modules/apps/transfer/types/token_test.go @@ -110,6 +110,33 @@ func TestValidate(t *testing.T) { }, ErrInvalidDenomForTransfer, }, + { + "failure: invalid amount string", + Token{ + Denom: "atom", + Amount: "value", + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + ErrInvalidAmount, + }, + { + "failure: amount is zero", + Token{ + Denom: "atom", + Amount: "0", + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + ErrInvalidAmount, + }, + { + "failure: amount is negative", + Token{ + Denom: "atom", + Amount: "-1", + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + ErrInvalidAmount, + }, { "failure: invalid identifier in trace", Token{ From 87eb32e5cd0918b2ddd0f5ff93dd6e9a8c1b1207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 23 May 2024 17:45:19 +0200 Subject: [PATCH 049/141] chore: remove duplicate test case --- modules/apps/transfer/ibc_module_test.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index e52b04fc7da..71f261480ed 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -144,12 +144,7 @@ func (suite *TransferTestSuite) TestOnChanOpenTry() { }, nil, types.V1, }, { - "success: invalid counterparty version, we use our proposed version", func() { - counterpartyVersion = "version" - }, nil, types.V2, - }, - { - "success: invalid counterparty version proposes new version", func() { + "success: invalid counterparty version, we propose new version", func() { // transfer module will propose the default version counterpartyVersion = "version" }, nil, types.V2, From e8b9d5a918a43310201b4b24db8052127a1884d2 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 23 May 2024 19:39:11 +0300 Subject: [PATCH 050/141] chore: address minor nits (#6374) --- modules/apps/transfer/types/msgs_test.go | 2 +- modules/apps/transfer/types/packet.go | 2 +- modules/apps/transfer/types/packet_test.go | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index 602551980c6..f1361214d02 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -42,7 +42,7 @@ var ( ibcCoins = sdk.NewCoins(sdk.NewCoin("ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdkmath.NewInt(100))) invalidIBCCoins = sdk.NewCoins(sdk.NewCoin("ibc/7F1D3FCF4AE79E1554", sdkmath.NewInt(100))) invalidDenomCoins = []sdk.Coin{{Denom: "0atom", Amount: sdkmath.NewInt(100)}} - zeroCoins = sdk.NewCoins(sdk.Coin{Denom: "atoms", Amount: sdkmath.NewInt(0)}) + zeroCoins = []sdk.Coin{{Denom: "atoms", Amount: sdkmath.NewInt(0)}} timeoutHeight = clienttypes.NewHeight(0, 10) ) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 649bc7cddad..e706084d56a 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -97,7 +97,7 @@ func (ftpd FungibleTokenPacketData) GetCustomPacketData(key string) interface{} return memoData } -// NewFungibleTokenPacketDataV2 constructs a new NewFungibleTokenPacketDataV2 instance +// NewFungibleTokenPacketDataV2 constructs a new FungibleTokenPacketDataV2 instance func NewFungibleTokenPacketDataV2( tokens []Token, sender, receiver string, diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 9292f207f7f..71a0cfc81c7 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" + ibctesting "github.com/cosmos/ibc-go/v8/testing" ) const ( @@ -338,6 +339,22 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { ), ibcerrors.ErrInvalidAddress, }, + { + "failure: memo field too large", + types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: denom, + Amount: largeAmount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + ibctesting.GenerateString(types.MaximumMemoLength+1), + ), + types.ErrInvalidMemo, + }, } for _, tc := range testCases { From 2519593ade4fe4fe2dd9c35ee918c23aa568b423 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 26 May 2024 23:06:35 +0200 Subject: [PATCH 051/141] fix lint warning, add extra godocs, and some other small fixes and cleanup --- modules/apps/transfer/ibc_module.go | 10 +- modules/apps/transfer/keeper/keeper.go | 2 +- .../apps/transfer/keeper/mbt_relay_test.go | 2 +- modules/apps/transfer/keeper/relay.go | 207 +++++++----------- modules/apps/transfer/keeper/relay_test.go | 15 +- modules/apps/transfer/types/keys.go | 4 - modules/apps/transfer/types/packet.pb.go | 2 +- modules/apps/transfer/types/transfer.pb.go | 73 +++--- modules/apps/transfer/types/tx.pb.go | 3 +- .../applications/transfer/v1/transfer.proto | 9 +- proto/ibc/applications/transfer/v1/tx.proto | 2 +- .../ibc/applications/transfer/v2/packet.proto | 2 +- 12 files changed, 149 insertions(+), 182 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 4bf07b6cd7a..602b177bb81 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -230,10 +230,7 @@ func (im IBCModule) OnRecvPacket( // only attempt the application logic if the packet data // was successfully decoded if ack.Success() { - err, async := im.keeper.OnRecvPacket(ctx, packet, data) - if async { - return nil // Ok if we do this, which guaranteee we have that we can return the proper ack later on? - } + async, err := im.keeper.OnRecvPacket(ctx, packet, data) if err != nil { ack = channeltypes.NewErrorAcknowledgement(err) ackErr = err @@ -241,6 +238,11 @@ func (im IBCModule) OnRecvPacket( } else { im.keeper.Logger(ctx).Info("successfully handled ICS-20 packet", "sequence", packet.Sequence) } + + if async { + // NOTE: acknowledgement will be written asynchronously + return nil + } } eventAttributes := []sdk.Attribute{ diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 3fb33e12a0a..913221651dd 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -304,7 +304,7 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability return k.scopedKeeper.ClaimCapability(ctx, cap, name) } -// SetForwardedPacket sets the forwarded packet in the private store. +// SetForwardedPacket sets the forwarded packet in the store. func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, sequence uint64, packet channeltypes.Packet) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshal(&packet) diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 14b95eb0b4a..a66999e4876 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -371,7 +371,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { } case "OnRecvPacket": var async bool - err, async = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, tc.packet.Data) + async, err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, tc.packet.Data) suite.Require().False(async) case "OnTimeoutPacket": diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index ecdb4cd96d7..675a2625196 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -1,6 +1,7 @@ package keeper import ( + "errors" "fmt" "strings" "time" @@ -179,49 +180,32 @@ func (k Keeper) sendTransfer( // and sent to the receiving address. Otherwise if the sender chain is sending // back tokens this chain originally transferred to it, the tokens are // unescrowed and sent to the receiving address. -func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) (error, bool) { +func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) (bool, error) { // validate packet data upon receiving - // same things here if we put the validate memo here this function would return an error. - if err := data.ValidateBasic(); err != nil { - return errorsmod.Wrapf(err, "error validating ICS-20 transfer packet data"), false + return false, errorsmod.Wrapf(err, "error validating ICS-20 transfer packet data") } if !k.GetParams(ctx).ReceiveEnabled { - return types.ErrReceiveDisabled, false + return false, types.ErrReceiveDisabled } - // Receiver addresses logic: - - var finalReceiver sdk.AccAddress - var receiver sdk.AccAddress - var err error - - if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { - // Transaction would abort already for previous check on Memo - forwardAddress := types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) - receiver = forwardAddress - finalReceiver, err = sdk.AccAddressFromBech32(data.Receiver) - if err != nil { - return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver), false - } - } else { - receiver, err = sdk.AccAddressFromBech32(data.Receiver) - if err != nil { - return errorsmod.Wrapf(err, "failed to decode receiver address: %s", data.Receiver), false - } - } + var ( + err error + receiver sdk.AccAddress // final receiver of tokens if there is no forwarding info, otherwise, receiver in the next hop + finalReceiver sdk.AccAddress // final receiver of tokens if there is forwarding info + ) - if string(data.Sender) == "" { - return errorsmod.Wrapf(err, "empty sender address: %s", data.Sender), false + receiver, err = sdk.AccAddressFromBech32(data.Receiver) + if err != nil { + return false, errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "failed to decode receiver address %s: %v", data.Receiver, err) } - - if string(receiver) == "" { - return errorsmod.Wrapf(err, "empty receiver address: %s", receiver), false + if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { + receiver = types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) + finalReceiver = receiver } var receivedTokens sdk.Coins - for _, token := range data.Tokens { fullDenomPath := token.GetFullDenomPath() @@ -233,7 +217,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t // parse the transfer amount transferAmount, ok := sdkmath.NewIntFromString(token.Amount) if !ok { - return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount: %s", token.Amount), false + return false, errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount: %s", token.Amount) } // This is the prefix that would have been prefixed to the denomination @@ -262,12 +246,12 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t token := sdk.NewCoin(denom, transferAmount) if k.bankKeeper.BlockedAddr(receiver) { - return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver), false + return false, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) } escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) if err := k.unescrowToken(ctx, escrowAddress, receiver, token); err != nil { - return err, false + return false, err } defer func() { @@ -287,9 +271,9 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t ), ) }() + // Appending token. The new denom has been computed receivedTokens = append(receivedTokens, token) - } // sender chain is the source, mint vouchers @@ -323,14 +307,14 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t if err := k.bankKeeper.MintCoins( ctx, types.ModuleName, sdk.NewCoins(voucher), ); err != nil { - return errorsmod.Wrap(err, "failed to mint IBC tokens"), false + return false, errorsmod.Wrap(err, "failed to mint IBC tokens") } // send to receiver if err := k.bankKeeper.SendCoinsFromModuleToAccount( ctx, types.ModuleName, receiver, sdk.NewCoins(voucher), ); err != nil { - return errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()), false + return false, errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()) } defer func() { @@ -351,23 +335,13 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t ) }() - // Appending voucher. The new denom has been computed receivedTokens = append(receivedTokens, voucher) - } // END OF FOR CYCLE - - /* If ack wasn't successful in the implementation we would have already errored out. No need of this check: - if !ack.Success() { - return ack - } - */ + } // Adding forwarding logic if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { memo := "" - nextForwardingPath := types.ForwardingInfo{ - Hops: data.ForwardingPath.Hops[1:], - Memo: data.ForwardingPath.Memo, - } + var nextForwardingPath types.ForwardingInfo if len(data.ForwardingPath.Hops) == 1 { memo = data.ForwardingPath.Memo @@ -375,37 +349,45 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t Hops: nil, Memo: data.ForwardingPath.Memo, } + } else { + nextForwardingPath = types.ForwardingInfo{ + Hops: data.ForwardingPath.Hops[1:], + Memo: data.ForwardingPath.Memo, + } } + // Assign to timestamp --> current + 1 h timeoutTimestamp := uint64(ctx.BlockTime().Add(time.Hour).UnixNano()) - sequence, err := k.sendTransfer(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, receivedTokens, receiver, string(finalReceiver), clienttypes.Height{}, timeoutTimestamp, memo, &nextForwardingPath) + sequence, err := k.sendTransfer( + ctx, + data.ForwardingPath.Hops[0].PortId, + data.ForwardingPath.Hops[0].ChannelId, + receivedTokens, + receiver, + string(finalReceiver), + clienttypes.Height{}, + timeoutTimestamp, + memo, + &nextForwardingPath, + ) if err != nil { - return err, false + return false, err } - k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortID, data.ForwardingPath.Hops[0].ChannelId, sequence, packet) - - // The return value will be used by the onRecvPacket in the ibc_module.go - // If we return nil here, then we will write a successful sinc ack. - // If we reutrn an error, then we will write a sinc error ack - // The onRecvPacket in the ibc_module.go has as return value ibcexported.Acknowledgement - // and it will return either an error ack or succesfull ack. - // Thus to achieve the correct behaviour, we should be able to return a nil value in the ibc_module.go - // onRecvPacket function. - // return nil - // Instead of returning simply nil, we will return a sentinel value that can be used to return nil in the ibc_module.go - // onRecvPacket function. - return nil, true - + k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortId, data.ForwardingPath.Hops[0].ChannelId, sequence, packet) + return true, nil } + // The ibc_module.go module will return the proper ack. - return nil, false + return false, nil } -// OnAcknowledgementPacket responds to the success or failure of a packet -// acknowledgement written on the receiving chain. If the acknowledgement -// was a success then nothing occurs. If the acknowledgement failed, then -// the sender is refunded their tokens using the refundPacketToken function. +// OnAcknowledgementPacket either reverts the state changes executed in receive +// and send packet if the chain acted as a middle hop on a multihop transfer; or +// responds to the success or failure of a packet acknowledgement written on the +// final receiving chain, if it acted as the original sender chain. If the +// acknowledgement was a success then nothing occurs. If the acknowledgement failed, +// then the sender is refunded their tokens using the refundPacketToken function. func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) error { channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) if !ok { @@ -416,36 +398,21 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac if found { switch ack.Response.(type) { case *channeltypes.Acknowledgement_Result: - // the acknowledgement succeeded on the receiving chain so nothing - // needs to be executed and no error needs to be returned - // here the ibc_module.go will generate the sucss ack. - - // Figure Out how to do this - - FungibleTokenPacketAcknowledgement := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) // []byte{byte(1)}) - // Error: "forwarded packet succeeded", - // Result: true, - // } - - return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, packet, FungibleTokenPacketAcknowledgement) - + // the acknowledgement succeeded on the receiving chain so + // we write the asynchronous acknowledgement for the sender + // of the previous packet. + FungibleTokenPacketAcknowledgement := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) + return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, FungibleTokenPacketAcknowledgement) case *channeltypes.Acknowledgement_Error: // the forwarded packet has failed, thus the funds have been refunded to the forwarding address. // we must revert the changes that came from successfully receiving the tokens on our chain // before propogating the error acknowledgement back to original sender chain + if err := k.revertInFlightChanges(ctx, packet, prevPacket, data); err != nil { + return err + } - // Should Check return value - k.revertInFlightChanges(ctx, packet, prevPacket, data) - // Figure Out how to do this - - FungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(fmt.Errorf("forwarded packet failed")) - /* channeltypes.Acknowledgement{ - channeltypes.Acknowledgement.Response.Error: "forwarded packet failed", - channeltypes.Acknowledgement.Response.Result: false, - }*/ - // set the acknowledgement so that it can be verified on the other side - return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, packet, FungibleTokenPacketAcknowledgement) - + FungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet failed")) + return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, FungibleTokenPacketAcknowledgement) default: return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected one of [%T, %T], got %T", channeltypes.Acknowledgement_Result{}, channeltypes.Acknowledgement_Error{}, ack.Response) } @@ -461,11 +428,11 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected one of [%T, %T], got %T", channeltypes.Acknowledgement_Result{}, channeltypes.Acknowledgement_Error{}, ack.Response) } } - return nil } -// OnTimeoutPacket refunds the sender since the original packet sent was -// never received and has been timed out. +// OnTimeoutPacket either reverts the state changes executed in receive and send +// packet if the chain acted as a middle hop on a multihop transfer; or refunds +// the sender if the original packet sent was never received and has been timed out. func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) error { channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) if !ok { @@ -474,16 +441,12 @@ func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, dat prevPacket, found := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) if found { - k.revertInFlightChanges(ctx, packet, prevPacket, data) - - FungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(fmt.Errorf("forwarded packet failed")) - - /*FungibleTokenPacketAcknowledgement := channeltypes.Acknowledgement{ - channeltypes.Acknowledgement.Response.Error: "forwarded packet failed", - channeltypes.Acknowledgement.Response.Result: false, - }*/ + if err := k.revertInFlightChanges(ctx, packet, prevPacket, data); err != nil { + return err + } - return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, packet, FungibleTokenPacketAcknowledgement) + FungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(fmt.Errorf("forwarded packet timed out")) + return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, FungibleTokenPacketAcknowledgement) } else { return k.refundPacketToken(ctx, packet, data) } @@ -536,15 +499,16 @@ func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, d return nil } +// revertInFlightChanges reverts the logic of receive packet and send packet +// that occurs in the middle chains during a packet forwarding. If an error +// occurs further down the line, the state changes on this chain must be +// reverted before sending back the error acknowledgement to ensure atomic packet forwarding. func (k Keeper) revertInFlightChanges(ctx sdk.Context, sentPacket channeltypes.Packet, receivedPacket channeltypes.Packet, sentPacketData types.FungibleTokenPacketDataV2) error { forwardEscrow := types.GetEscrowAddress(sentPacket.SourcePort, sentPacket.SourceChannel) reverseEscrow := types.GetEscrowAddress(receivedPacket.DestinationPort, receivedPacket.DestinationChannel) - // the token on our chain is the token in the sentPacket - // We could unmarshall the sentPacket data and use it in the for or use sentPacketData - // Need to understand how to deal with this. The bank functions wants a coin and not a v3token type + // the token on our chain is the token in the sentPacket for _, token := range sentPacketData.Tokens { - fullDenomPath := token.GetFullDenomPath() // parse the denomination from the full denom path @@ -555,25 +519,22 @@ func (k Keeper) revertInFlightChanges(ctx sdk.Context, sentPacket channeltypes.P if !ok { return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", transferAmount) } - sdkToken := sdk.NewCoin(trace.IBCDenom(), transferAmount) + coin := sdk.NewCoin(trace.IBCDenom(), transferAmount) // check if the packet we sent out was sending as source or not - // in this case we escrowed the outgoing tokens + // if it is source, then we escrowed the outgoing tokens if types.SenderChainIsSource(sentPacket.SourcePort, sentPacket.SourceChannel, fullDenomPath) { // check if the packet we received was a source token for our chain - // Check if here should be ReceiverChainIsSource + // check if here should be ReceiverChainIsSource if types.SenderChainIsSource(receivedPacket.DestinationPort, receivedPacket.DestinationChannel, fullDenomPath) { // receive sent tokens from the received escrow to the forward escrow account // so we must send the tokens back from the forward escrow to the original received escrow account - // To check if this is proper - - return k.unescrowToken(ctx, forwardEscrow, reverseEscrow, sdkToken) + return k.unescrowToken(ctx, forwardEscrow, reverseEscrow, coin) } else { // receive minted vouchers and sent to the forward escrow account // so we must remove the vouchers from the forward escrow account and burn them - // Is this ok? if err := k.bankKeeper.BurnCoins( - ctx, types.ModuleName, sdk.NewCoins(sdkToken), + ctx, types.ModuleName, sdk.NewCoins(coin), ); err != nil { return err } @@ -582,15 +543,13 @@ func (k Keeper) revertInFlightChanges(ctx sdk.Context, sentPacket channeltypes.P // in this case we burned the vouchers of the outgoing packets // check if the packet we received was a source token for our chain // in this case, the tokens were unescrowed from the reverse escrow account - if types.SenderChainIsSource(receivedPacket.DestinationPort, receivedPacket.DestinationChannel, token.Denom) { + if types.SenderChainIsSource(receivedPacket.DestinationPort, receivedPacket.DestinationChannel, fullDenomPath) { // in this case we must mint the burned vouchers and send them back to the escrow account - // mint vouchers back to sender - // Is this ok? - if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdkToken)); err != nil { + if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(coin)); err != nil { return err } - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, reverseEscrow, sdk.NewCoins(sdkToken)); err != nil { + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, reverseEscrow, sdk.NewCoins(coin)); err != nil { panic(fmt.Errorf("unable to send coins from module to account despite previously minting coins to module account: %v", err)) } } diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 53585121d7e..2a560964700 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -428,7 +428,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) var async bool - err, async = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) + async, err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) suite.Require().False(async) // check total amount in escrow of received token denom on receiving chain totalEscrow := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), sdk.DefaultBondDenom) @@ -469,7 +469,7 @@ func (suite *KeeperTestSuite) TestPathForwarding() { forwardingPath := types.ForwardingInfo{ Hops: []*types.Hop{ { - PortID: path2.EndpointA.ChannelConfig.PortID, + PortId: path2.EndpointA.ChannelConfig.PortID, ChannelId: path2.EndpointA.ChannelID, }, }, @@ -596,7 +596,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT // execute onRecvPacket, when chaninB receives the source token the escrow amount should decrease var async bool - err, async := suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) + async, err := suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) suite.Require().False(async) suite.Require().NoError(err) @@ -1045,7 +1045,7 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { forwardingPath := types.ForwardingInfo{ Hops: []*types.Hop{ { - PortID: path2.EndpointB.ChannelConfig.PortID, + PortId: path2.EndpointB.ChannelConfig.PortID, ChannelId: path2.EndpointB.ChannelID, }, }, @@ -1091,7 +1091,6 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { coin = sdk.NewCoin(denomTrace.IBCDenom(), amount) totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - } // This test is probably overcomplicated. Could have used RecvPacketWithResult directly. @@ -1137,7 +1136,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { forwardingPath := types.ForwardingInfo{ Hops: []*types.Hop{ { - PortID: path2.EndpointB.ChannelConfig.PortID, + PortId: path2.EndpointB.ChannelConfig.PortID, ChannelId: path2.EndpointB.ChannelID, }, }, @@ -1177,7 +1176,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) var async bool - err, async = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) + async, err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) // If forwarding has been triggered then the async must be true. suite.Require().True(async) suite.Require().Nil(err) @@ -1217,7 +1216,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { packetRecv = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) // execute onRecvPacket, when chaninA receives the tokens the escrow amount on B should increase to amount - err, async = suite.chainA.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainA.GetContext(), packetRecv, data) + async, err = suite.chainA.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainA.GetContext(), packetRecv, data) suite.Require().False(async) suite.Require().NoError(err) diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index 74152d66d46..2862087558e 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -100,10 +100,6 @@ func TotalEscrowForDenomKey(denom string) []byte { return []byte(fmt.Sprintf("%s/%s", KeyTotalEscrowPrefix, denom)) } -func TotalForwardForDenomKey(denom string) []byte { - return []byte(fmt.Sprintf("%s/%s", KeyTotalForwardPrefix, denom)) -} - // PacketForwardKey returns the store key under which the forwarded packet is stored // for the provided portID, channelID, and packet sequence. func PacketForwardKey(portID, channelID string, sequence uint64) []byte { diff --git a/modules/apps/transfer/types/packet.pb.go b/modules/apps/transfer/types/packet.pb.go index 9898482adc8..d9fd757b65e 100644 --- a/modules/apps/transfer/types/packet.pb.go +++ b/modules/apps/transfer/types/packet.pb.go @@ -119,7 +119,7 @@ type FungibleTokenPacketDataV2 struct { Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` // optional memo Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` - // optional forwardingInfo struct + // optional forwarding information ForwardingPath *ForwardingInfo `protobuf:"bytes,5,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` } diff --git a/modules/apps/transfer/types/transfer.pb.go b/modules/apps/transfer/types/transfer.pb.go index cc7cdff4d8b..b94c38fb080 100644 --- a/modules/apps/transfer/types/transfer.pb.go +++ b/modules/apps/transfer/types/transfer.pb.go @@ -139,6 +139,9 @@ func (m *Params) GetReceiveEnabled() bool { return false } +// ForwardingInfo defines a list of port ID, channel ID pairs determining the path +// through which a packet must be forwarded, and the memo string to be used in the +// final destination of the tokens. type ForwardingInfo struct { Hops []*Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops,omitempty"` Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` @@ -191,9 +194,11 @@ func (m *ForwardingInfo) GetMemo() string { return "" } +// Hop defines a port ID, channel ID pair specifying where tokens must be forwarded +// next in a multihop transfer. type Hop struct { - PortID string `protobuf:"bytes,1,opt,name=portID,proto3" json:"portID,omitempty"` - ChannelId string `protobuf:"bytes,2,opt,name=channelId,proto3" json:"channelId,omitempty"` + 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"` } func (m *Hop) Reset() { *m = Hop{} } @@ -229,9 +234,9 @@ func (m *Hop) XXX_DiscardUnknown() { var xxx_messageInfo_Hop proto.InternalMessageInfo -func (m *Hop) GetPortID() string { +func (m *Hop) GetPortId() string { if m != nil { - return m.PortID + return m.PortId } return "" } @@ -255,29 +260,29 @@ func init() { } var fileDescriptor_5041673e96e97901 = []byte{ - // 340 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xc1, 0x4a, 0xeb, 0x40, - 0x18, 0x85, 0x9b, 0xb6, 0x94, 0xdb, 0xe9, 0xa5, 0x17, 0x66, 0x71, 0xe9, 0xa2, 0x86, 0x36, 0x1b, - 0x0b, 0x62, 0x42, 0x15, 0x51, 0x70, 0x21, 0x48, 0x95, 0x76, 0xa7, 0xa5, 0x2b, 0x5d, 0x94, 0xc9, - 0xe4, 0x6f, 0x33, 0x90, 0xcc, 0x3f, 0xcc, 0xa4, 0x11, 0xdf, 0xc2, 0xc7, 0x72, 0xd9, 0xa5, 0x4b, - 0x69, 0x5f, 0x44, 0x32, 0xc6, 0xd0, 0x95, 0xbb, 0x93, 0x2f, 0xdf, 0x0c, 0x73, 0x38, 0xe4, 0x44, - 0x84, 0x3c, 0x60, 0x4a, 0x25, 0x82, 0xb3, 0x4c, 0xa0, 0x34, 0x41, 0xa6, 0x99, 0x34, 0x2b, 0xd0, - 0x41, 0x3e, 0xae, 0xb2, 0xaf, 0x34, 0x66, 0x48, 0xfb, 0x22, 0xe4, 0xfe, 0xa1, 0xec, 0x57, 0x42, - 0x3e, 0xf6, 0x6e, 0x08, 0x99, 0x80, 0xc4, 0x74, 0xa1, 0x19, 0x07, 0x4a, 0x49, 0x53, 0xb1, 0x2c, - 0xee, 0x39, 0x03, 0x67, 0xd4, 0x9e, 0xdb, 0x4c, 0x8f, 0x08, 0x09, 0x99, 0x81, 0x65, 0x54, 0x68, - 0xbd, 0xba, 0xfd, 0xd3, 0x2e, 0x88, 0x3d, 0xe7, 0x2d, 0x48, 0xeb, 0x81, 0x69, 0x96, 0x1a, 0x3a, - 0x24, 0x7f, 0x0d, 0xc8, 0x68, 0x09, 0x92, 0x85, 0x09, 0x44, 0xf6, 0x92, 0x3f, 0xf3, 0x4e, 0xc1, - 0xee, 0xbe, 0x11, 0x3d, 0x26, 0xff, 0x34, 0x70, 0x10, 0x39, 0x54, 0x56, 0xdd, 0x5a, 0xdd, 0x12, - 0x97, 0xa2, 0xf7, 0x4c, 0xba, 0xf7, 0xa8, 0x5f, 0x98, 0x8e, 0x84, 0x5c, 0xcf, 0xe4, 0x0a, 0xe9, - 0x05, 0x69, 0xc6, 0xa8, 0x4c, 0xcf, 0x19, 0x34, 0x46, 0x9d, 0xb3, 0xa1, 0xff, 0x5b, 0x2b, 0x7f, - 0x8a, 0x6a, 0x6e, 0xf5, 0xa2, 0x51, 0x0a, 0x29, 0x96, 0xef, 0xb6, 0xd9, 0xbb, 0x26, 0x8d, 0x29, - 0x2a, 0xfa, 0x9f, 0xb4, 0x14, 0xea, 0x6c, 0x36, 0x29, 0xeb, 0x96, 0x5f, 0xb4, 0x4f, 0xda, 0x3c, - 0x66, 0x52, 0x42, 0x32, 0x8b, 0x7e, 0xfa, 0x56, 0xe0, 0xf6, 0xf1, 0x7d, 0xe7, 0x3a, 0xdb, 0x9d, - 0xeb, 0x7c, 0xee, 0x5c, 0xe7, 0x6d, 0xef, 0xd6, 0xb6, 0x7b, 0xb7, 0xf6, 0xb1, 0x77, 0x6b, 0x4f, - 0x97, 0x6b, 0x91, 0xc5, 0x9b, 0xd0, 0xe7, 0x98, 0x06, 0x1c, 0x4d, 0x8a, 0x26, 0x10, 0x21, 0x3f, - 0x5d, 0x63, 0x90, 0x5f, 0x05, 0x29, 0x46, 0x9b, 0x04, 0x4c, 0xb1, 0xda, 0xc1, 0x5a, 0xd9, 0xab, - 0x02, 0x13, 0xb6, 0xec, 0x50, 0xe7, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbe, 0x42, 0x60, 0x0c, - 0xd7, 0x01, 0x00, 0x00, + // 342 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xc1, 0x4a, 0x2b, 0x31, + 0x14, 0x86, 0x3b, 0x6d, 0xe9, 0xbd, 0x4d, 0x2f, 0xbd, 0x90, 0x8d, 0x5d, 0xe8, 0xd0, 0xce, 0xc6, + 0x82, 0x38, 0x43, 0x15, 0xd1, 0x8d, 0x08, 0xa2, 0xd2, 0xee, 0xb4, 0x74, 0xa5, 0x8b, 0x92, 0x49, + 0xd2, 0x4e, 0x60, 0x26, 0x27, 0x24, 0xe9, 0x88, 0x6f, 0xe1, 0x63, 0xb9, 0xec, 0xd2, 0xa5, 0xb4, + 0x2f, 0x22, 0x89, 0x43, 0xe9, 0xca, 0xdd, 0xc9, 0x7f, 0xbe, 0x84, 0x7c, 0xfc, 0xe8, 0x44, 0xa4, + 0x34, 0x21, 0x4a, 0xe5, 0x82, 0x12, 0x2b, 0x40, 0x9a, 0xc4, 0x6a, 0x22, 0xcd, 0x82, 0xeb, 0xa4, + 0x1c, 0xed, 0xe6, 0x58, 0x69, 0xb0, 0x80, 0x0f, 0x45, 0x4a, 0xe3, 0x7d, 0x38, 0xde, 0x01, 0xe5, + 0x28, 0xba, 0x41, 0xe8, 0x8e, 0x4b, 0x28, 0x66, 0x9a, 0x50, 0x8e, 0x31, 0x6a, 0x2a, 0x62, 0xb3, + 0x5e, 0xd0, 0x0f, 0x86, 0xed, 0xa9, 0x9f, 0xf1, 0x11, 0x42, 0x29, 0x31, 0x7c, 0xce, 0x1c, 0xd6, + 0xab, 0xfb, 0x4d, 0xdb, 0x25, 0xfe, 0x5e, 0x34, 0x43, 0xad, 0x47, 0xa2, 0x49, 0x61, 0xf0, 0x00, + 0xfd, 0x33, 0x5c, 0xb2, 0x39, 0x97, 0x24, 0xcd, 0x39, 0xf3, 0x8f, 0xfc, 0x9d, 0x76, 0x5c, 0x76, + 0xff, 0x13, 0xe1, 0x63, 0xf4, 0x5f, 0x73, 0xca, 0x45, 0xc9, 0x77, 0x54, 0xdd, 0x53, 0xdd, 0x2a, + 0xae, 0xc0, 0xe8, 0x05, 0x75, 0x1f, 0x40, 0xbf, 0x12, 0xcd, 0x84, 0x5c, 0x4e, 0xe4, 0x02, 0xf0, + 0x05, 0x6a, 0x66, 0xa0, 0x4c, 0x2f, 0xe8, 0x37, 0x86, 0x9d, 0xb3, 0x41, 0xfc, 0x9b, 0x55, 0x3c, + 0x06, 0x35, 0xf5, 0xb8, 0x33, 0x2a, 0x78, 0x01, 0xd5, 0xbf, 0xfd, 0x1c, 0x5d, 0xa3, 0xc6, 0x18, + 0x14, 0x3e, 0x40, 0x7f, 0x14, 0x68, 0x3b, 0x17, 0xac, 0xf2, 0x6d, 0xb9, 0xe3, 0x84, 0x39, 0x63, + 0x9a, 0x11, 0x29, 0x79, 0xee, 0x76, 0x95, 0x71, 0x95, 0x4c, 0xd8, 0xed, 0xd3, 0xc7, 0x26, 0x0c, + 0xd6, 0x9b, 0x30, 0xf8, 0xda, 0x84, 0xc1, 0xfb, 0x36, 0xac, 0xad, 0xb7, 0x61, 0xed, 0x73, 0x1b, + 0xd6, 0x9e, 0x2f, 0x97, 0xc2, 0x66, 0xab, 0x34, 0xa6, 0x50, 0x24, 0x14, 0x4c, 0x01, 0x26, 0x11, + 0x29, 0x3d, 0x5d, 0x42, 0x52, 0x5e, 0x25, 0x05, 0xb0, 0x55, 0xce, 0x8d, 0xeb, 0x6d, 0xaf, 0x2f, + 0xfb, 0xa6, 0xb8, 0x49, 0x5b, 0xbe, 0xaa, 0xf3, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x97, 0xdc, + 0x67, 0x28, 0xd9, 0x01, 0x00, 0x00, } func (m *DenomTrace) Marshal() (dAtA []byte, err error) { @@ -431,10 +436,10 @@ func (m *Hop) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - if len(m.PortID) > 0 { - i -= len(m.PortID) - copy(dAtA[i:], m.PortID) - i = encodeVarintTransfer(dAtA, i, uint64(len(m.PortID))) + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintTransfer(dAtA, i, uint64(len(m.PortId))) i-- dAtA[i] = 0xa } @@ -509,7 +514,7 @@ func (m *Hop) Size() (n int) { } var l int _ = l - l = len(m.PortID) + l = len(m.PortId) if l > 0 { n += 1 + l + sovTransfer(uint64(l)) } @@ -877,7 +882,7 @@ func (m *Hop) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PortID", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -905,7 +910,7 @@ func (m *Hop) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.PortID = string(dAtA[iNdEx:postIndex]) + m.PortId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { diff --git a/modules/apps/transfer/types/tx.pb.go b/modules/apps/transfer/types/tx.pb.go index 124af2460d2..77cc4a4a29f 100644 --- a/modules/apps/transfer/types/tx.pb.go +++ b/modules/apps/transfer/types/tx.pb.go @@ -55,7 +55,8 @@ type MsgTransfer struct { // optional memo Memo string `protobuf:"bytes,8,opt,name=memo,proto3" json:"memo,omitempty"` // tokens to be transferred - Tokens []types.Coin `protobuf:"bytes,9,rep,name=tokens,proto3" json:"tokens"` + Tokens []types.Coin `protobuf:"bytes,9,rep,name=tokens,proto3" json:"tokens"` + // optional forwarding information ForwardingPath *ForwardingInfo `protobuf:"bytes,10,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` } diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index 36172d0f7bf..9afd130374f 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -27,12 +27,17 @@ message Params { bool receive_enabled = 2; } +// ForwardingInfo defines a list of port ID, channel ID pairs determining the path +// through which a packet must be forwarded, and the memo string to be used in the +// final destination of the tokens. message ForwardingInfo { repeated Hop hops = 1; string memo = 2; } +// Hop defines a port ID, channel ID pair specifying where tokens must be forwarded +// next in a multihop transfer. message Hop { - string portID = 1; - string channelId = 2; + string port_id = 1; + string channel_id = 2; } \ No newline at end of file diff --git a/proto/ibc/applications/transfer/v1/tx.proto b/proto/ibc/applications/transfer/v1/tx.proto index 116a8b26662..287b9a6bc52 100644 --- a/proto/ibc/applications/transfer/v1/tx.proto +++ b/proto/ibc/applications/transfer/v1/tx.proto @@ -51,7 +51,7 @@ message MsgTransfer { string memo = 8; // tokens to be transferred repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; - + // optional forwarding information ForwardingInfo forwarding_path = 10; } diff --git a/proto/ibc/applications/transfer/v2/packet.proto b/proto/ibc/applications/transfer/v2/packet.proto index b020f6879f1..697272c7952 100644 --- a/proto/ibc/applications/transfer/v2/packet.proto +++ b/proto/ibc/applications/transfer/v2/packet.proto @@ -35,7 +35,7 @@ message FungibleTokenPacketDataV2 { string receiver = 3; // optional memo string memo = 4; - // optional forwardingInfo struct + // optional forwarding information ibc.applications.transfer.v1.ForwardingInfo forwarding_path = 5; } From 64c2fc4cddf82979fad50d338b0b7256b024f33b Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Mon, 27 May 2024 19:21:49 +0200 Subject: [PATCH 052/141] fix finalReceiver address bug --- modules/apps/transfer/keeper/relay.go | 6 +- modules/apps/transfer/keeper/relay_test.go | 100 +++++++++++++++++++++ 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 675a2625196..479aed63fd8 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -201,8 +201,10 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return false, errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "failed to decode receiver address %s: %v", data.Receiver, err) } if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { + finalReceiver = receiver //, _ = sdk.AccAddressFromBech32(data.Receiver) + //finalReceiver = receiver receiver = types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) - finalReceiver = receiver + } var receivedTokens sdk.Coins @@ -364,7 +366,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t data.ForwardingPath.Hops[0].ChannelId, receivedTokens, receiver, - string(finalReceiver), + finalReceiver.String(), clienttypes.Height{}, timeoutTimestamp, memo, diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index c3f90ef2677..16a4166a511 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -1225,6 +1225,106 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") } +// Simplification of the above test. +func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { + amount := sdkmath.NewInt(100) + /* + Given the following topolgy: + + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A + stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake + + We want to trigger: + 1. A sends B over channel0. + 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions + At this point we want to assert: + A: escrowA = amount,denom + B: escrowB = amount,transfer/channel-0/denom + + */ + + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path2.Setup() + coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainA.SenderAccounts[1].SenderAccount + forwardingPath := types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortId: path2.EndpointB.ChannelConfig.PortID, + ChannelId: path2.EndpointB.ChannelID, + }, + }, + Memo: "", + } + + transferMsg := types.NewMsgTransfer( + path1.EndpointA.ChannelConfig.PortID, + path1.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + &forwardingPath, + ) + + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that Escrow A has amount + totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) + + // denomTrace path: transfer/channel-0 + denomTrace := types.DenomTrace{ + BaseDenom: sdk.DefaultBondDenom, + Path: fmt.Sprintf("%s/%s", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + } + + // Check that Escrow B has amount + coin = sdk.NewCoin(denomTrace.IBCDenom(), amount) + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) + + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path2.EndpointA.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointA.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // transfer/channel-1/transfer/channel-0/denom + denomTraceABA := types.DenomTrace{ + BaseDenom: sdk.DefaultBondDenom, + Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + } + // Check that the final receiver has received the expected tokens. + coin = sdk.NewCoin(denomTraceABA.IBCDenom(), amount) + postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") + +} + /* // TODO From 7cd726048ef07171859e46d522d32a6b267b6265 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Mon, 27 May 2024 21:10:46 +0200 Subject: [PATCH 053/141] wip - ack test scenario5 --- modules/apps/transfer/keeper/relay_test.go | 241 +++++++++++++++++++++ 1 file changed, 241 insertions(+) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 16a4166a511..e925a93e3d2 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -1325,6 +1325,247 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { } +// Simplification of the above test. +func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { + amount := sdkmath.NewInt(100) + /* + Given the following topolgy: + + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain C + stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake + + We want to trigger: + 0. A sends B over channel0 [path1] + 1. B sends C over channel1 [path2]. + 2. C recvs - This represent the checkpoint we will need to verify at the of the test + 3. C --> [path2] B --> [path1] A. + 4. OnRecv in B works properly, but OnRecv on A fails. Error Ack is written in A and relayed to B. + At this point we want to assert: + Everything has been reverted at checkpoint values. + + */ + + // Testing Topology + + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) + path2.Setup() + + // First we want to execute 0. + + coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainB.SenderAccounts[0].SenderAccount + + transferMsg := types.NewMsgTransfer( + path1.EndpointA.ChannelConfig.PortID, + path1.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + nil, + ) + + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that Escrow B has amount + totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) + + // transfer/channel-0/denom + denomTraceAB := types.DenomTrace{ + BaseDenom: sdk.DefaultBondDenom, + Path: fmt.Sprintf("%s/%s", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + } + // Check the coins have been received on B + coin = sdk.NewCoin(denomTraceAB.IBCDenom(), amount) + postCoinOnB := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnB.Amount, "final receiver balance has not increased") + + // A --> B Simple transfer happened properly. + + // Now we want to execute 1. + + // Now we want to trigget B -> C + sender = suite.chainB.SenderAccounts[0].SenderAccount + receiver = suite.chainC.SenderAccounts[0].SenderAccount + + transferMsg = types.NewMsgTransfer( + path2.EndpointA.ChannelConfig.PortID, + path2.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + nil, + ) + + result, err = suite.chainB.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that Escrow B has amount + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) + + // transfer/channel-1/transfer/channel-0/denom + denomTraceABC := types.DenomTrace{ + BaseDenom: sdk.DefaultBondDenom, + Path: fmt.Sprintf("%s/%s/%s/%s", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID), + } + // Check the coins have been received on C + coin = sdk.NewCoin(denomTraceABC.IBCDenom(), amount) + postCoinOnC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnC.Amount, "final receiver balance has not increased") + + // B -> C Simple transfer happened properly. + + // Now we want to trigger C -> B -> A + // The coin we want to send out is exactly the one we received on C + //coin = sdk.NewCoin(denomTraceBC.IBCDenom(), amount) + + sender = suite.chainC.SenderAccounts[0].SenderAccount + receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account + + forwardingPath := types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortId: path1.EndpointB.ChannelConfig.PortID, + ChannelId: path1.EndpointB.ChannelID, + }, + }, + Memo: "", + } + + transferMsg = types.NewMsgTransfer( + path2.EndpointB.ChannelConfig.PortID, + path2.EndpointB.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + &forwardingPath, + ) + + result, err = suite.chainC.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // Voucher have been burned on chain C + postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Vouchers have not been burned") + + // parse the packet from result events and recv packet on chainB + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path2.EndpointA.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointA.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // We have succesfully received the packet on B and forwarded it to A. + // Voucher have been burned on chain B + coin = sdk.NewCoin(denomTraceAB.IBCDenom(), amount) + postCoinOnB = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), postCoinOnB.Amount, "Vouchers have not been burned") + + // Now we can receive the packet on A. + // To trigger an error during the OnRecv, we have to manipulate the balance present in the escrow of A + // of denom + + // manipulate escrow account for denom on chain A + coin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(99)) + suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), coin) + totalEscrowChainA = suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(99), totalEscrowChainA.Amount) + + // parse the packet from result events and recv packet on chainA + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path1.EndpointA.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointA.RecvPacketWithResult(packet) + suite.Require().Error(err) + suite.Require().Nil(result) + + // NOW WE HAVE TO SEND ACK TO B, PROPAGTE ACK TO C, CHECK FINAL RESULTS + + // Check that Escrow A has amount + // totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + // suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) + + /* + // denomTrace path: transfer/channel-0 + denomTrace := types.DenomTrace{ + BaseDenom: sdk.DefaultBondDenom, + Path: fmt.Sprintf("%s/%s", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + } + + // Check that Escrow B has amount + coin = sdk.NewCoin(denomTrace.IBCDenom(), amount) + + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) + + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path2.EndpointA.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointA.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // transfer/channel-1/transfer/channel-0/denom + denomTraceABA := types.DenomTrace{ + BaseDenom: sdk.DefaultBondDenom, + Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), + } + // Check that the final receiver has received the expected tokens. + coin = sdk.NewCoin(denomTraceABA.IBCDenom(), amount) + postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") + */ +} + /* // TODO From 6673e74522761307cb2a4fbd9c5973b7cf776358 Mon Sep 17 00:00:00 2001 From: Hastur Date: Tue, 28 May 2024 19:45:13 +0700 Subject: [PATCH 054/141] add FungibleTokenPacketDataV2 test for ValidateBasic (#6398) --- modules/apps/transfer/types/packet_test.go | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 7e8d15747c9..5af2eddc289 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -220,6 +220,31 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { ), nil, }, + { + "success: valid packet with forwarding path hops", + types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "", + &types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortId: "transfer", + ChannelId: "channel-1", + }, + }, + Memo: "", + }, + ), + nil, + }, { "failure: invalid denom", types.NewFungibleTokenPacketDataV2( @@ -367,6 +392,31 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { ), types.ErrInvalidMemo, }, + { + "failure: memo must be empty if forwarding path hops is not empty", + types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: denom, + Amount: amount, + Trace: []string{"transfer/channel-0", "transfer/channel-1"}, + }, + }, + sender, + receiver, + "memo", + &types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortId: "transfer", + ChannelId: "channel-1", + }, + }, + Memo: "", + }, + ), + types.ErrInvalidMemo, + }, } for _, tc := range testCases { From 550eeefd41fac2a267df5fa0f21d2cf70eeb7646 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 28 May 2024 16:55:57 +0200 Subject: [PATCH 055/141] fix linter complaints --- modules/apps/transfer/keeper/relay.go | 42 +++++++++++----------- modules/apps/transfer/keeper/relay_test.go | 4 +-- modules/apps/transfer/types/packet_test.go | 4 +-- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 479aed63fd8..7838fcb4385 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -201,8 +201,8 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return false, errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "failed to decode receiver address %s: %v", data.Receiver, err) } if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { - finalReceiver = receiver //, _ = sdk.AccAddressFromBech32(data.Receiver) - //finalReceiver = receiver + finalReceiver = receiver // , _ = sdk.AccAddressFromBech32(data.Receiver) + receiver = types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) } @@ -393,7 +393,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) error { channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) if !ok { - errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } prevPacket, found := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) @@ -403,8 +403,8 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // the acknowledgement succeeded on the receiving chain so // we write the asynchronous acknowledgement for the sender // of the previous packet. - FungibleTokenPacketAcknowledgement := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) - return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, FungibleTokenPacketAcknowledgement) + fungibleTokenPacketAcknowledgement := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) + return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, fungibleTokenPacketAcknowledgement) case *channeltypes.Acknowledgement_Error: // the forwarded packet has failed, thus the funds have been refunded to the forwarding address. // we must revert the changes that came from successfully receiving the tokens on our chain @@ -413,8 +413,8 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac return err } - FungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet failed")) - return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, FungibleTokenPacketAcknowledgement) + fungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet failed")) + return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, fungibleTokenPacketAcknowledgement) default: return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected one of [%T, %T], got %T", channeltypes.Acknowledgement_Result{}, channeltypes.Acknowledgement_Error{}, ack.Response) } @@ -438,7 +438,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) error { channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) if !ok { - errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } prevPacket, found := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) @@ -447,11 +447,11 @@ func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, dat return err } - FungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(fmt.Errorf("forwarded packet timed out")) - return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, FungibleTokenPacketAcknowledgement) - } else { - return k.refundPacketToken(ctx, packet, data) + fungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(fmt.Errorf("forwarded packet timed out")) + return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, fungibleTokenPacketAcknowledgement) } + + return k.refundPacketToken(ctx, packet, data) } // refundPacketToken will unescrow and send back the tokens back to sender @@ -532,16 +532,16 @@ func (k Keeper) revertInFlightChanges(ctx sdk.Context, sentPacket channeltypes.P // receive sent tokens from the received escrow to the forward escrow account // so we must send the tokens back from the forward escrow to the original received escrow account return k.unescrowToken(ctx, forwardEscrow, reverseEscrow, coin) - } else { - // receive minted vouchers and sent to the forward escrow account - // so we must remove the vouchers from the forward escrow account and burn them - if err := k.bankKeeper.BurnCoins( - ctx, types.ModuleName, sdk.NewCoins(coin), - ); err != nil { - return err - } } - } else { + + // receive minted vouchers and sent to the forward escrow account + // so we must remove the vouchers from the forward escrow account and burn them + if err := k.bankKeeper.BurnCoins( + ctx, types.ModuleName, sdk.NewCoins(coin), + ); err != nil { + return err + } + } else { //nolint:gocritic // in this case we burned the vouchers of the outgoing packets // check if the packet we received was a source token for our chain // in this case, the tokens were unescrowed from the reverse escrow account diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index e925a93e3d2..0ec4c43c3cd 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -1322,7 +1322,6 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { coin = sdk.NewCoin(denomTraceABA.IBCDenom(), amount) postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") - } // Simplification of the above test. @@ -1451,7 +1450,6 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { // Now we want to trigger C -> B -> A // The coin we want to send out is exactly the one we received on C - //coin = sdk.NewCoin(denomTraceBC.IBCDenom(), amount) sender = suite.chainC.SenderAccounts[0].SenderAccount receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account @@ -1496,7 +1494,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { suite.Require().NoError(err) suite.Require().NotNil(result) - // We have succesfully received the packet on B and forwarded it to A. + // We have successfully received the packet on B and forwarded it to A. // Voucher have been burned on chain B coin = sdk.NewCoin(denomTraceAB.IBCDenom(), amount) postCoinOnB = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 5af2eddc289..a1abb6ef6df 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -236,7 +236,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { &types.ForwardingInfo{ Hops: []*types.Hop{ { - PortId: "transfer", + PortId: "transfer", ChannelId: "channel-1", }, }, @@ -408,7 +408,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { &types.ForwardingInfo{ Hops: []*types.Hop{ { - PortId: "transfer", + PortId: "transfer", ChannelId: "channel-1", }, }, From 4c54a889df5bd99f8e3b73cd29f8322f3daf9781 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Tue, 28 May 2024 17:02:23 +0200 Subject: [PATCH 056/141] add test - currently faling on middle hop revert --- modules/apps/transfer/keeper/relay_test.go | 118 +++++++++++++-------- 1 file changed, 76 insertions(+), 42 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 0ec4c43c3cd..30696455a9e 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -1324,7 +1324,10 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") } -// Simplification of the above test. +// This test replicates the Acknowledgement Failure Scenario 5 +// Currently seems like the middle hop is not reverting state changes when an error occurs. +// In turn the final hop properly reverts changes. There may be an error in the way async ack are managed +// or in the way i'm trying to activate the OnAck function. func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { amount := sdkmath.NewInt(100) /* @@ -1338,10 +1341,11 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { 1. B sends C over channel1 [path2]. 2. C recvs - This represent the checkpoint we will need to verify at the of the test 3. C --> [path2] B --> [path1] A. - 4. OnRecv in B works properly, but OnRecv on A fails. Error Ack is written in A and relayed to B. + 4. OnRecv in B works properly, but OnRecv on A fails. Error Ack is written in A, relayed to B and finally to C. At this point we want to assert: Everything has been reverted at checkpoint values. - + - C has amount of transfer/channel-1/transfer/channel-0/stake + - B totalEscrow has amount of transfer/channel-0/stake */ // Testing Topology @@ -1450,6 +1454,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { // Now we want to trigger C -> B -> A // The coin we want to send out is exactly the one we received on C + //coin = sdk.NewCoin(denomTraceBC.IBCDenom(), amount) sender = suite.chainC.SenderAccounts[0].SenderAccount receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account @@ -1494,7 +1499,12 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { suite.Require().NoError(err) suite.Require().NotNil(result) - // We have successfully received the packet on B and forwarded it to A. + // We have succesfully received the packet on B and forwarded it to A. + // Lets try to retrieve it in order to save it + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packet.Sequence) + suite.Require().True(found) + suite.Require().Equal(packet, forwardedPacket) + // Voucher have been burned on chain B coin = sdk.NewCoin(denomTraceAB.IBCDenom(), amount) postCoinOnB = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) @@ -1517,51 +1527,75 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { err = path1.EndpointA.UpdateClient() suite.Require().NoError(err) + //suite.Require().Equal(packet, forwardedPacket) result, err = path1.EndpointA.RecvPacketWithResult(packet) suite.Require().Error(err) suite.Require().Nil(result) - + // In theory now an error ack should have been written on chain A // NOW WE HAVE TO SEND ACK TO B, PROPAGTE ACK TO C, CHECK FINAL RESULTS - // Check that Escrow A has amount - // totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - // suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) + // Reconstruct packet data + denom, trace := convertinternal.ExtractDenomAndTraceFromV1Denom(denomTraceAB.GetFullDenomPath()) + data := types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: denom, + Amount: amount.String(), + Trace: trace, + }, + }, types.GetForwardAddress(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID).String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) + packetRecv := channeltypes.NewPacket(data.GetBytes(), 3, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) - /* - // denomTrace path: transfer/channel-0 - denomTrace := types.DenomTrace{ - BaseDenom: sdk.DefaultBondDenom, - Path: fmt.Sprintf("%s/%s", path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), - } - - // Check that Escrow B has amount - coin = sdk.NewCoin(denomTrace.IBCDenom(), amount) - - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - - packet, err = ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - err = path2.EndpointA.UpdateClient() - suite.Require().NoError(err) - - result, err = path2.EndpointA.RecvPacketWithResult(packet) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - // transfer/channel-1/transfer/channel-0/denom - denomTraceABA := types.DenomTrace{ - BaseDenom: sdk.DefaultBondDenom, - Path: fmt.Sprintf("%s/%s/%s/%s", path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), - } - // Check that the final receiver has received the expected tokens. - coin = sdk.NewCoin(denomTraceABA.IBCDenom(), amount) - postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") - */ + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + ack := channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed packet transfer")) + + //err = path1.EndpointA.AcknowledgePacket(packetRecv, ack.Acknowledgement()) + err = suite.chainB.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainB.GetContext(), packetRecv, data, ack) + suite.Require().NoError(err) + + // Check that Escrow B has been refunded amount + // NOTE This is failing. The revertInFlightsChanges sohuld mint back voucher to chainBescrow + // but this is not happening. It may be a problem related with how we're writing async acks. + // + coin = sdk.NewCoin(denomTraceAB.IBCDenom(), amount) + totalEscrowChainB = suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) + + denom, trace = convertinternal.ExtractDenomAndTraceFromV1Denom(denomTraceABC.GetFullDenomPath()) + data = types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: denom, + Amount: amount.String(), + Trace: trace, + }, + }, suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) + //suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String() This should be forward account of B + packet = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) + + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) + + // Check the status of account on chain C before executing ack. + coin = sdk.NewCoin(denomTraceABC.IBCDenom(), amount) + postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Final Hop balance has been refunded before Ack execution") + + // Execute ack + err = suite.chainC.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainC.GetContext(), forwardedPacket, data, ack) + suite.Require().NoError(err) + + // Check that everythig has been reverted + // + // Check the vouchers transfer/channel-1/transfer/channel-0/denom have been refunded on C + coin = sdk.NewCoin(denomTraceABC.IBCDenom(), amount) + postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnC.Amount, "final receiver balance has not increased") + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) } /* From debc4cba1c788319485e0375a3abb4922c9f6585 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Tue, 28 May 2024 17:26:31 +0200 Subject: [PATCH 057/141] add test comments --- modules/apps/transfer/keeper/relay_test.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 30696455a9e..a64282ba8eb 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -1341,7 +1341,9 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { 1. B sends C over channel1 [path2]. 2. C recvs - This represent the checkpoint we will need to verify at the of the test 3. C --> [path2] B --> [path1] A. - 4. OnRecv in B works properly, but OnRecv on A fails. Error Ack is written in A, relayed to B and finally to C. + 4. OnRecv in B works properly and trigger the packet forwarding to A + 5. Modify the balance of escrowA to cause an error during the onRecv + 6. OnRecv on A fails. Error Ack is written in A, relayed to B and finally to C. At this point we want to assert: Everything has been reverted at checkpoint values. - C has amount of transfer/channel-1/transfer/channel-0/stake @@ -1404,9 +1406,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { // A --> B Simple transfer happened properly. - // Now we want to execute 1. - - // Now we want to trigget B -> C + // Now we want to trigger B -> C sender = suite.chainB.SenderAccounts[0].SenderAccount receiver = suite.chainC.SenderAccounts[0].SenderAccount @@ -1514,17 +1514,17 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { // To trigger an error during the OnRecv, we have to manipulate the balance present in the escrow of A // of denom + // parse the packet from result events and recv packet on chainA + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + // manipulate escrow account for denom on chain A coin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(99)) suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), coin) totalEscrowChainA = suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) suite.Require().Equal(sdkmath.NewInt(99), totalEscrowChainA.Amount) - // parse the packet from result events and recv packet on chainA - packet, err = ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - err = path1.EndpointA.UpdateClient() suite.Require().NoError(err) //suite.Require().Equal(packet, forwardedPacket) @@ -1544,7 +1544,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { Amount: amount.String(), Trace: trace, }, - }, types.GetForwardAddress(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID).String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) + }, types.GetForwardAddress(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID).String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) packetRecv := channeltypes.NewPacket(data.GetBytes(), 3, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) err = path1.EndpointB.UpdateClient() From e50fa403f10bd75e720d15255384b7475d1b6284 Mon Sep 17 00:00:00 2001 From: Stefano Angieri Date: Tue, 28 May 2024 17:55:37 +0200 Subject: [PATCH 058/141] fixes --- modules/apps/transfer/keeper/relay_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index a64282ba8eb..d331e60e00e 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -1544,7 +1544,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { Amount: amount.String(), Trace: trace, }, - }, types.GetForwardAddress(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID).String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) + }, types.GetForwardAddress(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID).String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) packetRecv := channeltypes.NewPacket(data.GetBytes(), 3, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) err = path1.EndpointB.UpdateClient() @@ -1571,7 +1571,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { Amount: amount.String(), Trace: trace, }, - }, suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) + }, suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) //suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String() This should be forward account of B packet = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) @@ -1584,7 +1584,8 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Final Hop balance has been refunded before Ack execution") // Execute ack - err = suite.chainC.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainC.GetContext(), forwardedPacket, data, ack) + err = suite.chainC.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainC.GetContext(), packet, data, ack) + //err = path2.EndpointB.AcknowledgePacket(packet, ack.Acknowledgement()) suite.Require().NoError(err) // Check that everythig has been reverted From 7c8f5161136ff3260a71f65d36bd595c841ce33b Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Fri, 31 May 2024 15:35:20 +0200 Subject: [PATCH 059/141] retrieve channel capability only if there is a previous packet in store --- modules/apps/transfer/keeper/relay.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 65eb45e09fc..10a47f8dfb5 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -365,13 +365,13 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t // acknowledgement was a success then nothing occurs. If the acknowledgement failed, // then the sender is refunded their tokens using the refundPacketToken function. func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) error { - channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) - if !ok { - return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") - } - prevPacket, found := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) if found { + channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) + if !ok { + return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + switch ack.Response.(type) { case *channeltypes.Acknowledgement_Result: // the acknowledgement succeeded on the receiving chain so @@ -410,13 +410,13 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // packet if the chain acted as a middle hop on a multihop transfer; or refunds // the sender if the original packet sent was never received and has been timed out. func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) error { - channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) - if !ok { - return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") - } - prevPacket, found := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) if found { + channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) + if !ok { + return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + if err := k.revertInFlightChanges(ctx, packet, prevPacket, data); err != nil { return err } From efcfa5d877567731f6b4ff8dbd063a34ede5de00 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 9 Jun 2024 22:28:37 +0200 Subject: [PATCH 060/141] add missing parameter --- e2e/testsuite/testsuite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index b678850084b..380f7eee586 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -583,7 +583,7 @@ func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, Tokens: sdk.NewCoins(), } case transfertypes.V2: - msg = transfertypes.NewMsgTransfer(portID, channelID, tokens, sender, receiver, timeoutHeight, timeoutTimestamp, memo) + msg = transfertypes.NewMsgTransfer(portID, channelID, tokens, sender, receiver, timeoutHeight, timeoutTimestamp, memo, nil) default: panic(fmt.Errorf("unsupported transfer version: %s", version)) } From 21dbb37b5e958a7a154b33c3a8d78219e739ff95 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Mon, 10 Jun 2024 17:29:15 +0300 Subject: [PATCH 061/141] fix: e2e build failures. --- e2e/tests/transfer/incentivized_test.go | 2 ++ e2e/tests/transfer/upgrades_test.go | 1 + e2e/tests/upgrades/upgrade_test.go | 1 + e2e/testsuite/testsuite.go | 4 ++-- e2e/testsuite/tx.go | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) diff --git a/e2e/tests/transfer/incentivized_test.go b/e2e/tests/transfer/incentivized_test.go index 6b54c31b961..032a2c1a9e1 100644 --- a/e2e/tests/transfer/incentivized_test.go +++ b/e2e/tests/transfer/incentivized_test.go @@ -211,6 +211,7 @@ func (s *IncentivizedTransferTestSuite) TestMsgPayPacketFee_InvalidReceiverAccou s.GetTimeoutHeight(ctx, chainB), 0, "", + nil, ) txResp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgTransfer) // this message should be successful, as receiver account is not validated on the sending chain. @@ -349,6 +350,7 @@ func (s *IncentivizedTransferTestSuite) TestMultiMsg_MsgPayPacketFeeSingleSender s.GetTimeoutHeight(ctx, chainB), 0, "", + nil, ) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) diff --git a/e2e/tests/transfer/upgrades_test.go b/e2e/tests/transfer/upgrades_test.go index 10ea8b3c839..7eb9de1fb53 100644 --- a/e2e/tests/transfer/upgrades_test.go +++ b/e2e/tests/transfer/upgrades_test.go @@ -208,6 +208,7 @@ func (s *TransferChannelUpgradesTestSuite) TestChannelUpgrade_WithFeeMiddleware_ s.GetTimeoutHeight(ctx, chainB), 0, "", + nil, ) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) diff --git a/e2e/tests/upgrades/upgrade_test.go b/e2e/tests/upgrades/upgrade_test.go index 942a11d18ca..277157878c8 100644 --- a/e2e/tests/upgrades/upgrade_test.go +++ b/e2e/tests/upgrades/upgrade_test.go @@ -966,6 +966,7 @@ func (s *UpgradeTestSuite) TestV8ToV8_1ChainUpgrade_ChannelUpgrades() { s.GetTimeoutHeight(ctx, chainB), 0, "", + nil, ) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index 380f7eee586..9a113fbd7e9 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -563,7 +563,7 @@ func getValidatorsAndFullNodes(chainIdx int) (int, int) { } // GetMsgTransfer returns a MsgTransfer that is constructed based on the channel version -func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string) *transfertypes.MsgTransfer { +func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, forwardingPath *transfertypes.ForwardingInfo) *transfertypes.MsgTransfer { if len(tokens) == 0 { panic(errors.New("tokens cannot be empty")) } @@ -583,7 +583,7 @@ func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, Tokens: sdk.NewCoins(), } case transfertypes.V2: - msg = transfertypes.NewMsgTransfer(portID, channelID, tokens, sender, receiver, timeoutHeight, timeoutTimestamp, memo, nil) + msg = transfertypes.NewMsgTransfer(portID, channelID, tokens, sender, receiver, timeoutHeight, timeoutTimestamp, memo, forwardingPath) default: panic(fmt.Errorf("unsupported transfer version: %s", version)) } diff --git a/e2e/testsuite/tx.go b/e2e/testsuite/tx.go index f54887a3773..7395f393741 100644 --- a/e2e/testsuite/tx.go +++ b/e2e/testsuite/tx.go @@ -297,7 +297,7 @@ func (s *E2ETestSuite) Transfer(ctx context.Context, chain ibc.Chain, user ibc.W transferVersion = version.AppVersion } - msg := GetMsgTransfer(portID, channelID, transferVersion, tokens, sender, receiver, timeoutHeight, timeoutTimestamp, memo) + msg := GetMsgTransfer(portID, channelID, transferVersion, tokens, sender, receiver, timeoutHeight, timeoutTimestamp, memo, nil) return s.BroadcastMessages(ctx, chain, user, msg) } From 70d7a29d881a1a3b7f73c99eebd6a586ec0aaeef Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Tue, 11 Jun 2024 09:49:03 +0300 Subject: [PATCH 062/141] Use Transfer instead of sendTransfer when forwarding. (#6564) Pass nil as the next forwarding path if at final hop. Use consistent timeout for all hops. --- modules/apps/transfer/keeper/relay.go | 28 ++++++++++++--------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index ec27e395b92..711f2221391 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "strings" - "time" "github.com/hashicorp/go-metrics" @@ -277,40 +276,37 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t // Adding forwarding logic if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { memo := "" - var nextForwardingPath types.ForwardingInfo + + var nextForwardingPath *types.ForwardingInfo if len(data.ForwardingPath.Hops) == 1 { memo = data.ForwardingPath.Memo - nextForwardingPath = types.ForwardingInfo{ - Hops: nil, - Memo: data.ForwardingPath.Memo, - } + nextForwardingPath = nil } else { - nextForwardingPath = types.ForwardingInfo{ + nextForwardingPath = &types.ForwardingInfo{ Hops: data.ForwardingPath.Hops[1:], Memo: data.ForwardingPath.Memo, } } - // Assign to timestamp --> current + 1 h - timeoutTimestamp := uint64(ctx.BlockTime().Add(time.Hour).UnixNano()) - sequence, err := k.sendTransfer( - ctx, + msg := types.NewMsgTransfer( data.ForwardingPath.Hops[0].PortId, data.ForwardingPath.Hops[0].ChannelId, receivedCoins, - receiver, + receiver.String(), finalReceiver.String(), - clienttypes.Height{}, - timeoutTimestamp, + packet.TimeoutHeight, + packet.TimeoutTimestamp, memo, - &nextForwardingPath, + nextForwardingPath, ) + + resp, err := k.Transfer(ctx, msg) if err != nil { return false, err } - k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortId, data.ForwardingPath.Hops[0].ChannelId, sequence, packet) + k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortId, data.ForwardingPath.Hops[0].ChannelId, resp.Sequence, packet) return true, nil } From 465b16c6992bd032ab60651247e975462c177d7f Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Tue, 11 Jun 2024 10:45:51 +0300 Subject: [PATCH 063/141] lint: fix linter issues. --- modules/apps/transfer/keeper/relay.go | 1 - modules/apps/transfer/keeper/relay_test.go | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 711f2221391..c4957aae5e3 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -277,7 +277,6 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { memo := "" - var nextForwardingPath *types.ForwardingInfo if len(data.ForwardingPath.Hops) == 1 { memo = data.ForwardingPath.Memo diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 946d234dc50..c95872b60cf 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -1557,7 +1557,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { // Now we want to trigger C -> B -> A // The coin we want to send out is exactly the one we received on C - //coin = sdk.NewCoin(denomTraceBC.IBCDenom(), amount) + // coin = sdk.NewCoin(denomTraceBC.IBCDenom(), amount) sender = suite.chainC.SenderAccounts[0].SenderAccount receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account @@ -1602,7 +1602,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { suite.Require().NoError(err) suite.Require().NotNil(result) - // We have succesfully received the packet on B and forwarded it to A. + // We have successfully received the packet on B and forwarded it to A. // Lets try to retrieve it in order to save it forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packet.Sequence) suite.Require().True(found) @@ -1630,7 +1630,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { err = path1.EndpointA.UpdateClient() suite.Require().NoError(err) - //suite.Require().Equal(packet, forwardedPacket) + // suite.Require().Equal(packet, forwardedPacket) result, err = path1.EndpointA.RecvPacketWithResult(packet) suite.Require().Error(err) @@ -1653,7 +1653,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { suite.Require().NoError(err) ack := channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed packet transfer")) - //err = path1.EndpointA.AcknowledgePacket(packetRecv, ack.Acknowledgement()) + // err = path1.EndpointA.AcknowledgePacket(packetRecv, ack.Acknowledgement()) err = suite.chainB.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainB.GetContext(), packetRecv, data, ack) suite.Require().NoError(err) @@ -1673,7 +1673,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { Amount: amount.String(), }, }, suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) - //suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String() This should be forward account of B + // suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String() This should be forward account of B packet = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) err = path2.EndpointB.UpdateClient() @@ -1686,7 +1686,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { // Execute ack err = suite.chainC.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainC.GetContext(), packet, data, ack) - //err = path2.EndpointB.AcknowledgePacket(packet, ack.Acknowledgement()) + // err = path2.EndpointB.AcknowledgePacket(packet, ack.Acknowledgement()) suite.Require().NoError(err) // Check that everythig has been reverted From ec472cff4d39a2ddb3b3d4443616597d679a75a4 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Tue, 11 Jun 2024 14:22:14 +0300 Subject: [PATCH 064/141] tests(transfer): move forwarding tests to separate file. (#6568) --- .../transfer/keeper/relay_forwarding_test.go | 626 ++++++++++++++++++ modules/apps/transfer/keeper/relay_test.go | 625 ----------------- 2 files changed, 626 insertions(+), 625 deletions(-) create mode 100644 modules/apps/transfer/keeper/relay_forwarding_test.go diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go new file mode 100644 index 00000000000..bdb1aa2b0ae --- /dev/null +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -0,0 +1,626 @@ +package keeper_test + +import ( + "fmt" + + sdkmath "cosmossdk.io/math" + + 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" + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +func (suite *KeeperTestSuite) TestPathForwarding() { + amount := sdkmath.NewInt(100) + + // setup + // 2 transfer channels between chain A and chain B + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path2.Setup() + + coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainA.SenderAccounts[1].SenderAccount + forwardingPath := types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortId: path2.EndpointA.ChannelConfig.PortID, + ChannelId: path2.EndpointA.ChannelID, + }, + }, + Memo: "", + } + + transferMsg := types.NewMsgTransfer( + path1.EndpointA.ChannelConfig.PortID, + path1.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + &forwardingPath, + ) + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, packet.Sequence) + suite.Require().True(found) + suite.Require().Equal(packet, forwardedPacket) +} + +func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { + amount := sdkmath.NewInt(100) + /* + Given the following topolgy: + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A + stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake + We want to trigger: + 1. A sends B over channel0. + 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions + At this point we want to assert: + A: escrowA = amount,denom + B: escrowB = amount,transfer/channel-0/denom + */ + + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path2.Setup() + coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainA.SenderAccounts[1].SenderAccount + forwardingPath := types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortId: path2.EndpointB.ChannelConfig.PortID, + ChannelId: path2.EndpointB.ChannelID, + }, + }, + Memo: "", + } + + transferMsg := types.NewMsgTransfer( + path1.EndpointA.ChannelConfig.PortID, + path1.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + &forwardingPath, + ) + + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) + + // denom path: transfer/channel-0 + denom := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + + // Check that Escrow B has amount + coin = sdk.NewCoin(denom.IBCDenom(), amount) + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) +} + +// This test is probably overcomplicated. Could have used RecvPacketWithResult directly. +func (suite *KeeperTestSuite) TestHappyPathForwarding() { + amount := sdkmath.NewInt(100) + /* + Given the following topolgy: + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A + stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake + We want to trigger: + 1. A sends B over channel0. + 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions + At this point we want to assert: + A: escrowA = amount,denom + B: escrowB = amount,transfer/channel-0/denom + 3. A OnRecv + At this point we want to assert: + C: finalReceiver = amount,transfer/channel-1/transfer/channel-0/denom + */ + + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path2.Setup() + + // transfer/channel-1/transfer/channel-0/denom + denomABA := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID), types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + + // Check that initially the final receiver address has 0 ABA coins + coin := sdk.NewCoin(denomABA.IBCDenom(), amount) + preCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), preCoinOnA.Amount, "final receiver has not zero balance") + + coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainA.SenderAccounts[1].SenderAccount + forwardingPath := types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortId: path2.EndpointB.ChannelConfig.PortID, + ChannelId: path2.EndpointB.ChannelID, + }, + }, + Memo: "", + } + + transferMsg := types.NewMsgTransfer( + path1.EndpointA.ChannelConfig.PortID, + path1.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + &forwardingPath, + ) + + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + denom := types.Denom{Base: sdk.DefaultBondDenom} + data := types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: denom, + Amount: amount.String(), + }, + }, sender.GetAddress().String(), receiver.GetAddress().String(), "", &forwardingPath) + packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) + + var async bool + async, err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) + // If forwarding has been triggered then the async must be true. + suite.Require().True(async) + suite.Require().Nil(err) + + // denomTrace path: transfer/channel-0 + denom = types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + + // Check that Escrow B has amount + coin = sdk.NewCoin(denom.IBCDenom(), amount) + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(amount, totalEscrowChainB.Amount, "escrow account on B is different than amount") + + // Check that Escrow A has amount + coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) + totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(amount, totalEscrowChainA.Amount, "escrow account on A is different than amount") + + // Now during the onRecvPacket above a new msgTransfer has been sent + // We need to receive the packet on the final hand + + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + data = types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: denom, + Amount: amount.String(), + }, + }, types.GetForwardAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID).String(), receiver.GetAddress().String(), "", nil) + packetRecv = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) + + // execute onRecvPacket, when chaninA receives the tokens the escrow amount on B should increase to amount + async, err = suite.chainA.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainA.GetContext(), packetRecv, data) + suite.Require().False(async) + suite.Require().NoError(err) + + // Check that the final receiver has received the expected tokens. + coin = sdk.NewCoin(denomABA.IBCDenom(), amount) + postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") +} + +// Simplification of the above test. +func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { + amount := sdkmath.NewInt(100) + /* + Given the following topolgy: + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A + stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake + We want to trigger: + 1. A sends B over channel0. + 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions + At this point we want to assert: + A: escrowA = amount,denom + B: escrowB = amount,transfer/channel-0/denom + */ + + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path2.Setup() + coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainA.SenderAccounts[1].SenderAccount + forwardingPath := types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortId: path2.EndpointB.ChannelConfig.PortID, + ChannelId: path2.EndpointB.ChannelID, + }, + }, + Memo: "", + } + + transferMsg := types.NewMsgTransfer( + path1.EndpointA.ChannelConfig.PortID, + path1.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + &forwardingPath, + ) + + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that Escrow A has amount + totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) + + // denomTrace path: transfer/channel-0 + denomTrace := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + + // Check that Escrow B has amount + coin = sdk.NewCoin(denomTrace.IBCDenom(), amount) + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) + + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path2.EndpointA.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointA.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // transfer/channel-1/transfer/channel-0/denom + denomTraceABA := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID), types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + + // Check that the final receiver has received the expected tokens. + coin = sdk.NewCoin(denomTraceABA.IBCDenom(), amount) + postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") +} + +// This test replicates the Acknowledgement Failure Scenario 5 +// Currently seems like the middle hop is not reverting state changes when an error occurs. +// In turn the final hop properly reverts changes. There may be an error in the way async ack are managed +// or in the way i'm trying to activate the OnAck function. +func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { + amount := sdkmath.NewInt(100) + /* + Given the following topolgy: + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain C + stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake + We want to trigger: + 0. A sends B over channel0 [path1] + 1. B sends C over channel1 [path2]. + 2. C recvs - This represent the checkpoint we will need to verify at the of the test + 3. C --> [path2] B --> [path1] A. + 4. OnRecv in B works properly and trigger the packet forwarding to A + 5. Modify the balance of escrowA to cause an error during the onRecv + 6. OnRecv on A fails. Error Ack is written in A, relayed to B and finally to C. + At this point we want to assert: + Everything has been reverted at checkpoint values. + - C has amount of transfer/channel-1/transfer/channel-0/stake + - B totalEscrow has amount of transfer/channel-0/stake + */ + + // Testing Topology + + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) + path2.Setup() + + // First we want to execute 0. + + coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainB.SenderAccounts[0].SenderAccount + + transferMsg := types.NewMsgTransfer( + path1.EndpointA.ChannelConfig.PortID, + path1.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + nil, + ) + + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that Escrow B has amount + totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) + + // transfer/channel-0/denom + denomAB := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + + // Check the coins have been received on B + coin = sdk.NewCoin(denomAB.IBCDenom(), amount) + postCoinOnB := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnB.Amount, "final receiver balance has not increased") + + // A --> B Simple transfer happened properly. + + // Now we want to trigger B -> C + sender = suite.chainB.SenderAccounts[0].SenderAccount + receiver = suite.chainC.SenderAccounts[0].SenderAccount + + transferMsg = types.NewMsgTransfer( + path2.EndpointA.ChannelConfig.PortID, + path2.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + nil, + ) + + result, err = suite.chainB.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that Escrow B has amount + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) + + // transfer/channel-1/transfer/channel-0/denom + denomABC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), types.NewTrace(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID)) + + // Check the coins have been received on C + coin = sdk.NewCoin(denomABC.IBCDenom(), amount) + postCoinOnC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnC.Amount, "final receiver balance has not increased") + + // B -> C Simple transfer happened properly. + + // Now we want to trigger C -> B -> A + // The coin we want to send out is exactly the one we received on C + // coin = sdk.NewCoin(denomTraceBC.IBCDenom(), amount) + + sender = suite.chainC.SenderAccounts[0].SenderAccount + receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account + + forwardingPath := types.ForwardingInfo{ + Hops: []*types.Hop{ + { + PortId: path1.EndpointB.ChannelConfig.PortID, + ChannelId: path1.EndpointB.ChannelID, + }, + }, + Memo: "", + } + + transferMsg = types.NewMsgTransfer( + path2.EndpointB.ChannelConfig.PortID, + path2.EndpointB.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + suite.chainA.GetTimeoutHeight(), + 0, "", + &forwardingPath, + ) + + result, err = suite.chainC.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // Voucher have been burned on chain C + postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Vouchers have not been burned") + + // parse the packet from result events and recv packet on chainB + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = path2.EndpointA.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointA.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // We have successfully received the packet on B and forwarded it to A. + // Lets try to retrieve it in order to save it + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packet.Sequence) + suite.Require().True(found) + suite.Require().Equal(packet, forwardedPacket) + + // Voucher have been burned on chain B + coin = sdk.NewCoin(denomAB.IBCDenom(), amount) + postCoinOnB = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), postCoinOnB.Amount, "Vouchers have not been burned") + + // Now we can receive the packet on A. + // To trigger an error during the OnRecv, we have to manipulate the balance present in the escrow of A + // of denom + + // parse the packet from result events and recv packet on chainA + packet, err = ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + // manipulate escrow account for denom on chain A + coin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(99)) + suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), coin) + totalEscrowChainA = suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(99), totalEscrowChainA.Amount) + + err = path1.EndpointA.UpdateClient() + suite.Require().NoError(err) + // suite.Require().Equal(packet, forwardedPacket) + + result, err = path1.EndpointA.RecvPacketWithResult(packet) + suite.Require().Error(err) + suite.Require().Nil(result) + // In theory now an error ack should have been written on chain A + // NOW WE HAVE TO SEND ACK TO B, PROPAGTE ACK TO C, CHECK FINAL RESULTS + + // Reconstruct packet data + denom := types.ExtractDenomFromPath(denomAB.Path()) + data := types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: denom, + Amount: amount.String(), + }, + }, types.GetForwardAddress(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID).String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) + packetRecv := channeltypes.NewPacket(data.GetBytes(), 3, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + ack := channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed packet transfer")) + + // err = path1.EndpointA.AcknowledgePacket(packetRecv, ack.Acknowledgement()) + err = suite.chainB.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainB.GetContext(), packetRecv, data, ack) + suite.Require().NoError(err) + + // Check that Escrow B has been refunded amount + // NOTE This is failing. The revertInFlightsChanges sohuld mint back voucher to chainBescrow + // but this is not happening. It may be a problem related with how we're writing async acks. + // + coin = sdk.NewCoin(denomAB.IBCDenom(), amount) + totalEscrowChainB = suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) + + denom = types.ExtractDenomFromPath(denomABC.Path()) + data = types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: denom, + Amount: amount.String(), + }, + }, suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) + // suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String() This should be forward account of B + packet = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) + + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) + + // Check the status of account on chain C before executing ack. + coin = sdk.NewCoin(denomABC.IBCDenom(), amount) + postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Final Hop balance has been refunded before Ack execution") + + // Execute ack + err = suite.chainC.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainC.GetContext(), packet, data, ack) + // err = path2.EndpointB.AcknowledgePacket(packet, ack.Acknowledgement()) + suite.Require().NoError(err) + + // Check that everythig has been reverted + // + // Check the vouchers transfer/channel-1/transfer/channel-0/denom have been refunded on C + coin = sdk.NewCoin(denomABC.IBCDenom(), amount) + postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), postCoinOnC.Amount, "final receiver balance has not increased") + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) +} + +/* +// TODO + Test scenarios for failures ack +Check out the notion page: https://www.notion.so/interchain/ICS20-v2-path-forwarding-091f1ac788e84a538261c5a247cb5924 +// TODO +Test async ack is properly relayed to middle hop after forwarding transfer completition +// TODO +Tiemout during forwarding after middle hop execution reverts properly the state changes +*/ diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index c95872b60cf..924e5179a36 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -556,60 +556,6 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsSource() { } } -func (suite *KeeperTestSuite) TestPathForwarding() { - amount := sdkmath.NewInt(100) - - // setup - // 2 transfer channels between chain A and chain B - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() - - path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path2.Setup() - - coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) - sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ - Hops: []*types.Hop{ - { - PortId: path2.EndpointA.ChannelConfig.PortID, - ChannelId: path2.EndpointA.ChannelID, - }, - }, - Memo: "", - } - - transferMsg := types.NewMsgTransfer( - path1.EndpointA.ChannelConfig.PortID, - path1.EndpointA.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", - &forwardingPath, - ) - result, err := suite.chainA.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - // parse the packet from result events and recv packet on chainB - packet, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - err = path1.EndpointB.UpdateClient() - suite.Require().NoError(err) - - result, err = path1.EndpointB.RecvPacketWithResult(packet) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, packet.Sequence) - suite.Require().True(found) - suite.Require().Equal(packet, forwardedPacket) -} - func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCToken() { /* Given the following flow of tokens: @@ -1142,577 +1088,6 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI suite.Require().Equal(sdkmath.ZeroInt(), totalEscrowChainB.Amount) } -func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { - amount := sdkmath.NewInt(100) - /* - Given the following topolgy: - - chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A - stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake - - We want to trigger: - 1. A sends B over channel0. - 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions - At this point we want to assert: - A: escrowA = amount,denom - B: escrowB = amount,transfer/channel-0/denom - - */ - - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() - - path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path2.Setup() - coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) - sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ - Hops: []*types.Hop{ - { - PortId: path2.EndpointB.ChannelConfig.PortID, - ChannelId: path2.EndpointB.ChannelID, - }, - }, - Memo: "", - } - - transferMsg := types.NewMsgTransfer( - path1.EndpointA.ChannelConfig.PortID, - path1.EndpointA.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", - &forwardingPath, - ) - - result, err := suite.chainA.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - // parse the packet from result events and recv packet on chainB - packet, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - err = path1.EndpointB.UpdateClient() - suite.Require().NoError(err) - - result, err = path1.EndpointB.RecvPacketWithResult(packet) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) - - // denom path: transfer/channel-0 - denom := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) - - // Check that Escrow B has amount - coin = sdk.NewCoin(denom.IBCDenom(), amount) - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) -} - -// This test is probably overcomplicated. Could have used RecvPacketWithResult directly. -func (suite *KeeperTestSuite) TestHappyPathForwarding() { - amount := sdkmath.NewInt(100) - /* - Given the following topolgy: - - chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A - stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake - - We want to trigger: - 1. A sends B over channel0. - 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions - At this point we want to assert: - A: escrowA = amount,denom - B: escrowB = amount,transfer/channel-0/denom - 3. A OnRecv - At this point we want to assert: - C: finalReceiver = amount,transfer/channel-1/transfer/channel-0/denom - */ - - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() - - path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path2.Setup() - - // transfer/channel-1/transfer/channel-0/denom - denomABA := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID), types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) - - // Check that initially the final receiver address has 0 ABA coins - coin := sdk.NewCoin(denomABA.IBCDenom(), amount) - preCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(0), preCoinOnA.Amount, "final receiver has not zero balance") - - coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) - sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ - Hops: []*types.Hop{ - { - PortId: path2.EndpointB.ChannelConfig.PortID, - ChannelId: path2.EndpointB.ChannelID, - }, - }, - Memo: "", - } - - transferMsg := types.NewMsgTransfer( - path1.EndpointA.ChannelConfig.PortID, - path1.EndpointA.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", - &forwardingPath, - ) - - result, err := suite.chainA.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - // parse the packet from result events and recv packet on chainB - packet, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - denom := types.Denom{Base: sdk.DefaultBondDenom} - data := types.NewFungibleTokenPacketDataV2( - []types.Token{ - { - Denom: denom, - Amount: amount.String(), - }, - }, sender.GetAddress().String(), receiver.GetAddress().String(), "", &forwardingPath) - packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - - var async bool - async, err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) - // If forwarding has been triggered then the async must be true. - suite.Require().True(async) - suite.Require().Nil(err) - - // denomTrace path: transfer/channel-0 - denom = types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) - - // Check that Escrow B has amount - coin = sdk.NewCoin(denom.IBCDenom(), amount) - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) - suite.Require().Equal(amount, totalEscrowChainB.Amount, "escrow account on B is different than amount") - - // Check that Escrow A has amount - coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) - totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - suite.Require().Equal(amount, totalEscrowChainA.Amount, "escrow account on A is different than amount") - - // Now during the onRecvPacket above a new msgTransfer has been sent - // We need to receive the packet on the final hand - - packet, err = ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - data = types.NewFungibleTokenPacketDataV2( - []types.Token{ - { - Denom: denom, - Amount: amount.String(), - }, - }, types.GetForwardAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID).String(), receiver.GetAddress().String(), "", nil) - packetRecv = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) - - // execute onRecvPacket, when chaninA receives the tokens the escrow amount on B should increase to amount - async, err = suite.chainA.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainA.GetContext(), packetRecv, data) - suite.Require().False(async) - suite.Require().NoError(err) - - // Check that the final receiver has received the expected tokens. - coin = sdk.NewCoin(denomABA.IBCDenom(), amount) - postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") -} - -// Simplification of the above test. -func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { - amount := sdkmath.NewInt(100) - /* - Given the following topolgy: - - chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A - stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake - - We want to trigger: - 1. A sends B over channel0. - 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions - At this point we want to assert: - A: escrowA = amount,denom - B: escrowB = amount,transfer/channel-0/denom - - */ - - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() - - path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path2.Setup() - coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) - sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ - Hops: []*types.Hop{ - { - PortId: path2.EndpointB.ChannelConfig.PortID, - ChannelId: path2.EndpointB.ChannelID, - }, - }, - Memo: "", - } - - transferMsg := types.NewMsgTransfer( - path1.EndpointA.ChannelConfig.PortID, - path1.EndpointA.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", - &forwardingPath, - ) - - result, err := suite.chainA.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - // parse the packet from result events and recv packet on chainB - packet, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - err = path1.EndpointB.UpdateClient() - suite.Require().NoError(err) - - result, err = path1.EndpointB.RecvPacketWithResult(packet) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - // Check that Escrow A has amount - totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) - - // denomTrace path: transfer/channel-0 - denomTrace := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) - - // Check that Escrow B has amount - coin = sdk.NewCoin(denomTrace.IBCDenom(), amount) - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - - packet, err = ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - err = path2.EndpointA.UpdateClient() - suite.Require().NoError(err) - - result, err = path2.EndpointA.RecvPacketWithResult(packet) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - // transfer/channel-1/transfer/channel-0/denom - denomTraceABA := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID), types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) - - // Check that the final receiver has received the expected tokens. - coin = sdk.NewCoin(denomTraceABA.IBCDenom(), amount) - postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") -} - -// This test replicates the Acknowledgement Failure Scenario 5 -// Currently seems like the middle hop is not reverting state changes when an error occurs. -// In turn the final hop properly reverts changes. There may be an error in the way async ack are managed -// or in the way i'm trying to activate the OnAck function. -func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { - amount := sdkmath.NewInt(100) - /* - Given the following topolgy: - - chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain C - stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake - - We want to trigger: - 0. A sends B over channel0 [path1] - 1. B sends C over channel1 [path2]. - 2. C recvs - This represent the checkpoint we will need to verify at the of the test - 3. C --> [path2] B --> [path1] A. - 4. OnRecv in B works properly and trigger the packet forwarding to A - 5. Modify the balance of escrowA to cause an error during the onRecv - 6. OnRecv on A fails. Error Ack is written in A, relayed to B and finally to C. - At this point we want to assert: - Everything has been reverted at checkpoint values. - - C has amount of transfer/channel-1/transfer/channel-0/stake - - B totalEscrow has amount of transfer/channel-0/stake - */ - - // Testing Topology - - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() - - path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) - path2.Setup() - - // First we want to execute 0. - - coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) - sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainB.SenderAccounts[0].SenderAccount - - transferMsg := types.NewMsgTransfer( - path1.EndpointA.ChannelConfig.PortID, - path1.EndpointA.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", - nil, - ) - - result, err := suite.chainA.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - // parse the packet from result events and recv packet on chainB - packet, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - err = path1.EndpointB.UpdateClient() - suite.Require().NoError(err) - - result, err = path1.EndpointB.RecvPacketWithResult(packet) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - // Check that Escrow B has amount - totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) - - // transfer/channel-0/denom - denomAB := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) - - // Check the coins have been received on B - coin = sdk.NewCoin(denomAB.IBCDenom(), amount) - postCoinOnB := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnB.Amount, "final receiver balance has not increased") - - // A --> B Simple transfer happened properly. - - // Now we want to trigger B -> C - sender = suite.chainB.SenderAccounts[0].SenderAccount - receiver = suite.chainC.SenderAccounts[0].SenderAccount - - transferMsg = types.NewMsgTransfer( - path2.EndpointA.ChannelConfig.PortID, - path2.EndpointA.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", - nil, - ) - - result, err = suite.chainB.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - // parse the packet from result events and recv packet on chainB - packet, err = ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - err = path2.EndpointB.UpdateClient() - suite.Require().NoError(err) - - result, err = path2.EndpointB.RecvPacketWithResult(packet) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - // Check that Escrow B has amount - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - - // transfer/channel-1/transfer/channel-0/denom - denomABC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), types.NewTrace(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID)) - - // Check the coins have been received on C - coin = sdk.NewCoin(denomABC.IBCDenom(), amount) - postCoinOnC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnC.Amount, "final receiver balance has not increased") - - // B -> C Simple transfer happened properly. - - // Now we want to trigger C -> B -> A - // The coin we want to send out is exactly the one we received on C - // coin = sdk.NewCoin(denomTraceBC.IBCDenom(), amount) - - sender = suite.chainC.SenderAccounts[0].SenderAccount - receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account - - forwardingPath := types.ForwardingInfo{ - Hops: []*types.Hop{ - { - PortId: path1.EndpointB.ChannelConfig.PortID, - ChannelId: path1.EndpointB.ChannelID, - }, - }, - Memo: "", - } - - transferMsg = types.NewMsgTransfer( - path2.EndpointB.ChannelConfig.PortID, - path2.EndpointB.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", - &forwardingPath, - ) - - result, err = suite.chainC.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - // Voucher have been burned on chain C - postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Vouchers have not been burned") - - // parse the packet from result events and recv packet on chainB - packet, err = ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - err = path2.EndpointA.UpdateClient() - suite.Require().NoError(err) - - result, err = path2.EndpointA.RecvPacketWithResult(packet) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - // We have successfully received the packet on B and forwarded it to A. - // Lets try to retrieve it in order to save it - forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packet.Sequence) - suite.Require().True(found) - suite.Require().Equal(packet, forwardedPacket) - - // Voucher have been burned on chain B - coin = sdk.NewCoin(denomAB.IBCDenom(), amount) - postCoinOnB = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(0), postCoinOnB.Amount, "Vouchers have not been burned") - - // Now we can receive the packet on A. - // To trigger an error during the OnRecv, we have to manipulate the balance present in the escrow of A - // of denom - - // parse the packet from result events and recv packet on chainA - packet, err = ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packet) - - // manipulate escrow account for denom on chain A - coin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(99)) - suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), coin) - totalEscrowChainA = suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(99), totalEscrowChainA.Amount) - - err = path1.EndpointA.UpdateClient() - suite.Require().NoError(err) - // suite.Require().Equal(packet, forwardedPacket) - - result, err = path1.EndpointA.RecvPacketWithResult(packet) - suite.Require().Error(err) - suite.Require().Nil(result) - // In theory now an error ack should have been written on chain A - // NOW WE HAVE TO SEND ACK TO B, PROPAGTE ACK TO C, CHECK FINAL RESULTS - - // Reconstruct packet data - denom := types.ExtractDenomFromPath(denomAB.Path()) - data := types.NewFungibleTokenPacketDataV2( - []types.Token{ - { - Denom: denom, - Amount: amount.String(), - }, - }, types.GetForwardAddress(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID).String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) - packetRecv := channeltypes.NewPacket(data.GetBytes(), 3, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) - - err = path1.EndpointB.UpdateClient() - suite.Require().NoError(err) - ack := channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed packet transfer")) - - // err = path1.EndpointA.AcknowledgePacket(packetRecv, ack.Acknowledgement()) - err = suite.chainB.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainB.GetContext(), packetRecv, data, ack) - suite.Require().NoError(err) - - // Check that Escrow B has been refunded amount - // NOTE This is failing. The revertInFlightsChanges sohuld mint back voucher to chainBescrow - // but this is not happening. It may be a problem related with how we're writing async acks. - // - coin = sdk.NewCoin(denomAB.IBCDenom(), amount) - totalEscrowChainB = suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - - denom = types.ExtractDenomFromPath(denomABC.Path()) - data = types.NewFungibleTokenPacketDataV2( - []types.Token{ - { - Denom: denom, - Amount: amount.String(), - }, - }, suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) - // suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String() This should be forward account of B - packet = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) - - err = path2.EndpointB.UpdateClient() - suite.Require().NoError(err) - - // Check the status of account on chain C before executing ack. - coin = sdk.NewCoin(denomABC.IBCDenom(), amount) - postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Final Hop balance has been refunded before Ack execution") - - // Execute ack - err = suite.chainC.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainC.GetContext(), packet, data, ack) - // err = path2.EndpointB.AcknowledgePacket(packet, ack.Acknowledgement()) - suite.Require().NoError(err) - - // Check that everythig has been reverted - // - // Check the vouchers transfer/channel-1/transfer/channel-0/denom have been refunded on C - coin = sdk.NewCoin(denomABC.IBCDenom(), amount) - postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnC.Amount, "final receiver balance has not increased") - - err = path1.EndpointB.UpdateClient() - suite.Require().NoError(err) -} - -/* -// TODO - - Test scenarios for failures ack - -Check out the notion page: https://www.notion.so/interchain/ICS20-v2-path-forwarding-091f1ac788e84a538261c5a247cb5924 - -// TODO -Test async ack is properly relayed to middle hop after forwarding transfer completition - -// TODO -Tiemout during forwarding after middle hop execution reverts properly the state changes -*/ func (suite *KeeperTestSuite) TestPacketForwardsCompatibility() { // We are testing a scenario where a packet in the future has a new populated // field called "new_field". And this packet is being sent to this module which From e483b9a5fb6887c97c6f76257967b8b40bbf82cf Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 12 Jun 2024 12:32:46 +0200 Subject: [PATCH 065/141] chore: rename ForwardingInfo to Forwarding --- e2e/testsuite/testsuite.go | 20 ++-- modules/apps/transfer/keeper/export_test.go | 2 +- modules/apps/transfer/keeper/relay.go | 12 +-- .../transfer/keeper/relay_forwarding_test.go | 11 +-- modules/apps/transfer/types/msgs.go | 3 +- modules/apps/transfer/types/packet.go | 2 +- modules/apps/transfer/types/packet.pb.go | 56 +++++------ modules/apps/transfer/types/packet_test.go | 4 +- modules/apps/transfer/types/transfer.pb.go | 92 +++++++++---------- modules/apps/transfer/types/tx.pb.go | 89 +++++++++--------- .../applications/transfer/v1/transfer.proto | 4 +- proto/ibc/applications/transfer/v1/tx.proto | 2 +- .../ibc/applications/transfer/v2/packet.proto | 2 +- 13 files changed, 146 insertions(+), 153 deletions(-) diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index 9a113fbd7e9..e9c1d7fc96d 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -8,6 +8,14 @@ import ( "path" "strings" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + transfertypes "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" dockerclient "github.com/docker/docker/client" interchaintest "github.com/strangelove-ventures/interchaintest/v8" "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" @@ -17,21 +25,11 @@ import ( testifysuite "github.com/stretchr/testify/suite" "go.uber.org/zap" - sdkmath "cosmossdk.io/math" - - sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/ibc-go/e2e/internal/directories" "github.com/cosmos/ibc-go/e2e/relayer" "github.com/cosmos/ibc-go/e2e/testsuite/diagnostics" "github.com/cosmos/ibc-go/e2e/testsuite/query" "github.com/cosmos/ibc-go/e2e/testvalues" - feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" - transfertypes "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" ) const ( @@ -563,7 +561,7 @@ func getValidatorsAndFullNodes(chainIdx int) (int, int) { } // GetMsgTransfer returns a MsgTransfer that is constructed based on the channel version -func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, forwardingPath *transfertypes.ForwardingInfo) *transfertypes.MsgTransfer { +func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, forwardingPath *transfertypes.Forwarding) *transfertypes.MsgTransfer { if len(tokens) == 0 { panic(errors.New("tokens cannot be empty")) } diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index 760e04cc97f..670f85b7ac3 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -34,6 +34,6 @@ func (k Keeper) TokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // CreatePacketDataBytesFromVersion is a wrapper around createPacketDataBytesFromVersion for testing purposes -func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwardingPath *types.ForwardingInfo) []byte { +func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwardingPath *types.Forwarding) []byte { return createPacketDataBytesFromVersion(appVersion, sender, receiver, memo, tokens, forwardingPath) } diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index c4957aae5e3..ccd320f5471 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -5,13 +5,11 @@ import ( "fmt" "strings" - "github.com/hashicorp/go-metrics" - errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/hashicorp/go-metrics" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/events" internaltelemetry "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/telemetry" @@ -65,7 +63,7 @@ func (k Keeper) sendTransfer( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, - forwardingPath *types.ForwardingInfo, + forwardingPath *types.Forwarding, ) (uint64, error) { channel, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) if !found { @@ -277,12 +275,12 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { memo := "" - var nextForwardingPath *types.ForwardingInfo + var nextForwardingPath *types.Forwarding if len(data.ForwardingPath.Hops) == 1 { memo = data.ForwardingPath.Memo nextForwardingPath = nil } else { - nextForwardingPath = &types.ForwardingInfo{ + nextForwardingPath = &types.Forwarding{ Hops: data.ForwardingPath.Hops[1:], Memo: data.ForwardingPath.Memo, } @@ -551,7 +549,7 @@ func (k Keeper) tokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // createPacketDataBytesFromVersion creates the packet data bytes to be sent based on the application version. -func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwardingPath *types.ForwardingInfo) []byte { +func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwardingPath *types.Forwarding) []byte { var packetDataBytes []byte switch appVersion { case types.V1: diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index bdb1aa2b0ae..341b1daad80 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -4,7 +4,6 @@ import ( "fmt" sdkmath "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" @@ -27,7 +26,7 @@ func (suite *KeeperTestSuite) TestPathForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ + forwardingPath := types.Forwarding{ Hops: []*types.Hop{ { PortId: path2.EndpointA.ChannelConfig.PortID, @@ -89,7 +88,7 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ + forwardingPath := types.Forwarding{ Hops: []*types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, @@ -172,7 +171,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ + forwardingPath := types.Forwarding{ Hops: []*types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, @@ -280,7 +279,7 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ + forwardingPath := types.Forwarding{ Hops: []*types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, @@ -477,7 +476,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { sender = suite.chainC.SenderAccounts[0].SenderAccount receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account - forwardingPath := types.ForwardingInfo{ + forwardingPath := types.Forwarding{ Hops: []*types.Hop{ { PortId: path1.EndpointB.ChannelConfig.PortID, diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 3c10f3b5779..4dbfc9b8136 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -4,7 +4,6 @@ import ( "strings" errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -49,7 +48,7 @@ func NewMsgTransfer( tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, - forwardingPath *ForwardingInfo, + forwardingPath *Forwarding, ) *MsgTransfer { return &MsgTransfer{ SourcePort: sourcePort, diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index fcdb431695e..5513d2d62db 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -103,7 +103,7 @@ func NewFungibleTokenPacketDataV2( tokens []Token, sender, receiver string, memo string, - forwardingPath *ForwardingInfo, + forwardingPath *Forwarding, ) FungibleTokenPacketDataV2 { return FungibleTokenPacketDataV2{ Tokens: tokens, diff --git a/modules/apps/transfer/types/packet.pb.go b/modules/apps/transfer/types/packet.pb.go index 1eae85e38e9..b5e4fffdaef 100644 --- a/modules/apps/transfer/types/packet.pb.go +++ b/modules/apps/transfer/types/packet.pb.go @@ -120,7 +120,7 @@ type FungibleTokenPacketDataV2 struct { // optional memo Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` // optional forwarding information - ForwardingPath *ForwardingInfo `protobuf:"bytes,5,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` + ForwardingPath *Forwarding `protobuf:"bytes,5,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` } func (m *FungibleTokenPacketDataV2) Reset() { *m = FungibleTokenPacketDataV2{} } @@ -184,7 +184,7 @@ func (m *FungibleTokenPacketDataV2) GetMemo() string { return "" } -func (m *FungibleTokenPacketDataV2) GetForwardingPath() *ForwardingInfo { +func (m *FungibleTokenPacketDataV2) GetForwardingPath() *Forwarding { if m != nil { return m.ForwardingPath } @@ -201,31 +201,31 @@ func init() { } var fileDescriptor_653ca2ce9a5ca313 = []byte{ - // 379 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0xab, 0xd3, 0x40, - 0x14, 0x85, 0x33, 0xaf, 0x79, 0x45, 0xe7, 0x81, 0xc2, 0xf0, 0xd0, 0x58, 0x24, 0x3e, 0x9e, 0x9b, - 0x8a, 0x3a, 0x43, 0xe3, 0x42, 0xb7, 0x16, 0x29, 0xb8, 0xab, 0x45, 0x5d, 0xb8, 0x91, 0xc9, 0x64, - 0x9a, 0x0e, 0x6d, 0xe6, 0x86, 0x99, 0x49, 0xc4, 0x5f, 0xa1, 0x3f, 0xab, 0xcb, 0x2e, 0x5d, 0x89, - 0xb4, 0xbf, 0x43, 0x90, 0x4c, 0x6a, 0xdb, 0x4d, 0xb3, 0x3b, 0xe7, 0xe4, 0xde, 0xc3, 0x97, 0xb9, - 0xf8, 0x99, 0x4a, 0x05, 0xe3, 0x65, 0xb9, 0x52, 0x82, 0x3b, 0x05, 0xda, 0x32, 0x67, 0xb8, 0xb6, - 0x73, 0x69, 0x58, 0x9d, 0xb0, 0x92, 0x8b, 0xa5, 0x74, 0xb4, 0x34, 0xe0, 0x80, 0x3c, 0x56, 0xa9, - 0xa0, 0xa7, 0xa3, 0xf4, 0xff, 0x28, 0xad, 0x93, 0xc1, 0xb0, 0xb3, 0xc8, 0xc1, 0x52, 0xea, 0xb6, - 0x67, 0x70, 0x9d, 0x43, 0x0e, 0x5e, 0xb2, 0x46, 0xed, 0xd3, 0xe7, 0x1d, 0xfb, 0xa3, 0x83, 0x6e, - 0x87, 0x6f, 0x7f, 0x20, 0xfc, 0x70, 0x52, 0xe9, 0x5c, 0xa5, 0x2b, 0xf9, 0xb1, 0xa9, 0x9e, 0x7a, - 0xd0, 0x77, 0xdc, 0x71, 0x72, 0x8d, 0x2f, 0x33, 0xa9, 0xa1, 0x88, 0xd0, 0x0d, 0x1a, 0xde, 0x9d, - 0xb5, 0x86, 0x3c, 0xc0, 0x7d, 0x5e, 0x40, 0xa5, 0x5d, 0x74, 0xe1, 0xe3, 0xbd, 0x6b, 0x72, 0x2b, - 0x75, 0x26, 0x4d, 0xd4, 0x6b, 0xf3, 0xd6, 0x91, 0x01, 0xbe, 0x63, 0xa4, 0x90, 0xaa, 0x96, 0x26, - 0x0a, 0xfd, 0x97, 0x83, 0x27, 0x04, 0x87, 0x85, 0x2c, 0x20, 0xba, 0xf4, 0xb9, 0xd7, 0xb7, 0x7f, - 0x11, 0x7e, 0x74, 0x86, 0xe8, 0x73, 0x42, 0xde, 0xe2, 0xbe, 0x7f, 0x01, 0x1b, 0xa1, 0x9b, 0xde, - 0xf0, 0x2a, 0x79, 0x4a, 0xbb, 0xde, 0x92, 0xfa, 0x82, 0x71, 0xb8, 0xfe, 0xfd, 0x24, 0x98, 0xed, - 0x17, 0x4f, 0x40, 0x2f, 0xce, 0x82, 0xf6, 0xce, 0x80, 0x86, 0x47, 0x50, 0xf2, 0x09, 0xdf, 0x9f, - 0x83, 0xf9, 0xc6, 0x4d, 0xa6, 0x74, 0xfe, 0xb5, 0xe4, 0x6e, 0xe1, 0xff, 0xe3, 0x2a, 0x79, 0xd1, - 0xc5, 0x34, 0xa2, 0x93, 0xc3, 0xd2, 0x7b, 0x3d, 0x87, 0xd9, 0xbd, 0x63, 0xc9, 0x94, 0xbb, 0xc5, - 0xf8, 0xc3, 0x7a, 0x1b, 0xa3, 0xcd, 0x36, 0x46, 0x7f, 0xb6, 0x31, 0xfa, 0xb9, 0x8b, 0x83, 0xcd, - 0x2e, 0x0e, 0x7e, 0xed, 0xe2, 0xe0, 0xcb, 0xeb, 0x5c, 0xb9, 0x45, 0x95, 0x52, 0x01, 0x05, 0x13, - 0x60, 0x0b, 0xb0, 0x4c, 0xa5, 0xe2, 0x65, 0x0e, 0xac, 0x7e, 0xc3, 0x0a, 0xc8, 0xaa, 0x95, 0xb4, - 0xcd, 0xe1, 0x4f, 0x0e, 0xee, 0xbe, 0x97, 0xd2, 0xa6, 0x7d, 0x7f, 0xeb, 0x57, 0xff, 0x02, 0x00, - 0x00, 0xff, 0xff, 0x9a, 0x79, 0x3e, 0x9a, 0xa3, 0x02, 0x00, 0x00, + // 372 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0x0f, 0xd2, 0x30, + 0x1c, 0xc5, 0x57, 0x18, 0x44, 0x4b, 0xa2, 0x49, 0x43, 0x74, 0x12, 0x33, 0x09, 0x5e, 0x66, 0x8c, + 0x6d, 0x98, 0x07, 0xbd, 0x4a, 0x0c, 0x67, 0x20, 0xc6, 0x83, 0x17, 0xd3, 0x75, 0x65, 0x34, 0xb0, + 0x76, 0x69, 0xbb, 0x19, 0x3f, 0x85, 0x7e, 0x2c, 0x8e, 0x1c, 0x3d, 0x19, 0x03, 0x9f, 0xc2, 0x9b, + 0x59, 0x87, 0xc0, 0x85, 0xdd, 0xde, 0x7b, 0xfb, 0xff, 0x5f, 0x7e, 0xeb, 0x1f, 0xbe, 0x12, 0x09, + 0x23, 0xb4, 0x28, 0x76, 0x82, 0x51, 0x2b, 0x94, 0x34, 0xc4, 0x6a, 0x2a, 0xcd, 0x9a, 0x6b, 0x52, + 0xc5, 0xa4, 0xa0, 0x6c, 0xcb, 0x2d, 0x2e, 0xb4, 0xb2, 0x0a, 0x3d, 0x17, 0x09, 0xc3, 0xb7, 0xa3, + 0xf8, 0xff, 0x28, 0xae, 0xe2, 0x51, 0xd4, 0x5a, 0x64, 0xd5, 0x96, 0xcb, 0xa6, 0x67, 0x34, 0xcc, + 0x54, 0xa6, 0x9c, 0x24, 0xb5, 0x3a, 0xa7, 0xaf, 0x5b, 0xf6, 0xa7, 0x17, 0xdd, 0x0c, 0x4f, 0x7e, + 0x00, 0xf8, 0x74, 0x5e, 0xca, 0x4c, 0x24, 0x3b, 0xfe, 0xa9, 0xae, 0x5e, 0x38, 0xd0, 0x8f, 0xd4, + 0x52, 0x34, 0x84, 0xbd, 0x94, 0x4b, 0x95, 0x07, 0x60, 0x0c, 0xa2, 0x87, 0xab, 0xc6, 0xa0, 0x27, + 0xb0, 0x4f, 0x73, 0x55, 0x4a, 0x1b, 0x74, 0x5c, 0x7c, 0x76, 0x75, 0x6e, 0xb8, 0x4c, 0xb9, 0x0e, + 0xba, 0x4d, 0xde, 0x38, 0x34, 0x82, 0x0f, 0x34, 0x67, 0x5c, 0x54, 0x5c, 0x07, 0xbe, 0xfb, 0x72, + 0xf1, 0x08, 0x41, 0x3f, 0xe7, 0xb9, 0x0a, 0x7a, 0x2e, 0x77, 0x7a, 0xf2, 0x17, 0xc0, 0x67, 0x77, + 0x88, 0x3e, 0xc7, 0xe8, 0x03, 0xec, 0xbb, 0x17, 0x30, 0x01, 0x18, 0x77, 0xa3, 0x41, 0xfc, 0x12, + 0xb7, 0xbd, 0x25, 0x76, 0x05, 0x33, 0x7f, 0xff, 0xfb, 0x85, 0xb7, 0x3a, 0x2f, 0xde, 0x80, 0x76, + 0xee, 0x82, 0x76, 0xef, 0x80, 0xfa, 0x57, 0x50, 0xb4, 0x84, 0x8f, 0xd7, 0x4a, 0x7f, 0xa3, 0x3a, + 0x15, 0x32, 0xfb, 0x5a, 0x50, 0xbb, 0x71, 0xff, 0x31, 0x88, 0xa3, 0x36, 0xa6, 0x29, 0x9e, 0x5f, + 0x96, 0x56, 0x8f, 0xae, 0x05, 0x0b, 0x6a, 0x37, 0xb3, 0xe5, 0xfe, 0x18, 0x82, 0xc3, 0x31, 0x04, + 0x7f, 0x8e, 0x21, 0xf8, 0x79, 0x0a, 0xbd, 0xc3, 0x29, 0xf4, 0x7e, 0x9d, 0x42, 0xef, 0xcb, 0xbb, + 0x4c, 0xd8, 0x4d, 0x99, 0x60, 0xa6, 0x72, 0xc2, 0x94, 0xc9, 0x95, 0x21, 0x22, 0x61, 0x6f, 0x32, + 0x45, 0xaa, 0xf7, 0x24, 0x57, 0x69, 0xb9, 0xe3, 0xa6, 0x3e, 0xfa, 0xcd, 0xb1, 0xed, 0xf7, 0x82, + 0x9b, 0xa4, 0xef, 0xee, 0xfc, 0xf6, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x6b, 0xf8, 0x91, + 0x9f, 0x02, 0x00, 0x00, } func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { @@ -832,7 +832,7 @@ func (m *FungibleTokenPacketDataV2) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.ForwardingPath == nil { - m.ForwardingPath = &ForwardingInfo{} + m.ForwardingPath = &Forwarding{} } if err := m.ForwardingPath.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 9997751b69e..7ba33b11a59 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -233,7 +233,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - &types.ForwardingInfo{ + &types.Forwarding{ Hops: []*types.Hop{ { PortId: "transfer", @@ -399,7 +399,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "memo", - &types.ForwardingInfo{ + &types.Forwarding{ Hops: []*types.Hop{ { PortId: "transfer", diff --git a/modules/apps/transfer/types/transfer.pb.go b/modules/apps/transfer/types/transfer.pb.go index 75ee2e183d4..bfd375b7683 100644 --- a/modules/apps/transfer/types/transfer.pb.go +++ b/modules/apps/transfer/types/transfer.pb.go @@ -82,26 +82,26 @@ func (m *Params) GetReceiveEnabled() bool { return false } -// ForwardingInfo defines a list of port ID, channel ID pairs determining the path +// Forwarding defines a list of hops determining the path // through which a packet must be forwarded, and the memo string to be used in the // final destination of the tokens. -type ForwardingInfo struct { +type Forwarding struct { Hops []*Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops,omitempty"` Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` } -func (m *ForwardingInfo) Reset() { *m = ForwardingInfo{} } -func (m *ForwardingInfo) String() string { return proto.CompactTextString(m) } -func (*ForwardingInfo) ProtoMessage() {} -func (*ForwardingInfo) Descriptor() ([]byte, []int) { +func (m *Forwarding) Reset() { *m = Forwarding{} } +func (m *Forwarding) String() string { return proto.CompactTextString(m) } +func (*Forwarding) ProtoMessage() {} +func (*Forwarding) Descriptor() ([]byte, []int) { return fileDescriptor_5041673e96e97901, []int{1} } -func (m *ForwardingInfo) XXX_Unmarshal(b []byte) error { +func (m *Forwarding) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ForwardingInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *Forwarding) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ForwardingInfo.Marshal(b, m, deterministic) + return xxx_messageInfo_Forwarding.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -111,26 +111,26 @@ func (m *ForwardingInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro return b[:n], nil } } -func (m *ForwardingInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_ForwardingInfo.Merge(m, src) +func (m *Forwarding) XXX_Merge(src proto.Message) { + xxx_messageInfo_Forwarding.Merge(m, src) } -func (m *ForwardingInfo) XXX_Size() int { +func (m *Forwarding) XXX_Size() int { return m.Size() } -func (m *ForwardingInfo) XXX_DiscardUnknown() { - xxx_messageInfo_ForwardingInfo.DiscardUnknown(m) +func (m *Forwarding) XXX_DiscardUnknown() { + xxx_messageInfo_Forwarding.DiscardUnknown(m) } -var xxx_messageInfo_ForwardingInfo proto.InternalMessageInfo +var xxx_messageInfo_Forwarding proto.InternalMessageInfo -func (m *ForwardingInfo) GetHops() []*Hop { +func (m *Forwarding) GetHops() []*Hop { if m != nil { return m.Hops } return nil } -func (m *ForwardingInfo) GetMemo() string { +func (m *Forwarding) GetMemo() string { if m != nil { return m.Memo } @@ -193,7 +193,7 @@ func (m *Hop) GetChannelId() string { func init() { proto.RegisterType((*Params)(nil), "ibc.applications.transfer.v1.Params") - proto.RegisterType((*ForwardingInfo)(nil), "ibc.applications.transfer.v1.ForwardingInfo") + proto.RegisterType((*Forwarding)(nil), "ibc.applications.transfer.v1.Forwarding") proto.RegisterType((*Hop)(nil), "ibc.applications.transfer.v1.Hop") } @@ -202,27 +202,27 @@ func init() { } var fileDescriptor_5041673e96e97901 = []byte{ - // 308 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0x3f, 0x4f, 0x3a, 0x31, - 0x1c, 0xc6, 0xb9, 0x1f, 0x84, 0x9f, 0x14, 0x83, 0x49, 0x17, 0x19, 0xf4, 0x02, 0x2c, 0x92, 0x18, - 0xaf, 0x41, 0x63, 0x74, 0x71, 0x31, 0xd1, 0xc0, 0xa6, 0x17, 0x27, 0x1d, 0x48, 0xff, 0x01, 0x4d, - 0xae, 0xfd, 0x36, 0x6d, 0x39, 0xe3, 0xbb, 0xf0, 0x65, 0x39, 0x32, 0x3a, 0x1a, 0x78, 0x23, 0xe6, - 0x0e, 0x72, 0x61, 0x72, 0x7b, 0xfa, 0xe9, 0xa7, 0xe9, 0x93, 0x07, 0x9d, 0x2b, 0xc6, 0x09, 0xb5, - 0x36, 0x53, 0x9c, 0x06, 0x05, 0xc6, 0x93, 0xe0, 0xa8, 0xf1, 0x33, 0xe9, 0x48, 0x3e, 0xaa, 0x72, - 0x62, 0x1d, 0x04, 0xc0, 0x27, 0x8a, 0xf1, 0x64, 0x5f, 0x4e, 0x2a, 0x21, 0x1f, 0x0d, 0x5e, 0x50, - 0xf3, 0x89, 0x3a, 0xaa, 0x3d, 0xee, 0xa3, 0x43, 0x2f, 0x8d, 0x98, 0x4a, 0x43, 0x59, 0x26, 0x45, - 0x37, 0xea, 0x45, 0xc3, 0x83, 0xb4, 0x5d, 0xb0, 0x87, 0x2d, 0xc2, 0x67, 0xe8, 0xc8, 0x49, 0x2e, - 0x55, 0x2e, 0x2b, 0xeb, 0x5f, 0x69, 0x75, 0x76, 0x78, 0x27, 0x0e, 0xde, 0x50, 0xe7, 0x11, 0xdc, - 0x3b, 0x75, 0x42, 0x99, 0xf9, 0xc4, 0xcc, 0x00, 0x5f, 0xa3, 0xc6, 0x02, 0xac, 0xef, 0x46, 0xbd, - 0xfa, 0xb0, 0x7d, 0xd9, 0x4f, 0xfe, 0x2a, 0x95, 0x8c, 0xc1, 0xa6, 0xa5, 0x8e, 0x31, 0x6a, 0x68, - 0xa9, 0xa1, 0xfc, 0xa6, 0x95, 0x96, 0x79, 0x70, 0x87, 0xea, 0x63, 0xb0, 0xf8, 0x18, 0xfd, 0xb7, - 0xe0, 0xc2, 0x54, 0x6d, 0xab, 0xb6, 0xd2, 0x66, 0x71, 0x9c, 0x08, 0x7c, 0x8a, 0x10, 0x5f, 0x50, - 0x63, 0x64, 0x56, 0xdc, 0x6d, 0x5f, 0xb6, 0x76, 0x64, 0x22, 0xee, 0x9f, 0xbf, 0xd6, 0x71, 0xb4, - 0x5a, 0xc7, 0xd1, 0xcf, 0x3a, 0x8e, 0x3e, 0x37, 0x71, 0x6d, 0xb5, 0x89, 0x6b, 0xdf, 0x9b, 0xb8, - 0xf6, 0x7a, 0x33, 0x57, 0x61, 0xb1, 0x64, 0x09, 0x07, 0x4d, 0x38, 0x78, 0x0d, 0x9e, 0x28, 0xc6, - 0x2f, 0xe6, 0x40, 0xf2, 0x5b, 0xa2, 0x41, 0x2c, 0x33, 0xe9, 0x8b, 0xd9, 0xf7, 0xe6, 0x0e, 0x1f, - 0x56, 0x7a, 0xd6, 0x2c, 0x97, 0xbe, 0xfa, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x05, 0xad, 0xe6, 0x9f, - 0x98, 0x01, 0x00, 0x00, + // 306 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0x31, 0x4b, 0x33, 0x31, + 0x1c, 0xc6, 0x7b, 0x6f, 0x4b, 0x5f, 0xfb, 0xaf, 0x28, 0x64, 0xb1, 0x83, 0x1e, 0x6d, 0x17, 0x0b, + 0xe2, 0x85, 0x2a, 0xa2, 0x8b, 0x8b, 0xa0, 0xb4, 0x9b, 0x1e, 0x82, 0xe0, 0x52, 0x72, 0x49, 0x6c, + 0x03, 0x97, 0xfc, 0x43, 0x92, 0x9e, 0xf8, 0x2d, 0xfc, 0x58, 0x8e, 0x1d, 0x1d, 0xa5, 0xfd, 0x22, + 0x72, 0xd7, 0x52, 0x3a, 0xb9, 0x3d, 0xf9, 0xe5, 0x17, 0xf2, 0xf0, 0xc0, 0x99, 0xca, 0x38, 0x65, + 0xd6, 0xe6, 0x8a, 0xb3, 0xa0, 0xd0, 0x78, 0x1a, 0x1c, 0x33, 0xfe, 0x4d, 0x3a, 0x5a, 0x0c, 0xb7, + 0x39, 0xb1, 0x0e, 0x03, 0x92, 0x63, 0x95, 0xf1, 0x64, 0x57, 0x4e, 0xb6, 0x42, 0x31, 0xec, 0x3f, + 0x43, 0xf3, 0x91, 0x39, 0xa6, 0x3d, 0xe9, 0xc1, 0xbe, 0x97, 0x46, 0x4c, 0xa4, 0x61, 0x59, 0x2e, + 0x45, 0x27, 0xea, 0x46, 0x83, 0xbd, 0xb4, 0x5d, 0xb2, 0xfb, 0x35, 0x22, 0xa7, 0x70, 0xe8, 0x24, + 0x97, 0xaa, 0x90, 0x5b, 0xeb, 0x5f, 0x65, 0x1d, 0x6c, 0xf0, 0x46, 0xec, 0xbf, 0x00, 0x3c, 0xa0, + 0x7b, 0x67, 0x4e, 0x28, 0x33, 0x25, 0x57, 0xd0, 0x98, 0xa1, 0xf5, 0x9d, 0xa8, 0x5b, 0x1f, 0xb4, + 0x2f, 0x7a, 0xc9, 0x5f, 0x85, 0x92, 0x11, 0xda, 0xb4, 0xd2, 0x09, 0x81, 0x86, 0x96, 0x1a, 0xab, + 0x2f, 0x5a, 0x69, 0x95, 0xfb, 0xb7, 0x50, 0x1f, 0xa1, 0x25, 0x47, 0xf0, 0xdf, 0xa2, 0x0b, 0x13, + 0xb5, 0xae, 0xd9, 0x4a, 0x9b, 0xe5, 0x71, 0x2c, 0xc8, 0x09, 0x00, 0x9f, 0x31, 0x63, 0x64, 0x5e, + 0xde, 0xad, 0x5f, 0xb6, 0x36, 0x64, 0x2c, 0xee, 0x9e, 0xbe, 0x96, 0x71, 0xb4, 0x58, 0xc6, 0xd1, + 0xcf, 0x32, 0x8e, 0x3e, 0x57, 0x71, 0x6d, 0xb1, 0x8a, 0x6b, 0xdf, 0xab, 0xb8, 0xf6, 0x7a, 0x3d, + 0x55, 0x61, 0x36, 0xcf, 0x12, 0x8e, 0x9a, 0x72, 0xf4, 0x1a, 0x3d, 0x55, 0x19, 0x3f, 0x9f, 0x22, + 0x2d, 0x6e, 0xa8, 0x46, 0x31, 0xcf, 0xa5, 0x2f, 0x27, 0xdf, 0x99, 0x3a, 0x7c, 0x58, 0xe9, 0xb3, + 0x66, 0xb5, 0xf2, 0xe5, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x73, 0x9a, 0x7d, 0x45, 0x94, 0x01, + 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -268,7 +268,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *ForwardingInfo) Marshal() (dAtA []byte, err error) { +func (m *Forwarding) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -278,12 +278,12 @@ func (m *ForwardingInfo) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ForwardingInfo) MarshalTo(dAtA []byte) (int, error) { +func (m *Forwarding) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ForwardingInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Forwarding) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -375,7 +375,7 @@ func (m *Params) Size() (n int) { return n } -func (m *ForwardingInfo) Size() (n int) { +func (m *Forwarding) Size() (n int) { if m == nil { return 0 } @@ -507,7 +507,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { } return nil } -func (m *ForwardingInfo) Unmarshal(dAtA []byte) error { +func (m *Forwarding) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -530,10 +530,10 @@ func (m *ForwardingInfo) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ForwardingInfo: wiretype end group for non-group") + return fmt.Errorf("proto: Forwarding: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ForwardingInfo: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Forwarding: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/modules/apps/transfer/types/tx.pb.go b/modules/apps/transfer/types/tx.pb.go index 7550a142816..79c8d64f1ad 100644 --- a/modules/apps/transfer/types/tx.pb.go +++ b/modules/apps/transfer/types/tx.pb.go @@ -57,7 +57,7 @@ type MsgTransfer struct { // tokens to be transferred Tokens []types.Coin `protobuf:"bytes,9,rep,name=tokens,proto3" json:"tokens"` // optional forwarding information - ForwardingPath *ForwardingInfo `protobuf:"bytes,10,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` + ForwardingPath *Forwarding `protobuf:"bytes,10,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` } func (m *MsgTransfer) Reset() { *m = MsgTransfer{} } @@ -225,50 +225,49 @@ func init() { } var fileDescriptor_7401ed9bed2f8e09 = []byte{ - // 673 bytes of a gzipped FileDescriptorProto + // 669 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcf, 0x4f, 0x13, 0x4f, - 0x14, 0xef, 0x7e, 0x29, 0xfd, 0xc2, 0x54, 0x40, 0x46, 0x03, 0xcb, 0xc6, 0x6c, 0x9b, 0x46, 0x12, - 0x2c, 0x32, 0x93, 0x62, 0x0c, 0x86, 0x78, 0x2a, 0x89, 0xd1, 0x44, 0x12, 0xdc, 0xc0, 0xc5, 0x0b, - 0x99, 0xdd, 0x0e, 0xbb, 0x13, 0xba, 0x33, 0xeb, 0xcc, 0xb4, 0xea, 0xc5, 0x18, 0x4f, 0xc6, 0x93, - 0xf1, 0x2f, 0xf0, 0xe8, 0x91, 0x3f, 0x83, 0x23, 0x47, 0x4f, 0xc6, 0xc0, 0x81, 0x8b, 0x7f, 0x84, - 0xd9, 0xd9, 0xd9, 0x52, 0x3d, 0x54, 0xbd, 0xb4, 0xf3, 0xde, 0xfb, 0xbc, 0x1f, 0x9f, 0xcf, 0xbe, - 0x3c, 0xb0, 0xca, 0xc2, 0x08, 0x93, 0x2c, 0xeb, 0xb3, 0x88, 0x68, 0x26, 0xb8, 0xc2, 0x5a, 0x12, - 0xae, 0x8e, 0xa8, 0xc4, 0xc3, 0x0e, 0xd6, 0xaf, 0x50, 0x26, 0x85, 0x16, 0xf0, 0x16, 0x0b, 0x23, - 0x34, 0x0e, 0x43, 0x25, 0x0c, 0x0d, 0x3b, 0xde, 0x22, 0x49, 0x19, 0x17, 0xd8, 0xfc, 0x16, 0x09, - 0xde, 0xcd, 0x58, 0xc4, 0xc2, 0x3c, 0x71, 0xfe, 0xb2, 0xde, 0xe5, 0x48, 0xa8, 0x54, 0x28, 0x9c, - 0xaa, 0x38, 0x2f, 0x9f, 0xaa, 0xd8, 0x06, 0x7c, 0x1b, 0x08, 0x89, 0xa2, 0x78, 0xd8, 0x09, 0xa9, - 0x26, 0x1d, 0x1c, 0x09, 0xc6, 0x6d, 0xbc, 0x91, 0x8f, 0x19, 0x09, 0x49, 0x71, 0xd4, 0x67, 0x94, - 0xeb, 0x3c, 0xbb, 0x78, 0x59, 0xc0, 0xfa, 0x64, 0x1e, 0xe5, 0xb0, 0x06, 0xdc, 0xfa, 0x54, 0x05, - 0xf5, 0x5d, 0x15, 0xef, 0x5b, 0x2f, 0x6c, 0x80, 0xba, 0x12, 0x03, 0x19, 0xd1, 0xc3, 0x4c, 0x48, - 0xed, 0x3a, 0x4d, 0x67, 0x6d, 0x36, 0x00, 0x85, 0x6b, 0x4f, 0x48, 0x0d, 0x57, 0xc1, 0xbc, 0x05, - 0x44, 0x09, 0xe1, 0x9c, 0xf6, 0xdd, 0xff, 0x0c, 0x66, 0xae, 0xf0, 0xee, 0x14, 0x4e, 0xf8, 0x10, - 0x4c, 0x6b, 0x71, 0x4c, 0xb9, 0x3b, 0xd5, 0x74, 0xd6, 0xea, 0x9b, 0x2b, 0xa8, 0x60, 0x85, 0x72, - 0x56, 0xc8, 0xb2, 0x42, 0x3b, 0x82, 0xf1, 0x6e, 0xfd, 0xf4, 0x5b, 0xa3, 0xf2, 0xe5, 0xf2, 0xa4, - 0xed, 0xb8, 0x4e, 0x50, 0x24, 0xc1, 0x25, 0x50, 0x53, 0x94, 0xf7, 0xa8, 0x74, 0xab, 0xa6, 0xb8, - 0xb5, 0xa0, 0x07, 0x66, 0x24, 0x8d, 0x28, 0x1b, 0x52, 0xe9, 0x4e, 0x9b, 0xc8, 0xc8, 0x86, 0x4f, - 0xc1, 0xbc, 0x66, 0x29, 0x15, 0x03, 0x7d, 0x98, 0x50, 0x16, 0x27, 0xda, 0xad, 0x99, 0xd6, 0x1e, - 0xca, 0x3f, 0x58, 0x2e, 0x18, 0xb2, 0x32, 0x0d, 0x3b, 0xe8, 0xb1, 0x41, 0x74, 0x67, 0x47, 0xbd, - 0x83, 0x39, 0x9b, 0x5c, 0x44, 0xe0, 0x3a, 0x58, 0x2c, 0xab, 0xe5, 0xff, 0x4a, 0x93, 0x34, 0x73, - 0xff, 0x6f, 0x3a, 0x6b, 0xd5, 0xe0, 0xba, 0x0d, 0xec, 0x97, 0x7e, 0x08, 0x41, 0x35, 0xa5, 0xa9, - 0x70, 0x67, 0xcc, 0x48, 0xe6, 0x0d, 0xb7, 0x40, 0xcd, 0x70, 0x51, 0xee, 0x6c, 0x73, 0x6a, 0xb2, - 0x02, 0xd5, 0x7c, 0x8a, 0xc0, 0xc2, 0xe1, 0x01, 0x58, 0x38, 0x12, 0xf2, 0x25, 0x91, 0x3d, 0xc6, - 0xe3, 0xc3, 0x8c, 0xe8, 0xc4, 0x05, 0x86, 0xc8, 0x5d, 0x34, 0x69, 0xf3, 0xd0, 0xa3, 0x51, 0xd2, - 0x13, 0x7e, 0x24, 0x82, 0xf9, 0xab, 0x22, 0x7b, 0x44, 0x27, 0xdb, 0xed, 0xf7, 0x9f, 0x1b, 0x95, - 0x77, 0x97, 0x27, 0x6d, 0xab, 0xe5, 0x87, 0xcb, 0x93, 0xf6, 0x52, 0x31, 0xd2, 0x86, 0xea, 0x1d, - 0xe3, 0xb1, 0x25, 0x68, 0x6d, 0x81, 0x1b, 0x63, 0x66, 0x40, 0x55, 0x26, 0xb8, 0xa2, 0xb9, 0xfa, - 0x8a, 0xbe, 0x18, 0x50, 0x1e, 0x51, 0xb3, 0x18, 0xd5, 0x60, 0x64, 0x6f, 0x57, 0xf3, 0xf2, 0xad, - 0x37, 0x60, 0x61, 0x57, 0xc5, 0x07, 0x59, 0x8f, 0x68, 0xba, 0x47, 0x24, 0x49, 0x95, 0xf9, 0x94, - 0x2c, 0xe6, 0x54, 0xda, 0x5d, 0xb2, 0x16, 0xec, 0x82, 0x5a, 0x66, 0x10, 0x66, 0x7f, 0xea, 0x9b, - 0xb7, 0x27, 0xb3, 0x2b, 0xaa, 0x95, 0x52, 0x15, 0x99, 0xdb, 0x0b, 0x57, 0x9c, 0x4c, 0xd1, 0xd6, - 0x0a, 0x58, 0xfe, 0xad, 0x7f, 0x39, 0xfc, 0xe6, 0x0f, 0x07, 0x4c, 0xed, 0xaa, 0x18, 0x26, 0x60, - 0x66, 0xb4, 0xec, 0x77, 0x26, 0xf7, 0x1c, 0xd3, 0xc0, 0xeb, 0xfc, 0x35, 0x74, 0x24, 0x97, 0x06, - 0xd7, 0x7e, 0x51, 0x62, 0xe3, 0x8f, 0x25, 0xc6, 0xe1, 0xde, 0xfd, 0x7f, 0x82, 0x97, 0x5d, 0xbd, - 0xe9, 0xb7, 0xf9, 0x3a, 0x77, 0x9f, 0x9d, 0x9e, 0xfb, 0xce, 0xd9, 0xb9, 0xef, 0x7c, 0x3f, 0xf7, - 0x9d, 0x8f, 0x17, 0x7e, 0xe5, 0xec, 0xc2, 0xaf, 0x7c, 0xbd, 0xf0, 0x2b, 0xcf, 0xb7, 0x62, 0xa6, - 0x93, 0x41, 0x88, 0x22, 0x91, 0x62, 0x7b, 0x6a, 0x58, 0x18, 0x6d, 0xc4, 0x02, 0x0f, 0x1f, 0xe0, - 0x54, 0xf4, 0x06, 0x7d, 0xaa, 0xf2, 0xf3, 0x31, 0x76, 0x36, 0xf4, 0xeb, 0x8c, 0xaa, 0xb0, 0x66, - 0x2e, 0xc6, 0xbd, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xec, 0xa3, 0x95, 0xc7, 0x28, 0x05, 0x00, - 0x00, + 0x14, 0xef, 0x7e, 0x29, 0xfd, 0xc2, 0x54, 0x40, 0x46, 0x03, 0xcb, 0xc6, 0x6c, 0x9b, 0x46, 0x92, + 0x5a, 0xc2, 0x4c, 0x8a, 0x31, 0x18, 0xe2, 0xa9, 0x24, 0xc6, 0x83, 0x24, 0xb0, 0xc1, 0x8b, 0x17, + 0x32, 0xbb, 0x1d, 0x76, 0x27, 0x74, 0x67, 0xd6, 0x99, 0x69, 0xd5, 0x8b, 0x31, 0x9e, 0x8c, 0x07, + 0xe3, 0x9f, 0xe0, 0xd1, 0x23, 0x7f, 0x06, 0x47, 0x8e, 0x9e, 0x8c, 0x81, 0x03, 0x17, 0xff, 0x08, + 0xb3, 0xb3, 0xb3, 0xa5, 0x7a, 0xa8, 0x7a, 0x69, 0xe7, 0xbd, 0xf7, 0x79, 0x3f, 0x3e, 0x9f, 0x7d, + 0x79, 0x60, 0x9d, 0x85, 0x11, 0x26, 0x59, 0x36, 0x60, 0x11, 0xd1, 0x4c, 0x70, 0x85, 0xb5, 0x24, + 0x5c, 0x1d, 0x53, 0x89, 0x47, 0x5d, 0xac, 0x5f, 0xa1, 0x4c, 0x0a, 0x2d, 0xe0, 0x1d, 0x16, 0x46, + 0x68, 0x12, 0x86, 0x4a, 0x18, 0x1a, 0x75, 0xbd, 0x65, 0x92, 0x32, 0x2e, 0xb0, 0xf9, 0x2d, 0x12, + 0xbc, 0xdb, 0xb1, 0x88, 0x85, 0x79, 0xe2, 0xfc, 0x65, 0xbd, 0xab, 0x91, 0x50, 0xa9, 0x50, 0x38, + 0x55, 0x71, 0x5e, 0x3e, 0x55, 0xb1, 0x0d, 0xf8, 0x36, 0x10, 0x12, 0x45, 0xf1, 0xa8, 0x1b, 0x52, + 0x4d, 0xba, 0x38, 0x12, 0x8c, 0xdb, 0x78, 0x23, 0x1f, 0x33, 0x12, 0x92, 0xe2, 0x68, 0xc0, 0x28, + 0xd7, 0x79, 0x76, 0xf1, 0xb2, 0x80, 0x8d, 0xe9, 0x3c, 0xca, 0x61, 0x0d, 0xb8, 0xf5, 0xb1, 0x0a, + 0xea, 0x7b, 0x2a, 0x3e, 0xb4, 0x5e, 0xd8, 0x00, 0x75, 0x25, 0x86, 0x32, 0xa2, 0x47, 0x99, 0x90, + 0xda, 0x75, 0x9a, 0x4e, 0x7b, 0x3e, 0x00, 0x85, 0x6b, 0x5f, 0x48, 0x0d, 0xd7, 0xc1, 0xa2, 0x05, + 0x44, 0x09, 0xe1, 0x9c, 0x0e, 0xdc, 0xff, 0x0c, 0x66, 0xa1, 0xf0, 0xee, 0x16, 0x4e, 0xf8, 0x08, + 0xcc, 0x6a, 0x71, 0x42, 0xb9, 0x3b, 0xd3, 0x74, 0xda, 0xf5, 0xad, 0x35, 0x54, 0xb0, 0x42, 0x39, + 0x2b, 0x64, 0x59, 0xa1, 0x5d, 0xc1, 0x78, 0xaf, 0x7e, 0xf6, 0xad, 0x51, 0xf9, 0x72, 0x75, 0xda, + 0x71, 0x5c, 0x27, 0x28, 0x92, 0xe0, 0x0a, 0xa8, 0x29, 0xca, 0xfb, 0x54, 0xba, 0x55, 0x53, 0xdc, + 0x5a, 0xd0, 0x03, 0x73, 0x92, 0x46, 0x94, 0x8d, 0xa8, 0x74, 0x67, 0x4d, 0x64, 0x6c, 0xc3, 0xa7, + 0x60, 0x51, 0xb3, 0x94, 0x8a, 0xa1, 0x3e, 0x4a, 0x28, 0x8b, 0x13, 0xed, 0xd6, 0x4c, 0x6b, 0x0f, + 0xe5, 0x1f, 0x2c, 0x17, 0x0c, 0x59, 0x99, 0x46, 0x5d, 0xf4, 0xc4, 0x20, 0x7a, 0xf3, 0xe3, 0xde, + 0xc1, 0x82, 0x4d, 0x2e, 0x22, 0x70, 0x03, 0x2c, 0x97, 0xd5, 0xf2, 0x7f, 0xa5, 0x49, 0x9a, 0xb9, + 0xff, 0x37, 0x9d, 0x76, 0x35, 0xb8, 0x69, 0x03, 0x87, 0xa5, 0x1f, 0x42, 0x50, 0x4d, 0x69, 0x2a, + 0xdc, 0x39, 0x33, 0x92, 0x79, 0xc3, 0x6d, 0x50, 0x33, 0x5c, 0x94, 0x3b, 0xdf, 0x9c, 0x99, 0xae, + 0x40, 0x35, 0x9f, 0x22, 0xb0, 0x70, 0x78, 0x00, 0x96, 0x8e, 0x85, 0x7c, 0x49, 0x64, 0x9f, 0xf1, + 0xf8, 0x28, 0x23, 0x3a, 0x71, 0x81, 0x21, 0xd2, 0x46, 0xd3, 0x36, 0x0f, 0x3d, 0x1e, 0x27, 0x05, + 0x8b, 0xd7, 0x05, 0xf6, 0x89, 0x4e, 0x76, 0x3a, 0xef, 0x3f, 0x37, 0x2a, 0xef, 0xae, 0x4e, 0x3b, + 0x56, 0xc7, 0x0f, 0x57, 0xa7, 0x9d, 0x95, 0x62, 0x9c, 0x4d, 0xd5, 0x3f, 0xc1, 0x13, 0x0b, 0xd0, + 0xda, 0x06, 0xb7, 0x26, 0xcc, 0x80, 0xaa, 0x4c, 0x70, 0x45, 0x73, 0xe5, 0x15, 0x7d, 0x31, 0xa4, + 0x3c, 0xa2, 0x66, 0x29, 0xaa, 0xc1, 0xd8, 0xde, 0xa9, 0xe6, 0xe5, 0x5b, 0x6f, 0xc0, 0xd2, 0x9e, + 0x8a, 0x9f, 0x65, 0x7d, 0xa2, 0xe9, 0x3e, 0x91, 0x24, 0x55, 0xe6, 0x33, 0xb2, 0x98, 0x53, 0x69, + 0xf7, 0xc8, 0x5a, 0xb0, 0x07, 0x6a, 0x99, 0x41, 0x98, 0xdd, 0xa9, 0x6f, 0xdd, 0x9d, 0xce, 0xac, + 0xa8, 0x56, 0xca, 0x54, 0x64, 0xee, 0x2c, 0x5d, 0x73, 0x32, 0x45, 0x5b, 0x6b, 0x60, 0xf5, 0xb7, + 0xfe, 0xe5, 0xf0, 0x5b, 0x3f, 0x1c, 0x30, 0xb3, 0xa7, 0x62, 0x98, 0x80, 0xb9, 0xf1, 0xa2, 0xdf, + 0x9b, 0xde, 0x73, 0x42, 0x03, 0xaf, 0xfb, 0xd7, 0xd0, 0xb1, 0x5c, 0x1a, 0xdc, 0xf8, 0x45, 0x89, + 0xcd, 0x3f, 0x96, 0x98, 0x84, 0x7b, 0x0f, 0xfe, 0x09, 0x5e, 0x76, 0xf5, 0x66, 0xdf, 0xe6, 0xab, + 0xdc, 0x3b, 0x38, 0xbb, 0xf0, 0x9d, 0xf3, 0x0b, 0xdf, 0xf9, 0x7e, 0xe1, 0x3b, 0x9f, 0x2e, 0xfd, + 0xca, 0xf9, 0xa5, 0x5f, 0xf9, 0x7a, 0xe9, 0x57, 0x9e, 0x6f, 0xc7, 0x4c, 0x27, 0xc3, 0x10, 0x45, + 0x22, 0xc5, 0xf6, 0xcc, 0xb0, 0x30, 0xda, 0x8c, 0x05, 0x1e, 0x3d, 0xc4, 0xa9, 0xe8, 0x0f, 0x07, + 0x54, 0xe5, 0xa7, 0x63, 0xe2, 0x64, 0xe8, 0xd7, 0x19, 0x55, 0x61, 0xcd, 0x5c, 0x8b, 0xfb, 0x3f, + 0x03, 0x00, 0x00, 0xff, 0xff, 0x07, 0xeb, 0x25, 0x21, 0x24, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1028,7 +1027,7 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.ForwardingPath == nil { - m.ForwardingPath = &ForwardingInfo{} + m.ForwardingPath = &Forwarding{} } if err := m.ForwardingPath.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index 45dc9c0d2b5..6f970848fc8 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -17,10 +17,10 @@ message Params { bool receive_enabled = 2; } -// ForwardingInfo defines a list of port ID, channel ID pairs determining the path +// Forwarding defines a list of hops determining the path // through which a packet must be forwarded, and the memo string to be used in the // final destination of the tokens. -message ForwardingInfo { +message Forwarding { repeated Hop hops = 1; string memo = 2; } diff --git a/proto/ibc/applications/transfer/v1/tx.proto b/proto/ibc/applications/transfer/v1/tx.proto index 4caf0273b2c..abe573916c9 100644 --- a/proto/ibc/applications/transfer/v1/tx.proto +++ b/proto/ibc/applications/transfer/v1/tx.proto @@ -52,7 +52,7 @@ message MsgTransfer { // tokens to be transferred repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false]; // optional forwarding information - ForwardingInfo forwarding_path = 10; + Forwarding forwarding_path = 10; } // MsgTransferResponse defines the Msg/Transfer response type. diff --git a/proto/ibc/applications/transfer/v2/packet.proto b/proto/ibc/applications/transfer/v2/packet.proto index 702be8b2ffe..66fc7515448 100644 --- a/proto/ibc/applications/transfer/v2/packet.proto +++ b/proto/ibc/applications/transfer/v2/packet.proto @@ -37,5 +37,5 @@ message FungibleTokenPacketDataV2 { // optional memo string memo = 4; // optional forwarding information - ibc.applications.transfer.v1.ForwardingInfo forwarding_path = 5; + ibc.applications.transfer.v1.Forwarding forwarding_path = 5; } From 0c9f3684d7b194548db75956be23872d669fd09e Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 12 Jun 2024 12:33:13 +0200 Subject: [PATCH 066/141] Revert "chore: rename ForwardingInfo to Forwarding" This reverts commit e483b9a5fb6887c97c6f76257967b8b40bbf82cf. --- e2e/testsuite/testsuite.go | 20 ++-- modules/apps/transfer/keeper/export_test.go | 2 +- modules/apps/transfer/keeper/relay.go | 12 ++- .../transfer/keeper/relay_forwarding_test.go | 11 ++- modules/apps/transfer/types/msgs.go | 3 +- modules/apps/transfer/types/packet.go | 2 +- modules/apps/transfer/types/packet.pb.go | 56 +++++------ modules/apps/transfer/types/packet_test.go | 4 +- modules/apps/transfer/types/transfer.pb.go | 92 +++++++++---------- modules/apps/transfer/types/tx.pb.go | 89 +++++++++--------- .../applications/transfer/v1/transfer.proto | 4 +- proto/ibc/applications/transfer/v1/tx.proto | 2 +- .../ibc/applications/transfer/v2/packet.proto | 2 +- 13 files changed, 153 insertions(+), 146 deletions(-) diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index e9c1d7fc96d..9a113fbd7e9 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -8,14 +8,6 @@ import ( "path" "strings" - sdkmath "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" - transfertypes "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" dockerclient "github.com/docker/docker/client" interchaintest "github.com/strangelove-ventures/interchaintest/v8" "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" @@ -25,11 +17,21 @@ import ( testifysuite "github.com/stretchr/testify/suite" "go.uber.org/zap" + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/ibc-go/e2e/internal/directories" "github.com/cosmos/ibc-go/e2e/relayer" "github.com/cosmos/ibc-go/e2e/testsuite/diagnostics" "github.com/cosmos/ibc-go/e2e/testsuite/query" "github.com/cosmos/ibc-go/e2e/testvalues" + feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + transfertypes "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" ) const ( @@ -561,7 +563,7 @@ func getValidatorsAndFullNodes(chainIdx int) (int, int) { } // GetMsgTransfer returns a MsgTransfer that is constructed based on the channel version -func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, forwardingPath *transfertypes.Forwarding) *transfertypes.MsgTransfer { +func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, forwardingPath *transfertypes.ForwardingInfo) *transfertypes.MsgTransfer { if len(tokens) == 0 { panic(errors.New("tokens cannot be empty")) } diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index 670f85b7ac3..760e04cc97f 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -34,6 +34,6 @@ func (k Keeper) TokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // CreatePacketDataBytesFromVersion is a wrapper around createPacketDataBytesFromVersion for testing purposes -func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwardingPath *types.Forwarding) []byte { +func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwardingPath *types.ForwardingInfo) []byte { return createPacketDataBytesFromVersion(appVersion, sender, receiver, memo, tokens, forwardingPath) } diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index ccd320f5471..c4957aae5e3 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -5,11 +5,13 @@ import ( "fmt" "strings" + "github.com/hashicorp/go-metrics" + errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/hashicorp/go-metrics" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/events" internaltelemetry "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/telemetry" @@ -63,7 +65,7 @@ func (k Keeper) sendTransfer( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, - forwardingPath *types.Forwarding, + forwardingPath *types.ForwardingInfo, ) (uint64, error) { channel, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) if !found { @@ -275,12 +277,12 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { memo := "" - var nextForwardingPath *types.Forwarding + var nextForwardingPath *types.ForwardingInfo if len(data.ForwardingPath.Hops) == 1 { memo = data.ForwardingPath.Memo nextForwardingPath = nil } else { - nextForwardingPath = &types.Forwarding{ + nextForwardingPath = &types.ForwardingInfo{ Hops: data.ForwardingPath.Hops[1:], Memo: data.ForwardingPath.Memo, } @@ -549,7 +551,7 @@ func (k Keeper) tokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // createPacketDataBytesFromVersion creates the packet data bytes to be sent based on the application version. -func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwardingPath *types.Forwarding) []byte { +func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwardingPath *types.ForwardingInfo) []byte { var packetDataBytes []byte switch appVersion { case types.V1: diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 341b1daad80..bdb1aa2b0ae 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -4,6 +4,7 @@ import ( "fmt" sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" @@ -26,7 +27,7 @@ func (suite *KeeperTestSuite) TestPathForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.Forwarding{ + forwardingPath := types.ForwardingInfo{ Hops: []*types.Hop{ { PortId: path2.EndpointA.ChannelConfig.PortID, @@ -88,7 +89,7 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.Forwarding{ + forwardingPath := types.ForwardingInfo{ Hops: []*types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, @@ -171,7 +172,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.Forwarding{ + forwardingPath := types.ForwardingInfo{ Hops: []*types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, @@ -279,7 +280,7 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.Forwarding{ + forwardingPath := types.ForwardingInfo{ Hops: []*types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, @@ -476,7 +477,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { sender = suite.chainC.SenderAccounts[0].SenderAccount receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account - forwardingPath := types.Forwarding{ + forwardingPath := types.ForwardingInfo{ Hops: []*types.Hop{ { PortId: path1.EndpointB.ChannelConfig.PortID, diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 4dbfc9b8136..3c10f3b5779 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -4,6 +4,7 @@ import ( "strings" errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -48,7 +49,7 @@ func NewMsgTransfer( tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, - forwardingPath *Forwarding, + forwardingPath *ForwardingInfo, ) *MsgTransfer { return &MsgTransfer{ SourcePort: sourcePort, diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 5513d2d62db..fcdb431695e 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -103,7 +103,7 @@ func NewFungibleTokenPacketDataV2( tokens []Token, sender, receiver string, memo string, - forwardingPath *Forwarding, + forwardingPath *ForwardingInfo, ) FungibleTokenPacketDataV2 { return FungibleTokenPacketDataV2{ Tokens: tokens, diff --git a/modules/apps/transfer/types/packet.pb.go b/modules/apps/transfer/types/packet.pb.go index b5e4fffdaef..1eae85e38e9 100644 --- a/modules/apps/transfer/types/packet.pb.go +++ b/modules/apps/transfer/types/packet.pb.go @@ -120,7 +120,7 @@ type FungibleTokenPacketDataV2 struct { // optional memo Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` // optional forwarding information - ForwardingPath *Forwarding `protobuf:"bytes,5,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` + ForwardingPath *ForwardingInfo `protobuf:"bytes,5,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` } func (m *FungibleTokenPacketDataV2) Reset() { *m = FungibleTokenPacketDataV2{} } @@ -184,7 +184,7 @@ func (m *FungibleTokenPacketDataV2) GetMemo() string { return "" } -func (m *FungibleTokenPacketDataV2) GetForwardingPath() *Forwarding { +func (m *FungibleTokenPacketDataV2) GetForwardingPath() *ForwardingInfo { if m != nil { return m.ForwardingPath } @@ -201,31 +201,31 @@ func init() { } var fileDescriptor_653ca2ce9a5ca313 = []byte{ - // 372 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0x0f, 0xd2, 0x30, - 0x1c, 0xc5, 0x57, 0x18, 0x44, 0x4b, 0xa2, 0x49, 0x43, 0x74, 0x12, 0x33, 0x09, 0x5e, 0x66, 0x8c, - 0x6d, 0x98, 0x07, 0xbd, 0x4a, 0x0c, 0x67, 0x20, 0xc6, 0x83, 0x17, 0xd3, 0x75, 0x65, 0x34, 0xb0, - 0x76, 0x69, 0xbb, 0x19, 0x3f, 0x85, 0x7e, 0x2c, 0x8e, 0x1c, 0x3d, 0x19, 0x03, 0x9f, 0xc2, 0x9b, - 0x59, 0x87, 0xc0, 0x85, 0xdd, 0xde, 0x7b, 0xfb, 0xff, 0x5f, 0x7e, 0xeb, 0x1f, 0xbe, 0x12, 0x09, - 0x23, 0xb4, 0x28, 0x76, 0x82, 0x51, 0x2b, 0x94, 0x34, 0xc4, 0x6a, 0x2a, 0xcd, 0x9a, 0x6b, 0x52, - 0xc5, 0xa4, 0xa0, 0x6c, 0xcb, 0x2d, 0x2e, 0xb4, 0xb2, 0x0a, 0x3d, 0x17, 0x09, 0xc3, 0xb7, 0xa3, - 0xf8, 0xff, 0x28, 0xae, 0xe2, 0x51, 0xd4, 0x5a, 0x64, 0xd5, 0x96, 0xcb, 0xa6, 0x67, 0x34, 0xcc, - 0x54, 0xa6, 0x9c, 0x24, 0xb5, 0x3a, 0xa7, 0xaf, 0x5b, 0xf6, 0xa7, 0x17, 0xdd, 0x0c, 0x4f, 0x7e, - 0x00, 0xf8, 0x74, 0x5e, 0xca, 0x4c, 0x24, 0x3b, 0xfe, 0xa9, 0xae, 0x5e, 0x38, 0xd0, 0x8f, 0xd4, - 0x52, 0x34, 0x84, 0xbd, 0x94, 0x4b, 0x95, 0x07, 0x60, 0x0c, 0xa2, 0x87, 0xab, 0xc6, 0xa0, 0x27, - 0xb0, 0x4f, 0x73, 0x55, 0x4a, 0x1b, 0x74, 0x5c, 0x7c, 0x76, 0x75, 0x6e, 0xb8, 0x4c, 0xb9, 0x0e, - 0xba, 0x4d, 0xde, 0x38, 0x34, 0x82, 0x0f, 0x34, 0x67, 0x5c, 0x54, 0x5c, 0x07, 0xbe, 0xfb, 0x72, - 0xf1, 0x08, 0x41, 0x3f, 0xe7, 0xb9, 0x0a, 0x7a, 0x2e, 0x77, 0x7a, 0xf2, 0x17, 0xc0, 0x67, 0x77, - 0x88, 0x3e, 0xc7, 0xe8, 0x03, 0xec, 0xbb, 0x17, 0x30, 0x01, 0x18, 0x77, 0xa3, 0x41, 0xfc, 0x12, - 0xb7, 0xbd, 0x25, 0x76, 0x05, 0x33, 0x7f, 0xff, 0xfb, 0x85, 0xb7, 0x3a, 0x2f, 0xde, 0x80, 0x76, - 0xee, 0x82, 0x76, 0xef, 0x80, 0xfa, 0x57, 0x50, 0xb4, 0x84, 0x8f, 0xd7, 0x4a, 0x7f, 0xa3, 0x3a, - 0x15, 0x32, 0xfb, 0x5a, 0x50, 0xbb, 0x71, 0xff, 0x31, 0x88, 0xa3, 0x36, 0xa6, 0x29, 0x9e, 0x5f, - 0x96, 0x56, 0x8f, 0xae, 0x05, 0x0b, 0x6a, 0x37, 0xb3, 0xe5, 0xfe, 0x18, 0x82, 0xc3, 0x31, 0x04, - 0x7f, 0x8e, 0x21, 0xf8, 0x79, 0x0a, 0xbd, 0xc3, 0x29, 0xf4, 0x7e, 0x9d, 0x42, 0xef, 0xcb, 0xbb, - 0x4c, 0xd8, 0x4d, 0x99, 0x60, 0xa6, 0x72, 0xc2, 0x94, 0xc9, 0x95, 0x21, 0x22, 0x61, 0x6f, 0x32, - 0x45, 0xaa, 0xf7, 0x24, 0x57, 0x69, 0xb9, 0xe3, 0xa6, 0x3e, 0xfa, 0xcd, 0xb1, 0xed, 0xf7, 0x82, - 0x9b, 0xa4, 0xef, 0xee, 0xfc, 0xf6, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x6b, 0xf8, 0x91, - 0x9f, 0x02, 0x00, 0x00, + // 379 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0xab, 0xd3, 0x40, + 0x14, 0x85, 0x33, 0xaf, 0x79, 0x45, 0xe7, 0x81, 0xc2, 0xf0, 0xd0, 0x58, 0x24, 0x3e, 0x9e, 0x9b, + 0x8a, 0x3a, 0x43, 0xe3, 0x42, 0xb7, 0x16, 0x29, 0xb8, 0xab, 0x45, 0x5d, 0xb8, 0x91, 0xc9, 0x64, + 0x9a, 0x0e, 0x6d, 0xe6, 0x86, 0x99, 0x49, 0xc4, 0x5f, 0xa1, 0x3f, 0xab, 0xcb, 0x2e, 0x5d, 0x89, + 0xb4, 0xbf, 0x43, 0x90, 0x4c, 0x6a, 0xdb, 0x4d, 0xb3, 0x3b, 0xe7, 0xe4, 0xde, 0xc3, 0x97, 0xb9, + 0xf8, 0x99, 0x4a, 0x05, 0xe3, 0x65, 0xb9, 0x52, 0x82, 0x3b, 0x05, 0xda, 0x32, 0x67, 0xb8, 0xb6, + 0x73, 0x69, 0x58, 0x9d, 0xb0, 0x92, 0x8b, 0xa5, 0x74, 0xb4, 0x34, 0xe0, 0x80, 0x3c, 0x56, 0xa9, + 0xa0, 0xa7, 0xa3, 0xf4, 0xff, 0x28, 0xad, 0x93, 0xc1, 0xb0, 0xb3, 0xc8, 0xc1, 0x52, 0xea, 0xb6, + 0x67, 0x70, 0x9d, 0x43, 0x0e, 0x5e, 0xb2, 0x46, 0xed, 0xd3, 0xe7, 0x1d, 0xfb, 0xa3, 0x83, 0x6e, + 0x87, 0x6f, 0x7f, 0x20, 0xfc, 0x70, 0x52, 0xe9, 0x5c, 0xa5, 0x2b, 0xf9, 0xb1, 0xa9, 0x9e, 0x7a, + 0xd0, 0x77, 0xdc, 0x71, 0x72, 0x8d, 0x2f, 0x33, 0xa9, 0xa1, 0x88, 0xd0, 0x0d, 0x1a, 0xde, 0x9d, + 0xb5, 0x86, 0x3c, 0xc0, 0x7d, 0x5e, 0x40, 0xa5, 0x5d, 0x74, 0xe1, 0xe3, 0xbd, 0x6b, 0x72, 0x2b, + 0x75, 0x26, 0x4d, 0xd4, 0x6b, 0xf3, 0xd6, 0x91, 0x01, 0xbe, 0x63, 0xa4, 0x90, 0xaa, 0x96, 0x26, + 0x0a, 0xfd, 0x97, 0x83, 0x27, 0x04, 0x87, 0x85, 0x2c, 0x20, 0xba, 0xf4, 0xb9, 0xd7, 0xb7, 0x7f, + 0x11, 0x7e, 0x74, 0x86, 0xe8, 0x73, 0x42, 0xde, 0xe2, 0xbe, 0x7f, 0x01, 0x1b, 0xa1, 0x9b, 0xde, + 0xf0, 0x2a, 0x79, 0x4a, 0xbb, 0xde, 0x92, 0xfa, 0x82, 0x71, 0xb8, 0xfe, 0xfd, 0x24, 0x98, 0xed, + 0x17, 0x4f, 0x40, 0x2f, 0xce, 0x82, 0xf6, 0xce, 0x80, 0x86, 0x47, 0x50, 0xf2, 0x09, 0xdf, 0x9f, + 0x83, 0xf9, 0xc6, 0x4d, 0xa6, 0x74, 0xfe, 0xb5, 0xe4, 0x6e, 0xe1, 0xff, 0xe3, 0x2a, 0x79, 0xd1, + 0xc5, 0x34, 0xa2, 0x93, 0xc3, 0xd2, 0x7b, 0x3d, 0x87, 0xd9, 0xbd, 0x63, 0xc9, 0x94, 0xbb, 0xc5, + 0xf8, 0xc3, 0x7a, 0x1b, 0xa3, 0xcd, 0x36, 0x46, 0x7f, 0xb6, 0x31, 0xfa, 0xb9, 0x8b, 0x83, 0xcd, + 0x2e, 0x0e, 0x7e, 0xed, 0xe2, 0xe0, 0xcb, 0xeb, 0x5c, 0xb9, 0x45, 0x95, 0x52, 0x01, 0x05, 0x13, + 0x60, 0x0b, 0xb0, 0x4c, 0xa5, 0xe2, 0x65, 0x0e, 0xac, 0x7e, 0xc3, 0x0a, 0xc8, 0xaa, 0x95, 0xb4, + 0xcd, 0xe1, 0x4f, 0x0e, 0xee, 0xbe, 0x97, 0xd2, 0xa6, 0x7d, 0x7f, 0xeb, 0x57, 0xff, 0x02, 0x00, + 0x00, 0xff, 0xff, 0x9a, 0x79, 0x3e, 0x9a, 0xa3, 0x02, 0x00, 0x00, } func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { @@ -832,7 +832,7 @@ func (m *FungibleTokenPacketDataV2) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.ForwardingPath == nil { - m.ForwardingPath = &Forwarding{} + m.ForwardingPath = &ForwardingInfo{} } if err := m.ForwardingPath.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 7ba33b11a59..9997751b69e 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -233,7 +233,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - &types.Forwarding{ + &types.ForwardingInfo{ Hops: []*types.Hop{ { PortId: "transfer", @@ -399,7 +399,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "memo", - &types.Forwarding{ + &types.ForwardingInfo{ Hops: []*types.Hop{ { PortId: "transfer", diff --git a/modules/apps/transfer/types/transfer.pb.go b/modules/apps/transfer/types/transfer.pb.go index bfd375b7683..75ee2e183d4 100644 --- a/modules/apps/transfer/types/transfer.pb.go +++ b/modules/apps/transfer/types/transfer.pb.go @@ -82,26 +82,26 @@ func (m *Params) GetReceiveEnabled() bool { return false } -// Forwarding defines a list of hops determining the path +// ForwardingInfo defines a list of port ID, channel ID pairs determining the path // through which a packet must be forwarded, and the memo string to be used in the // final destination of the tokens. -type Forwarding struct { +type ForwardingInfo struct { Hops []*Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops,omitempty"` Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` } -func (m *Forwarding) Reset() { *m = Forwarding{} } -func (m *Forwarding) String() string { return proto.CompactTextString(m) } -func (*Forwarding) ProtoMessage() {} -func (*Forwarding) Descriptor() ([]byte, []int) { +func (m *ForwardingInfo) Reset() { *m = ForwardingInfo{} } +func (m *ForwardingInfo) String() string { return proto.CompactTextString(m) } +func (*ForwardingInfo) ProtoMessage() {} +func (*ForwardingInfo) Descriptor() ([]byte, []int) { return fileDescriptor_5041673e96e97901, []int{1} } -func (m *Forwarding) XXX_Unmarshal(b []byte) error { +func (m *ForwardingInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *Forwarding) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *ForwardingInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_Forwarding.Marshal(b, m, deterministic) + return xxx_messageInfo_ForwardingInfo.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -111,26 +111,26 @@ func (m *Forwarding) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *Forwarding) XXX_Merge(src proto.Message) { - xxx_messageInfo_Forwarding.Merge(m, src) +func (m *ForwardingInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ForwardingInfo.Merge(m, src) } -func (m *Forwarding) XXX_Size() int { +func (m *ForwardingInfo) XXX_Size() int { return m.Size() } -func (m *Forwarding) XXX_DiscardUnknown() { - xxx_messageInfo_Forwarding.DiscardUnknown(m) +func (m *ForwardingInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ForwardingInfo.DiscardUnknown(m) } -var xxx_messageInfo_Forwarding proto.InternalMessageInfo +var xxx_messageInfo_ForwardingInfo proto.InternalMessageInfo -func (m *Forwarding) GetHops() []*Hop { +func (m *ForwardingInfo) GetHops() []*Hop { if m != nil { return m.Hops } return nil } -func (m *Forwarding) GetMemo() string { +func (m *ForwardingInfo) GetMemo() string { if m != nil { return m.Memo } @@ -193,7 +193,7 @@ func (m *Hop) GetChannelId() string { func init() { proto.RegisterType((*Params)(nil), "ibc.applications.transfer.v1.Params") - proto.RegisterType((*Forwarding)(nil), "ibc.applications.transfer.v1.Forwarding") + proto.RegisterType((*ForwardingInfo)(nil), "ibc.applications.transfer.v1.ForwardingInfo") proto.RegisterType((*Hop)(nil), "ibc.applications.transfer.v1.Hop") } @@ -202,27 +202,27 @@ func init() { } var fileDescriptor_5041673e96e97901 = []byte{ - // 306 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0x31, 0x4b, 0x33, 0x31, - 0x1c, 0xc6, 0x7b, 0x6f, 0x4b, 0x5f, 0xfb, 0xaf, 0x28, 0x64, 0xb1, 0x83, 0x1e, 0x6d, 0x17, 0x0b, - 0xe2, 0x85, 0x2a, 0xa2, 0x8b, 0x8b, 0xa0, 0xb4, 0x9b, 0x1e, 0x82, 0xe0, 0x52, 0x72, 0x49, 0x6c, - 0x03, 0x97, 0xfc, 0x43, 0x92, 0x9e, 0xf8, 0x2d, 0xfc, 0x58, 0x8e, 0x1d, 0x1d, 0xa5, 0xfd, 0x22, - 0x72, 0xd7, 0x52, 0x3a, 0xb9, 0x3d, 0xf9, 0xe5, 0x17, 0xf2, 0xf0, 0xc0, 0x99, 0xca, 0x38, 0x65, - 0xd6, 0xe6, 0x8a, 0xb3, 0xa0, 0xd0, 0x78, 0x1a, 0x1c, 0x33, 0xfe, 0x4d, 0x3a, 0x5a, 0x0c, 0xb7, - 0x39, 0xb1, 0x0e, 0x03, 0x92, 0x63, 0x95, 0xf1, 0x64, 0x57, 0x4e, 0xb6, 0x42, 0x31, 0xec, 0x3f, - 0x43, 0xf3, 0x91, 0x39, 0xa6, 0x3d, 0xe9, 0xc1, 0xbe, 0x97, 0x46, 0x4c, 0xa4, 0x61, 0x59, 0x2e, - 0x45, 0x27, 0xea, 0x46, 0x83, 0xbd, 0xb4, 0x5d, 0xb2, 0xfb, 0x35, 0x22, 0xa7, 0x70, 0xe8, 0x24, - 0x97, 0xaa, 0x90, 0x5b, 0xeb, 0x5f, 0x65, 0x1d, 0x6c, 0xf0, 0x46, 0xec, 0xbf, 0x00, 0x3c, 0xa0, - 0x7b, 0x67, 0x4e, 0x28, 0x33, 0x25, 0x57, 0xd0, 0x98, 0xa1, 0xf5, 0x9d, 0xa8, 0x5b, 0x1f, 0xb4, - 0x2f, 0x7a, 0xc9, 0x5f, 0x85, 0x92, 0x11, 0xda, 0xb4, 0xd2, 0x09, 0x81, 0x86, 0x96, 0x1a, 0xab, - 0x2f, 0x5a, 0x69, 0x95, 0xfb, 0xb7, 0x50, 0x1f, 0xa1, 0x25, 0x47, 0xf0, 0xdf, 0xa2, 0x0b, 0x13, - 0xb5, 0xae, 0xd9, 0x4a, 0x9b, 0xe5, 0x71, 0x2c, 0xc8, 0x09, 0x00, 0x9f, 0x31, 0x63, 0x64, 0x5e, - 0xde, 0xad, 0x5f, 0xb6, 0x36, 0x64, 0x2c, 0xee, 0x9e, 0xbe, 0x96, 0x71, 0xb4, 0x58, 0xc6, 0xd1, - 0xcf, 0x32, 0x8e, 0x3e, 0x57, 0x71, 0x6d, 0xb1, 0x8a, 0x6b, 0xdf, 0xab, 0xb8, 0xf6, 0x7a, 0x3d, - 0x55, 0x61, 0x36, 0xcf, 0x12, 0x8e, 0x9a, 0x72, 0xf4, 0x1a, 0x3d, 0x55, 0x19, 0x3f, 0x9f, 0x22, - 0x2d, 0x6e, 0xa8, 0x46, 0x31, 0xcf, 0xa5, 0x2f, 0x27, 0xdf, 0x99, 0x3a, 0x7c, 0x58, 0xe9, 0xb3, - 0x66, 0xb5, 0xf2, 0xe5, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x73, 0x9a, 0x7d, 0x45, 0x94, 0x01, - 0x00, 0x00, + // 308 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0x3f, 0x4f, 0x3a, 0x31, + 0x1c, 0xc6, 0xb9, 0x1f, 0x84, 0x9f, 0x14, 0x83, 0x49, 0x17, 0x19, 0xf4, 0x02, 0x2c, 0x92, 0x18, + 0xaf, 0x41, 0x63, 0x74, 0x71, 0x31, 0xd1, 0xc0, 0xa6, 0x17, 0x27, 0x1d, 0x48, 0xff, 0x01, 0x4d, + 0xae, 0xfd, 0x36, 0x6d, 0x39, 0xe3, 0xbb, 0xf0, 0x65, 0x39, 0x32, 0x3a, 0x1a, 0x78, 0x23, 0xe6, + 0x0e, 0x72, 0x61, 0x72, 0x7b, 0xfa, 0xe9, 0xa7, 0xe9, 0x93, 0x07, 0x9d, 0x2b, 0xc6, 0x09, 0xb5, + 0x36, 0x53, 0x9c, 0x06, 0x05, 0xc6, 0x93, 0xe0, 0xa8, 0xf1, 0x33, 0xe9, 0x48, 0x3e, 0xaa, 0x72, + 0x62, 0x1d, 0x04, 0xc0, 0x27, 0x8a, 0xf1, 0x64, 0x5f, 0x4e, 0x2a, 0x21, 0x1f, 0x0d, 0x5e, 0x50, + 0xf3, 0x89, 0x3a, 0xaa, 0x3d, 0xee, 0xa3, 0x43, 0x2f, 0x8d, 0x98, 0x4a, 0x43, 0x59, 0x26, 0x45, + 0x37, 0xea, 0x45, 0xc3, 0x83, 0xb4, 0x5d, 0xb0, 0x87, 0x2d, 0xc2, 0x67, 0xe8, 0xc8, 0x49, 0x2e, + 0x55, 0x2e, 0x2b, 0xeb, 0x5f, 0x69, 0x75, 0x76, 0x78, 0x27, 0x0e, 0xde, 0x50, 0xe7, 0x11, 0xdc, + 0x3b, 0x75, 0x42, 0x99, 0xf9, 0xc4, 0xcc, 0x00, 0x5f, 0xa3, 0xc6, 0x02, 0xac, 0xef, 0x46, 0xbd, + 0xfa, 0xb0, 0x7d, 0xd9, 0x4f, 0xfe, 0x2a, 0x95, 0x8c, 0xc1, 0xa6, 0xa5, 0x8e, 0x31, 0x6a, 0x68, + 0xa9, 0xa1, 0xfc, 0xa6, 0x95, 0x96, 0x79, 0x70, 0x87, 0xea, 0x63, 0xb0, 0xf8, 0x18, 0xfd, 0xb7, + 0xe0, 0xc2, 0x54, 0x6d, 0xab, 0xb6, 0xd2, 0x66, 0x71, 0x9c, 0x08, 0x7c, 0x8a, 0x10, 0x5f, 0x50, + 0x63, 0x64, 0x56, 0xdc, 0x6d, 0x5f, 0xb6, 0x76, 0x64, 0x22, 0xee, 0x9f, 0xbf, 0xd6, 0x71, 0xb4, + 0x5a, 0xc7, 0xd1, 0xcf, 0x3a, 0x8e, 0x3e, 0x37, 0x71, 0x6d, 0xb5, 0x89, 0x6b, 0xdf, 0x9b, 0xb8, + 0xf6, 0x7a, 0x33, 0x57, 0x61, 0xb1, 0x64, 0x09, 0x07, 0x4d, 0x38, 0x78, 0x0d, 0x9e, 0x28, 0xc6, + 0x2f, 0xe6, 0x40, 0xf2, 0x5b, 0xa2, 0x41, 0x2c, 0x33, 0xe9, 0x8b, 0xd9, 0xf7, 0xe6, 0x0e, 0x1f, + 0x56, 0x7a, 0xd6, 0x2c, 0x97, 0xbe, 0xfa, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x05, 0xad, 0xe6, 0x9f, + 0x98, 0x01, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -268,7 +268,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *Forwarding) Marshal() (dAtA []byte, err error) { +func (m *ForwardingInfo) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -278,12 +278,12 @@ func (m *Forwarding) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *Forwarding) MarshalTo(dAtA []byte) (int, error) { +func (m *ForwardingInfo) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *Forwarding) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *ForwardingInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -375,7 +375,7 @@ func (m *Params) Size() (n int) { return n } -func (m *Forwarding) Size() (n int) { +func (m *ForwardingInfo) Size() (n int) { if m == nil { return 0 } @@ -507,7 +507,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { } return nil } -func (m *Forwarding) Unmarshal(dAtA []byte) error { +func (m *ForwardingInfo) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -530,10 +530,10 @@ func (m *Forwarding) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Forwarding: wiretype end group for non-group") + return fmt.Errorf("proto: ForwardingInfo: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Forwarding: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ForwardingInfo: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/modules/apps/transfer/types/tx.pb.go b/modules/apps/transfer/types/tx.pb.go index 79c8d64f1ad..7550a142816 100644 --- a/modules/apps/transfer/types/tx.pb.go +++ b/modules/apps/transfer/types/tx.pb.go @@ -57,7 +57,7 @@ type MsgTransfer struct { // tokens to be transferred Tokens []types.Coin `protobuf:"bytes,9,rep,name=tokens,proto3" json:"tokens"` // optional forwarding information - ForwardingPath *Forwarding `protobuf:"bytes,10,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` + ForwardingPath *ForwardingInfo `protobuf:"bytes,10,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` } func (m *MsgTransfer) Reset() { *m = MsgTransfer{} } @@ -225,49 +225,50 @@ func init() { } var fileDescriptor_7401ed9bed2f8e09 = []byte{ - // 669 bytes of a gzipped FileDescriptorProto + // 673 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcf, 0x4f, 0x13, 0x4f, - 0x14, 0xef, 0x7e, 0x29, 0xfd, 0xc2, 0x54, 0x40, 0x46, 0x03, 0xcb, 0xc6, 0x6c, 0x9b, 0x46, 0x92, - 0x5a, 0xc2, 0x4c, 0x8a, 0x31, 0x18, 0xe2, 0xa9, 0x24, 0xc6, 0x83, 0x24, 0xb0, 0xc1, 0x8b, 0x17, - 0x32, 0xbb, 0x1d, 0x76, 0x27, 0x74, 0x67, 0xd6, 0x99, 0x69, 0xd5, 0x8b, 0x31, 0x9e, 0x8c, 0x07, - 0xe3, 0x9f, 0xe0, 0xd1, 0x23, 0x7f, 0x06, 0x47, 0x8e, 0x9e, 0x8c, 0x81, 0x03, 0x17, 0xff, 0x08, - 0xb3, 0xb3, 0xb3, 0xa5, 0x7a, 0xa8, 0x7a, 0x69, 0xe7, 0xbd, 0xf7, 0x79, 0x3f, 0x3e, 0x9f, 0x7d, - 0x79, 0x60, 0x9d, 0x85, 0x11, 0x26, 0x59, 0x36, 0x60, 0x11, 0xd1, 0x4c, 0x70, 0x85, 0xb5, 0x24, - 0x5c, 0x1d, 0x53, 0x89, 0x47, 0x5d, 0xac, 0x5f, 0xa1, 0x4c, 0x0a, 0x2d, 0xe0, 0x1d, 0x16, 0x46, - 0x68, 0x12, 0x86, 0x4a, 0x18, 0x1a, 0x75, 0xbd, 0x65, 0x92, 0x32, 0x2e, 0xb0, 0xf9, 0x2d, 0x12, - 0xbc, 0xdb, 0xb1, 0x88, 0x85, 0x79, 0xe2, 0xfc, 0x65, 0xbd, 0xab, 0x91, 0x50, 0xa9, 0x50, 0x38, - 0x55, 0x71, 0x5e, 0x3e, 0x55, 0xb1, 0x0d, 0xf8, 0x36, 0x10, 0x12, 0x45, 0xf1, 0xa8, 0x1b, 0x52, - 0x4d, 0xba, 0x38, 0x12, 0x8c, 0xdb, 0x78, 0x23, 0x1f, 0x33, 0x12, 0x92, 0xe2, 0x68, 0xc0, 0x28, - 0xd7, 0x79, 0x76, 0xf1, 0xb2, 0x80, 0x8d, 0xe9, 0x3c, 0xca, 0x61, 0x0d, 0xb8, 0xf5, 0xb1, 0x0a, - 0xea, 0x7b, 0x2a, 0x3e, 0xb4, 0x5e, 0xd8, 0x00, 0x75, 0x25, 0x86, 0x32, 0xa2, 0x47, 0x99, 0x90, - 0xda, 0x75, 0x9a, 0x4e, 0x7b, 0x3e, 0x00, 0x85, 0x6b, 0x5f, 0x48, 0x0d, 0xd7, 0xc1, 0xa2, 0x05, - 0x44, 0x09, 0xe1, 0x9c, 0x0e, 0xdc, 0xff, 0x0c, 0x66, 0xa1, 0xf0, 0xee, 0x16, 0x4e, 0xf8, 0x08, - 0xcc, 0x6a, 0x71, 0x42, 0xb9, 0x3b, 0xd3, 0x74, 0xda, 0xf5, 0xad, 0x35, 0x54, 0xb0, 0x42, 0x39, - 0x2b, 0x64, 0x59, 0xa1, 0x5d, 0xc1, 0x78, 0xaf, 0x7e, 0xf6, 0xad, 0x51, 0xf9, 0x72, 0x75, 0xda, - 0x71, 0x5c, 0x27, 0x28, 0x92, 0xe0, 0x0a, 0xa8, 0x29, 0xca, 0xfb, 0x54, 0xba, 0x55, 0x53, 0xdc, - 0x5a, 0xd0, 0x03, 0x73, 0x92, 0x46, 0x94, 0x8d, 0xa8, 0x74, 0x67, 0x4d, 0x64, 0x6c, 0xc3, 0xa7, - 0x60, 0x51, 0xb3, 0x94, 0x8a, 0xa1, 0x3e, 0x4a, 0x28, 0x8b, 0x13, 0xed, 0xd6, 0x4c, 0x6b, 0x0f, - 0xe5, 0x1f, 0x2c, 0x17, 0x0c, 0x59, 0x99, 0x46, 0x5d, 0xf4, 0xc4, 0x20, 0x7a, 0xf3, 0xe3, 0xde, - 0xc1, 0x82, 0x4d, 0x2e, 0x22, 0x70, 0x03, 0x2c, 0x97, 0xd5, 0xf2, 0x7f, 0xa5, 0x49, 0x9a, 0xb9, - 0xff, 0x37, 0x9d, 0x76, 0x35, 0xb8, 0x69, 0x03, 0x87, 0xa5, 0x1f, 0x42, 0x50, 0x4d, 0x69, 0x2a, - 0xdc, 0x39, 0x33, 0x92, 0x79, 0xc3, 0x6d, 0x50, 0x33, 0x5c, 0x94, 0x3b, 0xdf, 0x9c, 0x99, 0xae, - 0x40, 0x35, 0x9f, 0x22, 0xb0, 0x70, 0x78, 0x00, 0x96, 0x8e, 0x85, 0x7c, 0x49, 0x64, 0x9f, 0xf1, - 0xf8, 0x28, 0x23, 0x3a, 0x71, 0x81, 0x21, 0xd2, 0x46, 0xd3, 0x36, 0x0f, 0x3d, 0x1e, 0x27, 0x05, - 0x8b, 0xd7, 0x05, 0xf6, 0x89, 0x4e, 0x76, 0x3a, 0xef, 0x3f, 0x37, 0x2a, 0xef, 0xae, 0x4e, 0x3b, - 0x56, 0xc7, 0x0f, 0x57, 0xa7, 0x9d, 0x95, 0x62, 0x9c, 0x4d, 0xd5, 0x3f, 0xc1, 0x13, 0x0b, 0xd0, - 0xda, 0x06, 0xb7, 0x26, 0xcc, 0x80, 0xaa, 0x4c, 0x70, 0x45, 0x73, 0xe5, 0x15, 0x7d, 0x31, 0xa4, - 0x3c, 0xa2, 0x66, 0x29, 0xaa, 0xc1, 0xd8, 0xde, 0xa9, 0xe6, 0xe5, 0x5b, 0x6f, 0xc0, 0xd2, 0x9e, - 0x8a, 0x9f, 0x65, 0x7d, 0xa2, 0xe9, 0x3e, 0x91, 0x24, 0x55, 0xe6, 0x33, 0xb2, 0x98, 0x53, 0x69, - 0xf7, 0xc8, 0x5a, 0xb0, 0x07, 0x6a, 0x99, 0x41, 0x98, 0xdd, 0xa9, 0x6f, 0xdd, 0x9d, 0xce, 0xac, - 0xa8, 0x56, 0xca, 0x54, 0x64, 0xee, 0x2c, 0x5d, 0x73, 0x32, 0x45, 0x5b, 0x6b, 0x60, 0xf5, 0xb7, - 0xfe, 0xe5, 0xf0, 0x5b, 0x3f, 0x1c, 0x30, 0xb3, 0xa7, 0x62, 0x98, 0x80, 0xb9, 0xf1, 0xa2, 0xdf, - 0x9b, 0xde, 0x73, 0x42, 0x03, 0xaf, 0xfb, 0xd7, 0xd0, 0xb1, 0x5c, 0x1a, 0xdc, 0xf8, 0x45, 0x89, - 0xcd, 0x3f, 0x96, 0x98, 0x84, 0x7b, 0x0f, 0xfe, 0x09, 0x5e, 0x76, 0xf5, 0x66, 0xdf, 0xe6, 0xab, - 0xdc, 0x3b, 0x38, 0xbb, 0xf0, 0x9d, 0xf3, 0x0b, 0xdf, 0xf9, 0x7e, 0xe1, 0x3b, 0x9f, 0x2e, 0xfd, - 0xca, 0xf9, 0xa5, 0x5f, 0xf9, 0x7a, 0xe9, 0x57, 0x9e, 0x6f, 0xc7, 0x4c, 0x27, 0xc3, 0x10, 0x45, - 0x22, 0xc5, 0xf6, 0xcc, 0xb0, 0x30, 0xda, 0x8c, 0x05, 0x1e, 0x3d, 0xc4, 0xa9, 0xe8, 0x0f, 0x07, - 0x54, 0xe5, 0xa7, 0x63, 0xe2, 0x64, 0xe8, 0xd7, 0x19, 0x55, 0x61, 0xcd, 0x5c, 0x8b, 0xfb, 0x3f, - 0x03, 0x00, 0x00, 0xff, 0xff, 0x07, 0xeb, 0x25, 0x21, 0x24, 0x05, 0x00, 0x00, + 0x14, 0xef, 0x7e, 0x29, 0xfd, 0xc2, 0x54, 0x40, 0x46, 0x03, 0xcb, 0xc6, 0x6c, 0x9b, 0x46, 0x12, + 0x2c, 0x32, 0x93, 0x62, 0x0c, 0x86, 0x78, 0x2a, 0x89, 0xd1, 0x44, 0x12, 0xdc, 0xc0, 0xc5, 0x0b, + 0x99, 0xdd, 0x0e, 0xbb, 0x13, 0xba, 0x33, 0xeb, 0xcc, 0xb4, 0xea, 0xc5, 0x18, 0x4f, 0xc6, 0x93, + 0xf1, 0x2f, 0xf0, 0xe8, 0x91, 0x3f, 0x83, 0x23, 0x47, 0x4f, 0xc6, 0xc0, 0x81, 0x8b, 0x7f, 0x84, + 0xd9, 0xd9, 0xd9, 0x52, 0x3d, 0x54, 0xbd, 0xb4, 0xf3, 0xde, 0xfb, 0xbc, 0x1f, 0x9f, 0xcf, 0xbe, + 0x3c, 0xb0, 0xca, 0xc2, 0x08, 0x93, 0x2c, 0xeb, 0xb3, 0x88, 0x68, 0x26, 0xb8, 0xc2, 0x5a, 0x12, + 0xae, 0x8e, 0xa8, 0xc4, 0xc3, 0x0e, 0xd6, 0xaf, 0x50, 0x26, 0x85, 0x16, 0xf0, 0x16, 0x0b, 0x23, + 0x34, 0x0e, 0x43, 0x25, 0x0c, 0x0d, 0x3b, 0xde, 0x22, 0x49, 0x19, 0x17, 0xd8, 0xfc, 0x16, 0x09, + 0xde, 0xcd, 0x58, 0xc4, 0xc2, 0x3c, 0x71, 0xfe, 0xb2, 0xde, 0xe5, 0x48, 0xa8, 0x54, 0x28, 0x9c, + 0xaa, 0x38, 0x2f, 0x9f, 0xaa, 0xd8, 0x06, 0x7c, 0x1b, 0x08, 0x89, 0xa2, 0x78, 0xd8, 0x09, 0xa9, + 0x26, 0x1d, 0x1c, 0x09, 0xc6, 0x6d, 0xbc, 0x91, 0x8f, 0x19, 0x09, 0x49, 0x71, 0xd4, 0x67, 0x94, + 0xeb, 0x3c, 0xbb, 0x78, 0x59, 0xc0, 0xfa, 0x64, 0x1e, 0xe5, 0xb0, 0x06, 0xdc, 0xfa, 0x54, 0x05, + 0xf5, 0x5d, 0x15, 0xef, 0x5b, 0x2f, 0x6c, 0x80, 0xba, 0x12, 0x03, 0x19, 0xd1, 0xc3, 0x4c, 0x48, + 0xed, 0x3a, 0x4d, 0x67, 0x6d, 0x36, 0x00, 0x85, 0x6b, 0x4f, 0x48, 0x0d, 0x57, 0xc1, 0xbc, 0x05, + 0x44, 0x09, 0xe1, 0x9c, 0xf6, 0xdd, 0xff, 0x0c, 0x66, 0xae, 0xf0, 0xee, 0x14, 0x4e, 0xf8, 0x10, + 0x4c, 0x6b, 0x71, 0x4c, 0xb9, 0x3b, 0xd5, 0x74, 0xd6, 0xea, 0x9b, 0x2b, 0xa8, 0x60, 0x85, 0x72, + 0x56, 0xc8, 0xb2, 0x42, 0x3b, 0x82, 0xf1, 0x6e, 0xfd, 0xf4, 0x5b, 0xa3, 0xf2, 0xe5, 0xf2, 0xa4, + 0xed, 0xb8, 0x4e, 0x50, 0x24, 0xc1, 0x25, 0x50, 0x53, 0x94, 0xf7, 0xa8, 0x74, 0xab, 0xa6, 0xb8, + 0xb5, 0xa0, 0x07, 0x66, 0x24, 0x8d, 0x28, 0x1b, 0x52, 0xe9, 0x4e, 0x9b, 0xc8, 0xc8, 0x86, 0x4f, + 0xc1, 0xbc, 0x66, 0x29, 0x15, 0x03, 0x7d, 0x98, 0x50, 0x16, 0x27, 0xda, 0xad, 0x99, 0xd6, 0x1e, + 0xca, 0x3f, 0x58, 0x2e, 0x18, 0xb2, 0x32, 0x0d, 0x3b, 0xe8, 0xb1, 0x41, 0x74, 0x67, 0x47, 0xbd, + 0x83, 0x39, 0x9b, 0x5c, 0x44, 0xe0, 0x3a, 0x58, 0x2c, 0xab, 0xe5, 0xff, 0x4a, 0x93, 0x34, 0x73, + 0xff, 0x6f, 0x3a, 0x6b, 0xd5, 0xe0, 0xba, 0x0d, 0xec, 0x97, 0x7e, 0x08, 0x41, 0x35, 0xa5, 0xa9, + 0x70, 0x67, 0xcc, 0x48, 0xe6, 0x0d, 0xb7, 0x40, 0xcd, 0x70, 0x51, 0xee, 0x6c, 0x73, 0x6a, 0xb2, + 0x02, 0xd5, 0x7c, 0x8a, 0xc0, 0xc2, 0xe1, 0x01, 0x58, 0x38, 0x12, 0xf2, 0x25, 0x91, 0x3d, 0xc6, + 0xe3, 0xc3, 0x8c, 0xe8, 0xc4, 0x05, 0x86, 0xc8, 0x5d, 0x34, 0x69, 0xf3, 0xd0, 0xa3, 0x51, 0xd2, + 0x13, 0x7e, 0x24, 0x82, 0xf9, 0xab, 0x22, 0x7b, 0x44, 0x27, 0xdb, 0xed, 0xf7, 0x9f, 0x1b, 0x95, + 0x77, 0x97, 0x27, 0x6d, 0xab, 0xe5, 0x87, 0xcb, 0x93, 0xf6, 0x52, 0x31, 0xd2, 0x86, 0xea, 0x1d, + 0xe3, 0xb1, 0x25, 0x68, 0x6d, 0x81, 0x1b, 0x63, 0x66, 0x40, 0x55, 0x26, 0xb8, 0xa2, 0xb9, 0xfa, + 0x8a, 0xbe, 0x18, 0x50, 0x1e, 0x51, 0xb3, 0x18, 0xd5, 0x60, 0x64, 0x6f, 0x57, 0xf3, 0xf2, 0xad, + 0x37, 0x60, 0x61, 0x57, 0xc5, 0x07, 0x59, 0x8f, 0x68, 0xba, 0x47, 0x24, 0x49, 0x95, 0xf9, 0x94, + 0x2c, 0xe6, 0x54, 0xda, 0x5d, 0xb2, 0x16, 0xec, 0x82, 0x5a, 0x66, 0x10, 0x66, 0x7f, 0xea, 0x9b, + 0xb7, 0x27, 0xb3, 0x2b, 0xaa, 0x95, 0x52, 0x15, 0x99, 0xdb, 0x0b, 0x57, 0x9c, 0x4c, 0xd1, 0xd6, + 0x0a, 0x58, 0xfe, 0xad, 0x7f, 0x39, 0xfc, 0xe6, 0x0f, 0x07, 0x4c, 0xed, 0xaa, 0x18, 0x26, 0x60, + 0x66, 0xb4, 0xec, 0x77, 0x26, 0xf7, 0x1c, 0xd3, 0xc0, 0xeb, 0xfc, 0x35, 0x74, 0x24, 0x97, 0x06, + 0xd7, 0x7e, 0x51, 0x62, 0xe3, 0x8f, 0x25, 0xc6, 0xe1, 0xde, 0xfd, 0x7f, 0x82, 0x97, 0x5d, 0xbd, + 0xe9, 0xb7, 0xf9, 0x3a, 0x77, 0x9f, 0x9d, 0x9e, 0xfb, 0xce, 0xd9, 0xb9, 0xef, 0x7c, 0x3f, 0xf7, + 0x9d, 0x8f, 0x17, 0x7e, 0xe5, 0xec, 0xc2, 0xaf, 0x7c, 0xbd, 0xf0, 0x2b, 0xcf, 0xb7, 0x62, 0xa6, + 0x93, 0x41, 0x88, 0x22, 0x91, 0x62, 0x7b, 0x6a, 0x58, 0x18, 0x6d, 0xc4, 0x02, 0x0f, 0x1f, 0xe0, + 0x54, 0xf4, 0x06, 0x7d, 0xaa, 0xf2, 0xf3, 0x31, 0x76, 0x36, 0xf4, 0xeb, 0x8c, 0xaa, 0xb0, 0x66, + 0x2e, 0xc6, 0xbd, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xec, 0xa3, 0x95, 0xc7, 0x28, 0x05, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1027,7 +1028,7 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.ForwardingPath == nil { - m.ForwardingPath = &Forwarding{} + m.ForwardingPath = &ForwardingInfo{} } if err := m.ForwardingPath.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index 6f970848fc8..45dc9c0d2b5 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -17,10 +17,10 @@ message Params { bool receive_enabled = 2; } -// Forwarding defines a list of hops determining the path +// ForwardingInfo defines a list of port ID, channel ID pairs determining the path // through which a packet must be forwarded, and the memo string to be used in the // final destination of the tokens. -message Forwarding { +message ForwardingInfo { repeated Hop hops = 1; string memo = 2; } diff --git a/proto/ibc/applications/transfer/v1/tx.proto b/proto/ibc/applications/transfer/v1/tx.proto index abe573916c9..4caf0273b2c 100644 --- a/proto/ibc/applications/transfer/v1/tx.proto +++ b/proto/ibc/applications/transfer/v1/tx.proto @@ -52,7 +52,7 @@ message MsgTransfer { // tokens to be transferred repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false]; // optional forwarding information - Forwarding forwarding_path = 10; + ForwardingInfo forwarding_path = 10; } // MsgTransferResponse defines the Msg/Transfer response type. diff --git a/proto/ibc/applications/transfer/v2/packet.proto b/proto/ibc/applications/transfer/v2/packet.proto index 66fc7515448..702be8b2ffe 100644 --- a/proto/ibc/applications/transfer/v2/packet.proto +++ b/proto/ibc/applications/transfer/v2/packet.proto @@ -37,5 +37,5 @@ message FungibleTokenPacketDataV2 { // optional memo string memo = 4; // optional forwarding information - ibc.applications.transfer.v1.Forwarding forwarding_path = 5; + ibc.applications.transfer.v1.ForwardingInfo forwarding_path = 5; } From 413b7c16046104eeb75915596a3e125761c2ba87 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Wed, 12 Jun 2024 18:48:27 +0300 Subject: [PATCH 067/141] nit(transfer): Mark hops as non nullable. (#6566) * nit(transfer): Mark hops as non nullable. * lint: fix additional linting issues --- .../transfer/keeper/relay_forwarding_test.go | 10 ++-- modules/apps/transfer/types/packet_test.go | 4 +- modules/apps/transfer/types/transfer.pb.go | 50 ++++++++++--------- .../applications/transfer/v1/transfer.proto | 6 ++- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index bdb1aa2b0ae..880e9dbcf89 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -28,7 +28,7 @@ func (suite *KeeperTestSuite) TestPathForwarding() { sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount forwardingPath := types.ForwardingInfo{ - Hops: []*types.Hop{ + Hops: []types.Hop{ { PortId: path2.EndpointA.ChannelConfig.PortID, ChannelId: path2.EndpointA.ChannelID, @@ -90,7 +90,7 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount forwardingPath := types.ForwardingInfo{ - Hops: []*types.Hop{ + Hops: []types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, ChannelId: path2.EndpointB.ChannelID, @@ -173,7 +173,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount forwardingPath := types.ForwardingInfo{ - Hops: []*types.Hop{ + Hops: []types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, ChannelId: path2.EndpointB.ChannelID, @@ -281,7 +281,7 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount forwardingPath := types.ForwardingInfo{ - Hops: []*types.Hop{ + Hops: []types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, ChannelId: path2.EndpointB.ChannelID, @@ -478,7 +478,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account forwardingPath := types.ForwardingInfo{ - Hops: []*types.Hop{ + Hops: []types.Hop{ { PortId: path1.EndpointB.ChannelConfig.PortID, ChannelId: path1.EndpointB.ChannelID, diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 9997751b69e..19c1d12e81d 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -234,7 +234,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { receiver, "", &types.ForwardingInfo{ - Hops: []*types.Hop{ + Hops: []types.Hop{ { PortId: "transfer", ChannelId: "channel-1", @@ -400,7 +400,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { receiver, "memo", &types.ForwardingInfo{ - Hops: []*types.Hop{ + Hops: []types.Hop{ { PortId: "transfer", ChannelId: "channel-1", diff --git a/modules/apps/transfer/types/transfer.pb.go b/modules/apps/transfer/types/transfer.pb.go index 75ee2e183d4..70af1be23e4 100644 --- a/modules/apps/transfer/types/transfer.pb.go +++ b/modules/apps/transfer/types/transfer.pb.go @@ -5,6 +5,7 @@ package types import ( fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" math "math" @@ -86,7 +87,7 @@ func (m *Params) GetReceiveEnabled() bool { // through which a packet must be forwarded, and the memo string to be used in the // final destination of the tokens. type ForwardingInfo struct { - Hops []*Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops,omitempty"` + Hops []Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops"` Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` } @@ -123,7 +124,7 @@ func (m *ForwardingInfo) XXX_DiscardUnknown() { var xxx_messageInfo_ForwardingInfo proto.InternalMessageInfo -func (m *ForwardingInfo) GetHops() []*Hop { +func (m *ForwardingInfo) GetHops() []Hop { if m != nil { return m.Hops } @@ -202,27 +203,28 @@ func init() { } var fileDescriptor_5041673e96e97901 = []byte{ - // 308 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0x3f, 0x4f, 0x3a, 0x31, - 0x1c, 0xc6, 0xb9, 0x1f, 0x84, 0x9f, 0x14, 0x83, 0x49, 0x17, 0x19, 0xf4, 0x02, 0x2c, 0x92, 0x18, - 0xaf, 0x41, 0x63, 0x74, 0x71, 0x31, 0xd1, 0xc0, 0xa6, 0x17, 0x27, 0x1d, 0x48, 0xff, 0x01, 0x4d, - 0xae, 0xfd, 0x36, 0x6d, 0x39, 0xe3, 0xbb, 0xf0, 0x65, 0x39, 0x32, 0x3a, 0x1a, 0x78, 0x23, 0xe6, - 0x0e, 0x72, 0x61, 0x72, 0x7b, 0xfa, 0xe9, 0xa7, 0xe9, 0x93, 0x07, 0x9d, 0x2b, 0xc6, 0x09, 0xb5, - 0x36, 0x53, 0x9c, 0x06, 0x05, 0xc6, 0x93, 0xe0, 0xa8, 0xf1, 0x33, 0xe9, 0x48, 0x3e, 0xaa, 0x72, - 0x62, 0x1d, 0x04, 0xc0, 0x27, 0x8a, 0xf1, 0x64, 0x5f, 0x4e, 0x2a, 0x21, 0x1f, 0x0d, 0x5e, 0x50, - 0xf3, 0x89, 0x3a, 0xaa, 0x3d, 0xee, 0xa3, 0x43, 0x2f, 0x8d, 0x98, 0x4a, 0x43, 0x59, 0x26, 0x45, - 0x37, 0xea, 0x45, 0xc3, 0x83, 0xb4, 0x5d, 0xb0, 0x87, 0x2d, 0xc2, 0x67, 0xe8, 0xc8, 0x49, 0x2e, - 0x55, 0x2e, 0x2b, 0xeb, 0x5f, 0x69, 0x75, 0x76, 0x78, 0x27, 0x0e, 0xde, 0x50, 0xe7, 0x11, 0xdc, - 0x3b, 0x75, 0x42, 0x99, 0xf9, 0xc4, 0xcc, 0x00, 0x5f, 0xa3, 0xc6, 0x02, 0xac, 0xef, 0x46, 0xbd, - 0xfa, 0xb0, 0x7d, 0xd9, 0x4f, 0xfe, 0x2a, 0x95, 0x8c, 0xc1, 0xa6, 0xa5, 0x8e, 0x31, 0x6a, 0x68, - 0xa9, 0xa1, 0xfc, 0xa6, 0x95, 0x96, 0x79, 0x70, 0x87, 0xea, 0x63, 0xb0, 0xf8, 0x18, 0xfd, 0xb7, - 0xe0, 0xc2, 0x54, 0x6d, 0xab, 0xb6, 0xd2, 0x66, 0x71, 0x9c, 0x08, 0x7c, 0x8a, 0x10, 0x5f, 0x50, - 0x63, 0x64, 0x56, 0xdc, 0x6d, 0x5f, 0xb6, 0x76, 0x64, 0x22, 0xee, 0x9f, 0xbf, 0xd6, 0x71, 0xb4, - 0x5a, 0xc7, 0xd1, 0xcf, 0x3a, 0x8e, 0x3e, 0x37, 0x71, 0x6d, 0xb5, 0x89, 0x6b, 0xdf, 0x9b, 0xb8, - 0xf6, 0x7a, 0x33, 0x57, 0x61, 0xb1, 0x64, 0x09, 0x07, 0x4d, 0x38, 0x78, 0x0d, 0x9e, 0x28, 0xc6, - 0x2f, 0xe6, 0x40, 0xf2, 0x5b, 0xa2, 0x41, 0x2c, 0x33, 0xe9, 0x8b, 0xd9, 0xf7, 0xe6, 0x0e, 0x1f, - 0x56, 0x7a, 0xd6, 0x2c, 0x97, 0xbe, 0xfa, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x05, 0xad, 0xe6, 0x9f, - 0x98, 0x01, 0x00, 0x00, + // 325 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0x4b, 0xc3, 0x30, + 0x18, 0x86, 0x5b, 0x37, 0xa6, 0xcb, 0x64, 0x42, 0x10, 0x1c, 0xa2, 0x75, 0xdb, 0xc5, 0x81, 0xd8, + 0x30, 0x3d, 0x28, 0x88, 0x97, 0x81, 0xb2, 0xdd, 0xb4, 0x78, 0xf2, 0x32, 0xd2, 0x34, 0xeb, 0x02, + 0x6d, 0xbe, 0x90, 0x74, 0x15, 0xff, 0x85, 0x3f, 0x6b, 0xc7, 0x1d, 0x3d, 0x89, 0x6c, 0x7f, 0x44, + 0x9a, 0x8e, 0xb2, 0x93, 0xb7, 0x37, 0x4f, 0x9e, 0x97, 0x7c, 0xe4, 0x43, 0x57, 0x22, 0x64, 0x84, + 0x2a, 0x95, 0x08, 0x46, 0x33, 0x01, 0xd2, 0x90, 0x4c, 0x53, 0x69, 0x66, 0x5c, 0x93, 0x7c, 0x58, + 0x65, 0x5f, 0x69, 0xc8, 0x00, 0x9f, 0x89, 0x90, 0xf9, 0xbb, 0xb2, 0x5f, 0x09, 0xf9, 0xf0, 0xf4, + 0x38, 0x86, 0x18, 0xac, 0x48, 0x8a, 0x54, 0x76, 0xfa, 0x6f, 0xa8, 0xf1, 0x42, 0x35, 0x4d, 0x0d, + 0xee, 0xa1, 0x43, 0xc3, 0x65, 0x34, 0xe5, 0x92, 0x86, 0x09, 0x8f, 0x3a, 0x6e, 0xd7, 0x1d, 0x1c, + 0x04, 0xad, 0x82, 0x3d, 0x95, 0x08, 0x5f, 0xa2, 0x23, 0xcd, 0x19, 0x17, 0x39, 0xaf, 0xac, 0x3d, + 0x6b, 0xb5, 0xb7, 0x78, 0x2b, 0xf6, 0x29, 0x6a, 0x3f, 0x83, 0xfe, 0xa0, 0x3a, 0x12, 0x32, 0x9e, + 0xc8, 0x19, 0xe0, 0x07, 0x54, 0x9f, 0x83, 0x32, 0x1d, 0xb7, 0x5b, 0x1b, 0xb4, 0x6e, 0x7a, 0xfe, + 0x7f, 0xa3, 0xfa, 0x63, 0x50, 0xa3, 0xfa, 0xf2, 0xe7, 0xc2, 0x09, 0x6c, 0x09, 0x63, 0x54, 0x4f, + 0x79, 0x0a, 0xf6, 0xb1, 0x66, 0x60, 0x73, 0xff, 0x11, 0xd5, 0xc6, 0xa0, 0xf0, 0x09, 0xda, 0x57, + 0xa0, 0xb3, 0xa9, 0x28, 0x07, 0x6e, 0x06, 0x8d, 0xe2, 0x38, 0x89, 0xf0, 0x39, 0x42, 0x6c, 0x4e, + 0xa5, 0xe4, 0x49, 0x71, 0x57, 0x36, 0x9b, 0x5b, 0x32, 0x89, 0x46, 0xaf, 0xcb, 0xb5, 0xe7, 0xae, + 0xd6, 0x9e, 0xfb, 0xbb, 0xf6, 0xdc, 0xaf, 0x8d, 0xe7, 0xac, 0x36, 0x9e, 0xf3, 0xbd, 0xf1, 0x9c, + 0xf7, 0xbb, 0x58, 0x64, 0xf3, 0x45, 0xe8, 0x33, 0x48, 0x09, 0x03, 0x93, 0x82, 0x21, 0x22, 0x64, + 0xd7, 0x31, 0x90, 0xfc, 0x9e, 0xa4, 0x10, 0x2d, 0x12, 0x6e, 0x8a, 0x95, 0xec, 0xac, 0x22, 0xfb, + 0x54, 0xdc, 0x84, 0x0d, 0xfb, 0xa3, 0xb7, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x6b, 0x1c, 0xa2, + 0x4b, 0xb4, 0x01, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -565,7 +567,7 @@ func (m *ForwardingInfo) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Hops = append(m.Hops, &Hop{}) + m.Hops = append(m.Hops, Hop{}) if err := m.Hops[len(m.Hops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index 45dc9c0d2b5..2eac86c7f6c 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -2,6 +2,8 @@ syntax = "proto3"; package ibc.applications.transfer.v1; +import "gogoproto/gogo.proto"; + option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; // Params defines the set of IBC transfer parameters. @@ -21,7 +23,7 @@ message Params { // through which a packet must be forwarded, and the memo string to be used in the // final destination of the tokens. message ForwardingInfo { - repeated Hop hops = 1; + repeated Hop hops = 1 [(gogoproto.nullable) = false]; string memo = 2; } @@ -30,4 +32,4 @@ message ForwardingInfo { message Hop { string port_id = 1; string channel_id = 2; -} \ No newline at end of file +} From ae2046a71ddaa853c77f9f0175cfbf8e8a89409f Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Wed, 12 Jun 2024 18:21:05 +0200 Subject: [PATCH 068/141] feat(transfer): add forwarding info validation to token packet (#6571) * feat(transfer): add forwarding info validation to token packet * Added NewForwardingInfo constructor * Removed redundant check * Clean up tests per cr comments * Back to Validate and use NewDenom --- modules/apps/transfer/types/errors.go | 1 + .../apps/transfer/types/forwarding_info.go | 39 +++++ .../transfer/types/forwarding_info_test.go | 151 ++++++++++++++++++ modules/apps/transfer/types/packet.go | 12 +- modules/apps/transfer/types/packet_test.go | 115 ++++++++++--- 5 files changed, 293 insertions(+), 25 deletions(-) create mode 100644 modules/apps/transfer/types/forwarding_info.go create mode 100644 modules/apps/transfer/types/forwarding_info_test.go diff --git a/modules/apps/transfer/types/errors.go b/modules/apps/transfer/types/errors.go index 2a7d90c0fbe..13f87f17a77 100644 --- a/modules/apps/transfer/types/errors.go +++ b/modules/apps/transfer/types/errors.go @@ -16,4 +16,5 @@ var ( ErrMaxTransferChannels = errorsmod.Register(ModuleName, 9, "max transfer channels") ErrInvalidAuthorization = errorsmod.Register(ModuleName, 10, "invalid transfer authorization") ErrInvalidMemo = errorsmod.Register(ModuleName, 11, "invalid memo") + ErrInvalidForwardingInfo = errorsmod.Register(ModuleName, 12, "invalid forwarding info") ) diff --git a/modules/apps/transfer/types/forwarding_info.go b/modules/apps/transfer/types/forwarding_info.go new file mode 100644 index 00000000000..167ca89bff0 --- /dev/null +++ b/modules/apps/transfer/types/forwarding_info.go @@ -0,0 +1,39 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" +) + +const MaximumNumberOfForwardingHops = 64 + +// NewForwardingInfo creates a new ForwardingInfo instance given a memo and a variable number of hops. +func NewForwardingInfo(memo string, hops ...Hop) *ForwardingInfo { + return &ForwardingInfo{ + Memo: memo, + Hops: hops, + } +} + +// Validate performs a basic validation of the ForwardingInfo fields. +func (fi ForwardingInfo) Validate() error { + if len(fi.Hops) > MaximumNumberOfForwardingHops { + return errorsmod.Wrapf(ErrInvalidForwardingInfo, "number of hops in forwarding path cannot exceed %d", MaximumNumberOfForwardingHops) + } + + for _, hop := range fi.Hops { + if err := host.PortIdentifierValidator(hop.PortId); err != nil { + return errorsmod.Wrapf(err, "invalid source port ID %s", hop.PortId) + } + if err := host.ChannelIdentifierValidator(hop.ChannelId); err != nil { + return errorsmod.Wrapf(err, "invalid source channel ID %s", hop.ChannelId) + } + } + + if len(fi.Memo) > MaximumMemoLength { + return errorsmod.Wrapf(ErrInvalidMemo, "memo length cannot exceed %d", MaximumMemoLength) + } + + return nil +} diff --git a/modules/apps/transfer/types/forwarding_info_test.go b/modules/apps/transfer/types/forwarding_info_test.go new file mode 100644 index 00000000000..7be1fadeeaa --- /dev/null +++ b/modules/apps/transfer/types/forwarding_info_test.go @@ -0,0 +1,151 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +var validHop = types.Hop{ + PortId: types.PortID, + ChannelId: ibctesting.FirstChannelID, +} + +func TestForwardingInfo_Validate(t *testing.T) { + tests := []struct { + name string + forwardingInfo *types.ForwardingInfo + expError error + }{ + { + "valid forwarding info with no hops", + types.NewForwardingInfo(""), + nil, + }, + { + "valid forwarding info with hops", + types.NewForwardingInfo("", validHop), + nil, + }, + { + "valid forwarding info with memo", + types.NewForwardingInfo(testMemo1, validHop, validHop), + nil, + }, + { + "valid forwarding info with max hops", + types.NewForwardingInfo("", generateHops(types.MaximumNumberOfForwardingHops)...), + nil, + }, + { + "valid forwarding info with max memo length", + types.NewForwardingInfo(ibctesting.GenerateString(types.MaximumMemoLength), validHop), + nil, + }, + { + "invalid forwarding info with too many hops", + types.NewForwardingInfo("", generateHops(types.MaximumNumberOfForwardingHops+1)...), + types.ErrInvalidForwardingInfo, + }, + { + "invalid forwarding info with too long memo", + types.NewForwardingInfo(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), + types.ErrInvalidMemo, + }, + { + "invalid forwarding info with too short hop port ID", + types.NewForwardingInfo( + "", + types.Hop{ + PortId: invalidShortPort, + ChannelId: ibctesting.FirstChannelID, + }, + ), + host.ErrInvalidID, + }, + { + "invalid forwarding info with too long hop port ID", + types.NewForwardingInfo( + "", + types.Hop{ + PortId: invalidLongPort, + ChannelId: ibctesting.FirstChannelID, + }, + ), + host.ErrInvalidID, + }, + { + "invalid forwarding info with non-alpha hop port ID", + types.NewForwardingInfo( + "", + types.Hop{ + PortId: invalidPort, + ChannelId: ibctesting.FirstChannelID, + }, + ), + host.ErrInvalidID, + }, + { + "invalid forwarding info with too long hop channel ID", + types.NewForwardingInfo( + "", + types.Hop{ + PortId: types.PortID, + ChannelId: invalidLongChannel, + }, + ), + host.ErrInvalidID, + }, + { + "invalid forwarding info with too short hop channel ID", + types.NewForwardingInfo( + "", + types.Hop{ + PortId: types.PortID, + ChannelId: invalidShortChannel, + }, + ), + host.ErrInvalidID, + }, + { + "invalid forwarding info with non-alpha hop channel ID", + types.NewForwardingInfo( + "", + types.Hop{ + PortId: types.PortID, + ChannelId: invalidChannel, + }, + ), + host.ErrInvalidID, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tc := tc + + err := tc.forwardingInfo.Validate() + + expPass := tc.expError == nil + if expPass { + require.NoError(t, err) + } else { + require.ErrorIs(t, err, tc.expError) + } + }) + } +} + +func generateHops(n int) []types.Hop { + hops := make([]types.Hop, n) + for i := 0; i < n; i++ { + hops[i] = types.Hop{ + PortId: types.PortID, + ChannelId: ibctesting.FirstChannelID, + } + } + return hops +} diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index fcdb431695e..e4f5179bd78 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -140,9 +140,15 @@ func (ftpd FungibleTokenPacketDataV2) ValidateBasic() error { return errorsmod.Wrapf(ErrInvalidMemo, "memo must not exceed %d bytes", MaximumMemoLength) } - // We cannot have non-empty memo and non-empty forwarding path hops at the same time. - if ftpd.ForwardingPath != nil && len(ftpd.ForwardingPath.Hops) > 0 && ftpd.Memo != "" { - return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", ftpd.Memo, ftpd.ForwardingPath.Hops) + if ftpd.ForwardingPath != nil { + if err := ftpd.ForwardingPath.Validate(); err != nil { + return err + } + + // We cannot have non-empty memo and non-empty forwarding path hops at the same time. + if len(ftpd.ForwardingPath.Hops) > 0 && ftpd.Memo != "" { + return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", ftpd.Memo, ftpd.ForwardingPath.Hops) + } } return nil diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 19c1d12e81d..509435f5323 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -223,25 +224,30 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { types.NewFungibleTokenPacketDataV2( []types.Token{ { - Denom: types.Denom{ - Base: denom, - Trace: []types.Trace{types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")}, - }, + Denom: types.NewDenom(denom, types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")), Amount: amount, }, }, sender, receiver, "", - &types.ForwardingInfo{ - Hops: []types.Hop{ - { - PortId: "transfer", - ChannelId: "channel-1", - }, + types.NewForwardingInfo("", validHop, validHop), + ), + nil, + }, + { + "success: valid packet with forwarding path hops with memo", + types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: types.NewDenom(denom, types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")), + Amount: amount, }, - Memo: "", }, + sender, + receiver, + "", + types.NewForwardingInfo("memo", validHop), ), nil, }, @@ -389,25 +395,90 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { types.NewFungibleTokenPacketDataV2( []types.Token{ { - Denom: types.Denom{ - Base: denom, - Trace: []types.Trace{types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")}, - }, + Denom: types.NewDenom(denom, types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")), Amount: amount, }, }, sender, receiver, "memo", - &types.ForwardingInfo{ - Hops: []types.Hop{ - { - PortId: "transfer", - ChannelId: "channel-1", - }, + types.NewForwardingInfo("", validHop), + ), + types.ErrInvalidMemo, + }, + { + "failure: invalid forwarding path port ID", + types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: types.NewDenom(denom, types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")), + Amount: amount, }, - Memo: "", }, + sender, + receiver, + "", + types.NewForwardingInfo( + "", + types.Hop{ + PortId: invalidPort, + ChannelId: "channel-1", + }, + ), + ), + host.ErrInvalidID, + }, + { + "failure: invalid forwarding path channel ID", + types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: types.NewDenom(denom, types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")), + Amount: amount, + }, + }, + sender, + receiver, + "", + types.NewForwardingInfo( + "", + types.Hop{ + PortId: "transfer", + ChannelId: invalidChannel, + }, + ), + ), + host.ErrInvalidID, + }, + { + "failure: invalid forwarding path too many hops", + types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: types.NewDenom(denom, types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")), + Amount: amount, + }, + }, + sender, + receiver, + "", + types.NewForwardingInfo("", generateHops(types.MaximumNumberOfForwardingHops+1)...), + ), + types.ErrInvalidForwardingInfo, + }, + { + "failure: invalid forwarding path too long memo", + types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: types.NewDenom(denom, types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")), + Amount: amount, + }, + }, + sender, + receiver, + "", + types.NewForwardingInfo(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), ), types.ErrInvalidMemo, }, From ba7c4a87a8b3efd8ae30193e13c4586139d1eaf9 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Thu, 13 Jun 2024 09:51:34 +0200 Subject: [PATCH 069/141] feat(transfer): add validation for forwarding info in msg transfer validate basic (#6583) --- modules/apps/transfer/types/msgs.go | 11 ++++ modules/apps/transfer/types/msgs_test.go | 77 +++++++++++++----------- 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 3c10f3b5779..a50a6e5719a 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -102,6 +102,17 @@ func (msg MsgTransfer) ValidateBasic() error { return errorsmod.Wrapf(ErrInvalidMemo, "memo must not exceed %d bytes", MaximumMemoLength) } + if msg.ForwardingPath != nil { + if err := msg.ForwardingPath.Validate(); err != nil { + return err + } + + // We cannot have non-empty memo and non-empty forwarding path hops at the same time. + if len(msg.ForwardingPath.Hops) > 0 && msg.Memo != "" { + return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", msg.Memo, msg.ForwardingPath.Hops) + } + } + for _, coin := range msg.GetCoins() { if err := validateIBCCoin(coin); err != nil { return errorsmod.Wrapf(ibcerrors.ErrInvalidCoins, "%s: %s", err.Error(), coin.String()) diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index 2f153eacca0..447fd619a36 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -79,19 +79,24 @@ func TestMsgTransferValidation(t *testing.T) { {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, {"multidenom: too many coins", types.NewMsgTransfer(validPort, validChannel, make([]sdk.Coin, types.MaximumTokensLength+1), sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, {"multidenom: both token and tokens are set", &types.MsgTransfer{validPort, validChannel, coin, sender, receiver, timeoutHeight, 0, "", coins, nil}, ibcerrors.ErrInvalidCoins}, + {"memo must be empty if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "memo", types.NewForwardingInfo("", validHop)), types.ErrInvalidMemo}, + {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwardingInfo("", types.Hop{PortId: invalidPort, ChannelId: validChannel})), host.ErrInvalidID}, + {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwardingInfo("", types.Hop{PortId: validPort, ChannelId: invalidChannel})), host.ErrInvalidID}, + {"invalid forwarding info too many hops", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwardingInfo("", generateHops(types.MaximumNumberOfForwardingHops+1)...)), types.ErrInvalidForwardingInfo}, + {"invalid forwarding info too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwardingInfo(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop)), types.ErrInvalidMemo}, } for _, tc := range testCases { - tc := tc - - err := tc.msg.ValidateBasic() - - expPass := tc.expError == nil - if expPass { - require.NoError(t, err) - } else { - require.ErrorIs(t, err, tc.expError) - } + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + + expPass := tc.expError == nil + if expPass { + require.NoError(t, err) + } else { + require.ErrorIs(t, err, tc.expError) + } + }) } } @@ -119,16 +124,16 @@ func TestMsgUpdateParamsValidateBasic(t *testing.T) { } for _, tc := range testCases { - tc := tc - - err := tc.msg.ValidateBasic() - - expPass := tc.expError == nil - if expPass { - require.NoError(t, err) - } else { - require.ErrorIs(t, err, tc.expError) - } + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + + expPass := tc.expError == nil + if expPass { + require.NoError(t, err) + } else { + require.ErrorIs(t, err, tc.expError) + } + }) } } @@ -144,21 +149,21 @@ func TestMsgUpdateParamsGetSigners(t *testing.T) { } for _, tc := range testCases { - tc := tc - - msg := types.MsgUpdateParams{ - Signer: tc.address.String(), - Params: types.DefaultParams(), - } - - encodingCfg := moduletestutil.MakeTestEncodingConfig(transfer.AppModuleBasic{}) - signers, _, err := encodingCfg.Codec.GetMsgV1Signers(&msg) - - if tc.expPass { - require.NoError(t, err) - require.Equal(t, tc.address.Bytes(), signers[0]) - } else { - require.Error(t, err) - } + t.Run(tc.name, func(t *testing.T) { + msg := types.MsgUpdateParams{ + Signer: tc.address.String(), + Params: types.DefaultParams(), + } + + encodingCfg := moduletestutil.MakeTestEncodingConfig(transfer.AppModuleBasic{}) + signers, _, err := encodingCfg.Codec.GetMsgV1Signers(&msg) + + if tc.expPass { + require.NoError(t, err) + require.Equal(t, tc.address.Bytes(), signers[0]) + } else { + require.Error(t, err) + } + }) } } From 6b3b5aa38f420d14e64fe14d80657210be73e927 Mon Sep 17 00:00:00 2001 From: srdtrk <59252793+srdtrk@users.noreply.github.com> Date: Thu, 13 Jun 2024 02:52:45 -0700 Subject: [PATCH 070/141] Fix and simplify reverts of forwarding state (#6574) * refactor: initial simplification attempt * refactor: further organize * fix: all tests fixed * docs: improved godocs * fix: logic and testing error * style: self suggestion * docs: suggestion * docs: spellcheck * style: suggestions * style: renamed to revertForwardedPacket * style: suggestion * docs: remove docs * docs: godoc suggestion * style: suggestion * docs: colin suggestions --- modules/apps/transfer/keeper/forwarding.go | 99 ++++++++++++ modules/apps/transfer/keeper/relay.go | 148 +++++------------- .../transfer/keeper/relay_forwarding_test.go | 24 +-- 3 files changed, 148 insertions(+), 123 deletions(-) create mode 100644 modules/apps/transfer/keeper/forwarding.go diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go new file mode 100644 index 00000000000..52e31e6d606 --- /dev/null +++ b/modules/apps/transfer/keeper/forwarding.go @@ -0,0 +1,99 @@ +package keeper + +import ( + "errors" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + 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" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" +) + +// ackForwardPacketError reverts the receive packet logic that occurs in the middle chain and writes the async ack for the prevPacket +func (k Keeper) ackForwardPacketError(ctx sdk.Context, prevPacket channeltypes.Packet, failedPacketData types.FungibleTokenPacketDataV2) error { + // the forwarded packet has failed, thus the funds have been refunded to the intermediate address. + // we must revert the changes that came from successfully receiving the tokens on our chain + // before propagating the error acknowledgement back to original sender chain + if err := k.revertForwardedPacket(ctx, prevPacket, failedPacketData); err != nil { + return err + } + + forwardAck := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet failed")) + return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) +} + +// ackForwardPacketSuccess writes a successful async acknowledgement for the prevPacket +func (k Keeper) ackForwardPacketSuccess(ctx sdk.Context, prevPacket channeltypes.Packet) error { + forwardAck := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) + return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) +} + +// ackForwardPacketTimeout reverts the receive packet logic that occurs in the middle chain and writes a failed async ack for the prevPacket +func (k Keeper) ackForwardPacketTimeout(ctx sdk.Context, prevPacket channeltypes.Packet, timeoutPacketData types.FungibleTokenPacketDataV2) error { + if err := k.revertForwardedPacket(ctx, prevPacket, timeoutPacketData); err != nil { + return err + } + + // the timeout is converted into an error acknowledgement in order to propagate the failed packet forwarding + // back to the original sender + forwardAck := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet timed out")) + return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) +} + +// acknowledgeForwardedPacket writes the async acknowledgement for packet +func (k Keeper) acknowledgeForwardedPacket(ctx sdk.Context, packet channeltypes.Packet, ack channeltypes.Acknowledgement) error { + capability, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.DestinationPort, packet.DestinationChannel)) + if !ok { + return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + + return k.ics4Wrapper.WriteAcknowledgement(ctx, capability, packet, ack) +} + +// revertForwardedPacket reverts the logic of receive packet that occurs in the middle chains during a packet forwarding. +// If the packet fails to be forwarded all the way to the final destination, the state changes on this chain must be reverted +// before sending back the error acknowledgement to ensure atomic packet forwarding. +func (k Keeper) revertForwardedPacket(ctx sdk.Context, prevPacket channeltypes.Packet, failedPacketData types.FungibleTokenPacketDataV2) error { + /* + Recall that RecvPacket handles an incoming packet depending on the denom of the received funds: + 1. If the funds are native, then the amount is sent to the receiver from the escrow. + 2. If the funds are foreign, then a voucher token is minted. + We revert it in this function by: + 1. Sending funds back to escrow if the funds are native. + 2. Burning voucher tokens if the funds are foreign + */ + + forwardingAddr := types.GetForwardAddress(prevPacket.DestinationPort, prevPacket.DestinationChannel) + escrow := types.GetEscrowAddress(prevPacket.DestinationPort, prevPacket.DestinationChannel) + + // we can iterate over the received tokens of prevPacket by iterating over the sent tokens of failedPacketData + for _, token := range failedPacketData.Tokens { + // parse the transfer amount + transferAmount, ok := sdkmath.NewIntFromString(token.Amount) + if !ok { + return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", transferAmount) + } + coin := sdk.NewCoin(token.Denom.IBCDenom(), transferAmount) + + // check if the token we received originated on the sender + // given that the packet is being reversed, we check the DestinationChannel and DestinationPort + // of the prevPacket to see if a hop was added to the trace during the receive step + if token.Denom.SenderChainIsSource(prevPacket.DestinationPort, prevPacket.DestinationChannel) { + // then send it back to the escrow address + if err := k.escrowCoin(ctx, forwardingAddr, escrow, coin); err != nil { + return err + } + + continue + } + + if err := k.burnCoin(ctx, forwardingAddr, coin); err != nil { + return err + } + } + return nil +} diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index c4957aae5e3..1b458408143 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -1,7 +1,6 @@ package keeper import ( - "errors" "fmt" "strings" @@ -320,44 +319,29 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t // acknowledgement was a success then nothing occurs. If the acknowledgement failed, // then the sender is refunded their tokens using the refundPacketToken function. func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) error { - prevPacket, found := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) - if found { - channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) - if !ok { - return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") - } + prevPacket, isForwarded := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) - switch ack.Response.(type) { - case *channeltypes.Acknowledgement_Result: - // the acknowledgement succeeded on the receiving chain so - // we write the asynchronous acknowledgement for the sender - // of the previous packet. - fungibleTokenPacketAcknowledgement := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) - return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, fungibleTokenPacketAcknowledgement) - case *channeltypes.Acknowledgement_Error: - // the forwarded packet has failed, thus the funds have been refunded to the forwarding address. - // we must revert the changes that came from successfully receiving the tokens on our chain - // before propogating the error acknowledgement back to original sender chain - if err := k.revertInFlightChanges(ctx, packet, prevPacket, data); err != nil { - return err - } + switch ack.Response.(type) { + case *channeltypes.Acknowledgement_Result: + if isForwarded { + return k.ackForwardPacketSuccess(ctx, prevPacket) + } - fungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet failed")) - return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, fungibleTokenPacketAcknowledgement) - default: - return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected one of [%T, %T], got %T", channeltypes.Acknowledgement_Result{}, channeltypes.Acknowledgement_Error{}, ack.Response) + // the acknowledgement succeeded on the receiving chain so nothing + // needs to be executed and no error needs to be returned + return nil + case *channeltypes.Acknowledgement_Error: + // We refund the tokens from the escrow address to the sender + if err := k.refundPacketTokens(ctx, packet, data); err != nil { + return err } - } else { - switch ack.Response.(type) { - case *channeltypes.Acknowledgement_Result: - // the acknowledgement succeeded on the receiving chain so nothing - // needs to be executed and no error needs to be returned - return nil - case *channeltypes.Acknowledgement_Error: - return k.refundPacketTokens(ctx, packet, data) - default: - return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected one of [%T, %T], got %T", channeltypes.Acknowledgement_Result{}, channeltypes.Acknowledgement_Error{}, ack.Response) + if isForwarded { + return k.ackForwardPacketError(ctx, prevPacket, data) } + + return nil + default: + return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected one of [%T, %T], got %T", channeltypes.Acknowledgement_Result{}, channeltypes.Acknowledgement_Error{}, ack.Response) } } @@ -365,22 +349,16 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac // packet if the chain acted as a middle hop on a multihop transfer; or refunds // the sender if the original packet sent was never received and has been timed out. func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) error { - prevPacket, found := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) - if found { - channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.SourcePort, packet.SourceChannel)) - if !ok { - return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") - } - - if err := k.revertInFlightChanges(ctx, packet, prevPacket, data); err != nil { - return err - } + if err := k.refundPacketTokens(ctx, packet, data); err != nil { + return err + } - fungibleTokenPacketAcknowledgement := channeltypes.NewErrorAcknowledgement(fmt.Errorf("forwarded packet timed out")) - return k.ics4Wrapper.WriteAcknowledgement(ctx, channelCap, prevPacket, fungibleTokenPacketAcknowledgement) + prevPacket, isForwarded := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) + if isForwarded { + return k.ackForwardPacketTimeout(ctx, prevPacket, data) } - return k.refundPacketTokens(ctx, packet, data) + return nil } // refundPacketTokens will unescrow and send back the tokens back to sender @@ -429,63 +407,6 @@ func (k Keeper) refundPacketTokens(ctx sdk.Context, packet channeltypes.Packet, return nil } -// revertInFlightChanges reverts the logic of receive packet and send packet -// that occurs in the middle chains during a packet forwarding. If an error -// occurs further down the line, the state changes on this chain must be -// reverted before sending back the error acknowledgement to ensure atomic packet forwarding. -func (k Keeper) revertInFlightChanges(ctx sdk.Context, sentPacket channeltypes.Packet, receivedPacket channeltypes.Packet, sentPacketData types.FungibleTokenPacketDataV2) error { - forwardEscrow := types.GetEscrowAddress(sentPacket.SourcePort, sentPacket.SourceChannel) - reverseEscrow := types.GetEscrowAddress(receivedPacket.DestinationPort, receivedPacket.DestinationChannel) - - // the token on our chain is the token in the sentPacket - for _, token := range sentPacketData.Tokens { - // parse the transfer amount - transferAmount, ok := sdkmath.NewIntFromString(token.Amount) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", transferAmount) - } - coin := sdk.NewCoin(token.Denom.IBCDenom(), transferAmount) - - // check if the packet we sent out was sending as source or not - // if it is source, then we escrowed the outgoing tokens - if token.Denom.SenderChainIsSource(sentPacket.SourcePort, sentPacket.SourceChannel) { - // check if the packet we received was a source token for our chain - // check if here should be ReceiverChainIsSource - if token.Denom.SenderChainIsSource(receivedPacket.DestinationPort, receivedPacket.DestinationChannel) { - // receive sent tokens from the received escrow to the forward escrow account - // so we must send the tokens back from the forward escrow to the original received escrow account - return k.unescrowCoin(ctx, forwardEscrow, reverseEscrow, coin) - } - - // receive minted vouchers and sent to the forward escrow account - // so we must remove the vouchers from the forward escrow account and burn them - if err := k.bankKeeper.BurnCoins( - ctx, types.ModuleName, sdk.NewCoins(coin), - ); err != nil { - return err - } - } else { //nolint:gocritic - // in this case we burned the vouchers of the outgoing packets - // check if the packet we received was a source token for our chain - // in this case, the tokens were unescrowed from the reverse escrow account - if token.Denom.SenderChainIsSource(receivedPacket.DestinationPort, receivedPacket.DestinationChannel) { - // in this case we must mint the burned vouchers and send them back to the escrow account - if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(coin)); err != nil { - return err - } - - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, reverseEscrow, sdk.NewCoins(coin)); err != nil { - panic(fmt.Errorf("unable to send coins from module to account despite previously minting coins to module account: %v", err)) - } - } - - // if it wasn't a source token on receive, then we simply had minted vouchers and burned them in the receive. - // So no state changes were made, and thus no reversion is necessary - } - } - return nil -} - // escrowCoin will send the given coin from the provided sender to the escrow address. It will also // update the total escrowed amount by adding the escrowed coin's amount to the current total escrow. func (k Keeper) escrowCoin(ctx sdk.Context, sender, escrowAddress sdk.AccAddress, coin sdk.Coin) error { @@ -572,3 +493,20 @@ func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, return packetDataBytes } + +// burnCoin sends coins from the account to the transfer module account and then burn them. +// We do this because bankKeeper.BurnCoins only works with a module account in SDK v0.50, +// the next version of the SDK will allow burning coins from any account. +// TODO: remove this function once we switch forwarding address to a module account (#6561) +func (k Keeper) burnCoin(ctx sdk.Context, account sdk.AccAddress, coin sdk.Coin) error { + coins := sdk.NewCoins(coin) + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, account, types.ModuleName, coins); err != nil { + return err + } + + if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins); err != nil { + return err + } + + return nil +} diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 880e9dbcf89..4647e87b554 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal" "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" @@ -349,9 +350,6 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { } // This test replicates the Acknowledgement Failure Scenario 5 -// Currently seems like the middle hop is not reverting state changes when an error occurs. -// In turn the final hop properly reverts changes. There may be an error in the way async ack are managed -// or in the way i'm trying to activate the OnAck function. func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { amount := sdkmath.NewInt(100) /* @@ -472,7 +470,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { // Now we want to trigger C -> B -> A // The coin we want to send out is exactly the one we received on C - // coin = sdk.NewCoin(denomTraceBC.IBCDenom(), amount) + coin = sdk.NewCoin(denomABC.IBCDenom(), amount) sender = suite.chainC.SenderAccounts[0].SenderAccount receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account @@ -554,33 +552,23 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { // NOW WE HAVE TO SEND ACK TO B, PROPAGTE ACK TO C, CHECK FINAL RESULTS // Reconstruct packet data - denom := types.ExtractDenomFromPath(denomAB.Path()) - data := types.NewFungibleTokenPacketDataV2( - []types.Token{ - { - Denom: denom, - Amount: amount.String(), - }, - }, types.GetForwardAddress(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID).String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) - packetRecv := channeltypes.NewPacket(data.GetBytes(), 3, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) + data, err := internal.UnmarshalPacketData(packet.Data, types.V2) + suite.Require().NoError(err) err = path1.EndpointB.UpdateClient() suite.Require().NoError(err) ack := channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed packet transfer")) // err = path1.EndpointA.AcknowledgePacket(packetRecv, ack.Acknowledgement()) - err = suite.chainB.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainB.GetContext(), packetRecv, data, ack) + err = suite.chainB.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainB.GetContext(), packet, data, ack) suite.Require().NoError(err) // Check that Escrow B has been refunded amount - // NOTE This is failing. The revertInFlightsChanges sohuld mint back voucher to chainBescrow - // but this is not happening. It may be a problem related with how we're writing async acks. - // coin = sdk.NewCoin(denomAB.IBCDenom(), amount) totalEscrowChainB = suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - denom = types.ExtractDenomFromPath(denomABC.Path()) + denom := types.ExtractDenomFromPath(denomABC.Path()) data = types.NewFungibleTokenPacketDataV2( []types.Token{ { From 5070e5018020ae5963e5d3ff053c0057afb1945a Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 13 Jun 2024 12:30:42 +0200 Subject: [PATCH 071/141] chore: rename ForwardingInfo to Forwarding (#6576) * chore: rename ForwardingInfo to Forwarding * chore: rename forwarding_path field to forwarding * chore: make lint-fix * chore: rename forwarding info -> forwarding * chore: renaming fixes before merge --- e2e/testsuite/testsuite.go | 4 +- .../host/keeper/relay_test.go | 2 +- modules/apps/callbacks/ibc_middleware_test.go | 8 +- .../apps/transfer/internal/convert/convert.go | 8 +- modules/apps/transfer/keeper/export_test.go | 4 +- modules/apps/transfer/keeper/msg_server.go | 2 +- modules/apps/transfer/keeper/relay.go | 38 +++---- .../transfer/keeper/relay_forwarding_test.go | 22 ++-- modules/apps/transfer/types/errors.go | 2 +- .../{forwarding_info.go => forwarding.go} | 12 +- ...arding_info_test.go => forwarding_test.go} | 64 +++++------ modules/apps/transfer/types/msgs.go | 14 +-- modules/apps/transfer/types/msgs_test.go | 10 +- modules/apps/transfer/types/packet.go | 20 ++-- modules/apps/transfer/types/packet.pb.go | 71 ++++++------ modules/apps/transfer/types/packet_test.go | 16 +-- modules/apps/transfer/types/transfer.pb.go | 94 ++++++++-------- modules/apps/transfer/types/tx.pb.go | 105 +++++++++--------- .../applications/transfer/v1/transfer.proto | 4 +- proto/ibc/applications/transfer/v1/tx.proto | 2 +- .../ibc/applications/transfer/v2/packet.proto | 2 +- 21 files changed, 251 insertions(+), 253 deletions(-) rename modules/apps/transfer/types/{forwarding_info.go => forwarding.go} (62%) rename modules/apps/transfer/types/{forwarding_info_test.go => forwarding_test.go} (53%) diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index 9a113fbd7e9..57af87efab2 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -563,7 +563,7 @@ func getValidatorsAndFullNodes(chainIdx int) (int, int) { } // GetMsgTransfer returns a MsgTransfer that is constructed based on the channel version -func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, forwardingPath *transfertypes.ForwardingInfo) *transfertypes.MsgTransfer { +func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, forwarding *transfertypes.Forwarding) *transfertypes.MsgTransfer { if len(tokens) == 0 { panic(errors.New("tokens cannot be empty")) } @@ -583,7 +583,7 @@ func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, Tokens: sdk.NewCoins(), } case transfertypes.V2: - msg = transfertypes.NewMsgTransfer(portID, channelID, tokens, sender, receiver, timeoutHeight, timeoutTimestamp, memo, forwardingPath) + msg = transfertypes.NewMsgTransfer(portID, channelID, tokens, sender, receiver, timeoutHeight, timeoutTimestamp, memo, forwarding) default: panic(fmt.Errorf("unsupported transfer version: %s", version)) } diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index c6c077591eb..c9a115fd45b 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -798,7 +798,7 @@ func (suite *KeeperTestSuite) TestJSONOnRecvPacket() { "timeout_height": { "revision_number": 1, "revision_height": 100 }, "timeout_timestamp": 0, "memo": "", - "forwarding_path": { "hops": [], "memo": "" } + "forwarding": { "hops": [], "memo": "" } } ] }`) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 4af804535d3..17b57e547a5 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -1003,10 +1003,10 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketDataV1() { Amount: ibctesting.TestCoin.Amount.String(), }, }, - Sender: ibctesting.TestAccAddress, - Receiver: ibctesting.TestAccAddress, - Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), - ForwardingPath: nil, + Sender: ibctesting.TestAccAddress, + Receiver: ibctesting.TestAccAddress, + Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), + Forwarding: nil, } portID := s.path.EndpointA.ChannelConfig.PortID diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go index 49459fc139a..9bc43844e63 100644 --- a/modules/apps/transfer/internal/convert/convert.go +++ b/modules/apps/transfer/internal/convert/convert.go @@ -21,9 +21,9 @@ func PacketDataV1ToV2(packetData types.FungibleTokenPacketData) (types.FungibleT Amount: packetData.Amount, }, }, - Sender: packetData.Sender, - Receiver: packetData.Receiver, - Memo: packetData.Memo, - ForwardingPath: nil, + Sender: packetData.Sender, + Receiver: packetData.Receiver, + Memo: packetData.Memo, + Forwarding: nil, }, nil } diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index 760e04cc97f..ebf94032046 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -34,6 +34,6 @@ func (k Keeper) TokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // CreatePacketDataBytesFromVersion is a wrapper around createPacketDataBytesFromVersion for testing purposes -func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwardingPath *types.ForwardingInfo) []byte { - return createPacketDataBytesFromVersion(appVersion, sender, receiver, memo, tokens, forwardingPath) +func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwarding *types.Forwarding) []byte { + return createPacketDataBytesFromVersion(appVersion, sender, receiver, memo, tokens, forwarding) } diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 4a12f84d5e3..507dc2c7b62 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -38,7 +38,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. sequence, err := k.sendTransfer( ctx, msg.SourcePort, msg.SourceChannel, coins, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, - msg.Memo, msg.ForwardingPath) + msg.Memo, msg.Forwarding) if err != nil { return nil, err } diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 1b458408143..928dca8121a 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -64,7 +64,7 @@ func (k Keeper) sendTransfer( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, - forwardingPath *types.ForwardingInfo, + forwarding *types.Forwarding, ) (uint64, error) { channel, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) if !found { @@ -140,7 +140,7 @@ func (k Keeper) sendTransfer( tokens = append(tokens, token) } - packetDataBytes := createPacketDataBytesFromVersion(appVersion, sender.String(), receiver, memo, tokens, forwardingPath) + packetDataBytes := createPacketDataBytesFromVersion(appVersion, sender.String(), receiver, memo, tokens, forwarding) sequence, err := k.ics4Wrapper.SendPacket(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, packetDataBytes) if err != nil { @@ -171,15 +171,15 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t var ( err error - receiver sdk.AccAddress // final receiver of tokens if there is no forwarding info, otherwise, receiver in the next hop - finalReceiver sdk.AccAddress // final receiver of tokens if there is forwarding info + receiver sdk.AccAddress // final receiver of tokens if there is no forwarding, otherwise, receiver in the next hop + finalReceiver sdk.AccAddress // final receiver of tokens if there is forwarding ) receiver, err = sdk.AccAddressFromBech32(data.Receiver) if err != nil { return false, errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "failed to decode receiver address %s: %v", data.Receiver, err) } - if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { + if data.Forwarding != nil && len(data.Forwarding.Hops) > 0 { finalReceiver = receiver // , _ = sdk.AccAddressFromBech32(data.Receiver) receiver = types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) } @@ -273,30 +273,30 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t } // Adding forwarding logic - if data.ForwardingPath != nil && len(data.ForwardingPath.Hops) > 0 { + if data.Forwarding != nil && len(data.Forwarding.Hops) > 0 { memo := "" - var nextForwardingPath *types.ForwardingInfo - if len(data.ForwardingPath.Hops) == 1 { - memo = data.ForwardingPath.Memo - nextForwardingPath = nil + var nextForwarding *types.Forwarding + if len(data.Forwarding.Hops) == 1 { + memo = data.Forwarding.Memo + nextForwarding = nil } else { - nextForwardingPath = &types.ForwardingInfo{ - Hops: data.ForwardingPath.Hops[1:], - Memo: data.ForwardingPath.Memo, + nextForwarding = &types.Forwarding{ + Hops: data.Forwarding.Hops[1:], + Memo: data.Forwarding.Memo, } } msg := types.NewMsgTransfer( - data.ForwardingPath.Hops[0].PortId, - data.ForwardingPath.Hops[0].ChannelId, + data.Forwarding.Hops[0].PortId, + data.Forwarding.Hops[0].ChannelId, receivedCoins, receiver.String(), finalReceiver.String(), packet.TimeoutHeight, packet.TimeoutTimestamp, memo, - nextForwardingPath, + nextForwarding, ) resp, err := k.Transfer(ctx, msg) @@ -304,7 +304,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return false, err } - k.SetForwardedPacket(ctx, data.ForwardingPath.Hops[0].PortId, data.ForwardingPath.Hops[0].ChannelId, resp.Sequence, packet) + k.SetForwardedPacket(ctx, data.Forwarding.Hops[0].PortId, data.Forwarding.Hops[0].ChannelId, resp.Sequence, packet) return true, nil } @@ -472,7 +472,7 @@ func (k Keeper) tokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // createPacketDataBytesFromVersion creates the packet data bytes to be sent based on the application version. -func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwardingPath *types.ForwardingInfo) []byte { +func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwarding *types.Forwarding) []byte { var packetDataBytes []byte switch appVersion { case types.V1: @@ -485,7 +485,7 @@ func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, packetData := types.NewFungibleTokenPacketData(token.Denom.Path(), token.Amount, sender, receiver, memo) packetDataBytes = packetData.GetBytes() case types.V2: - packetData := types.NewFungibleTokenPacketDataV2(tokens, sender, receiver, memo, forwardingPath) + packetData := types.NewFungibleTokenPacketDataV2(tokens, sender, receiver, memo, forwarding) packetDataBytes = packetData.GetBytes() default: panic(fmt.Errorf("app version must be one of %s", types.SupportedVersions)) diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 4647e87b554..52c25a9af69 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -28,7 +28,7 @@ func (suite *KeeperTestSuite) TestPathForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ + forwarding := types.Forwarding{ Hops: []types.Hop{ { PortId: path2.EndpointA.ChannelConfig.PortID, @@ -46,7 +46,7 @@ func (suite *KeeperTestSuite) TestPathForwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - &forwardingPath, + &forwarding, ) result, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -90,7 +90,7 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ + forwarding := types.Forwarding{ Hops: []types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, @@ -108,7 +108,7 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - &forwardingPath, + &forwarding, ) result, err := suite.chainA.SendMsgs(transferMsg) @@ -173,7 +173,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ + forwarding := types.Forwarding{ Hops: []types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, @@ -191,7 +191,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - &forwardingPath, + &forwarding, ) result, err := suite.chainA.SendMsgs(transferMsg) @@ -209,7 +209,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { Denom: denom, Amount: amount.String(), }, - }, sender.GetAddress().String(), receiver.GetAddress().String(), "", &forwardingPath) + }, sender.GetAddress().String(), receiver.GetAddress().String(), "", &forwarding) packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) var async bool @@ -281,7 +281,7 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwardingPath := types.ForwardingInfo{ + forwarding := types.Forwarding{ Hops: []types.Hop{ { PortId: path2.EndpointB.ChannelConfig.PortID, @@ -299,7 +299,7 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - &forwardingPath, + &forwarding, ) result, err := suite.chainA.SendMsgs(transferMsg) @@ -475,7 +475,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { sender = suite.chainC.SenderAccounts[0].SenderAccount receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account - forwardingPath := types.ForwardingInfo{ + forwarding := types.Forwarding{ Hops: []types.Hop{ { PortId: path1.EndpointB.ChannelConfig.PortID, @@ -493,7 +493,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - &forwardingPath, + &forwarding, ) result, err = suite.chainC.SendMsgs(transferMsg) diff --git a/modules/apps/transfer/types/errors.go b/modules/apps/transfer/types/errors.go index 13f87f17a77..70bbc6edc45 100644 --- a/modules/apps/transfer/types/errors.go +++ b/modules/apps/transfer/types/errors.go @@ -16,5 +16,5 @@ var ( ErrMaxTransferChannels = errorsmod.Register(ModuleName, 9, "max transfer channels") ErrInvalidAuthorization = errorsmod.Register(ModuleName, 10, "invalid transfer authorization") ErrInvalidMemo = errorsmod.Register(ModuleName, 11, "invalid memo") - ErrInvalidForwardingInfo = errorsmod.Register(ModuleName, 12, "invalid forwarding info") + ErrInvalidForwarding = errorsmod.Register(ModuleName, 12, "invalid token forwarding") ) diff --git a/modules/apps/transfer/types/forwarding_info.go b/modules/apps/transfer/types/forwarding.go similarity index 62% rename from modules/apps/transfer/types/forwarding_info.go rename to modules/apps/transfer/types/forwarding.go index 167ca89bff0..53ebbb456bc 100644 --- a/modules/apps/transfer/types/forwarding_info.go +++ b/modules/apps/transfer/types/forwarding.go @@ -8,18 +8,18 @@ import ( const MaximumNumberOfForwardingHops = 64 -// NewForwardingInfo creates a new ForwardingInfo instance given a memo and a variable number of hops. -func NewForwardingInfo(memo string, hops ...Hop) *ForwardingInfo { - return &ForwardingInfo{ +// NewForwarding creates a new Forwarding instance given a memo and a variable number of hops. +func NewForwarding(memo string, hops ...Hop) *Forwarding { + return &Forwarding{ Memo: memo, Hops: hops, } } -// Validate performs a basic validation of the ForwardingInfo fields. -func (fi ForwardingInfo) Validate() error { +// Validate performs a basic validation of the Forwarding fields. +func (fi Forwarding) Validate() error { if len(fi.Hops) > MaximumNumberOfForwardingHops { - return errorsmod.Wrapf(ErrInvalidForwardingInfo, "number of hops in forwarding path cannot exceed %d", MaximumNumberOfForwardingHops) + return errorsmod.Wrapf(ErrInvalidForwarding, "number of hops in forwarding path cannot exceed %d", MaximumNumberOfForwardingHops) } for _, hop := range fi.Hops { diff --git a/modules/apps/transfer/types/forwarding_info_test.go b/modules/apps/transfer/types/forwarding_test.go similarity index 53% rename from modules/apps/transfer/types/forwarding_info_test.go rename to modules/apps/transfer/types/forwarding_test.go index 7be1fadeeaa..fd1df5ea05b 100644 --- a/modules/apps/transfer/types/forwarding_info_test.go +++ b/modules/apps/transfer/types/forwarding_test.go @@ -15,50 +15,50 @@ var validHop = types.Hop{ ChannelId: ibctesting.FirstChannelID, } -func TestForwardingInfo_Validate(t *testing.T) { +func TestForwarding_Validate(t *testing.T) { tests := []struct { - name string - forwardingInfo *types.ForwardingInfo - expError error + name string + forwarding *types.Forwarding + expError error }{ { - "valid forwarding info with no hops", - types.NewForwardingInfo(""), + "valid forwarding with no hops", + types.NewForwarding(""), nil, }, { - "valid forwarding info with hops", - types.NewForwardingInfo("", validHop), + "valid forwarding with hops", + types.NewForwarding("", validHop), nil, }, { - "valid forwarding info with memo", - types.NewForwardingInfo(testMemo1, validHop, validHop), + "valid forwarding with memo", + types.NewForwarding(testMemo1, validHop, validHop), nil, }, { - "valid forwarding info with max hops", - types.NewForwardingInfo("", generateHops(types.MaximumNumberOfForwardingHops)...), + "valid forwarding with max hops", + types.NewForwarding("", generateHops(types.MaximumNumberOfForwardingHops)...), nil, }, { - "valid forwarding info with max memo length", - types.NewForwardingInfo(ibctesting.GenerateString(types.MaximumMemoLength), validHop), + "valid forwarding with max memo length", + types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength), validHop), nil, }, { - "invalid forwarding info with too many hops", - types.NewForwardingInfo("", generateHops(types.MaximumNumberOfForwardingHops+1)...), - types.ErrInvalidForwardingInfo, + "invalid forwarding with too many hops", + types.NewForwarding("", generateHops(types.MaximumNumberOfForwardingHops+1)...), + types.ErrInvalidForwarding, }, { - "invalid forwarding info with too long memo", - types.NewForwardingInfo(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), + "invalid forwarding with too long memo", + types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), types.ErrInvalidMemo, }, { - "invalid forwarding info with too short hop port ID", - types.NewForwardingInfo( + "invalid forwarding with too short hop port ID", + types.NewForwarding( "", types.Hop{ PortId: invalidShortPort, @@ -68,8 +68,8 @@ func TestForwardingInfo_Validate(t *testing.T) { host.ErrInvalidID, }, { - "invalid forwarding info with too long hop port ID", - types.NewForwardingInfo( + "invalid forwarding with too long hop port ID", + types.NewForwarding( "", types.Hop{ PortId: invalidLongPort, @@ -79,8 +79,8 @@ func TestForwardingInfo_Validate(t *testing.T) { host.ErrInvalidID, }, { - "invalid forwarding info with non-alpha hop port ID", - types.NewForwardingInfo( + "invalid forwarding with non-alpha hop port ID", + types.NewForwarding( "", types.Hop{ PortId: invalidPort, @@ -90,8 +90,8 @@ func TestForwardingInfo_Validate(t *testing.T) { host.ErrInvalidID, }, { - "invalid forwarding info with too long hop channel ID", - types.NewForwardingInfo( + "invalid forwarding with too long hop channel ID", + types.NewForwarding( "", types.Hop{ PortId: types.PortID, @@ -101,8 +101,8 @@ func TestForwardingInfo_Validate(t *testing.T) { host.ErrInvalidID, }, { - "invalid forwarding info with too short hop channel ID", - types.NewForwardingInfo( + "invalid forwarding with too short hop channel ID", + types.NewForwarding( "", types.Hop{ PortId: types.PortID, @@ -112,8 +112,8 @@ func TestForwardingInfo_Validate(t *testing.T) { host.ErrInvalidID, }, { - "invalid forwarding info with non-alpha hop channel ID", - types.NewForwardingInfo( + "invalid forwarding with non-alpha hop channel ID", + types.NewForwarding( "", types.Hop{ PortId: types.PortID, @@ -127,7 +127,7 @@ func TestForwardingInfo_Validate(t *testing.T) { t.Run(tc.name, func(t *testing.T) { tc := tc - err := tc.forwardingInfo.Validate() + err := tc.forwarding.Validate() expPass := tc.expError == nil if expPass { diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index a50a6e5719a..bd34f6cce49 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -49,7 +49,7 @@ func NewMsgTransfer( tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, - forwardingPath *ForwardingInfo, + forwarding *Forwarding, ) *MsgTransfer { return &MsgTransfer{ SourcePort: sourcePort, @@ -60,7 +60,7 @@ func NewMsgTransfer( TimeoutTimestamp: timeoutTimestamp, Memo: memo, Tokens: tokens, - ForwardingPath: forwardingPath, + Forwarding: forwarding, } } @@ -102,14 +102,14 @@ func (msg MsgTransfer) ValidateBasic() error { return errorsmod.Wrapf(ErrInvalidMemo, "memo must not exceed %d bytes", MaximumMemoLength) } - if msg.ForwardingPath != nil { - if err := msg.ForwardingPath.Validate(); err != nil { + if msg.Forwarding != nil { + if err := msg.Forwarding.Validate(); err != nil { return err } - // We cannot have non-empty memo and non-empty forwarding path hops at the same time. - if len(msg.ForwardingPath.Hops) > 0 && msg.Memo != "" { - return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", msg.Memo, msg.ForwardingPath.Hops) + // We cannot have non-empty memo and non-empty forwarding hops at the same time. + if len(msg.Forwarding.Hops) > 0 && msg.Memo != "" { + return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", msg.Memo, msg.Forwarding.Hops) } } diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index 447fd619a36..bc043339dc3 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -79,11 +79,11 @@ func TestMsgTransferValidation(t *testing.T) { {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, {"multidenom: too many coins", types.NewMsgTransfer(validPort, validChannel, make([]sdk.Coin, types.MaximumTokensLength+1), sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, {"multidenom: both token and tokens are set", &types.MsgTransfer{validPort, validChannel, coin, sender, receiver, timeoutHeight, 0, "", coins, nil}, ibcerrors.ErrInvalidCoins}, - {"memo must be empty if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "memo", types.NewForwardingInfo("", validHop)), types.ErrInvalidMemo}, - {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwardingInfo("", types.Hop{PortId: invalidPort, ChannelId: validChannel})), host.ErrInvalidID}, - {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwardingInfo("", types.Hop{PortId: validPort, ChannelId: invalidChannel})), host.ErrInvalidID}, - {"invalid forwarding info too many hops", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwardingInfo("", generateHops(types.MaximumNumberOfForwardingHops+1)...)), types.ErrInvalidForwardingInfo}, - {"invalid forwarding info too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwardingInfo(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop)), types.ErrInvalidMemo}, + {"memo must be empty if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "memo", types.NewForwarding("", validHop)), types.ErrInvalidMemo}, + {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwarding("", types.Hop{PortId: invalidPort, ChannelId: validChannel})), host.ErrInvalidID}, + {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwarding("", types.Hop{PortId: validPort, ChannelId: invalidChannel})), host.ErrInvalidID}, + {"invalid forwarding info too many hops", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwarding("", generateHops(types.MaximumNumberOfForwardingHops+1)...)), types.ErrInvalidForwarding}, + {"invalid forwarding info too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop)), types.ErrInvalidMemo}, } for _, tc := range testCases { diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index e4f5179bd78..fa1a45fadec 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -103,14 +103,14 @@ func NewFungibleTokenPacketDataV2( tokens []Token, sender, receiver string, memo string, - forwardingPath *ForwardingInfo, + forwarding *Forwarding, ) FungibleTokenPacketDataV2 { return FungibleTokenPacketDataV2{ - Tokens: tokens, - Sender: sender, - Receiver: receiver, - Memo: memo, - ForwardingPath: forwardingPath, + Tokens: tokens, + Sender: sender, + Receiver: receiver, + Memo: memo, + Forwarding: forwarding, } } @@ -140,14 +140,14 @@ func (ftpd FungibleTokenPacketDataV2) ValidateBasic() error { return errorsmod.Wrapf(ErrInvalidMemo, "memo must not exceed %d bytes", MaximumMemoLength) } - if ftpd.ForwardingPath != nil { - if err := ftpd.ForwardingPath.Validate(); err != nil { + if ftpd.Forwarding != nil { + if err := ftpd.Forwarding.Validate(); err != nil { return err } // We cannot have non-empty memo and non-empty forwarding path hops at the same time. - if len(ftpd.ForwardingPath.Hops) > 0 && ftpd.Memo != "" { - return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", ftpd.Memo, ftpd.ForwardingPath.Hops) + if len(ftpd.Forwarding.Hops) > 0 && ftpd.Memo != "" { + return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", ftpd.Memo, ftpd.Forwarding.Hops) } } diff --git a/modules/apps/transfer/types/packet.pb.go b/modules/apps/transfer/types/packet.pb.go index 1eae85e38e9..4004072b664 100644 --- a/modules/apps/transfer/types/packet.pb.go +++ b/modules/apps/transfer/types/packet.pb.go @@ -120,7 +120,7 @@ type FungibleTokenPacketDataV2 struct { // optional memo Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` // optional forwarding information - ForwardingPath *ForwardingInfo `protobuf:"bytes,5,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` + Forwarding *Forwarding `protobuf:"bytes,5,opt,name=forwarding,proto3" json:"forwarding,omitempty"` } func (m *FungibleTokenPacketDataV2) Reset() { *m = FungibleTokenPacketDataV2{} } @@ -184,9 +184,9 @@ func (m *FungibleTokenPacketDataV2) GetMemo() string { return "" } -func (m *FungibleTokenPacketDataV2) GetForwardingPath() *ForwardingInfo { +func (m *FungibleTokenPacketDataV2) GetForwarding() *Forwarding { if m != nil { - return m.ForwardingPath + return m.Forwarding } return nil } @@ -201,31 +201,30 @@ func init() { } var fileDescriptor_653ca2ce9a5ca313 = []byte{ - // 379 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0xab, 0xd3, 0x40, - 0x14, 0x85, 0x33, 0xaf, 0x79, 0x45, 0xe7, 0x81, 0xc2, 0xf0, 0xd0, 0x58, 0x24, 0x3e, 0x9e, 0x9b, - 0x8a, 0x3a, 0x43, 0xe3, 0x42, 0xb7, 0x16, 0x29, 0xb8, 0xab, 0x45, 0x5d, 0xb8, 0x91, 0xc9, 0x64, - 0x9a, 0x0e, 0x6d, 0xe6, 0x86, 0x99, 0x49, 0xc4, 0x5f, 0xa1, 0x3f, 0xab, 0xcb, 0x2e, 0x5d, 0x89, - 0xb4, 0xbf, 0x43, 0x90, 0x4c, 0x6a, 0xdb, 0x4d, 0xb3, 0x3b, 0xe7, 0xe4, 0xde, 0xc3, 0x97, 0xb9, - 0xf8, 0x99, 0x4a, 0x05, 0xe3, 0x65, 0xb9, 0x52, 0x82, 0x3b, 0x05, 0xda, 0x32, 0x67, 0xb8, 0xb6, - 0x73, 0x69, 0x58, 0x9d, 0xb0, 0x92, 0x8b, 0xa5, 0x74, 0xb4, 0x34, 0xe0, 0x80, 0x3c, 0x56, 0xa9, - 0xa0, 0xa7, 0xa3, 0xf4, 0xff, 0x28, 0xad, 0x93, 0xc1, 0xb0, 0xb3, 0xc8, 0xc1, 0x52, 0xea, 0xb6, - 0x67, 0x70, 0x9d, 0x43, 0x0e, 0x5e, 0xb2, 0x46, 0xed, 0xd3, 0xe7, 0x1d, 0xfb, 0xa3, 0x83, 0x6e, - 0x87, 0x6f, 0x7f, 0x20, 0xfc, 0x70, 0x52, 0xe9, 0x5c, 0xa5, 0x2b, 0xf9, 0xb1, 0xa9, 0x9e, 0x7a, - 0xd0, 0x77, 0xdc, 0x71, 0x72, 0x8d, 0x2f, 0x33, 0xa9, 0xa1, 0x88, 0xd0, 0x0d, 0x1a, 0xde, 0x9d, - 0xb5, 0x86, 0x3c, 0xc0, 0x7d, 0x5e, 0x40, 0xa5, 0x5d, 0x74, 0xe1, 0xe3, 0xbd, 0x6b, 0x72, 0x2b, - 0x75, 0x26, 0x4d, 0xd4, 0x6b, 0xf3, 0xd6, 0x91, 0x01, 0xbe, 0x63, 0xa4, 0x90, 0xaa, 0x96, 0x26, - 0x0a, 0xfd, 0x97, 0x83, 0x27, 0x04, 0x87, 0x85, 0x2c, 0x20, 0xba, 0xf4, 0xb9, 0xd7, 0xb7, 0x7f, - 0x11, 0x7e, 0x74, 0x86, 0xe8, 0x73, 0x42, 0xde, 0xe2, 0xbe, 0x7f, 0x01, 0x1b, 0xa1, 0x9b, 0xde, - 0xf0, 0x2a, 0x79, 0x4a, 0xbb, 0xde, 0x92, 0xfa, 0x82, 0x71, 0xb8, 0xfe, 0xfd, 0x24, 0x98, 0xed, - 0x17, 0x4f, 0x40, 0x2f, 0xce, 0x82, 0xf6, 0xce, 0x80, 0x86, 0x47, 0x50, 0xf2, 0x09, 0xdf, 0x9f, - 0x83, 0xf9, 0xc6, 0x4d, 0xa6, 0x74, 0xfe, 0xb5, 0xe4, 0x6e, 0xe1, 0xff, 0xe3, 0x2a, 0x79, 0xd1, - 0xc5, 0x34, 0xa2, 0x93, 0xc3, 0xd2, 0x7b, 0x3d, 0x87, 0xd9, 0xbd, 0x63, 0xc9, 0x94, 0xbb, 0xc5, - 0xf8, 0xc3, 0x7a, 0x1b, 0xa3, 0xcd, 0x36, 0x46, 0x7f, 0xb6, 0x31, 0xfa, 0xb9, 0x8b, 0x83, 0xcd, - 0x2e, 0x0e, 0x7e, 0xed, 0xe2, 0xe0, 0xcb, 0xeb, 0x5c, 0xb9, 0x45, 0x95, 0x52, 0x01, 0x05, 0x13, - 0x60, 0x0b, 0xb0, 0x4c, 0xa5, 0xe2, 0x65, 0x0e, 0xac, 0x7e, 0xc3, 0x0a, 0xc8, 0xaa, 0x95, 0xb4, - 0xcd, 0xe1, 0x4f, 0x0e, 0xee, 0xbe, 0x97, 0xd2, 0xa6, 0x7d, 0x7f, 0xeb, 0x57, 0xff, 0x02, 0x00, - 0x00, 0xff, 0xff, 0x9a, 0x79, 0x3e, 0x9a, 0xa3, 0x02, 0x00, 0x00, + // 365 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0xc1, 0x8e, 0xd3, 0x30, + 0x14, 0x8c, 0xdb, 0xb4, 0x02, 0xf7, 0x66, 0x55, 0x10, 0x2a, 0x14, 0xaa, 0x72, 0x09, 0x42, 0xd8, + 0x6a, 0x38, 0xc0, 0x95, 0x0a, 0x55, 0x1c, 0xa1, 0x42, 0x1c, 0xb8, 0x39, 0x8e, 0x1b, 0xac, 0x36, + 0x76, 0x64, 0x3b, 0x41, 0xfb, 0x15, 0xbb, 0x9f, 0xd5, 0x63, 0x8f, 0x7b, 0x5a, 0xad, 0xda, 0x1f, + 0xd8, 0x4f, 0x58, 0xc5, 0xe9, 0x76, 0x73, 0x69, 0x6e, 0x33, 0xe3, 0x79, 0xa3, 0xf1, 0x7b, 0xf0, + 0x83, 0x48, 0x18, 0xa1, 0x45, 0xb1, 0x15, 0x8c, 0x5a, 0xa1, 0xa4, 0x21, 0x56, 0x53, 0x69, 0xd6, + 0x5c, 0x93, 0x2a, 0x26, 0x05, 0x65, 0x1b, 0x6e, 0x71, 0xa1, 0x95, 0x55, 0xe8, 0xad, 0x48, 0x18, + 0x6e, 0x5b, 0xf1, 0x93, 0x15, 0x57, 0xf1, 0x24, 0xea, 0x0c, 0xb2, 0x6a, 0xc3, 0x65, 0x93, 0x33, + 0x19, 0x67, 0x2a, 0x53, 0x0e, 0x92, 0x1a, 0x9d, 0xd4, 0x8f, 0x1d, 0xf3, 0xf3, 0x33, 0x6e, 0xcc, + 0xb3, 0x6b, 0x00, 0x5f, 0x2f, 0x4b, 0x99, 0x89, 0x64, 0xcb, 0x7f, 0xd7, 0xd1, 0x3f, 0x5d, 0xd1, + 0xef, 0xd4, 0x52, 0x34, 0x86, 0x83, 0x94, 0x4b, 0x95, 0x07, 0x60, 0x0a, 0xa2, 0x97, 0xab, 0x86, + 0xa0, 0x57, 0x70, 0x48, 0x73, 0x55, 0x4a, 0x1b, 0xf4, 0x9c, 0x7c, 0x62, 0xb5, 0x6e, 0xb8, 0x4c, + 0xb9, 0x0e, 0xfa, 0x8d, 0xde, 0x30, 0x34, 0x81, 0x2f, 0x34, 0x67, 0x5c, 0x54, 0x5c, 0x07, 0xbe, + 0x7b, 0x39, 0x73, 0x84, 0xa0, 0x9f, 0xf3, 0x5c, 0x05, 0x03, 0xa7, 0x3b, 0x3c, 0x7b, 0x00, 0xf0, + 0xcd, 0x85, 0x46, 0x7f, 0x62, 0xf4, 0x0d, 0x0e, 0xdd, 0x06, 0x4c, 0x00, 0xa6, 0xfd, 0x68, 0x14, + 0xbf, 0xc7, 0x5d, 0xbb, 0xc4, 0x2e, 0x60, 0xe1, 0xef, 0xee, 0xde, 0x79, 0xab, 0xd3, 0x60, 0xab, + 0x68, 0xef, 0x62, 0xd1, 0xfe, 0x85, 0xa2, 0xfe, 0x73, 0x51, 0xf4, 0x03, 0xc2, 0xb5, 0xd2, 0xff, + 0xa9, 0x4e, 0x85, 0xcc, 0xdc, 0x17, 0x46, 0x71, 0xd4, 0x55, 0x67, 0x8e, 0x97, 0x67, 0xff, 0xaa, + 0x35, 0xbb, 0xf8, 0xb5, 0x3b, 0x84, 0x60, 0x7f, 0x08, 0xc1, 0xfd, 0x21, 0x04, 0x37, 0xc7, 0xd0, + 0xdb, 0x1f, 0x43, 0xef, 0xf6, 0x18, 0x7a, 0x7f, 0xbf, 0x64, 0xc2, 0xfe, 0x2b, 0x13, 0xcc, 0x54, + 0x4e, 0x98, 0x32, 0xb9, 0x32, 0x44, 0x24, 0xec, 0x53, 0xa6, 0x48, 0xf5, 0x95, 0xe4, 0x2a, 0x2d, + 0xb7, 0xdc, 0xd4, 0xb7, 0x6e, 0xdd, 0xd8, 0x5e, 0x15, 0xdc, 0x24, 0x43, 0x77, 0xde, 0xcf, 0x8f, + 0x01, 0x00, 0x00, 0xff, 0xff, 0x75, 0x75, 0x92, 0xad, 0x96, 0x02, 0x00, 0x00, } func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { @@ -306,9 +305,9 @@ func (m *FungibleTokenPacketDataV2) MarshalToSizedBuffer(dAtA []byte) (int, erro _ = i var l int _ = l - if m.ForwardingPath != nil { + if m.Forwarding != nil { { - size, err := m.ForwardingPath.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Forwarding.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -420,8 +419,8 @@ func (m *FungibleTokenPacketDataV2) Size() (n int) { if l > 0 { n += 1 + l + sovPacket(uint64(l)) } - if m.ForwardingPath != nil { - l = m.ForwardingPath.Size() + if m.Forwarding != nil { + l = m.Forwarding.Size() n += 1 + l + sovPacket(uint64(l)) } return n @@ -804,7 +803,7 @@ func (m *FungibleTokenPacketDataV2) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ForwardingPath", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Forwarding", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -831,10 +830,10 @@ func (m *FungibleTokenPacketDataV2) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.ForwardingPath == nil { - m.ForwardingPath = &ForwardingInfo{} + if m.Forwarding == nil { + m.Forwarding = &Forwarding{} } - if err := m.ForwardingPath.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Forwarding.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 509435f5323..e2af7801931 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -231,7 +231,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwardingInfo("", validHop, validHop), + types.NewForwarding("", validHop, validHop), ), nil, }, @@ -247,7 +247,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwardingInfo("memo", validHop), + types.NewForwarding("memo", validHop), ), nil, }, @@ -402,7 +402,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "memo", - types.NewForwardingInfo("", validHop), + types.NewForwarding("", validHop), ), types.ErrInvalidMemo, }, @@ -418,7 +418,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwardingInfo( + types.NewForwarding( "", types.Hop{ PortId: invalidPort, @@ -440,7 +440,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwardingInfo( + types.NewForwarding( "", types.Hop{ PortId: "transfer", @@ -462,9 +462,9 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwardingInfo("", generateHops(types.MaximumNumberOfForwardingHops+1)...), + types.NewForwarding("", generateHops(types.MaximumNumberOfForwardingHops+1)...), ), - types.ErrInvalidForwardingInfo, + types.ErrInvalidForwarding, }, { "failure: invalid forwarding path too long memo", @@ -478,7 +478,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwardingInfo(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), + types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), ), types.ErrInvalidMemo, }, diff --git a/modules/apps/transfer/types/transfer.pb.go b/modules/apps/transfer/types/transfer.pb.go index 70af1be23e4..7311d98c072 100644 --- a/modules/apps/transfer/types/transfer.pb.go +++ b/modules/apps/transfer/types/transfer.pb.go @@ -83,26 +83,26 @@ func (m *Params) GetReceiveEnabled() bool { return false } -// ForwardingInfo defines a list of port ID, channel ID pairs determining the path +// Forwarding defines a list of port ID, channel ID pairs determining the path // through which a packet must be forwarded, and the memo string to be used in the // final destination of the tokens. -type ForwardingInfo struct { +type Forwarding struct { Hops []Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops"` Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` } -func (m *ForwardingInfo) Reset() { *m = ForwardingInfo{} } -func (m *ForwardingInfo) String() string { return proto.CompactTextString(m) } -func (*ForwardingInfo) ProtoMessage() {} -func (*ForwardingInfo) Descriptor() ([]byte, []int) { +func (m *Forwarding) Reset() { *m = Forwarding{} } +func (m *Forwarding) String() string { return proto.CompactTextString(m) } +func (*Forwarding) ProtoMessage() {} +func (*Forwarding) Descriptor() ([]byte, []int) { return fileDescriptor_5041673e96e97901, []int{1} } -func (m *ForwardingInfo) XXX_Unmarshal(b []byte) error { +func (m *Forwarding) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ForwardingInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *Forwarding) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ForwardingInfo.Marshal(b, m, deterministic) + return xxx_messageInfo_Forwarding.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -112,26 +112,26 @@ func (m *ForwardingInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro return b[:n], nil } } -func (m *ForwardingInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_ForwardingInfo.Merge(m, src) +func (m *Forwarding) XXX_Merge(src proto.Message) { + xxx_messageInfo_Forwarding.Merge(m, src) } -func (m *ForwardingInfo) XXX_Size() int { +func (m *Forwarding) XXX_Size() int { return m.Size() } -func (m *ForwardingInfo) XXX_DiscardUnknown() { - xxx_messageInfo_ForwardingInfo.DiscardUnknown(m) +func (m *Forwarding) XXX_DiscardUnknown() { + xxx_messageInfo_Forwarding.DiscardUnknown(m) } -var xxx_messageInfo_ForwardingInfo proto.InternalMessageInfo +var xxx_messageInfo_Forwarding proto.InternalMessageInfo -func (m *ForwardingInfo) GetHops() []Hop { +func (m *Forwarding) GetHops() []Hop { if m != nil { return m.Hops } return nil } -func (m *ForwardingInfo) GetMemo() string { +func (m *Forwarding) GetMemo() string { if m != nil { return m.Memo } @@ -194,7 +194,7 @@ func (m *Hop) GetChannelId() string { func init() { proto.RegisterType((*Params)(nil), "ibc.applications.transfer.v1.Params") - proto.RegisterType((*ForwardingInfo)(nil), "ibc.applications.transfer.v1.ForwardingInfo") + proto.RegisterType((*Forwarding)(nil), "ibc.applications.transfer.v1.Forwarding") proto.RegisterType((*Hop)(nil), "ibc.applications.transfer.v1.Hop") } @@ -203,28 +203,28 @@ func init() { } var fileDescriptor_5041673e96e97901 = []byte{ - // 325 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0x4b, 0xc3, 0x30, - 0x18, 0x86, 0x5b, 0x37, 0xa6, 0xcb, 0x64, 0x42, 0x10, 0x1c, 0xa2, 0x75, 0xdb, 0xc5, 0x81, 0xd8, - 0x30, 0x3d, 0x28, 0x88, 0x97, 0x81, 0xb2, 0xdd, 0xb4, 0x78, 0xf2, 0x32, 0xd2, 0x34, 0xeb, 0x02, - 0x6d, 0xbe, 0x90, 0x74, 0x15, 0xff, 0x85, 0x3f, 0x6b, 0xc7, 0x1d, 0x3d, 0x89, 0x6c, 0x7f, 0x44, - 0x9a, 0x8e, 0xb2, 0x93, 0xb7, 0x37, 0x4f, 0x9e, 0x97, 0x7c, 0xe4, 0x43, 0x57, 0x22, 0x64, 0x84, - 0x2a, 0x95, 0x08, 0x46, 0x33, 0x01, 0xd2, 0x90, 0x4c, 0x53, 0x69, 0x66, 0x5c, 0x93, 0x7c, 0x58, - 0x65, 0x5f, 0x69, 0xc8, 0x00, 0x9f, 0x89, 0x90, 0xf9, 0xbb, 0xb2, 0x5f, 0x09, 0xf9, 0xf0, 0xf4, - 0x38, 0x86, 0x18, 0xac, 0x48, 0x8a, 0x54, 0x76, 0xfa, 0x6f, 0xa8, 0xf1, 0x42, 0x35, 0x4d, 0x0d, - 0xee, 0xa1, 0x43, 0xc3, 0x65, 0x34, 0xe5, 0x92, 0x86, 0x09, 0x8f, 0x3a, 0x6e, 0xd7, 0x1d, 0x1c, - 0x04, 0xad, 0x82, 0x3d, 0x95, 0x08, 0x5f, 0xa2, 0x23, 0xcd, 0x19, 0x17, 0x39, 0xaf, 0xac, 0x3d, - 0x6b, 0xb5, 0xb7, 0x78, 0x2b, 0xf6, 0x29, 0x6a, 0x3f, 0x83, 0xfe, 0xa0, 0x3a, 0x12, 0x32, 0x9e, - 0xc8, 0x19, 0xe0, 0x07, 0x54, 0x9f, 0x83, 0x32, 0x1d, 0xb7, 0x5b, 0x1b, 0xb4, 0x6e, 0x7a, 0xfe, - 0x7f, 0xa3, 0xfa, 0x63, 0x50, 0xa3, 0xfa, 0xf2, 0xe7, 0xc2, 0x09, 0x6c, 0x09, 0x63, 0x54, 0x4f, - 0x79, 0x0a, 0xf6, 0xb1, 0x66, 0x60, 0x73, 0xff, 0x11, 0xd5, 0xc6, 0xa0, 0xf0, 0x09, 0xda, 0x57, - 0xa0, 0xb3, 0xa9, 0x28, 0x07, 0x6e, 0x06, 0x8d, 0xe2, 0x38, 0x89, 0xf0, 0x39, 0x42, 0x6c, 0x4e, - 0xa5, 0xe4, 0x49, 0x71, 0x57, 0x36, 0x9b, 0x5b, 0x32, 0x89, 0x46, 0xaf, 0xcb, 0xb5, 0xe7, 0xae, - 0xd6, 0x9e, 0xfb, 0xbb, 0xf6, 0xdc, 0xaf, 0x8d, 0xe7, 0xac, 0x36, 0x9e, 0xf3, 0xbd, 0xf1, 0x9c, - 0xf7, 0xbb, 0x58, 0x64, 0xf3, 0x45, 0xe8, 0x33, 0x48, 0x09, 0x03, 0x93, 0x82, 0x21, 0x22, 0x64, - 0xd7, 0x31, 0x90, 0xfc, 0x9e, 0xa4, 0x10, 0x2d, 0x12, 0x6e, 0x8a, 0x95, 0xec, 0xac, 0x22, 0xfb, - 0x54, 0xdc, 0x84, 0x0d, 0xfb, 0xa3, 0xb7, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x6b, 0x1c, 0xa2, - 0x4b, 0xb4, 0x01, 0x00, 0x00, + // 324 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0x4b, 0xf3, 0x30, + 0x18, 0xc7, 0xdb, 0x77, 0x63, 0xaf, 0x7b, 0x26, 0x0a, 0x41, 0x70, 0x88, 0xd6, 0x6d, 0x17, 0x07, + 0x62, 0xc3, 0xf4, 0xa0, 0x20, 0x5e, 0x06, 0xca, 0x76, 0xd3, 0xe2, 0x49, 0x90, 0x91, 0xa6, 0xb1, + 0x0b, 0xb4, 0x79, 0x42, 0xd2, 0x55, 0xfc, 0x16, 0x7e, 0xac, 0x1d, 0x77, 0xf4, 0x24, 0xb2, 0x7d, + 0x11, 0x69, 0x3b, 0xc6, 0x4e, 0xde, 0xfe, 0xf9, 0xe5, 0xf7, 0x27, 0x0f, 0x79, 0xe0, 0x5c, 0x86, + 0x9c, 0x32, 0xad, 0x13, 0xc9, 0x59, 0x26, 0x51, 0x59, 0x9a, 0x19, 0xa6, 0xec, 0x9b, 0x30, 0x34, + 0x1f, 0x6c, 0xb2, 0xaf, 0x0d, 0x66, 0x48, 0x8e, 0x65, 0xc8, 0xfd, 0x6d, 0xd9, 0xdf, 0x08, 0xf9, + 0xe0, 0xe8, 0x20, 0xc6, 0x18, 0x4b, 0x91, 0x16, 0xa9, 0xea, 0xf4, 0x9e, 0xa1, 0xf1, 0xc8, 0x0c, + 0x4b, 0x2d, 0xe9, 0xc2, 0xae, 0x15, 0x2a, 0x9a, 0x08, 0xc5, 0xc2, 0x44, 0x44, 0x6d, 0xb7, 0xe3, + 0xf6, 0x77, 0x82, 0x56, 0xc1, 0xee, 0x2b, 0x44, 0xce, 0x60, 0xdf, 0x08, 0x2e, 0x64, 0x2e, 0x36, + 0xd6, 0xbf, 0xd2, 0xda, 0x5b, 0xe3, 0xb5, 0xd8, 0x7b, 0x05, 0x78, 0x40, 0xf3, 0xce, 0x4c, 0x24, + 0x55, 0x4c, 0x6e, 0xa1, 0x3e, 0x45, 0x6d, 0xdb, 0x6e, 0xa7, 0xd6, 0x6f, 0x5d, 0x76, 0xfd, 0xbf, + 0xc6, 0xf4, 0x47, 0xa8, 0x87, 0xf5, 0xf9, 0xf7, 0xa9, 0x13, 0x94, 0x25, 0x42, 0xa0, 0x9e, 0x8a, + 0x14, 0xcb, 0x87, 0x9a, 0x41, 0x99, 0x7b, 0x77, 0x50, 0x1b, 0xa1, 0x26, 0x87, 0xf0, 0x5f, 0xa3, + 0xc9, 0x26, 0xb2, 0x1a, 0xb6, 0x19, 0x34, 0x8a, 0xe3, 0x38, 0x22, 0x27, 0x00, 0x7c, 0xca, 0x94, + 0x12, 0x49, 0x71, 0x57, 0x35, 0x9b, 0x6b, 0x32, 0x8e, 0x86, 0x4f, 0xf3, 0xa5, 0xe7, 0x2e, 0x96, + 0x9e, 0xfb, 0xb3, 0xf4, 0xdc, 0xcf, 0x95, 0xe7, 0x2c, 0x56, 0x9e, 0xf3, 0xb5, 0xf2, 0x9c, 0x97, + 0xeb, 0x58, 0x66, 0xd3, 0x59, 0xe8, 0x73, 0x4c, 0x29, 0x47, 0x9b, 0xa2, 0xa5, 0x32, 0xe4, 0x17, + 0x31, 0xd2, 0xfc, 0x86, 0xa6, 0x18, 0xcd, 0x12, 0x61, 0x8b, 0x75, 0x6c, 0xad, 0x21, 0xfb, 0xd0, + 0xc2, 0x86, 0x8d, 0xf2, 0x37, 0xaf, 0x7e, 0x03, 0x00, 0x00, 0xff, 0xff, 0x95, 0xd0, 0x0d, 0xf6, + 0xb0, 0x01, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -270,7 +270,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *ForwardingInfo) Marshal() (dAtA []byte, err error) { +func (m *Forwarding) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -280,12 +280,12 @@ func (m *ForwardingInfo) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ForwardingInfo) MarshalTo(dAtA []byte) (int, error) { +func (m *Forwarding) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ForwardingInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Forwarding) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -377,7 +377,7 @@ func (m *Params) Size() (n int) { return n } -func (m *ForwardingInfo) Size() (n int) { +func (m *Forwarding) Size() (n int) { if m == nil { return 0 } @@ -509,7 +509,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { } return nil } -func (m *ForwardingInfo) Unmarshal(dAtA []byte) error { +func (m *Forwarding) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -532,10 +532,10 @@ func (m *ForwardingInfo) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ForwardingInfo: wiretype end group for non-group") + return fmt.Errorf("proto: Forwarding: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ForwardingInfo: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Forwarding: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/modules/apps/transfer/types/tx.pb.go b/modules/apps/transfer/types/tx.pb.go index 7550a142816..66acd8c1238 100644 --- a/modules/apps/transfer/types/tx.pb.go +++ b/modules/apps/transfer/types/tx.pb.go @@ -57,7 +57,7 @@ type MsgTransfer struct { // tokens to be transferred Tokens []types.Coin `protobuf:"bytes,9,rep,name=tokens,proto3" json:"tokens"` // optional forwarding information - ForwardingPath *ForwardingInfo `protobuf:"bytes,10,opt,name=forwarding_path,json=forwardingPath,proto3" json:"forwarding_path,omitempty"` + Forwarding *Forwarding `protobuf:"bytes,10,opt,name=forwarding,proto3" json:"forwarding,omitempty"` } func (m *MsgTransfer) Reset() { *m = MsgTransfer{} } @@ -225,50 +225,49 @@ func init() { } var fileDescriptor_7401ed9bed2f8e09 = []byte{ - // 673 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcf, 0x4f, 0x13, 0x4f, - 0x14, 0xef, 0x7e, 0x29, 0xfd, 0xc2, 0x54, 0x40, 0x46, 0x03, 0xcb, 0xc6, 0x6c, 0x9b, 0x46, 0x12, - 0x2c, 0x32, 0x93, 0x62, 0x0c, 0x86, 0x78, 0x2a, 0x89, 0xd1, 0x44, 0x12, 0xdc, 0xc0, 0xc5, 0x0b, - 0x99, 0xdd, 0x0e, 0xbb, 0x13, 0xba, 0x33, 0xeb, 0xcc, 0xb4, 0xea, 0xc5, 0x18, 0x4f, 0xc6, 0x93, - 0xf1, 0x2f, 0xf0, 0xe8, 0x91, 0x3f, 0x83, 0x23, 0x47, 0x4f, 0xc6, 0xc0, 0x81, 0x8b, 0x7f, 0x84, - 0xd9, 0xd9, 0xd9, 0x52, 0x3d, 0x54, 0xbd, 0xb4, 0xf3, 0xde, 0xfb, 0xbc, 0x1f, 0x9f, 0xcf, 0xbe, - 0x3c, 0xb0, 0xca, 0xc2, 0x08, 0x93, 0x2c, 0xeb, 0xb3, 0x88, 0x68, 0x26, 0xb8, 0xc2, 0x5a, 0x12, - 0xae, 0x8e, 0xa8, 0xc4, 0xc3, 0x0e, 0xd6, 0xaf, 0x50, 0x26, 0x85, 0x16, 0xf0, 0x16, 0x0b, 0x23, - 0x34, 0x0e, 0x43, 0x25, 0x0c, 0x0d, 0x3b, 0xde, 0x22, 0x49, 0x19, 0x17, 0xd8, 0xfc, 0x16, 0x09, - 0xde, 0xcd, 0x58, 0xc4, 0xc2, 0x3c, 0x71, 0xfe, 0xb2, 0xde, 0xe5, 0x48, 0xa8, 0x54, 0x28, 0x9c, - 0xaa, 0x38, 0x2f, 0x9f, 0xaa, 0xd8, 0x06, 0x7c, 0x1b, 0x08, 0x89, 0xa2, 0x78, 0xd8, 0x09, 0xa9, - 0x26, 0x1d, 0x1c, 0x09, 0xc6, 0x6d, 0xbc, 0x91, 0x8f, 0x19, 0x09, 0x49, 0x71, 0xd4, 0x67, 0x94, - 0xeb, 0x3c, 0xbb, 0x78, 0x59, 0xc0, 0xfa, 0x64, 0x1e, 0xe5, 0xb0, 0x06, 0xdc, 0xfa, 0x54, 0x05, - 0xf5, 0x5d, 0x15, 0xef, 0x5b, 0x2f, 0x6c, 0x80, 0xba, 0x12, 0x03, 0x19, 0xd1, 0xc3, 0x4c, 0x48, - 0xed, 0x3a, 0x4d, 0x67, 0x6d, 0x36, 0x00, 0x85, 0x6b, 0x4f, 0x48, 0x0d, 0x57, 0xc1, 0xbc, 0x05, - 0x44, 0x09, 0xe1, 0x9c, 0xf6, 0xdd, 0xff, 0x0c, 0x66, 0xae, 0xf0, 0xee, 0x14, 0x4e, 0xf8, 0x10, - 0x4c, 0x6b, 0x71, 0x4c, 0xb9, 0x3b, 0xd5, 0x74, 0xd6, 0xea, 0x9b, 0x2b, 0xa8, 0x60, 0x85, 0x72, - 0x56, 0xc8, 0xb2, 0x42, 0x3b, 0x82, 0xf1, 0x6e, 0xfd, 0xf4, 0x5b, 0xa3, 0xf2, 0xe5, 0xf2, 0xa4, - 0xed, 0xb8, 0x4e, 0x50, 0x24, 0xc1, 0x25, 0x50, 0x53, 0x94, 0xf7, 0xa8, 0x74, 0xab, 0xa6, 0xb8, - 0xb5, 0xa0, 0x07, 0x66, 0x24, 0x8d, 0x28, 0x1b, 0x52, 0xe9, 0x4e, 0x9b, 0xc8, 0xc8, 0x86, 0x4f, - 0xc1, 0xbc, 0x66, 0x29, 0x15, 0x03, 0x7d, 0x98, 0x50, 0x16, 0x27, 0xda, 0xad, 0x99, 0xd6, 0x1e, - 0xca, 0x3f, 0x58, 0x2e, 0x18, 0xb2, 0x32, 0x0d, 0x3b, 0xe8, 0xb1, 0x41, 0x74, 0x67, 0x47, 0xbd, - 0x83, 0x39, 0x9b, 0x5c, 0x44, 0xe0, 0x3a, 0x58, 0x2c, 0xab, 0xe5, 0xff, 0x4a, 0x93, 0x34, 0x73, - 0xff, 0x6f, 0x3a, 0x6b, 0xd5, 0xe0, 0xba, 0x0d, 0xec, 0x97, 0x7e, 0x08, 0x41, 0x35, 0xa5, 0xa9, - 0x70, 0x67, 0xcc, 0x48, 0xe6, 0x0d, 0xb7, 0x40, 0xcd, 0x70, 0x51, 0xee, 0x6c, 0x73, 0x6a, 0xb2, - 0x02, 0xd5, 0x7c, 0x8a, 0xc0, 0xc2, 0xe1, 0x01, 0x58, 0x38, 0x12, 0xf2, 0x25, 0x91, 0x3d, 0xc6, - 0xe3, 0xc3, 0x8c, 0xe8, 0xc4, 0x05, 0x86, 0xc8, 0x5d, 0x34, 0x69, 0xf3, 0xd0, 0xa3, 0x51, 0xd2, - 0x13, 0x7e, 0x24, 0x82, 0xf9, 0xab, 0x22, 0x7b, 0x44, 0x27, 0xdb, 0xed, 0xf7, 0x9f, 0x1b, 0x95, - 0x77, 0x97, 0x27, 0x6d, 0xab, 0xe5, 0x87, 0xcb, 0x93, 0xf6, 0x52, 0x31, 0xd2, 0x86, 0xea, 0x1d, - 0xe3, 0xb1, 0x25, 0x68, 0x6d, 0x81, 0x1b, 0x63, 0x66, 0x40, 0x55, 0x26, 0xb8, 0xa2, 0xb9, 0xfa, - 0x8a, 0xbe, 0x18, 0x50, 0x1e, 0x51, 0xb3, 0x18, 0xd5, 0x60, 0x64, 0x6f, 0x57, 0xf3, 0xf2, 0xad, - 0x37, 0x60, 0x61, 0x57, 0xc5, 0x07, 0x59, 0x8f, 0x68, 0xba, 0x47, 0x24, 0x49, 0x95, 0xf9, 0x94, - 0x2c, 0xe6, 0x54, 0xda, 0x5d, 0xb2, 0x16, 0xec, 0x82, 0x5a, 0x66, 0x10, 0x66, 0x7f, 0xea, 0x9b, - 0xb7, 0x27, 0xb3, 0x2b, 0xaa, 0x95, 0x52, 0x15, 0x99, 0xdb, 0x0b, 0x57, 0x9c, 0x4c, 0xd1, 0xd6, - 0x0a, 0x58, 0xfe, 0xad, 0x7f, 0x39, 0xfc, 0xe6, 0x0f, 0x07, 0x4c, 0xed, 0xaa, 0x18, 0x26, 0x60, - 0x66, 0xb4, 0xec, 0x77, 0x26, 0xf7, 0x1c, 0xd3, 0xc0, 0xeb, 0xfc, 0x35, 0x74, 0x24, 0x97, 0x06, - 0xd7, 0x7e, 0x51, 0x62, 0xe3, 0x8f, 0x25, 0xc6, 0xe1, 0xde, 0xfd, 0x7f, 0x82, 0x97, 0x5d, 0xbd, - 0xe9, 0xb7, 0xf9, 0x3a, 0x77, 0x9f, 0x9d, 0x9e, 0xfb, 0xce, 0xd9, 0xb9, 0xef, 0x7c, 0x3f, 0xf7, - 0x9d, 0x8f, 0x17, 0x7e, 0xe5, 0xec, 0xc2, 0xaf, 0x7c, 0xbd, 0xf0, 0x2b, 0xcf, 0xb7, 0x62, 0xa6, - 0x93, 0x41, 0x88, 0x22, 0x91, 0x62, 0x7b, 0x6a, 0x58, 0x18, 0x6d, 0xc4, 0x02, 0x0f, 0x1f, 0xe0, - 0x54, 0xf4, 0x06, 0x7d, 0xaa, 0xf2, 0xf3, 0x31, 0x76, 0x36, 0xf4, 0xeb, 0x8c, 0xaa, 0xb0, 0x66, - 0x2e, 0xc6, 0xbd, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xec, 0xa3, 0x95, 0xc7, 0x28, 0x05, 0x00, - 0x00, + // 659 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4f, 0x6f, 0xd3, 0x30, + 0x14, 0x6f, 0x58, 0x57, 0x36, 0x97, 0x6d, 0xcc, 0xa0, 0x2d, 0x8b, 0x50, 0x5a, 0x55, 0x4c, 0x2a, + 0x9d, 0x66, 0xab, 0x43, 0x68, 0x68, 0xe2, 0xd4, 0x49, 0x68, 0x07, 0x26, 0x8d, 0x68, 0x5c, 0xb8, + 0x4c, 0x49, 0xea, 0xa5, 0xd6, 0x1a, 0x3b, 0xd8, 0x6e, 0x81, 0x0b, 0x42, 0x48, 0x48, 0x88, 0x13, + 0x1f, 0x81, 0x23, 0xc7, 0x7d, 0x8c, 0x1d, 0x77, 0xe4, 0x84, 0xd0, 0x76, 0xd8, 0x85, 0x0f, 0x81, + 0xec, 0x38, 0x25, 0x70, 0x28, 0x70, 0x49, 0xfc, 0xde, 0xfb, 0xbd, 0x3f, 0xbf, 0x9f, 0x9f, 0x0c, + 0xd6, 0x69, 0x14, 0xe3, 0x30, 0xcb, 0x86, 0x34, 0x0e, 0x15, 0xe5, 0x4c, 0x62, 0x25, 0x42, 0x26, + 0x8f, 0x89, 0xc0, 0xe3, 0x2e, 0x56, 0xaf, 0x50, 0x26, 0xb8, 0xe2, 0xf0, 0x0e, 0x8d, 0x62, 0x54, + 0x86, 0xa1, 0x02, 0x86, 0xc6, 0x5d, 0x6f, 0x39, 0x4c, 0x29, 0xe3, 0xd8, 0x7c, 0xf3, 0x04, 0xef, + 0x76, 0xc2, 0x13, 0x6e, 0x8e, 0x58, 0x9f, 0xac, 0x77, 0x35, 0xe6, 0x32, 0xe5, 0x12, 0xa7, 0x32, + 0xd1, 0xe5, 0x53, 0x99, 0xd8, 0x80, 0x6f, 0x03, 0x51, 0x28, 0x09, 0x1e, 0x77, 0x23, 0xa2, 0xc2, + 0x2e, 0x8e, 0x39, 0x65, 0x36, 0xde, 0xd0, 0x63, 0xc6, 0x5c, 0x10, 0x1c, 0x0f, 0x29, 0x61, 0x4a, + 0x67, 0xe7, 0x27, 0x0b, 0xd8, 0x98, 0xce, 0xa3, 0x18, 0xd6, 0x80, 0x5b, 0xef, 0xab, 0xa0, 0xbe, + 0x2f, 0x93, 0x43, 0xeb, 0x85, 0x0d, 0x50, 0x97, 0x7c, 0x24, 0x62, 0x72, 0x94, 0x71, 0xa1, 0x5c, + 0xa7, 0xe9, 0xb4, 0xe7, 0x03, 0x90, 0xbb, 0x0e, 0xb8, 0x50, 0x70, 0x1d, 0x2c, 0x5a, 0x40, 0x3c, + 0x08, 0x19, 0x23, 0x43, 0xf7, 0x9a, 0xc1, 0x2c, 0xe4, 0xde, 0xdd, 0xdc, 0x09, 0x1f, 0x81, 0x59, + 0xc5, 0x4f, 0x08, 0x73, 0x67, 0x9a, 0x4e, 0xbb, 0xbe, 0xb5, 0x86, 0x72, 0x56, 0x48, 0xb3, 0x42, + 0x96, 0x15, 0xda, 0xe5, 0x94, 0xf5, 0xea, 0x67, 0xdf, 0x1a, 0x95, 0x2f, 0x57, 0xa7, 0x1d, 0xc7, + 0x75, 0x82, 0x3c, 0x09, 0xae, 0x80, 0x9a, 0x24, 0xac, 0x4f, 0x84, 0x5b, 0x35, 0xc5, 0xad, 0x05, + 0x3d, 0x30, 0x27, 0x48, 0x4c, 0xe8, 0x98, 0x08, 0x77, 0xd6, 0x44, 0x26, 0x36, 0x7c, 0x02, 0x16, + 0x15, 0x4d, 0x09, 0x1f, 0xa9, 0xa3, 0x01, 0xa1, 0xc9, 0x40, 0xb9, 0x35, 0xd3, 0xda, 0x43, 0xfa, + 0xc2, 0xb4, 0x60, 0xc8, 0xca, 0x34, 0xee, 0xa2, 0x3d, 0x83, 0xe8, 0xcd, 0x4f, 0x7a, 0x07, 0x0b, + 0x36, 0x39, 0x8f, 0xc0, 0x0d, 0xb0, 0x5c, 0x54, 0xd3, 0x7f, 0xa9, 0xc2, 0x34, 0x73, 0xaf, 0x37, + 0x9d, 0x76, 0x35, 0xb8, 0x69, 0x03, 0x87, 0x85, 0x1f, 0x42, 0x50, 0x4d, 0x49, 0xca, 0xdd, 0x39, + 0x33, 0x92, 0x39, 0xc3, 0x6d, 0x50, 0x33, 0x5c, 0xa4, 0x3b, 0xdf, 0x9c, 0x99, 0xae, 0x40, 0x55, + 0x4f, 0x11, 0x58, 0x38, 0xdc, 0x03, 0xe0, 0x98, 0x8b, 0x97, 0xa1, 0xe8, 0x53, 0x96, 0xb8, 0xc0, + 0x70, 0x68, 0xa3, 0x69, 0x4b, 0x87, 0x1e, 0x4f, 0xf0, 0x41, 0x29, 0x77, 0xa7, 0xf3, 0xe1, 0x73, + 0xa3, 0xf2, 0xee, 0xea, 0xb4, 0x63, 0xe5, 0xfb, 0x78, 0x75, 0xda, 0x59, 0xc9, 0xa7, 0xd8, 0x94, + 0xfd, 0x13, 0x5c, 0xba, 0xf7, 0xd6, 0x36, 0xb8, 0x55, 0x32, 0x03, 0x22, 0x33, 0xce, 0x24, 0xd1, + 0x82, 0x4b, 0xf2, 0x62, 0x44, 0x58, 0x4c, 0xcc, 0x2e, 0x54, 0x83, 0x89, 0xbd, 0x53, 0xd5, 0xe5, + 0x5b, 0x6f, 0xc0, 0xd2, 0xbe, 0x4c, 0x9e, 0x65, 0xfd, 0x50, 0x91, 0x83, 0x50, 0x84, 0xa9, 0x34, + 0xb7, 0x47, 0x13, 0x46, 0x84, 0x5d, 0x1f, 0x6b, 0xc1, 0x1e, 0xa8, 0x65, 0x06, 0x61, 0x56, 0xa6, + 0xbe, 0x75, 0x77, 0x3a, 0xab, 0xbc, 0x5a, 0xa1, 0x4e, 0x9e, 0xb9, 0xb3, 0xf4, 0x8b, 0x93, 0x29, + 0xda, 0x5a, 0x03, 0xab, 0x7f, 0xf4, 0x2f, 0x86, 0xdf, 0xfa, 0xe1, 0x80, 0x99, 0x7d, 0x99, 0xc0, + 0x01, 0x98, 0x9b, 0xec, 0xf7, 0xbd, 0xe9, 0x3d, 0x4b, 0x1a, 0x78, 0xdd, 0x7f, 0x86, 0x4e, 0xe4, + 0x52, 0xe0, 0xc6, 0x6f, 0x4a, 0x6c, 0xfe, 0xb5, 0x44, 0x19, 0xee, 0x3d, 0xf8, 0x2f, 0x78, 0xd1, + 0xd5, 0x9b, 0x7d, 0xab, 0x37, 0xb8, 0xf7, 0xf4, 0xec, 0xc2, 0x77, 0xce, 0x2f, 0x7c, 0xe7, 0xfb, + 0x85, 0xef, 0x7c, 0xba, 0xf4, 0x2b, 0xe7, 0x97, 0x7e, 0xe5, 0xeb, 0xa5, 0x5f, 0x79, 0xbe, 0x9d, + 0x50, 0x35, 0x18, 0x45, 0x28, 0xe6, 0x29, 0xb6, 0xaf, 0x0b, 0x8d, 0xe2, 0xcd, 0x84, 0xe3, 0xf1, + 0x43, 0x9c, 0xf2, 0xfe, 0x68, 0x48, 0xa4, 0x7e, 0x31, 0x4a, 0x2f, 0x85, 0x7a, 0x9d, 0x11, 0x19, + 0xd5, 0xcc, 0x23, 0x71, 0xff, 0x67, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x2c, 0x89, 0xb7, 0x1b, + 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -411,9 +410,9 @@ func (m *MsgTransfer) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.ForwardingPath != nil { + if m.Forwarding != nil { { - size, err := m.ForwardingPath.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Forwarding.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -641,8 +640,8 @@ func (m *MsgTransfer) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } - if m.ForwardingPath != nil { - l = m.ForwardingPath.Size() + if m.Forwarding != nil { + l = m.Forwarding.Size() n += 1 + l + sovTx(uint64(l)) } return n @@ -1000,7 +999,7 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 10: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ForwardingPath", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Forwarding", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1027,10 +1026,10 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.ForwardingPath == nil { - m.ForwardingPath = &ForwardingInfo{} + if m.Forwarding == nil { + m.Forwarding = &Forwarding{} } - if err := m.ForwardingPath.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Forwarding.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index 2eac86c7f6c..8e3456e3a29 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -19,10 +19,10 @@ message Params { bool receive_enabled = 2; } -// ForwardingInfo defines a list of port ID, channel ID pairs determining the path +// Forwarding defines a list of port ID, channel ID pairs determining the path // through which a packet must be forwarded, and the memo string to be used in the // final destination of the tokens. -message ForwardingInfo { +message Forwarding { repeated Hop hops = 1 [(gogoproto.nullable) = false]; string memo = 2; } diff --git a/proto/ibc/applications/transfer/v1/tx.proto b/proto/ibc/applications/transfer/v1/tx.proto index 4caf0273b2c..0a1c8d49d8c 100644 --- a/proto/ibc/applications/transfer/v1/tx.proto +++ b/proto/ibc/applications/transfer/v1/tx.proto @@ -52,7 +52,7 @@ message MsgTransfer { // tokens to be transferred repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false]; // optional forwarding information - ForwardingInfo forwarding_path = 10; + Forwarding forwarding = 10; } // MsgTransferResponse defines the Msg/Transfer response type. diff --git a/proto/ibc/applications/transfer/v2/packet.proto b/proto/ibc/applications/transfer/v2/packet.proto index 702be8b2ffe..a2948f5b996 100644 --- a/proto/ibc/applications/transfer/v2/packet.proto +++ b/proto/ibc/applications/transfer/v2/packet.proto @@ -37,5 +37,5 @@ message FungibleTokenPacketDataV2 { // optional memo string memo = 4; // optional forwarding information - ibc.applications.transfer.v1.ForwardingInfo forwarding_path = 5; + ibc.applications.transfer.v1.Forwarding forwarding = 5; } From d874b54bce51e705beea0c6667ad0e6e5f8bdfe7 Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Thu, 13 Jun 2024 13:11:40 +0100 Subject: [PATCH 072/141] Refactor packet forward functions (#6575) --- modules/apps/transfer/keeper/forwarding.go | 57 +++++++++++++++++++++- modules/apps/transfer/keeper/relay.go | 48 ++---------------- modules/apps/transfer/types/packet.go | 5 ++ 3 files changed, 65 insertions(+), 45 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 52e31e6d606..dab78bb32a5 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/transfer/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" ) // ackForwardPacketError reverts the receive packet logic that occurs in the middle chain and writes the async ack for the prevPacket @@ -38,8 +39,6 @@ func (k Keeper) ackForwardPacketTimeout(ctx sdk.Context, prevPacket channeltypes return err } - // the timeout is converted into an error acknowledgement in order to propagate the failed packet forwarding - // back to the original sender forwardAck := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet timed out")) return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) } @@ -97,3 +96,57 @@ func (k Keeper) revertForwardedPacket(ctx sdk.Context, prevPacket channeltypes.P } return nil } + +// forwardPacket forwards a fungible FungibleTokenPacketDataV2 to the next hop in the forwarding path. +func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDataV2, packet channeltypes.Packet, receivedCoins sdk.Coins) error { + var memo string + + var nextForwardingPath *types.Forwarding + if len(data.Forwarding.Hops) == 1 { + memo = data.Forwarding.Memo + nextForwardingPath = nil + } else { + nextForwardingPath = &types.Forwarding{ + Hops: data.Forwarding.Hops[1:], + Memo: data.Forwarding.Memo, + } + } + + // sending from the forward escrow address to the original receiver address. + sender := types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) + + msg := types.NewMsgTransfer( + data.Forwarding.Hops[0].PortId, + data.Forwarding.Hops[0].ChannelId, + receivedCoins, + sender.String(), + data.Receiver, + packet.TimeoutHeight, + packet.TimeoutTimestamp, + memo, + nextForwardingPath, + ) + + resp, err := k.Transfer(ctx, msg) + if err != nil { + return err + } + + k.SetForwardedPacket(ctx, data.Forwarding.Hops[0].PortId, data.Forwarding.Hops[0].ChannelId, resp.Sequence, packet) + return nil +} + +// getReceiverFromPacketData returns either the sender specified in the packet data or the forwarding address +// if there are still hops left to perform. +func getReceiverFromPacketData(data types.FungibleTokenPacketDataV2, portID, channelID string) (sdk.AccAddress, error) { + receiver, err := sdk.AccAddressFromBech32(data.Receiver) + if err != nil { + return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "failed to decode receiver address %s: %v", data.Receiver, err) + } + + if data.ShouldBeForwarded() { + receiver = types.GetForwardAddress(portID, channelID) + } + + return receiver, nil +} diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 928dca8121a..8b58787170d 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -169,19 +169,9 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return false, types.ErrReceiveDisabled } - var ( - err error - receiver sdk.AccAddress // final receiver of tokens if there is no forwarding, otherwise, receiver in the next hop - finalReceiver sdk.AccAddress // final receiver of tokens if there is forwarding - ) - - receiver, err = sdk.AccAddressFromBech32(data.Receiver) + receiver, err := getReceiverFromPacketData(data, packet.DestinationPort, packet.DestinationChannel) if err != nil { - return false, errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "failed to decode receiver address %s: %v", data.Receiver, err) - } - if data.Forwarding != nil && len(data.Forwarding.Hops) > 0 { - finalReceiver = receiver // , _ = sdk.AccAddressFromBech32(data.Receiver) - receiver = types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) + return false, err } var receivedCoins sdk.Coins @@ -272,39 +262,11 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t receivedCoins = append(receivedCoins, voucher) } - // Adding forwarding logic - if data.Forwarding != nil && len(data.Forwarding.Hops) > 0 { - memo := "" - - var nextForwarding *types.Forwarding - if len(data.Forwarding.Hops) == 1 { - memo = data.Forwarding.Memo - nextForwarding = nil - } else { - nextForwarding = &types.Forwarding{ - Hops: data.Forwarding.Hops[1:], - Memo: data.Forwarding.Memo, - } - } - - msg := types.NewMsgTransfer( - data.Forwarding.Hops[0].PortId, - data.Forwarding.Hops[0].ChannelId, - receivedCoins, - receiver.String(), - finalReceiver.String(), - packet.TimeoutHeight, - packet.TimeoutTimestamp, - memo, - nextForwarding, - ) - - resp, err := k.Transfer(ctx, msg) - if err != nil { + if data.ShouldBeForwarded() { + // we are now sending from the forward escrow address to the final receiver address. + if err := k.forwardPacket(ctx, data, packet, receivedCoins); err != nil { return false, err } - - k.SetForwardedPacket(ctx, data.Forwarding.Hops[0].PortId, data.Forwarding.Hops[0].ChannelId, resp.Sequence, packet) return true, nil } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index fa1a45fadec..b00ccc6e957 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -196,3 +196,8 @@ func (ftpd FungibleTokenPacketDataV2) GetCustomPacketData(key string) interface{ func (ftpd FungibleTokenPacketDataV2) GetPacketSender(sourcePortID string) string { return ftpd.Sender } + +// ShouldBeForwarded determines if the packet should be forwarded to the next hop. +func (ftpd FungibleTokenPacketDataV2) ShouldBeForwarded() bool { + return ftpd.Forwarding != nil && len(ftpd.Forwarding.Hops) > 0 +} From fbb9cd8a5c2e09c2c0ff7f208c1705988a9ec55e Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Thu, 13 Jun 2024 16:14:41 +0200 Subject: [PATCH 073/141] feat(transfer): validate forwarding memo in transfer authorization (#6591) --- .../transfer/types/transfer_authorization.go | 9 ++- .../types/transfer_authorization_test.go | 68 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index 01bcafb48c6..8d8ca7dbcaf 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -58,8 +58,13 @@ func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) return authz.AcceptResponse{}, errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "not allowed receiver address for transfer") } - err := validateMemo(ctx, msgTransfer.Memo, a.Allocations[index].AllowedPacketData) - if err != nil { + memo := msgTransfer.Memo + // in the case of forwarded transfers, the actual memo is stored in the forwarding path until the final destination + if msgTransfer.Forwarding != nil && len(msgTransfer.Forwarding.Hops) > 0 { + memo = msgTransfer.Forwarding.Memo + } + + if err := validateMemo(ctx, memo, a.Allocations[index].AllowedPacketData); err != nil { return authz.AcceptResponse{}, err } diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index 8aee601173c..718d299aac5 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -99,6 +99,21 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Nil(res.Updated) }, }, + { + "success: empty AllowedPacketData and empty memo in forwarding path", + func() { + allowedList := []string{} + transferAuthz.Allocations[0].AllowedPacketData = allowedList + msgTransfer.Forwarding = types.NewForwarding("", validHop) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().True(res.Delete) + suite.Require().Nil(res.Updated) + }, + }, { "success: AllowedPacketData allows any packet", func() { @@ -114,6 +129,21 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Nil(res.Updated) }, }, + { + "success: AllowedPacketData allows any packet in forwarding path", + func() { + allowedList := []string{"*"} + transferAuthz.Allocations[0].AllowedPacketData = allowedList + msgTransfer.Forwarding = types.NewForwarding(testMemo1, validHop) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().True(res.Delete) + suite.Require().Nil(res.Updated) + }, + }, { "success: transfer memo allowed", func() { @@ -129,6 +159,21 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Nil(res.Updated) }, }, + { + "success: transfer memo allowed in forwarding path", + func() { + allowedList := []string{testMemo1, testMemo2} + transferAuthz.Allocations[0].AllowedPacketData = allowedList + msgTransfer.Forwarding = types.NewForwarding(testMemo1, validHop) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + + suite.Require().True(res.Accept) + suite.Require().True(res.Delete) + suite.Require().Nil(res.Updated) + }, + }, { "empty AllowedPacketData but not empty memo", func() { @@ -140,6 +185,17 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Error(err) }, }, + { + "empty AllowedPacketData but not empty memo in forwarding path", + func() { + allowedList := []string{} + transferAuthz.Allocations[0].AllowedPacketData = allowedList + msgTransfer.Forwarding = types.NewForwarding(testMemo1, validHop) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + }, + }, { "memo not allowed", func() { @@ -152,6 +208,18 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().ErrorContains(err, fmt.Sprintf("not allowed memo: %s", testMemo2)) }, }, + { + "memo not allowed in forwarding path", + func() { + allowedList := []string{testMemo1} + transferAuthz.Allocations[0].AllowedPacketData = allowedList + msgTransfer.Forwarding = types.NewForwarding(testMemo2, validHop) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + suite.Require().ErrorContains(err, fmt.Sprintf("not allowed memo: %s", testMemo2)) + }, + }, { "test multiple coins does not overspend", func() { From c4987a762c89815655494efdd1f05475e9f5e64e Mon Sep 17 00:00:00 2001 From: Maintain Date: Fri, 14 Jun 2024 20:21:19 +0700 Subject: [PATCH 074/141] Add func convert token to coin ibc (#6584) * add func convert token to coin ibc * fix command: change func to ToCoin and add godoc * add unit test * Revert using ToCoin on Recv where trace manipulation occurs. Use ToCoin while forwarding. Update tests as per Carlos's review. * rename variable --------- Co-authored-by: Carlos Rodriguez Co-authored-by: DimitrisJim --- modules/apps/transfer/keeper/forwarding.go | 8 ++-- modules/apps/transfer/keeper/relay.go | 8 ++-- modules/apps/transfer/types/token.go | 17 +++++++ modules/apps/transfer/types/token_test.go | 53 ++++++++++++++++++++++ 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index dab78bb32a5..adc9449807c 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -4,7 +4,6 @@ import ( "errors" errorsmod "cosmossdk.io/errors" - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" @@ -72,11 +71,10 @@ func (k Keeper) revertForwardedPacket(ctx sdk.Context, prevPacket channeltypes.P // we can iterate over the received tokens of prevPacket by iterating over the sent tokens of failedPacketData for _, token := range failedPacketData.Tokens { // parse the transfer amount - transferAmount, ok := sdkmath.NewIntFromString(token.Amount) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", transferAmount) + coin, err := token.ToCoin() + if err != nil { + return err } - coin := sdk.NewCoin(token.Denom.IBCDenom(), transferAmount) // check if the token we received originated on the sender // given that the packet is being reversed, we check the DestinationChannel and DestinationPort diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 8b58787170d..2cefe2b4f5e 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -331,13 +331,11 @@ func (k Keeper) refundPacketTokens(ctx sdk.Context, packet channeltypes.Packet, // NOTE: packet data type already checked in handler.go for _, token := range data.Tokens { - transferAmount, ok := sdkmath.NewIntFromString(token.Amount) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", transferAmount) + coin, err := token.ToCoin() + if err != nil { + return err } - coin := sdk.NewCoin(token.Denom.IBCDenom(), transferAmount) - sender, err := sdk.AccAddressFromBech32(data.Sender) if err != nil { return err diff --git a/modules/apps/transfer/types/token.go b/modules/apps/transfer/types/token.go index 58a1eec402f..0f8b361516d 100644 --- a/modules/apps/transfer/types/token.go +++ b/modules/apps/transfer/types/token.go @@ -3,6 +3,8 @@ package types import ( errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" ) // Tokens is a slice of Tokens @@ -25,3 +27,18 @@ func (t Token) Validate() error { return nil } + +// ToCoin converts a Token to an sdk.Coin. +// +// The function parses the Amount field of the Token into an sdkmath.Int and returns a new sdk.Coin with +// the IBCDenom of the Token's Denom field and the parsed Amount. +// If the Amount cannot be parsed, an error is returned with a wrapped error message. +func (t Token) ToCoin() (sdk.Coin, error) { + transferAmount, ok := sdkmath.NewIntFromString(t.Amount) + if !ok { + return sdk.Coin{}, errorsmod.Wrapf(ErrInvalidAmount, "unable to parse transfer amount (%s) into math.Int", transferAmount) + } + + coin := sdk.NewCoin(t.Denom.IBCDenom(), transferAmount) + return coin, nil +} diff --git a/modules/apps/transfer/types/token_test.go b/modules/apps/transfer/types/token_test.go index 85f529a2e50..3c9a2f550d6 100644 --- a/modules/apps/transfer/types/token_test.go +++ b/modules/apps/transfer/types/token_test.go @@ -5,6 +5,10 @@ import ( "testing" "github.com/stretchr/testify/require" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" ) const ( @@ -149,3 +153,52 @@ func TestValidate(t *testing.T) { }) } } + +func TestToCoin(t *testing.T) { + testCases := []struct { + name string + token Token + expCoin sdk.Coin + expError error + }{ + { + "success: convert token to coin", + Token{ + Denom: Denom{ + Base: denom, + Trace: []Trace{}, + }, + Amount: amount, + }, + sdk.NewCoin(denom, sdkmath.NewInt(100)), + nil, + }, + { + "failure: invalid amount string", + Token{ + Denom: Denom{ + Base: denom, + Trace: []Trace{}, + }, + Amount: "value", + }, + sdk.Coin{}, + ErrInvalidAmount, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + coin, err := tc.token.ToCoin() + + require.Equal(t, tc.expCoin, coin, tc.name) + + expPass := tc.expError == nil + if expPass { + require.NoError(t, err, tc.name) + } else { + require.ErrorContains(t, err, tc.expError.Error(), tc.name) + } + }) + } +} From a90b6719092a315f4d271c78584248d07da47b03 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Fri, 14 Jun 2024 16:53:34 +0300 Subject: [PATCH 075/141] transfer: Disallow a forwarding object specified with zero hops and a memo (#6599) * transfer: Disallow a forwarding object specified with zero hops and a memo. * Apply suggestions from code review Co-authored-by: Carlos Rodriguez --------- Co-authored-by: Carlos Rodriguez Co-authored-by: Gjermund Garaba --- modules/apps/transfer/types/forwarding.go | 12 ++++++++---- modules/apps/transfer/types/forwarding_test.go | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/modules/apps/transfer/types/forwarding.go b/modules/apps/transfer/types/forwarding.go index 53ebbb456bc..21d1e634068 100644 --- a/modules/apps/transfer/types/forwarding.go +++ b/modules/apps/transfer/types/forwarding.go @@ -22,6 +22,14 @@ func (fi Forwarding) Validate() error { return errorsmod.Wrapf(ErrInvalidForwarding, "number of hops in forwarding path cannot exceed %d", MaximumNumberOfForwardingHops) } + if len(fi.Memo) > MaximumMemoLength { + return errorsmod.Wrapf(ErrInvalidMemo, "memo length cannot exceed %d", MaximumMemoLength) + } + + if len(fi.Hops) == 0 && fi.Memo != "" { + return errorsmod.Wrap(ErrInvalidForwarding, "memo specified when forwarding hops is empty") + } + for _, hop := range fi.Hops { if err := host.PortIdentifierValidator(hop.PortId); err != nil { return errorsmod.Wrapf(err, "invalid source port ID %s", hop.PortId) @@ -31,9 +39,5 @@ func (fi Forwarding) Validate() error { } } - if len(fi.Memo) > MaximumMemoLength { - return errorsmod.Wrapf(ErrInvalidMemo, "memo length cannot exceed %d", MaximumMemoLength) - } - return nil } diff --git a/modules/apps/transfer/types/forwarding_test.go b/modules/apps/transfer/types/forwarding_test.go index fd1df5ea05b..d9283164cf7 100644 --- a/modules/apps/transfer/types/forwarding_test.go +++ b/modules/apps/transfer/types/forwarding_test.go @@ -56,6 +56,11 @@ func TestForwarding_Validate(t *testing.T) { types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), types.ErrInvalidMemo, }, + { + "invalid forwarding with empty hops and specified memo", + types.NewForwarding("memo"), + types.ErrInvalidForwarding, + }, { "invalid forwarding with too short hop port ID", types.NewForwarding( From c348732c93abe6bb13e0e9520d04194b80e0599e Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Fri, 14 Jun 2024 17:46:30 +0200 Subject: [PATCH 076/141] feat(transfer): move async decision and handling to the ibc module onrecv callback (#6592) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: initial simplification attempt * refactor: further organize * fix: all tests fixed * chore: refactor packet forward functions * chore: use receiver address directly in msg transfer * feat(transfer): move async to ibc_module for onrecv * chore: fix linter * fix: logic and testing error * style: self suggestion * docs: suggestion * docs: spellcheck * style: suggestions * style: renamed to revertForwardedPacket * style: suggestion * docs: remove docs * Added tests for transfer OnRecv * Use new names and methods from feature branch * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Clean up test from cr feedback * move vars to beginning of function * lint * Update modules/apps/transfer/ibc_module.go Co-authored-by: Carlos Rodriguez * lint --------- Co-authored-by: srdtrk Co-authored-by: chatton Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: Carlos Rodriguez Co-authored-by: DimitrisJim --- modules/apps/transfer/ibc_module.go | 42 +++--- modules/apps/transfer/ibc_module_test.go | 131 ++++++++++++++++++ .../apps/transfer/internal/events/events.go | 2 +- .../apps/transfer/keeper/mbt_relay_test.go | 4 +- modules/apps/transfer/keeper/relay.go | 23 ++- .../transfer/keeper/relay_forwarding_test.go | 7 +- modules/apps/transfer/keeper/relay_test.go | 11 +- 7 files changed, 173 insertions(+), 47 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 4acacac2865..266d100f9af 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -178,39 +178,43 @@ func (IBCModule) OnChanCloseConfirm( // 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. +// Return nil to signal that the acknowledgement will be written asynchronously. func (im IBCModule) OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress, ) ibcexported.Acknowledgement { + var ( + ackErr error + data types.FungibleTokenPacketDataV2 + ) + ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - data, ackErr := im.getICS20PacketData(ctx, packet.GetData(), packet.GetDestPort(), packet.GetDestChannel()) + defer func() { + events.EmitOnRecvPacketEvent(ctx, data, ack, ackErr) + }() + + data, ackErr = im.getICS20PacketData(ctx, packet.GetData(), packet.GetDestPort(), packet.GetDestChannel()) if ackErr != nil { ackErr = errorsmod.Wrapf(ibcerrors.ErrInvalidType, ackErr.Error()) - im.keeper.Logger(ctx).Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence)) ack = channeltypes.NewErrorAcknowledgement(ackErr) + im.keeper.Logger(ctx).Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence)) + return ack } - // only attempt the application logic if the packet data - // was successfully decoded - if ack.Success() { - async, err := im.keeper.OnRecvPacket(ctx, packet, data) - if err != nil { - ack = channeltypes.NewErrorAcknowledgement(err) - ackErr = err - im.keeper.Logger(ctx).Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence)) - } else { - im.keeper.Logger(ctx).Info("successfully handled ICS-20 packet", "sequence", packet.Sequence) - } - - if async { - // NOTE: acknowledgement will be written asynchronously - return nil - } + 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 } - events.EmitOnRecvPacketEvent(ctx, data, ack, ackErr) + im.keeper.Logger(ctx).Info("successfully handled ICS-20 packet", "sequence", packet.Sequence) + + if data.Forwarding != nil { + // NOTE: acknowledgement will be written asynchronously + return nil + } // NOTE: acknowledgement will be written synchronously during IBC handler execution. return ack diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 73e09023580..f4e02a8e06f 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -1,6 +1,7 @@ package transfer_test import ( + "encoding/json" "errors" "math" @@ -12,11 +13,13 @@ import ( 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" ) @@ -273,6 +276,134 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() { } } +func (suite *TransferTestSuite) TestOnRecvPacket() { + // This test suite mostly covers the top-level logic of the ibc module OnRecvPacket function + // The core logic is covered in keeper OnRecvPacket + var packet channeltypes.Packet + var expectedAttributes []sdk.Attribute + testCases := []struct { + name string + malleate func() + expAck exported.Acknowledgement + expEventErrorMsg string + }{ + { + "success", func() {}, channeltypes.NewResultAcknowledgement([]byte{byte(1)}), "", + }, + { + "success: async aknowledgment with forwarding path", + func() { + packetData := types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: types.NewDenom(sdk.DefaultBondDenom), + Amount: sdkmath.NewInt(100).String(), + }, + }, + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + "", + types.NewForwarding("", types.Hop{PortId: "transfer", ChannelId: "channel-0"}), + ) + packet.Data = packetData.GetBytes() + }, + nil, + "", + }, + { + "failure: invalid packet data bytes", + func() { + packet.Data = []byte("invalid data") + + // Override expected attributes because this fails on unmarshaling packet data (so can't get the attributes) + expectedAttributes = []sdk.Attribute{ + sdk.NewAttribute(types.AttributeKeySender, ""), + sdk.NewAttribute(types.AttributeKeyReceiver, ""), + sdk.NewAttribute(types.AttributeKeyTokens, "null"), + sdk.NewAttribute(types.AttributeKeyMemo, ""), + sdk.NewAttribute(types.AttributeKeyAckSuccess, "false"), + sdk.NewAttribute(types.AttributeKeyAckError, "cannot unmarshal ICS20-V2 transfer packet data: invalid character 'i' looking for beginning of value: invalid type: invalid type"), + } + }, + channeltypes.NewErrorAcknowledgement(ibcerrors.ErrInvalidType), + "cannot unmarshal ICS20-V2 transfer packet data: invalid character 'i' looking for beginning of value: invalid type: invalid type", + }, + { + "failure: receive disabled", + func() { + suite.chainA.GetSimApp().TransferKeeper.SetParams(suite.chainA.GetContext(), types.Params{SendEnabled: false}) + }, + channeltypes.NewErrorAcknowledgement(types.ErrReceiveDisabled), + "fungible token transfers to this chain are disabled", + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path.Setup() + + packetData := types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: types.NewDenom(sdk.DefaultBondDenom), + Amount: sdkmath.NewInt(100).String(), + }, + }, + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + "", + nil, + ) + + tokensBz, err := json.Marshal(packetData.Tokens) + suite.Require().NoError(err) + expectedAttributes = []sdk.Attribute{ + sdk.NewAttribute(types.AttributeKeySender, packetData.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver), + sdk.NewAttribute(types.AttributeKeyTokens, string(tokensBz)), + sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), + } + if tc.expAck == nil || tc.expAck.Success() { + expectedAttributes = append(expectedAttributes, sdk.NewAttribute(types.AttributeKeyAckSuccess, "true")) + } else { + expectedAttributes = append(expectedAttributes, + sdk.NewAttribute(types.AttributeKeyAckSuccess, "false"), + sdk.NewAttribute(types.AttributeKeyAckError, tc.expEventErrorMsg), + ) + } + + seq := uint64(1) + packet = channeltypes.NewPacket(packetData.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) + + 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() // change fields in packet + + ctx := suite.chainA.GetContext() + ack := cbs.OnRecvPacket(ctx, packet, suite.chainA.SenderAccount.GetAddress()) + + suite.Require().Equal(tc.expAck, ack) + + expectedEvents := sdk.Events{ + sdk.NewEvent( + types.EventTypePacket, + expectedAttributes..., + ), + }.ToABCIEvents() + + expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{}) + ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents()) + }) + } +} + func (suite *TransferTestSuite) TestOnTimeoutPacket() { var path *ibctesting.Path var packet channeltypes.Packet diff --git a/modules/apps/transfer/internal/events/events.go b/modules/apps/transfer/internal/events/events.go index 4f1fd0b64f3..47ef145b0fb 100644 --- a/modules/apps/transfer/internal/events/events.go +++ b/modules/apps/transfer/internal/events/events.go @@ -31,7 +31,7 @@ func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.To // EmitOnRecvPacketEvent emits a fungible token packet event in the OnRecvPacket callback func EmitOnRecvPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement, ackErr error) { - jsonTokens := mustMarshalType[types.Tokens](types.Tokens(packetData.Tokens)) + jsonTokens := mustMarshalType[types.Tokens](packetData.Tokens) eventAttributes := []sdk.Attribute{ sdk.NewAttribute(types.AttributeKeySender, packetData.Sender), diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 24cc74bceef..294c7ea7ac2 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -365,9 +365,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { } case "OnRecvPacket": - var async bool - async, err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, tc.packet.Data) - suite.Require().False(async) + err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, tc.packet.Data) case "OnTimeoutPacket": registerDenomFn() diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 2cefe2b4f5e..e741f11ecfb 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -159,19 +159,19 @@ func (k Keeper) sendTransfer( // and sent to the receiving address. Otherwise if the sender chain is sending // back tokens this chain originally transferred to it, the tokens are // unescrowed and sent to the receiving address. -func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) (bool, error) { +func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) error { // validate packet data upon receiving if err := data.ValidateBasic(); err != nil { - return false, errorsmod.Wrapf(err, "error validating ICS-20 transfer packet data") + return errorsmod.Wrapf(err, "error validating ICS-20 transfer packet data") } if !k.GetParams(ctx).ReceiveEnabled { - return false, types.ErrReceiveDisabled + return types.ErrReceiveDisabled } receiver, err := getReceiverFromPacketData(data, packet.DestinationPort, packet.DestinationChannel) if err != nil { - return false, err + return err } var receivedCoins sdk.Coins @@ -184,7 +184,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t // parse the transfer amount transferAmount, ok := sdkmath.NewIntFromString(token.Amount) if !ok { - return false, errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount: %s", token.Amount) + return errorsmod.Wrapf(types.ErrInvalidAmount, "unable to parse transfer amount: %s", token.Amount) } // This is the prefix that would have been prefixed to the denomination @@ -203,12 +203,12 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t coin := sdk.NewCoin(token.Denom.IBCDenom(), transferAmount) if k.bankKeeper.BlockedAddr(receiver) { - return false, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) + return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) } escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel()) if err := k.unescrowCoin(ctx, escrowAddress, receiver, coin); err != nil { - return false, err + return err } denomPath := token.Denom.Path() @@ -245,14 +245,14 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t if err := k.bankKeeper.MintCoins( ctx, types.ModuleName, sdk.NewCoins(voucher), ); err != nil { - return false, errorsmod.Wrap(err, "failed to mint IBC tokens") + return errorsmod.Wrap(err, "failed to mint IBC tokens") } // send to receiver if err := k.bankKeeper.SendCoinsFromModuleToAccount( ctx, types.ModuleName, receiver, sdk.NewCoins(voucher), ); err != nil { - return false, errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()) + return errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()) } denomPath := token.Denom.Path() @@ -265,13 +265,12 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t if data.ShouldBeForwarded() { // we are now sending from the forward escrow address to the final receiver address. if err := k.forwardPacket(ctx, data, packet, receivedCoins); err != nil { - return false, err + return err } - return true, nil } // The ibc_module.go module will return the proper ack. - return false, nil + return nil } // OnAcknowledgementPacket either reverts the state changes executed in receive diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 52c25a9af69..025c3707f79 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -212,10 +212,8 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { }, sender.GetAddress().String(), receiver.GetAddress().String(), "", &forwarding) packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - var async bool - async, err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) + err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) // If forwarding has been triggered then the async must be true. - suite.Require().True(async) suite.Require().Nil(err) // denomTrace path: transfer/channel-0 @@ -248,8 +246,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { packetRecv = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) // execute onRecvPacket, when chaninA receives the tokens the escrow amount on B should increase to amount - async, err = suite.chainA.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainA.GetContext(), packetRecv, data) - suite.Require().False(async) + err = suite.chainA.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainA.GetContext(), packetRecv, data) suite.Require().NoError(err) // Check that the final receiver has received the expected tokens. diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 924e5179a36..71b53fa77be 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -384,9 +384,8 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsNotSource() { }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, nil) packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - var async bool - async, err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) - suite.Require().False(async) + err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) + // check total amount in escrow of received token denom on receiving chain totalEscrow := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), sdk.DefaultBondDenom) suite.Require().Equal(expEscrowAmount, totalEscrow.Amount) @@ -536,7 +535,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsSource() { }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, nil) packet = channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) - _, err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) + err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) // check total amount in escrow of received token denom on receiving chain totalEscrow := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), sdk.DefaultBondDenom) @@ -645,9 +644,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) // execute onRecvPacket, when chaninB receives the source token the escrow amount should decrease - var async bool - async, err := suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) - suite.Require().False(async) + err := suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) suite.Require().NoError(err) // check total amount in escrow of sent token on receiving chain From c00ddd9552679f1dea8afdd4840c52b12e695450 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Mon, 17 Jun 2024 12:31:03 +0200 Subject: [PATCH 077/141] chore: use NewForwarding instead of direct init (#6605) --- modules/apps/transfer/keeper/forwarding.go | 5 +- .../transfer/keeper/relay_forwarding_test.go | 77 +++++++------------ 2 files changed, 27 insertions(+), 55 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index adc9449807c..7ae224473f2 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -104,10 +104,7 @@ func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDat memo = data.Forwarding.Memo nextForwardingPath = nil } else { - nextForwardingPath = &types.Forwarding{ - Hops: data.Forwarding.Hops[1:], - Memo: data.Forwarding.Memo, - } + nextForwardingPath = types.NewForwarding(data.Forwarding.Memo, data.Forwarding.Hops[1:]...) } // sending from the forward escrow address to the original receiver address. diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 025c3707f79..ac4698003e1 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -28,15 +28,10 @@ func (suite *KeeperTestSuite) TestPathForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwarding := types.Forwarding{ - Hops: []types.Hop{ - { - PortId: path2.EndpointA.ChannelConfig.PortID, - ChannelId: path2.EndpointA.ChannelID, - }, - }, - Memo: "", - } + forwarding := types.NewForwarding("", types.Hop{ + PortId: path2.EndpointA.ChannelConfig.PortID, + ChannelId: path2.EndpointA.ChannelID, + }) transferMsg := types.NewMsgTransfer( path1.EndpointA.ChannelConfig.PortID, @@ -46,7 +41,7 @@ func (suite *KeeperTestSuite) TestPathForwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - &forwarding, + forwarding, ) result, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -90,15 +85,10 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwarding := types.Forwarding{ - Hops: []types.Hop{ - { - PortId: path2.EndpointB.ChannelConfig.PortID, - ChannelId: path2.EndpointB.ChannelID, - }, - }, - Memo: "", - } + forwarding := types.NewForwarding("", types.Hop{ + PortId: path2.EndpointB.ChannelConfig.PortID, + ChannelId: path2.EndpointB.ChannelID, + }) transferMsg := types.NewMsgTransfer( path1.EndpointA.ChannelConfig.PortID, @@ -108,7 +98,7 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - &forwarding, + forwarding, ) result, err := suite.chainA.SendMsgs(transferMsg) @@ -173,15 +163,10 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwarding := types.Forwarding{ - Hops: []types.Hop{ - { - PortId: path2.EndpointB.ChannelConfig.PortID, - ChannelId: path2.EndpointB.ChannelID, - }, - }, - Memo: "", - } + forwarding := types.NewForwarding("", types.Hop{ + PortId: path2.EndpointB.ChannelConfig.PortID, + ChannelId: path2.EndpointB.ChannelID, + }) transferMsg := types.NewMsgTransfer( path1.EndpointA.ChannelConfig.PortID, @@ -191,7 +176,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - &forwarding, + forwarding, ) result, err := suite.chainA.SendMsgs(transferMsg) @@ -209,7 +194,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { Denom: denom, Amount: amount.String(), }, - }, sender.GetAddress().String(), receiver.GetAddress().String(), "", &forwarding) + }, sender.GetAddress().String(), receiver.GetAddress().String(), "", forwarding) packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) @@ -278,15 +263,10 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwarding := types.Forwarding{ - Hops: []types.Hop{ - { - PortId: path2.EndpointB.ChannelConfig.PortID, - ChannelId: path2.EndpointB.ChannelID, - }, - }, - Memo: "", - } + forwarding := types.NewForwarding("", types.Hop{ + PortId: path2.EndpointB.ChannelConfig.PortID, + ChannelId: path2.EndpointB.ChannelID, + }) transferMsg := types.NewMsgTransfer( path1.EndpointA.ChannelConfig.PortID, @@ -296,7 +276,7 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - &forwarding, + forwarding, ) result, err := suite.chainA.SendMsgs(transferMsg) @@ -472,15 +452,10 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { sender = suite.chainC.SenderAccounts[0].SenderAccount receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account - forwarding := types.Forwarding{ - Hops: []types.Hop{ - { - PortId: path1.EndpointB.ChannelConfig.PortID, - ChannelId: path1.EndpointB.ChannelID, - }, - }, - Memo: "", - } + forwarding := types.NewForwarding("", types.Hop{ + PortId: path1.EndpointB.ChannelConfig.PortID, + ChannelId: path1.EndpointB.ChannelID, + }) transferMsg = types.NewMsgTransfer( path2.EndpointB.ChannelConfig.PortID, @@ -490,7 +465,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - &forwarding, + forwarding, ) result, err = suite.chainC.SendMsgs(transferMsg) From fc6c111182af338d2438f26d64798e10a777e919 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Mon, 17 Jun 2024 13:43:42 +0300 Subject: [PATCH 078/141] Reduce max forwarding to 16 (#6610) --- modules/apps/transfer/types/forwarding.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/types/forwarding.go b/modules/apps/transfer/types/forwarding.go index 21d1e634068..e8bf83f8dbf 100644 --- a/modules/apps/transfer/types/forwarding.go +++ b/modules/apps/transfer/types/forwarding.go @@ -6,7 +6,7 @@ import ( host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) -const MaximumNumberOfForwardingHops = 64 +const MaximumNumberOfForwardingHops = 16 // denotes the maximum number of forwarding hops allowed // NewForwarding creates a new Forwarding instance given a memo and a variable number of hops. func NewForwarding(memo string, hops ...Hop) *Forwarding { From 72714b3ddc85d4ada8d99c5c076bb71bbdc4ae64 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Mon, 17 Jun 2024 17:04:09 +0200 Subject: [PATCH 079/141] feat(transfer): use single byte ack for successful forward (#6604) Co-authored-by: Nikolas De Giorgis --- modules/apps/transfer/keeper/forwarding.go | 2 +- .../transfer/keeper/relay_forwarding_test.go | 69 +++++++++++++------ 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 7ae224473f2..a583f050128 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -28,7 +28,7 @@ func (k Keeper) ackForwardPacketError(ctx sdk.Context, prevPacket channeltypes.P // ackForwardPacketSuccess writes a successful async acknowledgement for the prevPacket func (k Keeper) ackForwardPacketSuccess(ctx sdk.Context, prevPacket channeltypes.Packet) error { - forwardAck := channeltypes.NewResultAcknowledgement([]byte("forwarded packet succeeded")) + forwardAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) } diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index ac4698003e1..66f6f1ff3bd 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -245,11 +245,11 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { amount := sdkmath.NewInt(100) /* Given the following topolgy: - chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain C stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake We want to trigger: - 1. A sends B over channel0. - 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions + 1. Single transfer forwarding token from A -> B -> C + 2. B onRecv . 2.1(B sends C over channel1) Atomic Actions At this point we want to assert: A: escrowA = amount,denom B: escrowB = amount,transfer/channel-0/denom @@ -258,20 +258,20 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) path1.Setup() - path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) path2.Setup() - coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + coinOnA := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainA.SenderAccounts[1].SenderAccount + receiver := suite.chainC.SenderAccounts[0].SenderAccount forwarding := types.NewForwarding("", types.Hop{ - PortId: path2.EndpointB.ChannelConfig.PortID, - ChannelId: path2.EndpointB.ChannelID, + PortId: path2.EndpointA.ChannelConfig.PortID, + ChannelId: path2.EndpointA.ChannelID, }) transferMsg := types.NewMsgTransfer( path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, - sdk.NewCoins(coin), + sdk.NewCoins(coinOnA), sender.GetAddress().String(), receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), @@ -283,47 +283,72 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { suite.Require().NoError(err) // message committed // parse the packet from result events and recv packet on chainB - packet, err := ibctesting.ParsePacketFromEvents(result.Events) + packetFromAtoB, err := ibctesting.ParsePacketFromEvents(result.Events) suite.Require().NoError(err) - suite.Require().NotNil(packet) + suite.Require().NotNil(packetFromAtoB) err = path1.EndpointB.UpdateClient() suite.Require().NoError(err) - result, err = path1.EndpointB.RecvPacketWithResult(packet) + result, err = path1.EndpointB.RecvPacketWithResult(packetFromAtoB) suite.Require().NoError(err) suite.Require().NotNil(result) // Check that Escrow A has amount - totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) + totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coinOnA.GetDenom()) suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) // denomTrace path: transfer/channel-0 denomTrace := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) // Check that Escrow B has amount - coin = sdk.NewCoin(denomTrace.IBCDenom(), amount) - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) + coinOnB := sdk.NewCoin(denomTrace.IBCDenom(), amount) + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coinOnB.GetDenom()) suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - packet, err = ibctesting.ParsePacketFromEvents(result.Events) + packetFromBtoC, err := ibctesting.ParsePacketFromEvents(result.Events) suite.Require().NoError(err) - suite.Require().NotNil(packet) + suite.Require().NotNil(packetFromBtoC) err = path2.EndpointA.UpdateClient() suite.Require().NoError(err) - result, err = path2.EndpointA.RecvPacketWithResult(packet) + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointB.RecvPacketWithResult(packetFromBtoC) suite.Require().NoError(err) suite.Require().NotNil(result) // transfer/channel-1/transfer/channel-0/denom - denomTraceABA := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID), types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + denomTraceABC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID), types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) // Check that the final receiver has received the expected tokens. - coin = sdk.NewCoin(denomTraceABA.IBCDenom(), amount) - postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") + coinOnC := sdk.NewCoin(denomTraceABC.IBCDenom(), amount) + balanceOnC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), receiver.GetAddress(), coinOnC.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(100), balanceOnC.Amount, "final receiver balance has not increased") + + successAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + successAckBz := channeltypes.CommitAcknowledgement(successAck.Acknowledgement()) + ackOnC := suite.chainC.GetAcknowledgement(packetFromBtoC) + suite.Require().Equal(successAckBz, ackOnC) + + // Ack back to B + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) + + err = path2.EndpointA.AcknowledgePacket(packetFromBtoC, successAck.Acknowledgement()) + suite.Require().NoError(err) + + ackOnB := suite.chainB.GetAcknowledgement(packetFromAtoB) + suite.Require().Equal(successAckBz, ackOnB) + + // Ack back to A + err = path1.EndpointA.UpdateClient() + suite.Require().NoError(err) + + err = path1.EndpointA.AcknowledgePacket(packetFromAtoB, successAck.Acknowledgement()) + suite.Require().NoError(err) } // This test replicates the Acknowledgement Failure Scenario 5 From c546f69b7ad0e312fe0102c172462b3669a7e650 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Tue, 18 Jun 2024 11:56:00 +0300 Subject: [PATCH 080/141] chore(transfer/cli): add forwarding flag to tx cli (#6609) Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/client/cli/tx.go | 44 +++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index 66df04f9495..096d72abc74 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -23,6 +23,7 @@ const ( flagPacketTimeoutTimestamp = "packet-timeout-timestamp" flagAbsoluteTimeouts = "absolute-timeouts" flagMemo = "memo" + flagForwarding = "forwarding" ) // defaultRelativePacketTimeoutTimestamp is the default packet timeout timestamp (in nanoseconds) @@ -90,6 +91,17 @@ using the {packet-timeout-timestamp} flag. If no timeout value is set then a def return err } + forwarding, err := parseForwarding(cmd) + if err != nil { + return err + } + + // If parsed, set and replace memo. + if forwarding != nil { + forwarding.Memo = memo + memo = "" + } + // NOTE: relative timeouts using block height are not supported. // if the timeouts are not absolute, CLI users rely solely on local clock time in order to calculate relative timestamps. if !absoluteTimeouts { @@ -111,8 +123,9 @@ using the {packet-timeout-timestamp} flag. If no timeout value is set then a def } msg := types.NewMsgTransfer( - srcPort, srcChannel, coins, sender, receiver, timeoutHeight, timeoutTimestamp, memo, nil, + srcPort, srcChannel, coins, sender, receiver, timeoutHeight, timeoutTimestamp, memo, forwarding, ) + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, } @@ -121,7 +134,36 @@ using the {packet-timeout-timestamp} flag. If no timeout value is set then a def cmd.Flags().Uint64(flagPacketTimeoutTimestamp, defaultRelativePacketTimeoutTimestamp, "Packet timeout timestamp in nanoseconds from now. Default is 10 minutes. The timeout is disabled when set to 0.") cmd.Flags().Bool(flagAbsoluteTimeouts, false, "Timeout flags are used as absolute timeouts.") cmd.Flags().String(flagMemo, "", "Memo to be sent along with the packet.") + cmd.Flags().String(flagForwarding, "", "Forwarding information in the form of a comma separated list of portID/channelID pairs, denoting the intermediary hops. If forwarding is specified any memo set will be included in the forwarding information created.") flags.AddTxFlagsToCmd(cmd) return cmd } + +// parseForwarding parses the forwarding flag into a Forwarding object or nil if the flag is not specified. If the flag cannot +// be parsed or the hops aren't in the portID/channelID format an error is returned. +func parseForwarding(cmd *cobra.Command) (*types.Forwarding, error) { + var hops []types.Hop + + forwardingString, err := cmd.Flags().GetString(flagForwarding) + if err != nil { + return nil, err + } + if strings.TrimSpace(forwardingString) == "" { + return nil, nil + } + + pairs := strings.Split(forwardingString, ",") + for _, pair := range pairs { + pairSplit := strings.Split(pair, "/") + if len(pairSplit) != 2 { + return nil, fmt.Errorf("expected a portID/channelID pair, found %s", pair) + } + + hop := types.Hop{PortId: pairSplit[0], ChannelId: pairSplit[1]} + hops = append(hops, hop) + } + + forwarding := types.NewForwarding("", hops...) + return forwarding, nil +} From 60a6b9945beaf03820f6490c7853304c40601b2e Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Tue, 18 Jun 2024 18:08:54 +0300 Subject: [PATCH 081/141] chore(transfer): make Forwarding non-null (#6618) * chore(transfer): make Forwarding non-null * chore(transfer): always validate forwarding. --- e2e/tests/transfer/authz_test.go | 8 +- e2e/tests/transfer/incentivized_test.go | 5 +- e2e/tests/transfer/upgrades_test.go | 3 +- e2e/tests/upgrades/upgrade_test.go | 3 +- e2e/testsuite/testsuite.go | 2 +- e2e/testsuite/tx.go | 3 +- .../host/keeper/relay_test.go | 4 +- modules/apps/29-fee/keeper/events_test.go | 2 +- modules/apps/29-fee/transfer_test.go | 4 +- modules/apps/callbacks/ibc_middleware_test.go | 14 ++- modules/apps/callbacks/replay_test.go | 2 +- modules/apps/callbacks/transfer_test.go | 4 +- modules/apps/transfer/client/cli/tx.go | 10 +- modules/apps/transfer/ibc_module.go | 2 +- modules/apps/transfer/ibc_module_test.go | 4 +- .../apps/transfer/internal/convert/convert.go | 2 +- modules/apps/transfer/internal/packet_test.go | 18 +-- modules/apps/transfer/keeper/export_test.go | 2 +- modules/apps/transfer/keeper/forwarding.go | 3 +- .../apps/transfer/keeper/invariants_test.go | 2 +- .../apps/transfer/keeper/mbt_relay_test.go | 4 +- .../apps/transfer/keeper/msg_server_test.go | 2 +- modules/apps/transfer/keeper/relay.go | 4 +- .../transfer/keeper/relay_forwarding_test.go | 8 +- modules/apps/transfer/keeper/relay_test.go | 34 +++--- modules/apps/transfer/transfer_test.go | 6 +- modules/apps/transfer/types/forwarding.go | 4 +- .../apps/transfer/types/forwarding_test.go | 2 +- modules/apps/transfer/types/msgs.go | 16 ++- modules/apps/transfer/types/msgs_test.go | 49 ++++---- modules/apps/transfer/types/packet.go | 18 ++- modules/apps/transfer/types/packet.pb.go | 79 ++++++------- modules/apps/transfer/types/packet_test.go | 44 +++---- .../transfer/types/transfer_authorization.go | 2 +- .../types/transfer_authorization_test.go | 8 +- modules/apps/transfer/types/tx.pb.go | 111 ++++++++---------- proto/ibc/applications/transfer/v1/tx.proto | 2 +- .../ibc/applications/transfer/v2/packet.proto | 2 +- testing/solomachine.go | 2 +- 39 files changed, 243 insertions(+), 251 deletions(-) diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index fc0d4586af0..495ffc3e880 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -127,7 +127,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - nil, + transfertypes.Forwarding{}, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -188,7 +188,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_MsgTransfer_Succeeds() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - nil, + transfertypes.Forwarding{}, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -271,7 +271,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - nil, + transfertypes.Forwarding{}, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) @@ -332,7 +332,7 @@ func (suite *AuthzTransferTestSuite) TestAuthz_InvalidTransferAuthorizations() { suite.GetTimeoutHeight(ctx, chainB), 0, "", - nil, + transfertypes.Forwarding{}, ) protoAny, err := codectypes.NewAnyWithValue(transferMsg) diff --git a/e2e/tests/transfer/incentivized_test.go b/e2e/tests/transfer/incentivized_test.go index 032a2c1a9e1..7d2cf8668a0 100644 --- a/e2e/tests/transfer/incentivized_test.go +++ b/e2e/tests/transfer/incentivized_test.go @@ -20,6 +20,7 @@ import ( "github.com/cosmos/ibc-go/e2e/testsuite/query" "github.com/cosmos/ibc-go/e2e/testvalues" feetypes "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" ) @@ -211,7 +212,7 @@ func (s *IncentivizedTransferTestSuite) TestMsgPayPacketFee_InvalidReceiverAccou s.GetTimeoutHeight(ctx, chainB), 0, "", - nil, + transfertypes.Forwarding{}, ) txResp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgTransfer) // this message should be successful, as receiver account is not validated on the sending chain. @@ -350,7 +351,7 @@ func (s *IncentivizedTransferTestSuite) TestMultiMsg_MsgPayPacketFeeSingleSender s.GetTimeoutHeight(ctx, chainB), 0, "", - nil, + transfertypes.Forwarding{}, ) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) diff --git a/e2e/tests/transfer/upgrades_test.go b/e2e/tests/transfer/upgrades_test.go index 7eb9de1fb53..09e527f0e9e 100644 --- a/e2e/tests/transfer/upgrades_test.go +++ b/e2e/tests/transfer/upgrades_test.go @@ -19,6 +19,7 @@ import ( "github.com/cosmos/ibc-go/e2e/testsuite/query" "github.com/cosmos/ibc-go/e2e/testvalues" feetypes "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" ) @@ -208,7 +209,7 @@ func (s *TransferChannelUpgradesTestSuite) TestChannelUpgrade_WithFeeMiddleware_ s.GetTimeoutHeight(ctx, chainB), 0, "", - nil, + transfertypes.Forwarding{}, ) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) diff --git a/e2e/tests/upgrades/upgrade_test.go b/e2e/tests/upgrades/upgrade_test.go index 277157878c8..68c65329e75 100644 --- a/e2e/tests/upgrades/upgrade_test.go +++ b/e2e/tests/upgrades/upgrade_test.go @@ -28,6 +28,7 @@ import ( "github.com/cosmos/ibc-go/e2e/testsuite/query" "github.com/cosmos/ibc-go/e2e/testvalues" feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" v7migrations "github.com/cosmos/ibc-go/v8/modules/core/02-client/migrations/v7" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" @@ -966,7 +967,7 @@ func (s *UpgradeTestSuite) TestV8ToV8_1ChainUpgrade_ChannelUpgrades() { s.GetTimeoutHeight(ctx, chainB), 0, "", - nil, + transfertypes.Forwarding{}, ) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index d62e3d3c603..2fd9d9503e2 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -625,7 +625,7 @@ func getValidatorsAndFullNodes(chainIdx int) (int, int) { } // GetMsgTransfer returns a MsgTransfer that is constructed based on the channel version -func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, forwarding *transfertypes.Forwarding) *transfertypes.MsgTransfer { +func GetMsgTransfer(portID, channelID, version string, tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, forwarding transfertypes.Forwarding) *transfertypes.MsgTransfer { if len(tokens) == 0 { panic(errors.New("tokens cannot be empty")) } diff --git a/e2e/testsuite/tx.go b/e2e/testsuite/tx.go index 7395f393741..ae8fc60f58d 100644 --- a/e2e/testsuite/tx.go +++ b/e2e/testsuite/tx.go @@ -30,6 +30,7 @@ import ( "github.com/cosmos/ibc-go/e2e/testsuite/sanitize" "github.com/cosmos/ibc-go/e2e/testvalues" feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + transfertypes "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" ) @@ -297,7 +298,7 @@ func (s *E2ETestSuite) Transfer(ctx context.Context, chain ibc.Chain, user ibc.W transferVersion = version.AppVersion } - msg := GetMsgTransfer(portID, channelID, transferVersion, tokens, sender, receiver, timeoutHeight, timeoutTimestamp, memo, nil) + msg := GetMsgTransfer(portID, channelID, transferVersion, tokens, sender, receiver, timeoutHeight, timeoutTimestamp, memo, transfertypes.Forwarding{}) return s.BroadcastMessages(ctx, chain, user, msg) } diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index c9a115fd45b..fbd05e641cd 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -353,7 +353,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.chainB.GetTimeoutHeight(), 0, "", - nil, + transfertypes.Forwarding{}, ) data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) @@ -389,7 +389,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.chainB.GetTimeoutHeight(), 0, "", - nil, + transfertypes.Forwarding{}, ) data, err := icatypes.SerializeCosmosTx(suite.chainA.GetSimApp().AppCodec(), []proto.Message{msg}, encoding) diff --git a/modules/apps/29-fee/keeper/events_test.go b/modules/apps/29-fee/keeper/events_test.go index 93b27ceef64..f9a14aa3a50 100644 --- a/modules/apps/29-fee/keeper/events_test.go +++ b/modules/apps/29-fee/keeper/events_test.go @@ -115,7 +115,7 @@ func (suite *KeeperTestSuite) TestDistributeFeeEvent() { path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100))), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", - nil, + transfertypes.Forwarding{}, ) res, err := suite.chainA.SendMsgs(msgPayPacketFee, msgTransfer) diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 14fdfb42545..3d2beb18a49 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -46,7 +46,7 @@ func (suite *FeeTestSuite) TestFeeTransfer() { msgs := []sdk.Msg{ types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), - transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, tc.coinsToTransfer, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", nil), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, tc.coinsToTransfer, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", transfertypes.Forwarding{}), } res, err := suite.chainA.SendMsgs(msgs...) @@ -157,7 +157,7 @@ func (suite *FeeTestSuite) TestTransferFeeUpgrade() { fee := types.NewFee(defaultRecvFee, defaultAckFee, defaultTimeoutFee) msgs := []sdk.Msg{ types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), - transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", nil), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(ibctesting.TestCoin), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, "", transfertypes.Forwarding{}), } res, err := suite.chainA.SendMsgs(msgs...) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 03e0e6cc0e1..923b4bb6c8e 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -24,6 +24,8 @@ import ( ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) +var emptyForwarding = transfertypes.Forwarding{} + func (s *CallbacksTestSuite) TestNewIBCMiddleware() { testCases := []struct { name string @@ -186,7 +188,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract), - nil, + emptyForwarding, ) chanCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) @@ -328,7 +330,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, simapp.SuccessContract, userGasLimit), - nil, + emptyForwarding, ) packet = channeltypes.Packet{ @@ -494,7 +496,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { sdk.NewCoins(ibctesting.TestCoin), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), // set user gas limit above panic level in mock contract keeper - nil, + emptyForwarding, ) res, err := s.chainA.SendMsgs(msg) @@ -662,7 +664,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), - nil, + emptyForwarding, ) packet = channeltypes.Packet{ @@ -794,7 +796,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), - nil, + emptyForwarding, ) packet = channeltypes.Packet{ @@ -1018,7 +1020,7 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketDataV1() { Sender: ibctesting.TestAccAddress, Receiver: ibctesting.TestAccAddress, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), - Forwarding: nil, + Forwarding: emptyForwarding, } portID := s.path.EndpointA.ChannelConfig.PortID diff --git a/modules/apps/callbacks/replay_test.go b/modules/apps/callbacks/replay_test.go index d04a614136d..4c619346597 100644 --- a/modules/apps/callbacks/replay_test.go +++ b/modules/apps/callbacks/replay_test.go @@ -330,7 +330,7 @@ func (s *CallbacksTestSuite) ExecuteFailedTransfer(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, - nil, + transfertypes.Forwarding{}, ) res, err := s.chainA.SendMsgs(msg) diff --git a/modules/apps/callbacks/transfer_test.go b/modules/apps/callbacks/transfer_test.go index 970fe36447e..c1e935e204d 100644 --- a/modules/apps/callbacks/transfer_test.go +++ b/modules/apps/callbacks/transfer_test.go @@ -193,7 +193,7 @@ func (s *CallbacksTestSuite) ExecuteTransfer(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 100), 0, memo, - nil, + transfertypes.Forwarding{}, ) res, err := s.chainA.SendMsgs(msg) @@ -228,7 +228,7 @@ func (s *CallbacksTestSuite) ExecuteTransferTimeout(memo string) { s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), timeoutHeight, timeoutTimestamp, memo, - nil, + transfertypes.Forwarding{}, ) res, err := s.chainA.SendMsgs(msg) diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index 096d72abc74..e4fd1a67511 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -97,7 +97,7 @@ using the {packet-timeout-timestamp} flag. If no timeout value is set then a def } // If parsed, set and replace memo. - if forwarding != nil { + if len(forwarding.Hops) > 0 { forwarding.Memo = memo memo = "" } @@ -142,22 +142,22 @@ using the {packet-timeout-timestamp} flag. If no timeout value is set then a def // parseForwarding parses the forwarding flag into a Forwarding object or nil if the flag is not specified. If the flag cannot // be parsed or the hops aren't in the portID/channelID format an error is returned. -func parseForwarding(cmd *cobra.Command) (*types.Forwarding, error) { +func parseForwarding(cmd *cobra.Command) (types.Forwarding, error) { var hops []types.Hop forwardingString, err := cmd.Flags().GetString(flagForwarding) if err != nil { - return nil, err + return types.Forwarding{}, err } if strings.TrimSpace(forwardingString) == "" { - return nil, nil + return types.Forwarding{}, nil } pairs := strings.Split(forwardingString, ",") for _, pair := range pairs { pairSplit := strings.Split(pair, "/") if len(pairSplit) != 2 { - return nil, fmt.Errorf("expected a portID/channelID pair, found %s", pair) + return types.Forwarding{}, fmt.Errorf("expected a portID/channelID pair, found %s", pair) } hop := types.Hop{PortId: pairSplit[0], ChannelId: pairSplit[1]} diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 266d100f9af..45a56ec6dc9 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -211,7 +211,7 @@ func (im IBCModule) OnRecvPacket( im.keeper.Logger(ctx).Info("successfully handled ICS-20 packet", "sequence", packet.Sequence) - if data.Forwarding != nil { + if data.ShouldBeForwarded() { // NOTE: acknowledgement will be written asynchronously return nil } diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index f4e02a8e06f..cbf937dd9a4 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -355,7 +355,7 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", - nil, + types.Forwarding{}, ) tokensBz, err := json.Marshal(packetData.Tokens) @@ -476,7 +476,7 @@ func (suite *TransferTestSuite) TestOnTimeoutPacket() { timeoutHeight, 0, "", - nil, + types.Forwarding{}, ) res, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go index 9bc43844e63..c266d42519a 100644 --- a/modules/apps/transfer/internal/convert/convert.go +++ b/modules/apps/transfer/internal/convert/convert.go @@ -24,6 +24,6 @@ func PacketDataV1ToV2(packetData types.FungibleTokenPacketData) (types.FungibleT Sender: packetData.Sender, Receiver: packetData.Receiver, Memo: packetData.Memo, - Forwarding: nil, + Forwarding: types.Forwarding{}, }, nil } diff --git a/modules/apps/transfer/internal/packet_test.go b/modules/apps/transfer/internal/packet_test.go index 604a8769a51..4cb975622fe 100644 --- a/modules/apps/transfer/internal/packet_test.go +++ b/modules/apps/transfer/internal/packet_test.go @@ -10,6 +10,8 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ) +var emptyForwarding = types.Forwarding{} + func TestUnmarshalPacketData(t *testing.T) { var ( packetDataBz []byte @@ -35,7 +37,7 @@ func TestUnmarshalPacketData(t *testing.T) { Denom: types.NewDenom("atom", types.NewTrace("transfer", "channel-0")), Amount: "1000", }, - }, "sender", "receiver", "", nil) + }, "sender", "receiver", "", emptyForwarding) packetDataBz = packetData.GetBytes() version = types.V2 @@ -92,7 +94,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom", types.NewTrace("transfer", "channel-0")), Amount: "1000", }, - }, sender, receiver, "", nil), + }, sender, receiver, "", emptyForwarding), nil, }, { @@ -104,7 +106,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom"), Amount: "1000", }, - }, sender, receiver, "", nil), + }, sender, receiver, "", emptyForwarding), nil, }, { @@ -116,7 +118,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom/withslash", types.NewTrace("transfer", "channel-0")), Amount: "1000", }, - }, sender, receiver, "", nil), + }, sender, receiver, "", emptyForwarding), nil, }, { @@ -128,7 +130,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom/", types.NewTrace("transfer", "channel-0")), Amount: "1000", }, - }, sender, receiver, "", nil), + }, sender, receiver, "", emptyForwarding), nil, }, { @@ -140,7 +142,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom/pool", types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")), Amount: "1000", }, - }, sender, receiver, "", nil), + }, sender, receiver, "", emptyForwarding), nil, }, { @@ -152,7 +154,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom", types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1"), types.NewTrace("transfer-custom", "channel-2")), Amount: "1000", }, - }, sender, receiver, "", nil), + }, sender, receiver, "", emptyForwarding), nil, }, { @@ -164,7 +166,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom/pool", types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1"), types.NewTrace("transfer-custom", "channel-2")), Amount: "1000", }, - }, sender, receiver, "", nil), + }, sender, receiver, "", emptyForwarding), nil, }, { diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index ebf94032046..582ef3ea5bd 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -34,6 +34,6 @@ func (k Keeper) TokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // CreatePacketDataBytesFromVersion is a wrapper around createPacketDataBytesFromVersion for testing purposes -func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwarding *types.Forwarding) []byte { +func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwarding types.Forwarding) []byte { return createPacketDataBytesFromVersion(appVersion, sender, receiver, memo, tokens, forwarding) } diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index a583f050128..69fdfdf5db9 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -99,10 +99,9 @@ func (k Keeper) revertForwardedPacket(ctx sdk.Context, prevPacket channeltypes.P func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDataV2, packet channeltypes.Packet, receivedCoins sdk.Coins) error { var memo string - var nextForwardingPath *types.Forwarding + var nextForwardingPath types.Forwarding if len(data.Forwarding.Hops) == 1 { memo = data.Forwarding.Memo - nextForwardingPath = nil } else { nextForwardingPath = types.NewForwarding(data.Forwarding.Memo, data.Forwarding.Hops[1:]...) } diff --git a/modules/apps/transfer/keeper/invariants_test.go b/modules/apps/transfer/keeper/invariants_test.go index 28b6a33d867..61474cfafbc 100644 --- a/modules/apps/transfer/keeper/invariants_test.go +++ b/modules/apps/transfer/keeper/invariants_test.go @@ -56,7 +56,7 @@ func (suite *KeeperTestSuite) TestTotalEscrowPerDenomInvariant() { suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - nil, + types.Forwarding{}, ) res, err := suite.chainA.SendMsgs(msg) diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 294c7ea7ac2..6d99322d105 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -159,7 +159,7 @@ func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPack AddressFromString(packet.Data.Sender), AddressFromString(packet.Data.Receiver), "", - nil, + types.Forwarding{}, ), } } @@ -358,7 +358,7 @@ func (suite *KeeperTestSuite) TestModelBasedRelay() { tc.packet.Data.Receiver, suite.chainA.GetTimeoutHeight(), 0, // only use timeout height "", - nil, + types.Forwarding{}, ) _, err = suite.chainB.GetSimApp().TransferKeeper.Transfer(suite.chainB.GetContext(), msg) diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index d77ee61ca9d..1ce9458fdb1 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -129,7 +129,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, // only use timeout height "memo", - nil, + types.Forwarding{}, ) // send some coins of the second denom from bank module to the sender account as well diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index e741f11ecfb..2bfedcc0493 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -64,7 +64,7 @@ func (k Keeper) sendTransfer( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, - forwarding *types.Forwarding, + forwarding types.Forwarding, ) (uint64, error) { channel, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) if !found { @@ -431,7 +431,7 @@ func (k Keeper) tokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // createPacketDataBytesFromVersion creates the packet data bytes to be sent based on the application version. -func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwarding *types.Forwarding) []byte { +func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwarding types.Forwarding) []byte { var packetDataBytes []byte switch appVersion { case types.V1: diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 66f6f1ff3bd..8cea5d23a0b 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -227,7 +227,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { Denom: denom, Amount: amount.String(), }, - }, types.GetForwardAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID).String(), receiver.GetAddress().String(), "", nil) + }, types.GetForwardAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID).String(), receiver.GetAddress().String(), "", types.Forwarding{}) packetRecv = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) // execute onRecvPacket, when chaninA receives the tokens the escrow amount on B should increase to amount @@ -394,7 +394,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - nil, + types.Forwarding{}, ) result, err := suite.chainA.SendMsgs(transferMsg) @@ -438,7 +438,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { receiver.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - nil, + types.Forwarding{}, ) result, err = suite.chainB.SendMsgs(transferMsg) @@ -572,7 +572,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { Denom: denom, Amount: amount.String(), }, - }, suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", nil) + }, suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", types.Forwarding{}) // suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String() This should be forward account of B packet = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 71b53fa77be..7376823f6c5 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -21,6 +21,8 @@ import ( ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) +var emptyForwarding = types.Forwarding{} + // TestSendTransfer tests sending from chainA to chainB using both coin // that originate on chainA and coin that originate on chainB. func (suite *KeeperTestSuite) TestSendTransfer() { @@ -159,7 +161,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { expEscrowAmount = sdkmath.ZeroInt() // create IBC token on chainA - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", nil) + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", emptyForwarding) result, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -179,7 +181,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, // only use timeout height memo, - nil, + emptyForwarding, ) res, err := suite.chainA.GetSimApp().TransferKeeper.Transfer(suite.chainA.GetContext(), msg) @@ -248,7 +250,7 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0, "", - nil, + emptyForwarding, ) result, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -269,7 +271,7 @@ func (suite *KeeperTestSuite) TestSendTransferSetsTotalEscrowAmountForSourceIBCT suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", - nil, + emptyForwarding, ) res, err := suite.chainB.GetSimApp().TransferKeeper.Transfer(suite.chainB.GetContext(), msg) @@ -368,7 +370,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsNotSource() { // send coin from chainA to chainB coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) - transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo, nil) + transferMsg := types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo, emptyForwarding) _, err := suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -381,7 +383,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsNotSource() { Denom: types.NewDenom(sdk.DefaultBondDenom, []types.Trace{}...), Amount: amount.String(), }, - }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, nil) + }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, emptyForwarding) packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) @@ -503,7 +505,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsSource() { // send coin from chainB to chainA, receive them, acknowledge them coin := sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) - transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, memo, nil) + transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(1, 110), 0, memo, emptyForwarding) res, err := suite.chainB.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -520,7 +522,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsSource() { // send coin back from chainA to chainB coin = sdk.NewCoin(denom.IBCDenom(), amount) - transferMsg = types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo, nil) + transferMsg = types.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, sdk.NewCoins(coin), suite.chainA.SenderAccount.GetAddress().String(), receiver, clienttypes.NewHeight(1, 110), 0, memo, emptyForwarding) _, err = suite.chainA.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed @@ -532,7 +534,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsSource() { Denom: denom, Amount: amount.String(), }, - }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, nil) + }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, emptyForwarding) packet = channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) @@ -610,7 +612,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT Denom: denom, Amount: amount.String(), }, - }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", nil) + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", emptyForwarding) packet := channeltypes.NewPacket( data.GetBytes(), seq, @@ -741,7 +743,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { Denom: denom, Amount: amount.String(), }, - }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", nil) + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", emptyForwarding) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preAcknowledgementBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denom.IBCDenom()) @@ -836,7 +838,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", - nil, + emptyForwarding, ) packet := channeltypes.NewPacket( data.GetBytes(), @@ -976,7 +978,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { Denom: denom, Amount: amount, }, - }, sender, suite.chainB.SenderAccount.GetAddress().String(), "", nil) + }, sender, suite.chainB.SenderAccount.GetAddress().String(), "", emptyForwarding) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preTimeoutBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denom.IBCDenom()) @@ -1062,7 +1064,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI Denom: denom, Amount: amount.String(), }, - }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", nil) + }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", emptyForwarding) packet := channeltypes.NewPacket( data.GetBytes(), seq, @@ -1269,7 +1271,7 @@ func (suite *KeeperTestSuite) TestCreatePacketDataBytesFromVersion() { types.V2, func() {}, func(bz []byte) { - expPacketData := types.NewFungibleTokenPacketDataV2(types.Tokens{types.Token{}}, "", "", "", nil) + expPacketData := types.NewFungibleTokenPacketDataV2(types.Tokens{types.Token{}}, "", "", "", emptyForwarding) suite.Require().Equal(bz, expPacketData.GetBytes()) }, nil, @@ -1299,7 +1301,7 @@ func (suite *KeeperTestSuite) TestCreatePacketDataBytesFromVersion() { tc.malleate() createFunc := func() { - bz = transferkeeper.CreatePacketDataBytesFromVersion(tc.appVersion, "", "", "", tokens, nil) + bz = transferkeeper.CreatePacketDataBytesFromVersion(tc.appVersion, "", "", "", tokens, emptyForwarding) } expPanic := tc.expPanicErr != nil diff --git a/modules/apps/transfer/transfer_test.go b/modules/apps/transfer/transfer_test.go index 9fad7947408..b3198fc8cc1 100644 --- a/modules/apps/transfer/transfer_test.go +++ b/modules/apps/transfer/transfer_test.go @@ -80,7 +80,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { } // send from chainA to chainB - msg := types.NewMsgTransfer(pathAToB.EndpointA.ChannelConfig.PortID, pathAToB.EndpointA.ChannelID, originalCoins, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", nil) + msg := types.NewMsgTransfer(pathAToB.EndpointA.ChannelConfig.PortID, pathAToB.EndpointA.ChannelID, originalCoins, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", types.Forwarding{}) res, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -120,7 +120,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { traceBToC := types.NewTrace(pathBToC.EndpointB.ChannelConfig.PortID, pathBToC.EndpointB.ChannelID) // send from chainB to chainC - msg = types.NewMsgTransfer(pathBToC.EndpointA.ChannelConfig.PortID, pathBToC.EndpointA.ChannelID, coinsSentFromAToB, suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", nil) + msg = types.NewMsgTransfer(pathBToC.EndpointA.ChannelConfig.PortID, pathBToC.EndpointA.ChannelID, coinsSentFromAToB, suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", types.Forwarding{}) res, err = suite.chainB.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -149,7 +149,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { } // send from chainC back to chainB - msg = types.NewMsgTransfer(pathBToC.EndpointB.ChannelConfig.PortID, pathBToC.EndpointB.ChannelID, coinsSentFromBToC, suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", nil) + msg = types.NewMsgTransfer(pathBToC.EndpointB.ChannelConfig.PortID, pathBToC.EndpointB.ChannelID, coinsSentFromBToC, suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "", types.Forwarding{}) res, err = suite.chainC.SendMsgs(msg) suite.Require().NoError(err) // message committed diff --git a/modules/apps/transfer/types/forwarding.go b/modules/apps/transfer/types/forwarding.go index e8bf83f8dbf..a95efebff85 100644 --- a/modules/apps/transfer/types/forwarding.go +++ b/modules/apps/transfer/types/forwarding.go @@ -9,8 +9,8 @@ import ( const MaximumNumberOfForwardingHops = 16 // denotes the maximum number of forwarding hops allowed // NewForwarding creates a new Forwarding instance given a memo and a variable number of hops. -func NewForwarding(memo string, hops ...Hop) *Forwarding { - return &Forwarding{ +func NewForwarding(memo string, hops ...Hop) Forwarding { + return Forwarding{ Memo: memo, Hops: hops, } diff --git a/modules/apps/transfer/types/forwarding_test.go b/modules/apps/transfer/types/forwarding_test.go index d9283164cf7..236f78d65d6 100644 --- a/modules/apps/transfer/types/forwarding_test.go +++ b/modules/apps/transfer/types/forwarding_test.go @@ -18,7 +18,7 @@ var validHop = types.Hop{ func TestForwarding_Validate(t *testing.T) { tests := []struct { name string - forwarding *types.Forwarding + forwarding types.Forwarding expError error }{ { diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index bd34f6cce49..9a3d4b821fc 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -49,7 +49,7 @@ func NewMsgTransfer( tokens sdk.Coins, sender, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, - forwarding *Forwarding, + forwarding Forwarding, ) *MsgTransfer { return &MsgTransfer{ SourcePort: sourcePort, @@ -102,15 +102,13 @@ func (msg MsgTransfer) ValidateBasic() error { return errorsmod.Wrapf(ErrInvalidMemo, "memo must not exceed %d bytes", MaximumMemoLength) } - if msg.Forwarding != nil { - if err := msg.Forwarding.Validate(); err != nil { - return err - } + if err := msg.Forwarding.Validate(); err != nil { + return err + } - // We cannot have non-empty memo and non-empty forwarding hops at the same time. - if len(msg.Forwarding.Hops) > 0 && msg.Memo != "" { - return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", msg.Memo, msg.Forwarding.Hops) - } + // We cannot have non-empty memo and non-empty forwarding hops at the same time. + if len(msg.Forwarding.Hops) > 0 && msg.Memo != "" { + return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", msg.Memo, msg.Forwarding.Hops) } for _, coin := range msg.GetCoins() { diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index bc043339dc3..49caeb04831 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -47,7 +47,8 @@ var ( invalidDenomCoins = []sdk.Coin{{Denom: "0atom", Amount: sdkmath.NewInt(100)}} zeroCoins = []sdk.Coin{{Denom: "atoms", Amount: sdkmath.NewInt(0)}} - timeoutHeight = clienttypes.NewHeight(0, 10) + timeoutHeight = clienttypes.NewHeight(0, 10) + emptyForwarding = types.Forwarding{} ) // TestMsgTransferValidation tests ValidateBasic for MsgTransfer @@ -57,28 +58,28 @@ func TestMsgTransferValidation(t *testing.T) { msg *types.MsgTransfer expError error }{ - {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), nil}, - {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, timeoutHeight, 0, "", nil), nil}, - {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, timeoutHeight, 0, "", nil), nil}, - {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, - {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), host.ErrInvalidID}, - {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), host.ErrInvalidID}, - {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), host.ErrInvalidID}, - {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), host.ErrInvalidID}, - {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), host.ErrInvalidID}, - {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1), nil), types.ErrInvalidMemo}, - {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, timeoutHeight, 0, "", nil), host.ErrInvalidID}, - {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, - {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, - {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidAddress}, - {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidAddress}, - {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidAddress}, - {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, - {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, - {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, - {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, - {"multidenom: too many coins", types.NewMsgTransfer(validPort, validChannel, make([]sdk.Coin, types.MaximumTokensLength+1), sender, receiver, timeoutHeight, 0, "", nil), ibcerrors.ErrInvalidCoins}, - {"multidenom: both token and tokens are set", &types.MsgTransfer{validPort, validChannel, coin, sender, receiver, timeoutHeight, 0, "", coins, nil}, ibcerrors.ErrInvalidCoins}, + {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), nil}, + {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), nil}, + {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, timeoutHeight, 0, "", emptyForwarding), nil}, + {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, + {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, + {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, + {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, + {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, + {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1), emptyForwarding), types.ErrInvalidMemo}, + {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, + {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidAddress}, + {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidAddress}, + {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidAddress}, + {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"multidenom: too many coins", types.NewMsgTransfer(validPort, validChannel, make([]sdk.Coin, types.MaximumTokensLength+1), sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"multidenom: both token and tokens are set", &types.MsgTransfer{validPort, validChannel, coin, sender, receiver, timeoutHeight, 0, "", coins, emptyForwarding}, ibcerrors.ErrInvalidCoins}, {"memo must be empty if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "memo", types.NewForwarding("", validHop)), types.ErrInvalidMemo}, {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwarding("", types.Hop{PortId: invalidPort, ChannelId: validChannel})), host.ErrInvalidID}, {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwarding("", types.Hop{PortId: validPort, ChannelId: invalidChannel})), host.ErrInvalidID}, @@ -103,7 +104,7 @@ func TestMsgTransferValidation(t *testing.T) { // TestMsgTransferGetSigners tests GetSigners for MsgTransfer func TestMsgTransferGetSigners(t *testing.T) { addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) - msg := types.NewMsgTransfer(validPort, validChannel, coins, addr.String(), receiver, timeoutHeight, 0, "", nil) + msg := types.NewMsgTransfer(validPort, validChannel, coins, addr.String(), receiver, timeoutHeight, 0, "", emptyForwarding) encodingCfg := moduletestutil.MakeTestEncodingConfig(transfer.AppModuleBasic{}) signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg) diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index b00ccc6e957..6f74c1f4d54 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -103,7 +103,7 @@ func NewFungibleTokenPacketDataV2( tokens []Token, sender, receiver string, memo string, - forwarding *Forwarding, + forwarding Forwarding, ) FungibleTokenPacketDataV2 { return FungibleTokenPacketDataV2{ Tokens: tokens, @@ -140,15 +140,13 @@ func (ftpd FungibleTokenPacketDataV2) ValidateBasic() error { return errorsmod.Wrapf(ErrInvalidMemo, "memo must not exceed %d bytes", MaximumMemoLength) } - if ftpd.Forwarding != nil { - if err := ftpd.Forwarding.Validate(); err != nil { - return err - } + if err := ftpd.Forwarding.Validate(); err != nil { + return err + } - // We cannot have non-empty memo and non-empty forwarding path hops at the same time. - if len(ftpd.Forwarding.Hops) > 0 && ftpd.Memo != "" { - return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", ftpd.Memo, ftpd.Forwarding.Hops) - } + // We cannot have non-empty memo and non-empty forwarding path hops at the same time. + if len(ftpd.Forwarding.Hops) > 0 && ftpd.Memo != "" { + return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", ftpd.Memo, ftpd.Forwarding.Hops) } return nil @@ -199,5 +197,5 @@ func (ftpd FungibleTokenPacketDataV2) GetPacketSender(sourcePortID string) strin // ShouldBeForwarded determines if the packet should be forwarded to the next hop. func (ftpd FungibleTokenPacketDataV2) ShouldBeForwarded() bool { - return ftpd.Forwarding != nil && len(ftpd.Forwarding.Hops) > 0 + return len(ftpd.Forwarding.Hops) > 0 } diff --git a/modules/apps/transfer/types/packet.pb.go b/modules/apps/transfer/types/packet.pb.go index 4004072b664..fd02225dc97 100644 --- a/modules/apps/transfer/types/packet.pb.go +++ b/modules/apps/transfer/types/packet.pb.go @@ -120,7 +120,7 @@ type FungibleTokenPacketDataV2 struct { // optional memo Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` // optional forwarding information - Forwarding *Forwarding `protobuf:"bytes,5,opt,name=forwarding,proto3" json:"forwarding,omitempty"` + Forwarding Forwarding `protobuf:"bytes,5,opt,name=forwarding,proto3" json:"forwarding"` } func (m *FungibleTokenPacketDataV2) Reset() { *m = FungibleTokenPacketDataV2{} } @@ -184,11 +184,11 @@ func (m *FungibleTokenPacketDataV2) GetMemo() string { return "" } -func (m *FungibleTokenPacketDataV2) GetForwarding() *Forwarding { +func (m *FungibleTokenPacketDataV2) GetForwarding() Forwarding { if m != nil { return m.Forwarding } - return nil + return Forwarding{} } func init() { @@ -202,29 +202,29 @@ func init() { var fileDescriptor_653ca2ce9a5ca313 = []byte{ // 365 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0xc1, 0x8e, 0xd3, 0x30, - 0x14, 0x8c, 0xdb, 0xb4, 0x02, 0xf7, 0x66, 0x55, 0x10, 0x2a, 0x14, 0xaa, 0x72, 0x09, 0x42, 0xd8, - 0x6a, 0x38, 0xc0, 0x95, 0x0a, 0x55, 0x1c, 0xa1, 0x42, 0x1c, 0xb8, 0x39, 0x8e, 0x1b, 0xac, 0x36, - 0x76, 0x64, 0x3b, 0x41, 0xfb, 0x15, 0xbb, 0x9f, 0xd5, 0x63, 0x8f, 0x7b, 0x5a, 0xad, 0xda, 0x1f, - 0xd8, 0x4f, 0x58, 0xc5, 0xe9, 0x76, 0x73, 0x69, 0x6e, 0x33, 0xe3, 0x79, 0xa3, 0xf1, 0x7b, 0xf0, - 0x83, 0x48, 0x18, 0xa1, 0x45, 0xb1, 0x15, 0x8c, 0x5a, 0xa1, 0xa4, 0x21, 0x56, 0x53, 0x69, 0xd6, - 0x5c, 0x93, 0x2a, 0x26, 0x05, 0x65, 0x1b, 0x6e, 0x71, 0xa1, 0x95, 0x55, 0xe8, 0xad, 0x48, 0x18, - 0x6e, 0x5b, 0xf1, 0x93, 0x15, 0x57, 0xf1, 0x24, 0xea, 0x0c, 0xb2, 0x6a, 0xc3, 0x65, 0x93, 0x33, - 0x19, 0x67, 0x2a, 0x53, 0x0e, 0x92, 0x1a, 0x9d, 0xd4, 0x8f, 0x1d, 0xf3, 0xf3, 0x33, 0x6e, 0xcc, - 0xb3, 0x6b, 0x00, 0x5f, 0x2f, 0x4b, 0x99, 0x89, 0x64, 0xcb, 0x7f, 0xd7, 0xd1, 0x3f, 0x5d, 0xd1, - 0xef, 0xd4, 0x52, 0x34, 0x86, 0x83, 0x94, 0x4b, 0x95, 0x07, 0x60, 0x0a, 0xa2, 0x97, 0xab, 0x86, - 0xa0, 0x57, 0x70, 0x48, 0x73, 0x55, 0x4a, 0x1b, 0xf4, 0x9c, 0x7c, 0x62, 0xb5, 0x6e, 0xb8, 0x4c, - 0xb9, 0x0e, 0xfa, 0x8d, 0xde, 0x30, 0x34, 0x81, 0x2f, 0x34, 0x67, 0x5c, 0x54, 0x5c, 0x07, 0xbe, - 0x7b, 0x39, 0x73, 0x84, 0xa0, 0x9f, 0xf3, 0x5c, 0x05, 0x03, 0xa7, 0x3b, 0x3c, 0x7b, 0x00, 0xf0, - 0xcd, 0x85, 0x46, 0x7f, 0x62, 0xf4, 0x0d, 0x0e, 0xdd, 0x06, 0x4c, 0x00, 0xa6, 0xfd, 0x68, 0x14, - 0xbf, 0xc7, 0x5d, 0xbb, 0xc4, 0x2e, 0x60, 0xe1, 0xef, 0xee, 0xde, 0x79, 0xab, 0xd3, 0x60, 0xab, - 0x68, 0xef, 0x62, 0xd1, 0xfe, 0x85, 0xa2, 0xfe, 0x73, 0x51, 0xf4, 0x03, 0xc2, 0xb5, 0xd2, 0xff, - 0xa9, 0x4e, 0x85, 0xcc, 0xdc, 0x17, 0x46, 0x71, 0xd4, 0x55, 0x67, 0x8e, 0x97, 0x67, 0xff, 0xaa, - 0x35, 0xbb, 0xf8, 0xb5, 0x3b, 0x84, 0x60, 0x7f, 0x08, 0xc1, 0xfd, 0x21, 0x04, 0x37, 0xc7, 0xd0, - 0xdb, 0x1f, 0x43, 0xef, 0xf6, 0x18, 0x7a, 0x7f, 0xbf, 0x64, 0xc2, 0xfe, 0x2b, 0x13, 0xcc, 0x54, - 0x4e, 0x98, 0x32, 0xb9, 0x32, 0x44, 0x24, 0xec, 0x53, 0xa6, 0x48, 0xf5, 0x95, 0xe4, 0x2a, 0x2d, - 0xb7, 0xdc, 0xd4, 0xb7, 0x6e, 0xdd, 0xd8, 0x5e, 0x15, 0xdc, 0x24, 0x43, 0x77, 0xde, 0xcf, 0x8f, - 0x01, 0x00, 0x00, 0xff, 0xff, 0x75, 0x75, 0x92, 0xad, 0x96, 0x02, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xb1, 0xae, 0xd3, 0x30, + 0x18, 0x85, 0xe3, 0x36, 0xad, 0xc0, 0xdd, 0xac, 0x0a, 0x42, 0x85, 0x42, 0x55, 0x96, 0x20, 0x84, + 0xad, 0x86, 0x01, 0x56, 0x2a, 0xd4, 0x11, 0x41, 0x85, 0x18, 0xd8, 0x1c, 0xc7, 0x0d, 0x56, 0x1b, + 0x3b, 0xb2, 0x9d, 0x20, 0x9e, 0x02, 0x1e, 0xab, 0x63, 0x47, 0xa6, 0xab, 0xab, 0xf6, 0x1d, 0xee, + 0x7c, 0x15, 0x27, 0xb7, 0x37, 0x4b, 0xb3, 0xfd, 0xe7, 0xe4, 0xf8, 0xe8, 0xcb, 0xff, 0xc3, 0x37, + 0x22, 0x61, 0x84, 0x16, 0xc5, 0x5e, 0x30, 0x6a, 0x85, 0x92, 0x86, 0x58, 0x4d, 0xa5, 0xd9, 0x72, + 0x4d, 0xaa, 0x98, 0x14, 0x94, 0xed, 0xb8, 0xc5, 0x85, 0x56, 0x56, 0xa1, 0x97, 0x22, 0x61, 0xb8, + 0x1b, 0xc5, 0x0f, 0x51, 0x5c, 0xc5, 0xb3, 0xa8, 0xb7, 0xc8, 0xaa, 0x1d, 0x97, 0x4d, 0xcf, 0x6c, + 0x9a, 0xa9, 0x4c, 0xb9, 0x91, 0xd4, 0x53, 0xeb, 0xbe, 0xed, 0x79, 0xbf, 0xbc, 0xcc, 0x4d, 0x78, + 0xf1, 0x17, 0xc0, 0xe7, 0xeb, 0x52, 0x66, 0x22, 0xd9, 0xf3, 0xef, 0x75, 0xf5, 0x57, 0x07, 0xfa, + 0x99, 0x5a, 0x8a, 0xa6, 0x70, 0x94, 0x72, 0xa9, 0xf2, 0x00, 0xcc, 0x41, 0xf4, 0x74, 0xd3, 0x08, + 0xf4, 0x0c, 0x8e, 0x69, 0xae, 0x4a, 0x69, 0x83, 0x81, 0xb3, 0x5b, 0x55, 0xfb, 0x86, 0xcb, 0x94, + 0xeb, 0x60, 0xd8, 0xf8, 0x8d, 0x42, 0x33, 0xf8, 0x44, 0x73, 0xc6, 0x45, 0xc5, 0x75, 0xe0, 0xbb, + 0x2f, 0x17, 0x8d, 0x10, 0xf4, 0x73, 0x9e, 0xab, 0x60, 0xe4, 0x7c, 0x37, 0x2f, 0xee, 0x00, 0x7c, + 0x71, 0x85, 0xe8, 0x47, 0x8c, 0x3e, 0xc1, 0xb1, 0xdb, 0x80, 0x09, 0xc0, 0x7c, 0x18, 0x4d, 0xe2, + 0xd7, 0xb8, 0x6f, 0x97, 0xd8, 0x15, 0xac, 0xfc, 0xc3, 0xcd, 0x2b, 0x6f, 0xd3, 0x3e, 0xec, 0x80, + 0x0e, 0xae, 0x82, 0x0e, 0xaf, 0x80, 0xfa, 0x8f, 0xa0, 0xe8, 0x0b, 0x84, 0x5b, 0xa5, 0x7f, 0x53, + 0x9d, 0x0a, 0x99, 0xb9, 0x5f, 0x98, 0xc4, 0x51, 0x1f, 0xce, 0x12, 0xaf, 0x2f, 0xf9, 0x96, 0xa9, + 0xd3, 0xb0, 0xfa, 0x76, 0x38, 0x85, 0xe0, 0x78, 0x0a, 0xc1, 0xed, 0x29, 0x04, 0xff, 0xce, 0xa1, + 0x77, 0x3c, 0x87, 0xde, 0xff, 0x73, 0xe8, 0xfd, 0xfc, 0x90, 0x09, 0xfb, 0xab, 0x4c, 0x30, 0x53, + 0x39, 0x61, 0xca, 0xe4, 0xca, 0x10, 0x91, 0xb0, 0x77, 0x99, 0x22, 0xd5, 0x47, 0x92, 0xab, 0xb4, + 0xdc, 0x73, 0x53, 0x5f, 0xbc, 0x73, 0x69, 0xfb, 0xa7, 0xe0, 0x26, 0x19, 0xbb, 0x23, 0xbf, 0xbf, + 0x0f, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xa2, 0xd3, 0x30, 0x9c, 0x02, 0x00, 0x00, } func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { @@ -305,18 +305,16 @@ func (m *FungibleTokenPacketDataV2) MarshalToSizedBuffer(dAtA []byte) (int, erro _ = i var l int _ = l - if m.Forwarding != nil { - { - size, err := m.Forwarding.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintPacket(dAtA, i, uint64(size)) + { + size, err := m.Forwarding.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x2a + i -= size + i = encodeVarintPacket(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x2a if len(m.Memo) > 0 { i -= len(m.Memo) copy(dAtA[i:], m.Memo) @@ -419,10 +417,8 @@ func (m *FungibleTokenPacketDataV2) Size() (n int) { if l > 0 { n += 1 + l + sovPacket(uint64(l)) } - if m.Forwarding != nil { - l = m.Forwarding.Size() - n += 1 + l + sovPacket(uint64(l)) - } + l = m.Forwarding.Size() + n += 1 + l + sovPacket(uint64(l)) return n } @@ -830,9 +826,6 @@ func (m *FungibleTokenPacketDataV2) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Forwarding == nil { - m.Forwarding = &Forwarding{} - } if err := m.Forwarding.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index e2af7801931..69b7a30068b 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -183,7 +183,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - nil, + emptyForwarding, ), nil, }, @@ -199,7 +199,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "memo", - nil, + emptyForwarding, ), nil, }, @@ -215,7 +215,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "memo", - nil, + emptyForwarding, ), nil, }, @@ -263,7 +263,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - nil, + emptyForwarding, ), types.ErrInvalidDenomForTransfer, }, @@ -279,7 +279,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - nil, + emptyForwarding, ), types.ErrInvalidAmount, }, @@ -290,7 +290,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - nil, + emptyForwarding, ), types.ErrInvalidAmount, }, @@ -306,7 +306,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - nil, + emptyForwarding, ), types.ErrInvalidAmount, }, @@ -322,7 +322,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - nil, + emptyForwarding, ), types.ErrInvalidAmount, }, @@ -338,7 +338,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "memo", - nil, + emptyForwarding, ), types.ErrInvalidAmount, }, @@ -354,7 +354,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { "", receiver, "memo", - nil, + emptyForwarding, ), ibcerrors.ErrInvalidAddress, }, @@ -370,7 +370,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, "", "", - nil, + emptyForwarding, ), ibcerrors.ErrInvalidAddress, }, @@ -386,7 +386,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, ibctesting.GenerateString(types.MaximumMemoLength+1), - nil, + emptyForwarding, ), types.ErrInvalidMemo, }, @@ -516,7 +516,7 @@ func TestGetPacketSender(t *testing.T) { sender, receiver, "", - nil, + emptyForwarding, ), sender, }, @@ -532,7 +532,7 @@ func TestGetPacketSender(t *testing.T) { "", receiver, "abc", - nil, + emptyForwarding, ), "", }, @@ -563,7 +563,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver), - nil, + emptyForwarding, ), map[string]interface{}{ @@ -582,7 +582,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, receiver), - nil, + emptyForwarding, ), map[string]interface{}{ "address": receiver, @@ -601,7 +601,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, `{"src_callback": "string"}`, - nil, + emptyForwarding, ), "string", }, @@ -617,7 +617,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, fmt.Sprintf(`{"dest_callback": {"address": "%s", "min_gas": "200000"}}`, receiver), - nil, + emptyForwarding, ), nil, }, @@ -633,7 +633,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, "", - nil, + emptyForwarding, ), nil, }, @@ -649,7 +649,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, "invalid", - nil, + emptyForwarding, ), nil, }, @@ -681,7 +681,7 @@ func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { sender, receiver, "", - nil, + emptyForwarding, ), false, }, @@ -697,7 +697,7 @@ func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { sender, receiver, "abc", - nil, + emptyForwarding, ), true, }, diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index 8d8ca7dbcaf..0d59e9bdc94 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -60,7 +60,7 @@ func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) memo := msgTransfer.Memo // in the case of forwarded transfers, the actual memo is stored in the forwarding path until the final destination - if msgTransfer.Forwarding != nil && len(msgTransfer.Forwarding.Hops) > 0 { + if len(msgTransfer.Forwarding.Hops) > 0 { memo = msgTransfer.Forwarding.Memo } diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index 718d299aac5..0b108525709 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -299,7 +299,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.chainB.GetTimeoutHeight(), 0, "", - nil, + emptyForwarding, ) }, func(res authz.AcceptResponse, err error) { @@ -342,7 +342,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.chainB.GetTimeoutHeight(), 0, "", - nil, + emptyForwarding, ) }, func(res authz.AcceptResponse, err error) { @@ -379,7 +379,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.chainB.GetTimeoutHeight(), 0, "", - nil, + emptyForwarding, ) }, func(res authz.AcceptResponse, err error) { @@ -420,7 +420,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.chainB.GetTimeoutHeight(), 0, "", - nil, + emptyForwarding, ) tc.malleate() diff --git a/modules/apps/transfer/types/tx.pb.go b/modules/apps/transfer/types/tx.pb.go index 66acd8c1238..518107142a6 100644 --- a/modules/apps/transfer/types/tx.pb.go +++ b/modules/apps/transfer/types/tx.pb.go @@ -57,7 +57,7 @@ type MsgTransfer struct { // tokens to be transferred Tokens []types.Coin `protobuf:"bytes,9,rep,name=tokens,proto3" json:"tokens"` // optional forwarding information - Forwarding *Forwarding `protobuf:"bytes,10,opt,name=forwarding,proto3" json:"forwarding,omitempty"` + Forwarding Forwarding `protobuf:"bytes,10,opt,name=forwarding,proto3" json:"forwarding"` } func (m *MsgTransfer) Reset() { *m = MsgTransfer{} } @@ -226,47 +226,47 @@ func init() { var fileDescriptor_7401ed9bed2f8e09 = []byte{ // 659 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4f, 0x6f, 0xd3, 0x30, - 0x14, 0x6f, 0x58, 0x57, 0x36, 0x97, 0x6d, 0xcc, 0xa0, 0x2d, 0x8b, 0x50, 0x5a, 0x55, 0x4c, 0x2a, - 0x9d, 0x66, 0xab, 0x43, 0x68, 0x68, 0xe2, 0xd4, 0x49, 0x68, 0x07, 0x26, 0x8d, 0x68, 0x5c, 0xb8, - 0x4c, 0x49, 0xea, 0xa5, 0xd6, 0x1a, 0x3b, 0xd8, 0x6e, 0x81, 0x0b, 0x42, 0x48, 0x48, 0x88, 0x13, - 0x1f, 0x81, 0x23, 0xc7, 0x7d, 0x8c, 0x1d, 0x77, 0xe4, 0x84, 0xd0, 0x76, 0xd8, 0x85, 0x0f, 0x81, - 0xec, 0x38, 0x25, 0x70, 0x28, 0x70, 0x49, 0xfc, 0xde, 0xfb, 0xbd, 0x3f, 0xbf, 0x9f, 0x9f, 0x0c, - 0xd6, 0x69, 0x14, 0xe3, 0x30, 0xcb, 0x86, 0x34, 0x0e, 0x15, 0xe5, 0x4c, 0x62, 0x25, 0x42, 0x26, - 0x8f, 0x89, 0xc0, 0xe3, 0x2e, 0x56, 0xaf, 0x50, 0x26, 0xb8, 0xe2, 0xf0, 0x0e, 0x8d, 0x62, 0x54, - 0x86, 0xa1, 0x02, 0x86, 0xc6, 0x5d, 0x6f, 0x39, 0x4c, 0x29, 0xe3, 0xd8, 0x7c, 0xf3, 0x04, 0xef, - 0x76, 0xc2, 0x13, 0x6e, 0x8e, 0x58, 0x9f, 0xac, 0x77, 0x35, 0xe6, 0x32, 0xe5, 0x12, 0xa7, 0x32, - 0xd1, 0xe5, 0x53, 0x99, 0xd8, 0x80, 0x6f, 0x03, 0x51, 0x28, 0x09, 0x1e, 0x77, 0x23, 0xa2, 0xc2, - 0x2e, 0x8e, 0x39, 0x65, 0x36, 0xde, 0xd0, 0x63, 0xc6, 0x5c, 0x10, 0x1c, 0x0f, 0x29, 0x61, 0x4a, - 0x67, 0xe7, 0x27, 0x0b, 0xd8, 0x98, 0xce, 0xa3, 0x18, 0xd6, 0x80, 0x5b, 0xef, 0xab, 0xa0, 0xbe, - 0x2f, 0x93, 0x43, 0xeb, 0x85, 0x0d, 0x50, 0x97, 0x7c, 0x24, 0x62, 0x72, 0x94, 0x71, 0xa1, 0x5c, - 0xa7, 0xe9, 0xb4, 0xe7, 0x03, 0x90, 0xbb, 0x0e, 0xb8, 0x50, 0x70, 0x1d, 0x2c, 0x5a, 0x40, 0x3c, - 0x08, 0x19, 0x23, 0x43, 0xf7, 0x9a, 0xc1, 0x2c, 0xe4, 0xde, 0xdd, 0xdc, 0x09, 0x1f, 0x81, 0x59, - 0xc5, 0x4f, 0x08, 0x73, 0x67, 0x9a, 0x4e, 0xbb, 0xbe, 0xb5, 0x86, 0x72, 0x56, 0x48, 0xb3, 0x42, - 0x96, 0x15, 0xda, 0xe5, 0x94, 0xf5, 0xea, 0x67, 0xdf, 0x1a, 0x95, 0x2f, 0x57, 0xa7, 0x1d, 0xc7, - 0x75, 0x82, 0x3c, 0x09, 0xae, 0x80, 0x9a, 0x24, 0xac, 0x4f, 0x84, 0x5b, 0x35, 0xc5, 0xad, 0x05, - 0x3d, 0x30, 0x27, 0x48, 0x4c, 0xe8, 0x98, 0x08, 0x77, 0xd6, 0x44, 0x26, 0x36, 0x7c, 0x02, 0x16, - 0x15, 0x4d, 0x09, 0x1f, 0xa9, 0xa3, 0x01, 0xa1, 0xc9, 0x40, 0xb9, 0x35, 0xd3, 0xda, 0x43, 0xfa, - 0xc2, 0xb4, 0x60, 0xc8, 0xca, 0x34, 0xee, 0xa2, 0x3d, 0x83, 0xe8, 0xcd, 0x4f, 0x7a, 0x07, 0x0b, - 0x36, 0x39, 0x8f, 0xc0, 0x0d, 0xb0, 0x5c, 0x54, 0xd3, 0x7f, 0xa9, 0xc2, 0x34, 0x73, 0xaf, 0x37, - 0x9d, 0x76, 0x35, 0xb8, 0x69, 0x03, 0x87, 0x85, 0x1f, 0x42, 0x50, 0x4d, 0x49, 0xca, 0xdd, 0x39, - 0x33, 0x92, 0x39, 0xc3, 0x6d, 0x50, 0x33, 0x5c, 0xa4, 0x3b, 0xdf, 0x9c, 0x99, 0xae, 0x40, 0x55, - 0x4f, 0x11, 0x58, 0x38, 0xdc, 0x03, 0xe0, 0x98, 0x8b, 0x97, 0xa1, 0xe8, 0x53, 0x96, 0xb8, 0xc0, - 0x70, 0x68, 0xa3, 0x69, 0x4b, 0x87, 0x1e, 0x4f, 0xf0, 0x41, 0x29, 0x77, 0xa7, 0xf3, 0xe1, 0x73, - 0xa3, 0xf2, 0xee, 0xea, 0xb4, 0x63, 0xe5, 0xfb, 0x78, 0x75, 0xda, 0x59, 0xc9, 0xa7, 0xd8, 0x94, - 0xfd, 0x13, 0x5c, 0xba, 0xf7, 0xd6, 0x36, 0xb8, 0x55, 0x32, 0x03, 0x22, 0x33, 0xce, 0x24, 0xd1, - 0x82, 0x4b, 0xf2, 0x62, 0x44, 0x58, 0x4c, 0xcc, 0x2e, 0x54, 0x83, 0x89, 0xbd, 0x53, 0xd5, 0xe5, - 0x5b, 0x6f, 0xc0, 0xd2, 0xbe, 0x4c, 0x9e, 0x65, 0xfd, 0x50, 0x91, 0x83, 0x50, 0x84, 0xa9, 0x34, - 0xb7, 0x47, 0x13, 0x46, 0x84, 0x5d, 0x1f, 0x6b, 0xc1, 0x1e, 0xa8, 0x65, 0x06, 0x61, 0x56, 0xa6, - 0xbe, 0x75, 0x77, 0x3a, 0xab, 0xbc, 0x5a, 0xa1, 0x4e, 0x9e, 0xb9, 0xb3, 0xf4, 0x8b, 0x93, 0x29, - 0xda, 0x5a, 0x03, 0xab, 0x7f, 0xf4, 0x2f, 0x86, 0xdf, 0xfa, 0xe1, 0x80, 0x99, 0x7d, 0x99, 0xc0, - 0x01, 0x98, 0x9b, 0xec, 0xf7, 0xbd, 0xe9, 0x3d, 0x4b, 0x1a, 0x78, 0xdd, 0x7f, 0x86, 0x4e, 0xe4, - 0x52, 0xe0, 0xc6, 0x6f, 0x4a, 0x6c, 0xfe, 0xb5, 0x44, 0x19, 0xee, 0x3d, 0xf8, 0x2f, 0x78, 0xd1, - 0xd5, 0x9b, 0x7d, 0xab, 0x37, 0xb8, 0xf7, 0xf4, 0xec, 0xc2, 0x77, 0xce, 0x2f, 0x7c, 0xe7, 0xfb, - 0x85, 0xef, 0x7c, 0xba, 0xf4, 0x2b, 0xe7, 0x97, 0x7e, 0xe5, 0xeb, 0xa5, 0x5f, 0x79, 0xbe, 0x9d, - 0x50, 0x35, 0x18, 0x45, 0x28, 0xe6, 0x29, 0xb6, 0xaf, 0x0b, 0x8d, 0xe2, 0xcd, 0x84, 0xe3, 0xf1, - 0x43, 0x9c, 0xf2, 0xfe, 0x68, 0x48, 0xa4, 0x7e, 0x31, 0x4a, 0x2f, 0x85, 0x7a, 0x9d, 0x11, 0x19, - 0xd5, 0xcc, 0x23, 0x71, 0xff, 0x67, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x2c, 0x89, 0xb7, 0x1b, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x31, 0x6f, 0x13, 0x31, + 0x14, 0xce, 0xd1, 0x34, 0xb4, 0x0e, 0x6d, 0xa9, 0x41, 0xed, 0xf5, 0x84, 0x2e, 0x51, 0x44, 0xa5, + 0x90, 0xaa, 0xb6, 0x52, 0x84, 0x8a, 0x2a, 0xa6, 0x54, 0x42, 0x0c, 0x14, 0x95, 0x53, 0x59, 0x58, + 0xaa, 0xbb, 0x8b, 0x7b, 0xb1, 0x9a, 0xb3, 0x0f, 0xdb, 0x09, 0xb0, 0x20, 0xc4, 0x84, 0x60, 0xe1, + 0x27, 0x30, 0x32, 0xf6, 0x67, 0x74, 0xec, 0xc8, 0x84, 0x50, 0x3b, 0x74, 0xe1, 0x47, 0x20, 0xfb, + 0x7c, 0xe1, 0x60, 0x08, 0xb0, 0xdc, 0xf9, 0xbd, 0xf7, 0xbd, 0xef, 0xbd, 0xf7, 0xf9, 0xc9, 0x60, + 0x9d, 0x46, 0x31, 0x0e, 0xb3, 0x6c, 0x48, 0xe3, 0x50, 0x51, 0xce, 0x24, 0x56, 0x22, 0x64, 0xf2, + 0x88, 0x08, 0x3c, 0xee, 0x62, 0xf5, 0x0a, 0x65, 0x82, 0x2b, 0x0e, 0x6f, 0xd1, 0x28, 0x46, 0x65, + 0x18, 0x2a, 0x60, 0x68, 0xdc, 0xf5, 0x96, 0xc3, 0x94, 0x32, 0x8e, 0xcd, 0x37, 0x4f, 0xf0, 0x6e, + 0x26, 0x3c, 0xe1, 0xe6, 0x88, 0xf5, 0xc9, 0x7a, 0x57, 0x63, 0x2e, 0x53, 0x2e, 0x71, 0x2a, 0x13, + 0x4d, 0x9f, 0xca, 0xc4, 0x06, 0x7c, 0x1b, 0x88, 0x42, 0x49, 0xf0, 0xb8, 0x1b, 0x11, 0x15, 0x76, + 0x71, 0xcc, 0x29, 0xb3, 0xf1, 0x86, 0x6e, 0x33, 0xe6, 0x82, 0xe0, 0x78, 0x48, 0x09, 0x53, 0x3a, + 0x3b, 0x3f, 0x59, 0xc0, 0xc6, 0xf4, 0x39, 0x8a, 0x66, 0x0d, 0xb8, 0xf5, 0xb1, 0x0a, 0xea, 0x7b, + 0x32, 0x39, 0xb0, 0x5e, 0xd8, 0x00, 0x75, 0xc9, 0x47, 0x22, 0x26, 0x87, 0x19, 0x17, 0xca, 0x75, + 0x9a, 0x4e, 0x7b, 0x3e, 0x00, 0xb9, 0x6b, 0x9f, 0x0b, 0x05, 0xd7, 0xc1, 0xa2, 0x05, 0xc4, 0x83, + 0x90, 0x31, 0x32, 0x74, 0xaf, 0x18, 0xcc, 0x42, 0xee, 0xdd, 0xcd, 0x9d, 0xf0, 0x01, 0x98, 0x55, + 0xfc, 0x98, 0x30, 0x77, 0xa6, 0xe9, 0xb4, 0xeb, 0x5b, 0x6b, 0x28, 0x9f, 0x0a, 0xe9, 0xa9, 0x90, + 0x9d, 0x0a, 0xed, 0x72, 0xca, 0x7a, 0xf5, 0xd3, 0x6f, 0x8d, 0xca, 0x97, 0xcb, 0x93, 0x8e, 0xe3, + 0x3a, 0x41, 0x9e, 0x04, 0x57, 0x40, 0x4d, 0x12, 0xd6, 0x27, 0xc2, 0xad, 0x1a, 0x72, 0x6b, 0x41, + 0x0f, 0xcc, 0x09, 0x12, 0x13, 0x3a, 0x26, 0xc2, 0x9d, 0x35, 0x91, 0x89, 0x0d, 0x1f, 0x83, 0x45, + 0x45, 0x53, 0xc2, 0x47, 0xea, 0x70, 0x40, 0x68, 0x32, 0x50, 0x6e, 0xcd, 0x94, 0xf6, 0x90, 0xbe, + 0x30, 0x2d, 0x18, 0xb2, 0x32, 0x8d, 0xbb, 0xe8, 0x91, 0x41, 0xf4, 0xe6, 0x27, 0xb5, 0x83, 0x05, + 0x9b, 0x9c, 0x47, 0xe0, 0x06, 0x58, 0x2e, 0xd8, 0xf4, 0x5f, 0xaa, 0x30, 0xcd, 0xdc, 0xab, 0x4d, + 0xa7, 0x5d, 0x0d, 0xae, 0xdb, 0xc0, 0x41, 0xe1, 0x87, 0x10, 0x54, 0x53, 0x92, 0x72, 0x77, 0xce, + 0xb4, 0x64, 0xce, 0x70, 0x1b, 0xd4, 0xcc, 0x2c, 0xd2, 0x9d, 0x6f, 0xce, 0x4c, 0x57, 0xa0, 0xaa, + 0xbb, 0x08, 0x2c, 0x1c, 0x3e, 0x01, 0xe0, 0x88, 0x8b, 0x97, 0xa1, 0xe8, 0x53, 0x96, 0xb8, 0xc0, + 0xcc, 0xd0, 0x46, 0xd3, 0x96, 0x0e, 0x3d, 0x9c, 0xe0, 0x2d, 0x57, 0x89, 0x61, 0xa7, 0xf3, 0xfe, + 0x73, 0xa3, 0xf2, 0xee, 0xf2, 0xa4, 0x63, 0x45, 0xfc, 0x70, 0x79, 0xd2, 0x59, 0xc9, 0x7b, 0xd9, + 0x94, 0xfd, 0x63, 0x5c, 0xba, 0xfd, 0xd6, 0x36, 0xb8, 0x51, 0x32, 0x03, 0x22, 0x33, 0xce, 0x24, + 0xd1, 0xb2, 0x4b, 0xf2, 0x62, 0x44, 0x58, 0x4c, 0xcc, 0x46, 0x54, 0x83, 0x89, 0xbd, 0x53, 0xd5, + 0xf4, 0xad, 0x37, 0x60, 0x69, 0x4f, 0x26, 0xcf, 0xb2, 0x7e, 0xa8, 0xc8, 0x7e, 0x28, 0xc2, 0x54, + 0x9a, 0x3b, 0xa4, 0x09, 0x23, 0xc2, 0x2e, 0x91, 0xb5, 0x60, 0x0f, 0xd4, 0x32, 0x83, 0x30, 0x8b, + 0x53, 0xdf, 0xba, 0x3d, 0x7d, 0xb6, 0x9c, 0xad, 0xd0, 0x28, 0xcf, 0xdc, 0x59, 0xfa, 0x35, 0x93, + 0x21, 0x6d, 0xad, 0x81, 0xd5, 0x3f, 0xea, 0x17, 0xcd, 0x6f, 0xfd, 0x70, 0xc0, 0xcc, 0x9e, 0x4c, + 0xe0, 0x00, 0xcc, 0x4d, 0xb6, 0xfc, 0xce, 0xf4, 0x9a, 0x25, 0x0d, 0xbc, 0xee, 0x3f, 0x43, 0x27, + 0x72, 0x29, 0x70, 0xed, 0x37, 0x25, 0x36, 0xff, 0x4a, 0x51, 0x86, 0x7b, 0xf7, 0xfe, 0x0b, 0x5e, + 0x54, 0xf5, 0x66, 0xdf, 0xea, 0x3d, 0xee, 0x3d, 0x3d, 0x3d, 0xf7, 0x9d, 0xb3, 0x73, 0xdf, 0xf9, + 0x7e, 0xee, 0x3b, 0x9f, 0x2e, 0xfc, 0xca, 0xd9, 0x85, 0x5f, 0xf9, 0x7a, 0xe1, 0x57, 0x9e, 0x6f, + 0x27, 0x54, 0x0d, 0x46, 0x11, 0x8a, 0x79, 0x8a, 0xed, 0x1b, 0x43, 0xa3, 0x78, 0x33, 0xe1, 0x78, + 0x7c, 0x1f, 0xa7, 0xbc, 0x3f, 0x1a, 0x12, 0xa9, 0xdf, 0x8d, 0xd2, 0x7b, 0xa1, 0x5e, 0x67, 0x44, + 0x46, 0x35, 0xf3, 0x54, 0xdc, 0xfd, 0x19, 0x00, 0x00, 0xff, 0xff, 0xaf, 0x48, 0x04, 0x1e, 0x21, 0x05, 0x00, 0x00, } @@ -410,18 +410,16 @@ func (m *MsgTransfer) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Forwarding != nil { - { - size, err := m.Forwarding.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) + { + size, err := m.Forwarding.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } - i-- - dAtA[i] = 0x52 + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x52 if len(m.Tokens) > 0 { for iNdEx := len(m.Tokens) - 1; iNdEx >= 0; iNdEx-- { { @@ -640,10 +638,8 @@ func (m *MsgTransfer) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } - if m.Forwarding != nil { - l = m.Forwarding.Size() - n += 1 + l + sovTx(uint64(l)) - } + l = m.Forwarding.Size() + n += 1 + l + sovTx(uint64(l)) return n } @@ -1026,9 +1022,6 @@ func (m *MsgTransfer) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Forwarding == nil { - m.Forwarding = &Forwarding{} - } if err := m.Forwarding.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } diff --git a/proto/ibc/applications/transfer/v1/tx.proto b/proto/ibc/applications/transfer/v1/tx.proto index 0a1c8d49d8c..6a422d0c74d 100644 --- a/proto/ibc/applications/transfer/v1/tx.proto +++ b/proto/ibc/applications/transfer/v1/tx.proto @@ -52,7 +52,7 @@ message MsgTransfer { // tokens to be transferred repeated cosmos.base.v1beta1.Coin tokens = 9 [(gogoproto.nullable) = false]; // optional forwarding information - Forwarding forwarding = 10; + Forwarding forwarding = 10 [(gogoproto.nullable) = false]; } // MsgTransferResponse defines the Msg/Transfer response type. diff --git a/proto/ibc/applications/transfer/v2/packet.proto b/proto/ibc/applications/transfer/v2/packet.proto index a2948f5b996..9999e7ea87c 100644 --- a/proto/ibc/applications/transfer/v2/packet.proto +++ b/proto/ibc/applications/transfer/v2/packet.proto @@ -37,5 +37,5 @@ message FungibleTokenPacketDataV2 { // optional memo string memo = 4; // optional forwarding information - ibc.applications.transfer.v1.Forwarding forwarding = 5; + ibc.applications.transfer.v1.Forwarding forwarding = 5 [(gogoproto.nullable) = false]; } diff --git a/testing/solomachine.go b/testing/solomachine.go index c97ced04875..74a127686a6 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -378,7 +378,7 @@ func (solo *Solomachine) SendTransfer(chain *TestChain, portID, channelID string clienttypes.ZeroHeight(), uint64(chain.GetContext().BlockTime().Add(time.Hour).UnixNano()), "", - nil, + transfertypes.Forwarding{}, ) for _, fn := range fns { From dc4764106a67a822f39fdd4524869f41f18f0ae6 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 18 Jun 2024 17:55:20 +0200 Subject: [PATCH 082/141] chore: restructure functions with logical ordering (#6638) --- modules/apps/transfer/keeper/forwarding.go | 82 +++++++++++----------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 69fdfdf5db9..52513f10c4f 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -13,6 +13,47 @@ import ( ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ) +// forwardPacket forwards a fungible FungibleTokenPacketDataV2 to the next hop in the forwarding path. +func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDataV2, packet channeltypes.Packet, receivedCoins sdk.Coins) error { + var memo string + + var nextForwardingPath types.Forwarding + if len(data.Forwarding.Hops) == 1 { + memo = data.Forwarding.Memo + } else { + nextForwardingPath = types.NewForwarding(data.Forwarding.Memo, data.Forwarding.Hops[1:]...) + } + + // sending from the forward escrow address to the original receiver address. + sender := types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) + + msg := types.NewMsgTransfer( + data.Forwarding.Hops[0].PortId, + data.Forwarding.Hops[0].ChannelId, + receivedCoins, + sender.String(), + data.Receiver, + packet.TimeoutHeight, + packet.TimeoutTimestamp, + memo, + nextForwardingPath, + ) + + resp, err := k.Transfer(ctx, msg) + if err != nil { + return err + } + + k.SetForwardedPacket(ctx, data.Forwarding.Hops[0].PortId, data.Forwarding.Hops[0].ChannelId, resp.Sequence, packet) + return nil +} + +// ackForwardPacketSuccess writes a successful async acknowledgement for the prevPacket +func (k Keeper) ackForwardPacketSuccess(ctx sdk.Context, prevPacket channeltypes.Packet) error { + forwardAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) +} + // ackForwardPacketError reverts the receive packet logic that occurs in the middle chain and writes the async ack for the prevPacket func (k Keeper) ackForwardPacketError(ctx sdk.Context, prevPacket channeltypes.Packet, failedPacketData types.FungibleTokenPacketDataV2) error { // the forwarded packet has failed, thus the funds have been refunded to the intermediate address. @@ -26,12 +67,6 @@ func (k Keeper) ackForwardPacketError(ctx sdk.Context, prevPacket channeltypes.P return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) } -// ackForwardPacketSuccess writes a successful async acknowledgement for the prevPacket -func (k Keeper) ackForwardPacketSuccess(ctx sdk.Context, prevPacket channeltypes.Packet) error { - forwardAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) -} - // ackForwardPacketTimeout reverts the receive packet logic that occurs in the middle chain and writes a failed async ack for the prevPacket func (k Keeper) ackForwardPacketTimeout(ctx sdk.Context, prevPacket channeltypes.Packet, timeoutPacketData types.FungibleTokenPacketDataV2) error { if err := k.revertForwardedPacket(ctx, prevPacket, timeoutPacketData); err != nil { @@ -95,41 +130,6 @@ func (k Keeper) revertForwardedPacket(ctx sdk.Context, prevPacket channeltypes.P return nil } -// forwardPacket forwards a fungible FungibleTokenPacketDataV2 to the next hop in the forwarding path. -func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDataV2, packet channeltypes.Packet, receivedCoins sdk.Coins) error { - var memo string - - var nextForwardingPath types.Forwarding - if len(data.Forwarding.Hops) == 1 { - memo = data.Forwarding.Memo - } else { - nextForwardingPath = types.NewForwarding(data.Forwarding.Memo, data.Forwarding.Hops[1:]...) - } - - // sending from the forward escrow address to the original receiver address. - sender := types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) - - msg := types.NewMsgTransfer( - data.Forwarding.Hops[0].PortId, - data.Forwarding.Hops[0].ChannelId, - receivedCoins, - sender.String(), - data.Receiver, - packet.TimeoutHeight, - packet.TimeoutTimestamp, - memo, - nextForwardingPath, - ) - - resp, err := k.Transfer(ctx, msg) - if err != nil { - return err - } - - k.SetForwardedPacket(ctx, data.Forwarding.Hops[0].PortId, data.Forwarding.Hops[0].ChannelId, resp.Sequence, packet) - return nil -} - // getReceiverFromPacketData returns either the sender specified in the packet data or the forwarding address // if there are still hops left to perform. func getReceiverFromPacketData(data types.FungibleTokenPacketDataV2, portID, channelID string) (sdk.AccAddress, error) { From 832b1bd85da7f72f49d3112e5101c16c830c49b5 Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Wed, 19 Jun 2024 09:12:19 +0100 Subject: [PATCH 083/141] test: Add tests for OnTimeoutPacket when middle chain times out packet (#6596) * Create ontimeoutpacket test for forwarding --------- Co-authored-by: Carlos Rodriguez --- .../transfer/keeper/relay_forwarding_test.go | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 8cea5d23a0b..7dae98356a4 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -1,7 +1,9 @@ package keeper_test import ( + "errors" "fmt" + "time" sdkmath "cosmossdk.io/math" @@ -609,3 +611,178 @@ Test async ack is properly relayed to middle hop after forwarding transfer compl // TODO Tiemout during forwarding after middle hop execution reverts properly the state changes */ + +func (suite *KeeperTestSuite) setupForwardingPaths() (pathAtoB, pathBtoC *ibctesting.Path) { + pathAtoB = ibctesting.NewTransferPath(suite.chainA, suite.chainB) + pathBtoC = ibctesting.NewTransferPath(suite.chainB, suite.chainC) + pathAtoB.Setup() + pathBtoC.Setup() + return pathAtoB, pathBtoC +} + +type amountType int + +const ( + escrow amountType = iota + balance +) + +func (suite *KeeperTestSuite) assertAmountOnChain(chain *ibctesting.TestChain, balanceType amountType, amount sdkmath.Int, denom string) { + var total sdk.Coin + switch balanceType { + case escrow: + total = chain.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(chain.GetContext(), denom) + case balance: + total = chain.GetSimApp().BankKeeper.GetBalance(chain.GetContext(), chain.SenderAccounts[0].SenderAccount.GetAddress(), denom) + default: + suite.Fail("invalid amountType %s", balanceType) + } + suite.Require().Equal(amount, total.Amount, fmt.Sprintf("Chain %s: got balance of %d, wanted %d", chain.Name(), total.Amount, amount)) +} + +// TestOnTimeoutPacketForwarding tests the scenario in which a packet goes from +// A to C, using B as a forwarding hop. The packet times out when going to C +// from B and we verify that funds are properly returned to A. +func (suite *KeeperTestSuite) TestOnTimeoutPacketForwarding() { + pathAtoB, pathBtoC := suite.setupForwardingPaths() + + amount := sdkmath.NewInt(100) + coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainC.SenderAccounts[0].SenderAccount + + denomA := types.NewDenom(coin.Denom) + denomAB := types.NewDenom(coin.Denom, types.NewTrace(pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID)) + denomABC := types.NewDenom(coin.Denom, append(denomAB.Trace, types.NewTrace(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID))...) + + originalABalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), sender.GetAddress(), coin.Denom) + + forwarding := types.Forwarding{ + Hops: []types.Hop{ + { + PortId: pathBtoC.EndpointA.ChannelConfig.PortID, + ChannelId: pathBtoC.EndpointA.ChannelID, + }, + }, + } + + transferMsg := types.NewMsgTransfer( + pathAtoB.EndpointA.ChannelConfig.PortID, + pathAtoB.EndpointA.ChannelID, + sdk.NewCoins(coin), + sender.GetAddress().String(), + receiver.GetAddress().String(), + clienttypes.ZeroHeight(), + uint64(suite.chainA.GetContext().BlockTime().Add(time.Minute*5).UnixNano()), + "", + forwarding, + ) + + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packet, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packet) + + err = pathAtoB.EndpointB.UpdateClient() + suite.Require().NoError(err) + + // Receive packet on B. + result, err = pathAtoB.EndpointB.RecvPacketWithResult(packet) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + err = pathBtoC.EndpointA.UpdateClient() + suite.Require().NoError(err) + + err = pathBtoC.EndpointB.UpdateClient() + suite.Require().NoError(err) + + // Make sure funds went from A to B's escrow account. + suite.assertAmountOnChain(suite.chainA, balance, originalABalance.Amount.Sub(amount), denomA.IBCDenom()) + suite.assertAmountOnChain(suite.chainB, escrow, amount, denomAB.IBCDenom()) + + // Check that forwarded packet exists + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, packet.Sequence) + suite.Require().True(found, "Chain B has no forwarded packet") + suite.Require().Equal(packet, forwardedPacket, "ForwardedPacket stored in ChainB is not the same that was sent") + + address := types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel).String() + data := types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(pathAtoB.EndpointA.ChannelConfig.PortID, pathAtoB.EndpointA.ChannelID)), + Amount: "100", + }, + }, + address, + receiver.GetAddress().String(), + "", types.Forwarding{}, + ) + + packet = channeltypes.NewPacket( + data.GetBytes(), + 1, + pathBtoC.EndpointA.ChannelConfig.PortID, + pathBtoC.EndpointA.ChannelID, + pathBtoC.EndpointB.ChannelConfig.PortID, + pathBtoC.EndpointB.ChannelID, + packet.TimeoutHeight, + 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) + suite.Require().True(ok) + + // Trigger OnTimeoutPacket for chainB + err = cbs.OnTimeoutPacket(suite.chainB.GetContext(), packet, nil) + suite.Require().NoError(err) + + // Ensure that chainB has an ack. + storedAck, found := suite.chainB.App.GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainB.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + suite.Require().True(found, "chainB does not have an ack") + + // And that this ack is of the type we expect (Error due to time out) + ack := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet timed out")) + ackbytes := channeltypes.CommitAcknowledgement(ack.Acknowledgement()) + suite.Require().Equal(ackbytes, storedAck) + + data = types.NewFungibleTokenPacketDataV2( + []types.Token{ + { + Denom: types.NewDenom(sdk.DefaultBondDenom), + Amount: "100", + }, + }, + sender.GetAddress().String(), + receiver.GetAddress().String(), + "", forwarding, + ) + + packet = channeltypes.NewPacket( + data.GetBytes(), + 1, + pathAtoB.EndpointA.ChannelConfig.PortID, + pathAtoB.EndpointA.ChannelID, + pathAtoB.EndpointB.ChannelConfig.PortID, + pathAtoB.EndpointB.ChannelID, + packet.TimeoutHeight, + packet.TimeoutTimestamp) + + // Send the ack to chain A. + err = suite.chainA.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, data, ack) + suite.Require().NoError(err) + + // Finally, check that A,B, and C escrow accounts do not have fund. + suite.assertAmountOnChain(suite.chainC, escrow, sdkmath.NewInt(0), denomABC.IBCDenom()) + suite.assertAmountOnChain(suite.chainB, escrow, sdkmath.NewInt(0), denomAB.IBCDenom()) + suite.assertAmountOnChain(suite.chainA, escrow, sdkmath.NewInt(0), denomA.IBCDenom()) + + // And that A has its original balance back. + suite.assertAmountOnChain(suite.chainA, balance, originalABalance.Amount, coin.Denom) +} From 360b2f8811f89b1e79ae8f5eb8be6ae62fa7c1fc Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Wed, 19 Jun 2024 15:48:45 +0200 Subject: [PATCH 084/141] feat(transfer): add ShouldBeForwarded convenience method to msg transfer (#6595) * feat(transfer): add should-be-forwarded convenience method to msg transfer * Clean up packet and transfer msg validation for forwarding logic --------- Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/types/msgs.go | 7 ++++++- modules/apps/transfer/types/packet.go | 2 +- modules/apps/transfer/types/transfer_authorization.go | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 9a3d4b821fc..edf45df9eab 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -107,7 +107,7 @@ func (msg MsgTransfer) ValidateBasic() error { } // We cannot have non-empty memo and non-empty forwarding hops at the same time. - if len(msg.Forwarding.Hops) > 0 && msg.Memo != "" { + if msg.ShouldBeForwarded() && msg.Memo != "" { return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", msg.Memo, msg.Forwarding.Hops) } @@ -131,6 +131,11 @@ func (msg MsgTransfer) GetCoins() sdk.Coins { return coins } +// ShouldBeForwarded determines if the transfer should be forwarded to the next hop. +func (msg MsgTransfer) ShouldBeForwarded() bool { + return len(msg.Forwarding.Hops) > 0 +} + // isValidIBCCoin returns true if the token provided is valid, // and should be used to transfer tokens. func isValidIBCCoin(coin sdk.Coin) bool { diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 6f74c1f4d54..6f8a34a4e24 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -145,7 +145,7 @@ func (ftpd FungibleTokenPacketDataV2) ValidateBasic() error { } // We cannot have non-empty memo and non-empty forwarding path hops at the same time. - if len(ftpd.Forwarding.Hops) > 0 && ftpd.Memo != "" { + if ftpd.ShouldBeForwarded() && ftpd.Memo != "" { return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", ftpd.Memo, ftpd.Forwarding.Hops) } diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index 0d59e9bdc94..5419b503512 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -60,7 +60,7 @@ func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) memo := msgTransfer.Memo // in the case of forwarded transfers, the actual memo is stored in the forwarding path until the final destination - if len(msgTransfer.Forwarding.Hops) > 0 { + if msgTransfer.ShouldBeForwarded() { memo = msgTransfer.Forwarding.Memo } From 84c7c33cdfd70031a8ca56d3c5f31af1f7f21d21 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 19 Jun 2024 16:42:55 +0200 Subject: [PATCH 085/141] disallow timeout height usage when forwarding packets (#6641) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * disallow non-zero timeout height when forwarding tokens * typo * move constant * use time to create default timeout timestamp delta * Apply suggestions from code review * refactor: add GetTimeoutTimestamp helper fn to the testing pkg * lint --------- Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- modules/apps/transfer/ibc_module_test.go | 2 +- modules/apps/transfer/keeper/forwarding.go | 3 +- .../transfer/keeper/relay_forwarding_test.go | 22 ++++---- modules/apps/transfer/types/msgs.go | 13 ++++- modules/apps/transfer/types/msgs_test.go | 55 ++++++++++--------- testing/chain.go | 6 ++ testing/values.go | 2 + 7 files changed, 60 insertions(+), 43 deletions(-) diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index cbf937dd9a4..171f6d8108f 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -376,7 +376,7 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { } seq := uint64(1) - packet = channeltypes.NewPacket(packetData.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) + packet = channeltypes.NewPacket(packetData.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.ZeroHeight(), suite.chainA.GetTimeoutTimestamp()) module, _, err := suite.chainA.App.GetIBCKeeper().PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort) suite.Require().NoError(err) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 52513f10c4f..72b2e6f2f60 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -8,6 +8,7 @@ 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" @@ -33,7 +34,7 @@ func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDat receivedCoins, sender.String(), data.Receiver, - packet.TimeoutHeight, + clienttypes.ZeroHeight(), packet.TimeoutTimestamp, memo, nextForwardingPath, diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 7dae98356a4..78191ce7f04 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -41,8 +41,8 @@ func (suite *KeeperTestSuite) TestPathForwarding() { sdk.NewCoins(coin), sender.GetAddress().String(), receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", + clienttypes.ZeroHeight(), + suite.chainA.GetTimeoutTimestamp(), "", forwarding, ) result, err := suite.chainA.SendMsgs(transferMsg) @@ -98,8 +98,8 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { sdk.NewCoins(coin), sender.GetAddress().String(), receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", + clienttypes.ZeroHeight(), + suite.chainA.GetTimeoutTimestamp(), "", forwarding, ) @@ -176,8 +176,8 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { sdk.NewCoins(coin), sender.GetAddress().String(), receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", + clienttypes.ZeroHeight(), + suite.chainA.GetTimeoutTimestamp(), "", forwarding, ) @@ -197,7 +197,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { Amount: amount.String(), }, }, sender.GetAddress().String(), receiver.GetAddress().String(), "", forwarding) - packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) + packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.ZeroHeight(), suite.chainA.GetTimeoutTimestamp()) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) // If forwarding has been triggered then the async must be true. @@ -276,8 +276,8 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { sdk.NewCoins(coinOnA), sender.GetAddress().String(), receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", + clienttypes.ZeroHeight(), + suite.chainA.GetTimeoutTimestamp(), "", forwarding, ) @@ -490,8 +490,8 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { sdk.NewCoins(coin), sender.GetAddress().String(), receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", + clienttypes.ZeroHeight(), + suite.chainA.GetTimeoutTimestamp(), "", forwarding, ) diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index edf45df9eab..2e6bf3d5ba6 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -106,9 +106,16 @@ func (msg MsgTransfer) ValidateBasic() error { return err } - // We cannot have non-empty memo and non-empty forwarding hops at the same time. - if msg.ShouldBeForwarded() && msg.Memo != "" { - return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", msg.Memo, msg.Forwarding.Hops) + if msg.ShouldBeForwarded() { + // when forwarding, the timeout height must not be set + if !msg.TimeoutHeight.IsZero() { + return errorsmod.Wrapf(ErrInvalidPacketTimeout, "timeout height must not be set if forwarding path hops is not empty: %s, %s", msg.TimeoutHeight, msg.Forwarding.Hops) + } + + // when forwarding, the memo must be empty + if msg.Memo != "" { + return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", msg.Memo, msg.Forwarding.Hops) + } } for _, coin := range msg.GetCoins() { diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index 49caeb04831..03fc39f61fb 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -58,33 +58,34 @@ func TestMsgTransferValidation(t *testing.T) { msg *types.MsgTransfer expError error }{ - {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), nil}, - {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), nil}, - {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, timeoutHeight, 0, "", emptyForwarding), nil}, - {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, - {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, - {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, - {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, - {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, - {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, - {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, ibctesting.GenerateString(types.MaximumMemoLength+1), emptyForwarding), types.ErrInvalidMemo}, - {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), host.ErrInvalidID}, - {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, - {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, - {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidAddress}, - {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidAddress}, - {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidAddress}, - {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, - {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, - {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, - {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, - {"multidenom: too many coins", types.NewMsgTransfer(validPort, validChannel, make([]sdk.Coin, types.MaximumTokensLength+1), sender, receiver, timeoutHeight, 0, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, - {"multidenom: both token and tokens are set", &types.MsgTransfer{validPort, validChannel, coin, sender, receiver, timeoutHeight, 0, "", coins, emptyForwarding}, ibcerrors.ErrInvalidCoins}, - {"memo must be empty if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "memo", types.NewForwarding("", validHop)), types.ErrInvalidMemo}, - {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwarding("", types.Hop{PortId: invalidPort, ChannelId: validChannel})), host.ErrInvalidID}, - {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwarding("", types.Hop{PortId: validPort, ChannelId: invalidChannel})), host.ErrInvalidID}, - {"invalid forwarding info too many hops", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwarding("", generateHops(types.MaximumNumberOfForwardingHops+1)...)), types.ErrInvalidForwarding}, - {"invalid forwarding info too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 0, "", types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop)), types.ErrInvalidMemo}, + {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), nil}, + {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), nil}, + {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), nil}, + {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), host.ErrInvalidID}, + {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), host.ErrInvalidID}, + {"port id contains non-alpha", types.NewMsgTransfer(invalidPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), host.ErrInvalidID}, + {"too short channel id", types.NewMsgTransfer(validPort, invalidShortChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), host.ErrInvalidID}, + {"too long channel id", types.NewMsgTransfer(validPort, invalidLongChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), host.ErrInvalidID}, + {"too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, ibctesting.GenerateString(types.MaximumMemoLength+1), emptyForwarding), types.ErrInvalidMemo}, + {"channel id contains non-alpha", types.NewMsgTransfer(validPort, invalidChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), host.ErrInvalidID}, + {"invalid denom", types.NewMsgTransfer(validPort, validChannel, invalidDenomCoins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"missing sender address", types.NewMsgTransfer(validPort, validChannel, coins, emptyAddr, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidAddress}, + {"missing recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, "", clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidAddress}, + {"too long recipient address", types.NewMsgTransfer(validPort, validChannel, coins, sender, ibctesting.GenerateString(types.MaximumReceiverLength+1), clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidAddress}, + {"empty coins", types.NewMsgTransfer(validPort, validChannel, sdk.NewCoins(), sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"multidenom: invalid denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidDenomCoins...), sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"multidenom: invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, coins.Add(invalidIBCCoins...), sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"multidenom: too many coins", types.NewMsgTransfer(validPort, validChannel, make([]sdk.Coin, types.MaximumTokensLength+1), sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, + {"multidenom: both token and tokens are set", &types.MsgTransfer{validPort, validChannel, coin, sender, receiver, clienttypes.ZeroHeight(), 100, "", coins, emptyForwarding}, ibcerrors.ErrInvalidCoins}, + {"timeout height must be zero if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 100, "memo", types.NewForwarding("", validHop)), types.ErrInvalidPacketTimeout}, + {"memo must be empty if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "memo", types.NewForwarding("", validHop)), types.ErrInvalidMemo}, + {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding("", types.Hop{PortId: invalidPort, ChannelId: validChannel})), host.ErrInvalidID}, + {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding("", types.Hop{PortId: validPort, ChannelId: invalidChannel})), host.ErrInvalidID}, + {"invalid forwarding info too many hops", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding("", generateHops(types.MaximumNumberOfForwardingHops+1)...)), types.ErrInvalidForwarding}, + {"invalid forwarding info too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop)), types.ErrInvalidMemo}, } for _, tc := range testCases { diff --git a/testing/chain.go b/testing/chain.go index 663e4fe853a..6a264a6e64d 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -629,6 +629,12 @@ func (chain *TestChain) GetTimeoutHeight() clienttypes.Height { return clienttypes.NewHeight(clienttypes.ParseChainID(chain.ChainID), uint64(chain.GetContext().BlockHeight())+100) } +// GetTimeoutTimestamp is a convenience function which returns a IBC packet timeout timestamp +// to be used for testing. It returns the current block timestamp + default timestamp delta (1 hour). +func (chain *TestChain) GetTimeoutTimestamp() uint64 { + return uint64(chain.GetContext().BlockTime().UnixNano()) + DefaultTimeoutTimestampDelta +} + // DeleteKey deletes the specified key from the ibc store. func (chain *TestChain) DeleteKey(key []byte) { storeKey := chain.GetSimApp().GetKey(exported.StoreKey) diff --git a/testing/values.go b/testing/values.go index e8e6dd006e7..d91dcb1c898 100644 --- a/testing/values.go +++ b/testing/values.go @@ -55,6 +55,8 @@ var ( // DefaultTrustLevel sets params variables used to create a TM client DefaultTrustLevel = ibctm.DefaultTrustLevel + DefaultTimeoutTimestampDelta = uint64(time.Hour.Nanoseconds()) + TestAccAddress = "cosmos17dtl0mjt3t77kpuhg2edqzjpszulwhgzuj9ljs" TestCoin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100)) TestCoins = sdk.NewCoins(TestCoin) From 007dee1c3059925eeadbb87f6fb5eadf7410117a Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 19 Jun 2024 18:02:08 +0200 Subject: [PATCH 086/141] nit: make set forwarded packet unexported (#6637) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Gjermund Garaba Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- modules/apps/transfer/keeper/forwarding.go | 2 +- modules/apps/transfer/keeper/keeper.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 72b2e6f2f60..c85de4cbcc1 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 return err } - k.SetForwardedPacket(ctx, data.Forwarding.Hops[0].PortId, data.Forwarding.Hops[0].ChannelId, resp.Sequence, packet) + k.setForwardedPacket(ctx, data.Forwarding.Hops[0].PortId, data.Forwarding.Hops[0].ChannelId, resp.Sequence, packet) return nil } diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 5973d241359..2fd82e639a3 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -308,8 +308,8 @@ func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability return k.scopedKeeper.ClaimCapability(ctx, cap, name) } -// SetForwardedPacket sets the forwarded packet in the store. -func (k Keeper) SetForwardedPacket(ctx sdk.Context, portID, channelID string, sequence uint64, packet channeltypes.Packet) { +// setForwardedPacket sets the forwarded packet in the store. +func (k Keeper) setForwardedPacket(ctx sdk.Context, portID, channelID string, sequence uint64, packet channeltypes.Packet) { store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshal(&packet) store.Set(types.PacketForwardKey(portID, channelID, sequence), bz) From 14d54864cf9642687047d047d1aea08913c8944a Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Wed, 19 Jun 2024 18:38:23 +0200 Subject: [PATCH 087/141] feat(transfer): use registered error code for error acks in token forwarding (#6648) * Add typed errors to packet forwarding * Use forward errors in tests * Make ack construction consistent --- modules/apps/transfer/keeper/forwarding.go | 6 +- .../transfer/keeper/relay_forwarding_test.go | 84 +++++++++---------- modules/apps/transfer/types/errors.go | 2 + testing/events.go | 13 +++ 4 files changed, 55 insertions(+), 50 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index c85de4cbcc1..3e5f0d3718a 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -1,8 +1,6 @@ package keeper import ( - "errors" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -64,7 +62,7 @@ func (k Keeper) ackForwardPacketError(ctx sdk.Context, prevPacket channeltypes.P return err } - forwardAck := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet failed")) + forwardAck := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketFailed) return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) } @@ -74,7 +72,7 @@ func (k Keeper) ackForwardPacketTimeout(ctx sdk.Context, prevPacket channeltypes return err } - forwardAck := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet timed out")) + forwardAck := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketTimedOut) return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) } diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 78191ce7f04..3a2a3543195 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - "errors" "fmt" "time" @@ -9,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal" "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" @@ -403,14 +401,14 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { suite.Require().NoError(err) // message committed // parse the packet from result events and recv packet on chainB - packet, err := ibctesting.ParsePacketFromEvents(result.Events) + packetFromAtoB, err := ibctesting.ParsePacketFromEvents(result.Events) suite.Require().NoError(err) - suite.Require().NotNil(packet) + suite.Require().NotNil(packetFromAtoB) err = path1.EndpointB.UpdateClient() suite.Require().NoError(err) - result, err = path1.EndpointB.RecvPacketWithResult(packet) + result, err = path1.EndpointB.RecvPacketWithResult(packetFromAtoB) suite.Require().NoError(err) suite.Require().NotNil(result) @@ -447,14 +445,14 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { suite.Require().NoError(err) // message committed // parse the packet from result events and recv packet on chainB - packet, err = ibctesting.ParsePacketFromEvents(result.Events) + packetFromBtoC, err := ibctesting.ParsePacketFromEvents(result.Events) suite.Require().NoError(err) - suite.Require().NotNil(packet) + suite.Require().NotNil(packetFromBtoC) err = path2.EndpointB.UpdateClient() suite.Require().NoError(err) - result, err = path2.EndpointB.RecvPacketWithResult(packet) + result, err = path2.EndpointB.RecvPacketWithResult(packetFromBtoC) suite.Require().NoError(err) suite.Require().NotNil(result) @@ -503,22 +501,22 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Vouchers have not been burned") // parse the packet from result events and recv packet on chainB - packet, err = ibctesting.ParsePacketFromEvents(result.Events) + packetFromCtoB, err := ibctesting.ParsePacketFromEvents(result.Events) suite.Require().NoError(err) - suite.Require().NotNil(packet) + suite.Require().NotNil(packetFromCtoB) err = path2.EndpointA.UpdateClient() suite.Require().NoError(err) - result, err = path2.EndpointA.RecvPacketWithResult(packet) + result, err = path2.EndpointA.RecvPacketWithResult(packetFromCtoB) suite.Require().NoError(err) suite.Require().NotNil(result) // We have successfully received the packet on B and forwarded it to A. // Lets try to retrieve it in order to save it - forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packet.Sequence) + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packetFromCtoB.Sequence) suite.Require().True(found) - suite.Require().Equal(packet, forwardedPacket) + suite.Require().Equal(packetFromCtoB, forwardedPacket) // Voucher have been burned on chain B coin = sdk.NewCoin(denomAB.IBCDenom(), amount) @@ -530,36 +528,37 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { // of denom // parse the packet from result events and recv packet on chainA - packet, err = ibctesting.ParsePacketFromEvents(result.Events) + packetFromBtoA, err := ibctesting.ParsePacketFromEvents(result.Events) suite.Require().NoError(err) - suite.Require().NotNil(packet) + suite.Require().NotNil(packetFromBtoA) - // manipulate escrow account for denom on chain A - coin = sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(99)) - suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), coin) - totalEscrowChainA = suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(99), totalEscrowChainA.Amount) + // turn off receive on chain A to trigger an error + suite.chainA.GetSimApp().TransferKeeper.SetParams(suite.chainA.GetContext(), types.Params{ + SendEnabled: true, + ReceiveEnabled: false, + }) err = path1.EndpointA.UpdateClient() suite.Require().NoError(err) - // suite.Require().Equal(packet, forwardedPacket) - result, err = path1.EndpointA.RecvPacketWithResult(packet) - suite.Require().Error(err) - suite.Require().Nil(result) - // In theory now an error ack should have been written on chain A - // NOW WE HAVE TO SEND ACK TO B, PROPAGTE ACK TO C, CHECK FINAL RESULTS + result, err = path1.EndpointA.RecvPacketWithResult(packetFromBtoA) + suite.Require().NoError(err) - // Reconstruct packet data - data, err := internal.UnmarshalPacketData(packet.Data, types.V2) + // An error ack has been written on chainA + // Now we need to propagate it back to chainB and chainC + packetSequenceOnA, err := ibctesting.ParsePacketSequenceFromEvents(result.Events) suite.Require().NoError(err) + errorAckOnA := channeltypes.NewErrorAcknowledgement(types.ErrReceiveDisabled) + errorAckCommitmentOnA := channeltypes.CommitAcknowledgement(errorAckOnA.Acknowledgement()) + ackOnC, found := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainA.GetContext(), path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, packetSequenceOnA) + suite.Require().True(found) + suite.Require().Equal(errorAckCommitmentOnA, ackOnC) + err = path1.EndpointB.UpdateClient() suite.Require().NoError(err) - ack := channeltypes.NewErrorAcknowledgement(fmt.Errorf("failed packet transfer")) - // err = path1.EndpointA.AcknowledgePacket(packetRecv, ack.Acknowledgement()) - err = suite.chainB.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainB.GetContext(), packet, data, ack) + err = path1.EndpointB.AcknowledgePacket(packetFromBtoA, errorAckOnA.Acknowledgement()) suite.Require().NoError(err) // Check that Escrow B has been refunded amount @@ -567,31 +566,24 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { totalEscrowChainB = suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - denom := types.ExtractDenomFromPath(denomABC.Path()) - data = types.NewFungibleTokenPacketDataV2( - []types.Token{ - { - Denom: denom, - Amount: amount.String(), - }, - }, suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String(), suite.chainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "", types.Forwarding{}) - // suite.chainC.SenderAccounts[0].SenderAccount.GetAddress().String() This should be forward account of B - packet = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) - err = path2.EndpointB.UpdateClient() suite.Require().NoError(err) + errorAckOnB := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketFailed) + errorAckCommitmentOnB := channeltypes.CommitAcknowledgement(errorAckOnB.Acknowledgement()) + ackOnB := suite.chainB.GetAcknowledgement(packetFromCtoB) + suite.Require().Equal(errorAckCommitmentOnB, ackOnB) + // Check the status of account on chain C before executing ack. coin = sdk.NewCoin(denomABC.IBCDenom(), amount) postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Final Hop balance has been refunded before Ack execution") // Execute ack - err = suite.chainC.GetSimApp().TransferKeeper.OnAcknowledgementPacket(suite.chainC.GetContext(), packet, data, ack) - // err = path2.EndpointB.AcknowledgePacket(packet, ack.Acknowledgement()) + err = path2.EndpointB.AcknowledgePacket(packetFromCtoB, errorAckOnB.Acknowledgement()) suite.Require().NoError(err) - // Check that everythig has been reverted + // Check that everything has been reverted // // Check the vouchers transfer/channel-1/transfer/channel-0/denom have been refunded on C coin = sdk.NewCoin(denomABC.IBCDenom(), amount) @@ -748,7 +740,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketForwarding() { suite.Require().True(found, "chainB does not have an ack") // And that this ack is of the type we expect (Error due to time out) - ack := channeltypes.NewErrorAcknowledgement(errors.New("forwarded packet timed out")) + ack := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketTimedOut) ackbytes := channeltypes.CommitAcknowledgement(ack.Acknowledgement()) suite.Require().Equal(ackbytes, storedAck) diff --git a/modules/apps/transfer/types/errors.go b/modules/apps/transfer/types/errors.go index 70bbc6edc45..fc6b0dad5c2 100644 --- a/modules/apps/transfer/types/errors.go +++ b/modules/apps/transfer/types/errors.go @@ -17,4 +17,6 @@ var ( ErrInvalidAuthorization = errorsmod.Register(ModuleName, 10, "invalid transfer authorization") ErrInvalidMemo = errorsmod.Register(ModuleName, 11, "invalid memo") ErrInvalidForwarding = errorsmod.Register(ModuleName, 12, "invalid token forwarding") + ErrForwardedPacketTimedOut = errorsmod.Register(ModuleName, 13, "forwarded packet timed out") + ErrForwardedPacketFailed = errorsmod.Register(ModuleName, 14, "forwarded packet failed") ) diff --git a/testing/events.go b/testing/events.go index af585a87669..5954b5b4b51 100644 --- a/testing/events.go +++ b/testing/events.go @@ -174,6 +174,19 @@ func ParseProposalIDFromEvents(events []abci.Event) (uint64, error) { return 0, fmt.Errorf("proposalID event attribute not found") } +// ParsePacketSequenceFromEvents parses events emitted from MsgRecvPacket and returns the packet sequence +func ParsePacketSequenceFromEvents(events []abci.Event) (uint64, error) { + for _, event := range events { + for _, attribute := range event.Attributes { + if attribute.Key == "packet_sequence" { + return strconv.ParseUint(attribute.Value, 10, 64) + } + } + } + + return 0, fmt.Errorf("packet sequence event attribute not found") +} + // AssertEvents asserts that expected events are present in the actual events. func AssertEvents( suite *testifysuite.Suite, From a28a5497d74fa112ed96c567dc11eb15081a1a5d Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 20 Jun 2024 10:38:07 +0300 Subject: [PATCH 088/141] chore(transfer): emit forwarding information in events. (#6647) * chore(transfer): emit forwarding information in events. * nit: rename as per Carlos's suggestion --- modules/apps/transfer/ibc_module_test.go | 17 +++++++++++ .../apps/transfer/internal/events/events.go | 30 ++++++++++++------- .../apps/transfer/keeper/msg_server_test.go | 8 +++-- modules/apps/transfer/keeper/relay.go | 2 +- modules/apps/transfer/types/events.go | 1 + 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 171f6d8108f..0b30c6718e6 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -306,6 +306,15 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { types.NewForwarding("", types.Hop{PortId: "transfer", ChannelId: "channel-0"}), ) packet.Data = packetData.GetBytes() + + forwardingBz, err := json.Marshal(packetData.Forwarding) + suite.Require().NoError(err) + for i, attr := range expectedAttributes { + if attr.Key == types.AttributeKeyForwarding { + expectedAttributes[i].Value = string(forwardingBz) + break + } + } }, nil, "", @@ -316,11 +325,15 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { packet.Data = []byte("invalid data") // Override expected attributes because this fails on unmarshaling packet data (so can't get the attributes) + forwardingBz, err := json.Marshal(types.Forwarding{}) + suite.Require().NoError(err) + expectedAttributes = []sdk.Attribute{ sdk.NewAttribute(types.AttributeKeySender, ""), sdk.NewAttribute(types.AttributeKeyReceiver, ""), sdk.NewAttribute(types.AttributeKeyTokens, "null"), sdk.NewAttribute(types.AttributeKeyMemo, ""), + sdk.NewAttribute(types.AttributeKeyForwarding, string(forwardingBz)), sdk.NewAttribute(types.AttributeKeyAckSuccess, "false"), sdk.NewAttribute(types.AttributeKeyAckError, "cannot unmarshal ICS20-V2 transfer packet data: invalid character 'i' looking for beginning of value: invalid type: invalid type"), } @@ -360,11 +373,15 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { tokensBz, err := json.Marshal(packetData.Tokens) suite.Require().NoError(err) + forwardingBz, err := json.Marshal(packetData.Forwarding) + suite.Require().NoError(err) + expectedAttributes = []sdk.Attribute{ sdk.NewAttribute(types.AttributeKeySender, packetData.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver), sdk.NewAttribute(types.AttributeKeyTokens, string(tokensBz)), sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), + sdk.NewAttribute(types.AttributeKeyForwarding, string(forwardingBz)), } if tc.expAck == nil || tc.expAck.Success() { expectedAttributes = append(expectedAttributes, sdk.NewAttribute(types.AttributeKeyAckSuccess, "true")) diff --git a/modules/apps/transfer/internal/events/events.go b/modules/apps/transfer/internal/events/events.go index 47ef145b0fb..6a1646e4ce7 100644 --- a/modules/apps/transfer/internal/events/events.go +++ b/modules/apps/transfer/internal/events/events.go @@ -11,16 +11,18 @@ import ( ) // EmitTransferEvent emits a ibc transfer event on successful transfers. -func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.Tokens, memo string) { - jsonTokens := mustMarshalType[types.Tokens](tokens) +func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.Tokens, memo string, forwarding types.Forwarding) { + tokensStr := mustMarshalType[types.Tokens](tokens) + forwardingStr := mustMarshalType[types.Forwarding](forwarding) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeTransfer, sdk.NewAttribute(types.AttributeKeySender, sender), sdk.NewAttribute(types.AttributeKeyReceiver, receiver), - sdk.NewAttribute(types.AttributeKeyTokens, jsonTokens), + sdk.NewAttribute(types.AttributeKeyTokens, tokensStr), sdk.NewAttribute(types.AttributeKeyMemo, memo), + sdk.NewAttribute(types.AttributeKeyForwarding, forwardingStr), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -31,13 +33,15 @@ func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.To // EmitOnRecvPacketEvent emits a fungible token packet event in the OnRecvPacket callback func EmitOnRecvPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement, ackErr error) { - jsonTokens := mustMarshalType[types.Tokens](packetData.Tokens) + tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) + forwardingStr := mustMarshalType[types.Forwarding](packetData.Forwarding) eventAttributes := []sdk.Attribute{ sdk.NewAttribute(types.AttributeKeySender, packetData.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver), - sdk.NewAttribute(types.AttributeKeyTokens, jsonTokens), + sdk.NewAttribute(types.AttributeKeyTokens, tokensStr), sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), + sdk.NewAttribute(types.AttributeKeyForwarding, forwardingStr), sdk.NewAttribute(types.AttributeKeyAckSuccess, strconv.FormatBool(ack.Success())), } @@ -59,15 +63,17 @@ func EmitOnRecvPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacket // EmitOnAcknowledgementPacketEvent emits a fungible token packet event in the OnAcknowledgementPacket callback func EmitOnAcknowledgementPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) { - jsonTokens := mustMarshalType[types.Tokens](types.Tokens(packetData.Tokens)) + tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) + forwardingStr := mustMarshalType[types.Forwarding](packetData.Forwarding) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypePacket, sdk.NewAttribute(sdk.AttributeKeySender, packetData.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver), - sdk.NewAttribute(types.AttributeKeyTokens, jsonTokens), + sdk.NewAttribute(types.AttributeKeyTokens, tokensStr), sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), + sdk.NewAttribute(types.AttributeKeyForwarding, forwardingStr), sdk.NewAttribute(types.AttributeKeyAck, ack.String()), ), sdk.NewEvent( @@ -96,14 +102,16 @@ func EmitOnAcknowledgementPacketEvent(ctx sdk.Context, packetData types.Fungible // EmitOnTimeoutPacketEvent emits a fungible token packet event in the OnTimeoutPacket callback func EmitOnTimeoutEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2) { - jsonTokens := mustMarshalType[types.Tokens](types.Tokens(packetData.Tokens)) + tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) + forwardingStr := mustMarshalType[types.Forwarding](packetData.Forwarding) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeTimeout, sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Sender), - sdk.NewAttribute(types.AttributeKeyRefundTokens, jsonTokens), + sdk.NewAttribute(types.AttributeKeyRefundTokens, tokensStr), sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), + sdk.NewAttribute(types.AttributeKeyForwarding, forwardingStr), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -114,13 +122,13 @@ func EmitOnTimeoutEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDat // EmitDenomEvent emits a denomination event in the OnRecv callback. func EmitDenomEvent(ctx sdk.Context, token types.Token) { - jsonDenom := mustMarshalType[types.Denom](token.Denom) + denomStr := mustMarshalType[types.Denom](token.Denom) ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeDenom, sdk.NewAttribute(types.AttributeKeyDenomHash, token.Denom.Hash().String()), - sdk.NewAttribute(types.AttributeKeyDenom, jsonDenom), + sdk.NewAttribute(types.AttributeKeyDenom, denomStr), ), ) } diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 1ce9458fdb1..2a9be02aed7 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -149,7 +149,10 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { tokens = append(tokens, token) } - jsonTokens, err := json.Marshal(types.Tokens(tokens)) + tokensBz, err := json.Marshal(types.Tokens(tokens)) + suite.Require().NoError(err) + + forwardingBz, err := json.Marshal(msg.Forwarding) suite.Require().NoError(err) res, err := suite.chainA.GetSimApp().TransferKeeper.Transfer(ctx, msg) @@ -162,8 +165,9 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { sdk.NewEvent(types.EventTypeTransfer, sdk.NewAttribute(types.AttributeKeySender, msg.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), - sdk.NewAttribute(types.AttributeKeyTokens, string(jsonTokens)), + sdk.NewAttribute(types.AttributeKeyTokens, string(tokensBz)), sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), + sdk.NewAttribute(types.AttributeKeyForwarding, string(forwardingBz)), ), sdk.NewEvent( sdk.EventTypeMessage, diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 2bfedcc0493..5b555eae9c6 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -147,7 +147,7 @@ func (k Keeper) sendTransfer( return 0, err } - events.EmitTransferEvent(ctx, sender.String(), receiver, tokens, memo) + events.EmitTransferEvent(ctx, sender.String(), receiver, tokens, memo, forwarding) defer internaltelemetry.ReportTransferTelemetry(tokens, labels) diff --git a/modules/apps/transfer/types/events.go b/modules/apps/transfer/types/events.go index d982298c12b..90f2137d11f 100644 --- a/modules/apps/transfer/types/events.go +++ b/modules/apps/transfer/types/events.go @@ -19,4 +19,5 @@ const ( AttributeKeyAck = "acknowledgement" AttributeKeyAckError = "error" AttributeKeyMemo = "memo" + AttributeKeyForwarding = "forwarding" ) From 64bc502454161e6d3146ad3ae70a8a9a347c7212 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Thu, 20 Jun 2024 12:37:08 +0200 Subject: [PATCH 089/141] Fix e2e test --- e2e/tests/transfer/upgradesv1_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/e2e/tests/transfer/upgradesv1_test.go b/e2e/tests/transfer/upgradesv1_test.go index 254b288127f..11f6b656879 100644 --- a/e2e/tests/transfer/upgradesv1_test.go +++ b/e2e/tests/transfer/upgradesv1_test.go @@ -306,6 +306,7 @@ func (s *TransferChannelUpgradesV1TestSuite) TestChannelUpgrade_WithFeeMiddlewar s.GetTimeoutHeight(ctx, chainB), 0, "", + transfertypes.Forwarding{}, ) resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgPayPacketFee, msgTransfer) s.AssertTxSuccess(resp) From 87d1f91c4a6e5758c3a3dc508b4269df003c6c29 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 20 Jun 2024 22:22:40 +0300 Subject: [PATCH 090/141] Refactor forwarding messages for Transfer and Packet (#6655) * feat(transfer): add unwind, refactor proto structure. gen-all * tests(transfer/types): fix test failures in types tests. * tests(transfer/keeper): fix test failures in keeper tests. * cli(transfer): fix cli usage. pending flag for unwind. * tests(callbacks): fix failing tests in callbacks. * tests(transfer/internal): fix failures in internal package. * tests(transfer): fix test failures in top level tranfer package. * tests(ica/host/keeper): fix repr of msg transfer in ica host msg execution. * lint(all): lint this bad boy * chore(transfer/types): amend validation for MsgTransfer's ShouldBeForwarded, add tests for ForwardedPacketData, minor nits. * nit(self): only pass relevant fields to create packet data; minor comment improvement. * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * chore(merge): fix merge issues. * chore(proto): mention optional nature of fields. * memo: do not drop it * validation: drop requirement on memo being empty on msg transfer. --------- Co-authored-by: Carlos Rodriguez --- .../host/keeper/relay_test.go | 2 +- modules/apps/callbacks/ibc_middleware_test.go | 14 +- modules/apps/transfer/client/cli/tx.go | 10 +- modules/apps/transfer/ibc_module_test.go | 4 +- .../apps/transfer/internal/convert/convert.go | 2 +- .../apps/transfer/internal/events/events.go | 6 +- modules/apps/transfer/internal/packet_test.go | 18 +- modules/apps/transfer/keeper/export_test.go | 4 +- modules/apps/transfer/keeper/forwarding.go | 10 +- .../apps/transfer/keeper/mbt_relay_test.go | 2 +- modules/apps/transfer/keeper/relay.go | 13 +- .../transfer/keeper/relay_forwarding_test.go | 20 +- modules/apps/transfer/keeper/relay_test.go | 23 +- modules/apps/transfer/types/forwarding.go | 42 ++- .../apps/transfer/types/forwarding_test.go | 138 +++++++- modules/apps/transfer/types/msgs.go | 7 +- modules/apps/transfer/types/msgs_test.go | 12 +- modules/apps/transfer/types/packet.go | 2 +- modules/apps/transfer/types/packet.pb.go | 295 ++++++++++++++++-- modules/apps/transfer/types/packet_test.go | 60 ++-- modules/apps/transfer/types/transfer.pb.go | 132 ++++---- .../transfer/types/transfer_authorization.go | 8 +- .../types/transfer_authorization_test.go | 43 +-- .../applications/transfer/v1/transfer.proto | 10 +- .../ibc/applications/transfer/v2/packet.proto | 12 +- 25 files changed, 613 insertions(+), 276 deletions(-) diff --git a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go index fbd05e641cd..bcef1c4f900 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/relay_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/relay_test.go @@ -798,7 +798,7 @@ func (suite *KeeperTestSuite) TestJSONOnRecvPacket() { "timeout_height": { "revision_number": 1, "revision_height": 100 }, "timeout_timestamp": 0, "memo": "", - "forwarding": { "hops": [], "memo": "" } + "forwarding": { "hops": [], "unwind": false } } ] }`) diff --git a/modules/apps/callbacks/ibc_middleware_test.go b/modules/apps/callbacks/ibc_middleware_test.go index 923b4bb6c8e..d0d7505d514 100644 --- a/modules/apps/callbacks/ibc_middleware_test.go +++ b/modules/apps/callbacks/ibc_middleware_test.go @@ -24,7 +24,7 @@ import ( ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) -var emptyForwarding = transfertypes.Forwarding{} +var emptyForwardingPacketData = transfertypes.ForwardingPacketData{} func (s *CallbacksTestSuite) TestNewIBCMiddleware() { testCases := []struct { @@ -188,7 +188,7 @@ func (s *CallbacksTestSuite) TestSendPacket() { ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract), - emptyForwarding, + emptyForwardingPacketData, ) chanCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID) @@ -330,7 +330,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() { ibctesting.TestAccAddress, ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, simapp.SuccessContract, userGasLimit), - emptyForwarding, + emptyForwardingPacketData, ) packet = channeltypes.Packet{ @@ -496,7 +496,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() { sdk.NewCoins(ibctesting.TestCoin), s.chainA.SenderAccount.GetAddress().String(), s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp, fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), // set user gas limit above panic level in mock contract keeper - emptyForwarding, + transfertypes.Forwarding{}, ) res, err := s.chainA.SendMsgs(msg) @@ -664,7 +664,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() { ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit), - emptyForwarding, + emptyForwardingPacketData, ) packet = channeltypes.Packet{ @@ -796,7 +796,7 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() { ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(), fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress), - emptyForwarding, + emptyForwardingPacketData, ) packet = channeltypes.Packet{ @@ -1020,7 +1020,7 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketDataV1() { Sender: ibctesting.TestAccAddress, Receiver: ibctesting.TestAccAddress, Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress), - Forwarding: emptyForwarding, + Forwarding: emptyForwardingPacketData, } portID := s.path.EndpointA.ChannelConfig.PortID diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index e4fd1a67511..550f5c34620 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -96,12 +96,6 @@ using the {packet-timeout-timestamp} flag. If no timeout value is set then a def return err } - // If parsed, set and replace memo. - if len(forwarding.Hops) > 0 { - forwarding.Memo = memo - memo = "" - } - // NOTE: relative timeouts using block height are not supported. // if the timeouts are not absolute, CLI users rely solely on local clock time in order to calculate relative timestamps. if !absoluteTimeouts { @@ -164,6 +158,6 @@ func parseForwarding(cmd *cobra.Command) (types.Forwarding, error) { hops = append(hops, hop) } - forwarding := types.NewForwarding("", hops...) - return forwarding, nil + // TODO(jim): Add flag for unwind value + return types.NewForwarding(false, hops...), nil } diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 0b30c6718e6..327009b0ef4 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -303,7 +303,7 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", - types.NewForwarding("", types.Hop{PortId: "transfer", ChannelId: "channel-0"}), + types.NewForwardingPacketData("", types.Hop{PortId: "transfer", ChannelId: "channel-0"}), ) packet.Data = packetData.GetBytes() @@ -368,7 +368,7 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", - types.Forwarding{}, + types.ForwardingPacketData{}, ) tokensBz, err := json.Marshal(packetData.Tokens) diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go index c266d42519a..fbb90ec7e56 100644 --- a/modules/apps/transfer/internal/convert/convert.go +++ b/modules/apps/transfer/internal/convert/convert.go @@ -24,6 +24,6 @@ func PacketDataV1ToV2(packetData types.FungibleTokenPacketData) (types.FungibleT Sender: packetData.Sender, Receiver: packetData.Receiver, Memo: packetData.Memo, - Forwarding: types.Forwarding{}, + Forwarding: types.ForwardingPacketData{}, }, nil } diff --git a/modules/apps/transfer/internal/events/events.go b/modules/apps/transfer/internal/events/events.go index 82121c0e067..70556ab5c97 100644 --- a/modules/apps/transfer/internal/events/events.go +++ b/modules/apps/transfer/internal/events/events.go @@ -34,7 +34,7 @@ func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.To // EmitOnRecvPacketEvent emits a fungible token packet event in the OnRecvPacket callback func EmitOnRecvPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement, ackErr error) { tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) - forwardingStr := mustMarshalType[types.Forwarding](packetData.Forwarding) + forwardingStr := mustMarshalType[types.ForwardingPacketData](packetData.Forwarding) eventAttributes := []sdk.Attribute{ sdk.NewAttribute(types.AttributeKeySender, packetData.Sender), @@ -64,7 +64,7 @@ func EmitOnRecvPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacket // EmitOnAcknowledgementPacketEvent emits a fungible token packet event in the OnAcknowledgementPacket callback func EmitOnAcknowledgementPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) { tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) - forwardingStr := mustMarshalType[types.Forwarding](packetData.Forwarding) + forwardingStr := mustMarshalType[types.ForwardingPacketData](packetData.Forwarding) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( @@ -103,7 +103,7 @@ func EmitOnAcknowledgementPacketEvent(ctx sdk.Context, packetData types.Fungible // EmitOnTimeoutEvent emits a fungible token packet event in the OnTimeoutPacket callback func EmitOnTimeoutEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2) { tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) - forwardingStr := mustMarshalType[types.Forwarding](packetData.Forwarding) + forwardingStr := mustMarshalType[types.ForwardingPacketData](packetData.Forwarding) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( diff --git a/modules/apps/transfer/internal/packet_test.go b/modules/apps/transfer/internal/packet_test.go index 4cb975622fe..ab56c593111 100644 --- a/modules/apps/transfer/internal/packet_test.go +++ b/modules/apps/transfer/internal/packet_test.go @@ -10,7 +10,7 @@ import ( "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ) -var emptyForwarding = types.Forwarding{} +var emptyForwardingPacketData = types.ForwardingPacketData{} func TestUnmarshalPacketData(t *testing.T) { var ( @@ -37,7 +37,7 @@ func TestUnmarshalPacketData(t *testing.T) { Denom: types.NewDenom("atom", types.NewTrace("transfer", "channel-0")), Amount: "1000", }, - }, "sender", "receiver", "", emptyForwarding) + }, "sender", "receiver", "", emptyForwardingPacketData) packetDataBz = packetData.GetBytes() version = types.V2 @@ -94,7 +94,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom", types.NewTrace("transfer", "channel-0")), Amount: "1000", }, - }, sender, receiver, "", emptyForwarding), + }, sender, receiver, "", emptyForwardingPacketData), nil, }, { @@ -106,7 +106,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom"), Amount: "1000", }, - }, sender, receiver, "", emptyForwarding), + }, sender, receiver, "", emptyForwardingPacketData), nil, }, { @@ -118,7 +118,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom/withslash", types.NewTrace("transfer", "channel-0")), Amount: "1000", }, - }, sender, receiver, "", emptyForwarding), + }, sender, receiver, "", emptyForwardingPacketData), nil, }, { @@ -130,7 +130,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom/", types.NewTrace("transfer", "channel-0")), Amount: "1000", }, - }, sender, receiver, "", emptyForwarding), + }, sender, receiver, "", emptyForwardingPacketData), nil, }, { @@ -142,7 +142,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom/pool", types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1")), Amount: "1000", }, - }, sender, receiver, "", emptyForwarding), + }, sender, receiver, "", emptyForwardingPacketData), nil, }, { @@ -154,7 +154,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom", types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1"), types.NewTrace("transfer-custom", "channel-2")), Amount: "1000", }, - }, sender, receiver, "", emptyForwarding), + }, sender, receiver, "", emptyForwardingPacketData), nil, }, { @@ -166,7 +166,7 @@ func TestPacketV1ToPacketV2(t *testing.T) { Denom: types.NewDenom("atom/pool", types.NewTrace("transfer", "channel-0"), types.NewTrace("transfer", "channel-1"), types.NewTrace("transfer-custom", "channel-2")), Amount: "1000", }, - }, sender, receiver, "", emptyForwarding), + }, sender, receiver, "", emptyForwardingPacketData), nil, }, { diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index 582ef3ea5bd..b5fbc235504 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -34,6 +34,6 @@ func (k Keeper) TokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // CreatePacketDataBytesFromVersion is a wrapper around createPacketDataBytesFromVersion for testing purposes -func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwarding types.Forwarding) []byte { - return createPacketDataBytesFromVersion(appVersion, sender, receiver, memo, tokens, forwarding) +func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, hops []types.Hop) []byte { + return createPacketDataBytesFromVersion(appVersion, sender, receiver, memo, tokens, hops) } diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 3e5f0d3718a..c33dc58f460 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -14,13 +14,9 @@ import ( // forwardPacket forwards a fungible FungibleTokenPacketDataV2 to the next hop in the forwarding path. func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDataV2, packet channeltypes.Packet, receivedCoins sdk.Coins) error { - var memo string - var nextForwardingPath types.Forwarding - if len(data.Forwarding.Hops) == 1 { - memo = data.Forwarding.Memo - } else { - nextForwardingPath = types.NewForwarding(data.Forwarding.Memo, data.Forwarding.Hops[1:]...) + if len(data.Forwarding.Hops) > 1 { + nextForwardingPath = types.NewForwarding(false, data.Forwarding.Hops[1:]...) } // sending from the forward escrow address to the original receiver address. @@ -34,7 +30,7 @@ func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDat data.Receiver, clienttypes.ZeroHeight(), packet.TimeoutTimestamp, - memo, + data.Forwarding.DestinationMemo, nextForwardingPath, ) diff --git a/modules/apps/transfer/keeper/mbt_relay_test.go b/modules/apps/transfer/keeper/mbt_relay_test.go index 6d99322d105..33eeab9bee7 100644 --- a/modules/apps/transfer/keeper/mbt_relay_test.go +++ b/modules/apps/transfer/keeper/mbt_relay_test.go @@ -159,7 +159,7 @@ func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPack AddressFromString(packet.Data.Sender), AddressFromString(packet.Data.Receiver), "", - types.Forwarding{}, + types.ForwardingPacketData{}, ), } } diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 5b555eae9c6..ce65244452e 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -140,7 +140,7 @@ func (k Keeper) sendTransfer( tokens = append(tokens, token) } - packetDataBytes := createPacketDataBytesFromVersion(appVersion, sender.String(), receiver, memo, tokens, forwarding) + packetDataBytes := createPacketDataBytesFromVersion(appVersion, sender.String(), receiver, memo, tokens, forwarding.Hops) sequence, err := k.ics4Wrapper.SendPacket(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, packetDataBytes) if err != nil { @@ -431,7 +431,7 @@ func (k Keeper) tokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // createPacketDataBytesFromVersion creates the packet data bytes to be sent based on the application version. -func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, forwarding types.Forwarding) []byte { +func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, hops []types.Hop) []byte { var packetDataBytes []byte switch appVersion { case types.V1: @@ -444,7 +444,14 @@ func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, packetData := types.NewFungibleTokenPacketData(token.Denom.Path(), token.Amount, sender, receiver, memo) packetDataBytes = packetData.GetBytes() case types.V2: - packetData := types.NewFungibleTokenPacketDataV2(tokens, sender, receiver, memo, forwarding) + // If forwarding is needed, move memo to forwarding packet data and set packet.Memo to empty string. + var forwardingPacketData types.ForwardingPacketData + if len(hops) > 0 { + forwardingPacketData = types.NewForwardingPacketData(memo, hops...) + memo = "" + } + + packetData := types.NewFungibleTokenPacketDataV2(tokens, sender, receiver, memo, forwardingPacketData) packetDataBytes = packetData.GetBytes() default: panic(fmt.Errorf("app version must be one of %s", types.SupportedVersions)) diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 3a2a3543195..591321db516 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -28,7 +28,7 @@ func (suite *KeeperTestSuite) TestPathForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwarding := types.NewForwarding("", types.Hop{ + forwarding := types.NewForwarding(false, types.Hop{ PortId: path2.EndpointA.ChannelConfig.PortID, ChannelId: path2.EndpointA.ChannelID, }) @@ -85,7 +85,7 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwarding := types.NewForwarding("", types.Hop{ + forwarding := types.NewForwarding(false, types.Hop{ PortId: path2.EndpointB.ChannelConfig.PortID, ChannelId: path2.EndpointB.ChannelID, }) @@ -163,7 +163,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwarding := types.NewForwarding("", types.Hop{ + forwarding := types.NewForwarding(false, types.Hop{ PortId: path2.EndpointB.ChannelConfig.PortID, ChannelId: path2.EndpointB.ChannelID, }) @@ -187,6 +187,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { suite.Require().NoError(err) suite.Require().NotNil(packet) + forwardingPacketData := types.NewForwardingPacketData("", forwarding.Hops...) denom := types.Denom{Base: sdk.DefaultBondDenom} data := types.NewFungibleTokenPacketDataV2( []types.Token{ @@ -194,7 +195,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { Denom: denom, Amount: amount.String(), }, - }, sender.GetAddress().String(), receiver.GetAddress().String(), "", forwarding) + }, sender.GetAddress().String(), receiver.GetAddress().String(), "", forwardingPacketData) packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.ZeroHeight(), suite.chainA.GetTimeoutTimestamp()) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) @@ -227,7 +228,7 @@ func (suite *KeeperTestSuite) TestHappyPathForwarding() { Denom: denom, Amount: amount.String(), }, - }, types.GetForwardAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID).String(), receiver.GetAddress().String(), "", types.Forwarding{}) + }, types.GetForwardAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID).String(), receiver.GetAddress().String(), "", types.ForwardingPacketData{}) packetRecv = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) // execute onRecvPacket, when chaninA receives the tokens the escrow amount on B should increase to amount @@ -263,7 +264,7 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { coinOnA := sdk.NewCoin(sdk.DefaultBondDenom, amount) sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainC.SenderAccounts[0].SenderAccount - forwarding := types.NewForwarding("", types.Hop{ + forwarding := types.NewForwarding(false, types.Hop{ PortId: path2.EndpointA.ChannelConfig.PortID, ChannelId: path2.EndpointA.ChannelID, }) @@ -477,7 +478,7 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { sender = suite.chainC.SenderAccounts[0].SenderAccount receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account - forwarding := types.NewForwarding("", types.Hop{ + forwarding := types.NewForwarding(false, types.Hop{ PortId: path1.EndpointB.ChannelConfig.PortID, ChannelId: path1.EndpointB.ChannelID, }) @@ -711,7 +712,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketForwarding() { }, address, receiver.GetAddress().String(), - "", types.Forwarding{}, + "", types.ForwardingPacketData{}, ) packet = channeltypes.NewPacket( @@ -744,6 +745,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketForwarding() { ackbytes := channeltypes.CommitAcknowledgement(ack.Acknowledgement()) suite.Require().Equal(ackbytes, storedAck) + forwardingPacketData := types.NewForwardingPacketData("", forwarding.Hops...) data = types.NewFungibleTokenPacketDataV2( []types.Token{ { @@ -753,7 +755,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketForwarding() { }, sender.GetAddress().String(), receiver.GetAddress().String(), - "", forwarding, + "", forwardingPacketData, ) packet = channeltypes.NewPacket( diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 7376823f6c5..937815d9344 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -21,7 +21,10 @@ import ( ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) -var emptyForwarding = types.Forwarding{} +var ( + emptyForwarding = types.Forwarding{} + emptyForwardingPacketData = types.ForwardingPacketData{} +) // TestSendTransfer tests sending from chainA to chainB using both coin // that originate on chainA and coin that originate on chainB. @@ -383,7 +386,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsNotSource() { Denom: types.NewDenom(sdk.DefaultBondDenom, []types.Trace{}...), Amount: amount.String(), }, - }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, emptyForwarding) + }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, emptyForwardingPacketData) packet := channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) @@ -534,7 +537,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsSource() { Denom: denom, Amount: amount.String(), }, - }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, emptyForwarding) + }, suite.chainA.SenderAccount.GetAddress().String(), receiver, memo, emptyForwardingPacketData) packet = channeltypes.NewPacket(data.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data) @@ -612,7 +615,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacketSetsTotalEscrowAmountForSourceIBCT Denom: denom, Amount: amount.String(), }, - }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", emptyForwarding) + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", emptyForwardingPacketData) packet := channeltypes.NewPacket( data.GetBytes(), seq, @@ -743,7 +746,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() { Denom: denom, Amount: amount.String(), }, - }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", emptyForwarding) + }, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), "", emptyForwardingPacketData) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preAcknowledgementBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denom.IBCDenom()) @@ -838,7 +841,7 @@ func (suite *KeeperTestSuite) TestOnAcknowledgementPacketSetsTotalEscrowAmountFo suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", - emptyForwarding, + emptyForwardingPacketData, ) packet := channeltypes.NewPacket( data.GetBytes(), @@ -978,7 +981,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacket() { Denom: denom, Amount: amount, }, - }, sender, suite.chainB.SenderAccount.GetAddress().String(), "", emptyForwarding) + }, sender, suite.chainB.SenderAccount.GetAddress().String(), "", emptyForwardingPacketData) packet := channeltypes.NewPacket(data.GetBytes(), 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.NewHeight(1, 100), 0) preTimeoutBalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), denom.IBCDenom()) @@ -1064,7 +1067,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketSetsTotalEscrowAmountForSourceI Denom: denom, Amount: amount.String(), }, - }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", emptyForwarding) + }, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), "", emptyForwardingPacketData) packet := channeltypes.NewPacket( data.GetBytes(), seq, @@ -1271,7 +1274,7 @@ func (suite *KeeperTestSuite) TestCreatePacketDataBytesFromVersion() { types.V2, func() {}, func(bz []byte) { - expPacketData := types.NewFungibleTokenPacketDataV2(types.Tokens{types.Token{}}, "", "", "", emptyForwarding) + expPacketData := types.NewFungibleTokenPacketDataV2(types.Tokens{types.Token{}}, "", "", "", emptyForwardingPacketData) suite.Require().Equal(bz, expPacketData.GetBytes()) }, nil, @@ -1301,7 +1304,7 @@ func (suite *KeeperTestSuite) TestCreatePacketDataBytesFromVersion() { tc.malleate() createFunc := func() { - bz = transferkeeper.CreatePacketDataBytesFromVersion(tc.appVersion, "", "", "", tokens, emptyForwarding) + bz = transferkeeper.CreatePacketDataBytesFromVersion(tc.appVersion, "", "", "", tokens, nil) } expPanic := tc.expPanicErr != nil diff --git a/modules/apps/transfer/types/forwarding.go b/modules/apps/transfer/types/forwarding.go index a95efebff85..895bfb9e286 100644 --- a/modules/apps/transfer/types/forwarding.go +++ b/modules/apps/transfer/types/forwarding.go @@ -8,26 +8,52 @@ import ( const MaximumNumberOfForwardingHops = 16 // denotes the maximum number of forwarding hops allowed -// NewForwarding creates a new Forwarding instance given a memo and a variable number of hops. -func NewForwarding(memo string, hops ...Hop) Forwarding { +// NewForwarding creates a new Forwarding instance given an unwind value and a variable number of hops. +func NewForwarding(unwind bool, hops ...Hop) Forwarding { return Forwarding{ - Memo: memo, - Hops: hops, + Unwind: unwind, + Hops: hops, } } // Validate performs a basic validation of the Forwarding fields. func (fi Forwarding) Validate() error { if len(fi.Hops) > MaximumNumberOfForwardingHops { - return errorsmod.Wrapf(ErrInvalidForwarding, "number of hops in forwarding path cannot exceed %d", MaximumNumberOfForwardingHops) + return errorsmod.Wrapf(ErrInvalidForwarding, "number of hops in forwarding cannot exceed %d", MaximumNumberOfForwardingHops) } - if len(fi.Memo) > MaximumMemoLength { + for _, hop := range fi.Hops { + if err := host.PortIdentifierValidator(hop.PortId); err != nil { + return errorsmod.Wrapf(err, "invalid hop source port ID %s", hop.PortId) + } + if err := host.ChannelIdentifierValidator(hop.ChannelId); err != nil { + return errorsmod.Wrapf(err, "invalid source channel ID %s", hop.ChannelId) + } + } + + return nil +} + +// NewForwardingPacketData creates a new ForwardingPacketData instance given a memo and a variable number of hops. +func NewForwardingPacketData(destinationMemo string, hops ...Hop) ForwardingPacketData { + return ForwardingPacketData{ + DestinationMemo: destinationMemo, + Hops: hops, + } +} + +// Validate performs a basic validation of the ForwardingPacketData fields. +func (fi ForwardingPacketData) Validate() error { + if len(fi.Hops) > MaximumNumberOfForwardingHops { + return errorsmod.Wrapf(ErrInvalidForwarding, "number of hops in forwarding packet data cannot exceed %d", MaximumNumberOfForwardingHops) + } + + if len(fi.DestinationMemo) > MaximumMemoLength { return errorsmod.Wrapf(ErrInvalidMemo, "memo length cannot exceed %d", MaximumMemoLength) } - if len(fi.Hops) == 0 && fi.Memo != "" { - return errorsmod.Wrap(ErrInvalidForwarding, "memo specified when forwarding hops is empty") + if len(fi.Hops) == 0 && fi.DestinationMemo != "" { + return errorsmod.Wrap(ErrInvalidForwarding, "memo specified when forwarding packet data hops is empty") } for _, hop := range fi.Hops { diff --git a/modules/apps/transfer/types/forwarding_test.go b/modules/apps/transfer/types/forwarding_test.go index 236f78d65d6..c8633c7f72f 100644 --- a/modules/apps/transfer/types/forwarding_test.go +++ b/modules/apps/transfer/types/forwarding_test.go @@ -23,47 +23,156 @@ func TestForwarding_Validate(t *testing.T) { }{ { "valid forwarding with no hops", - types.NewForwarding(""), + types.NewForwarding(false), nil, }, { "valid forwarding with hops", - types.NewForwarding("", validHop), + types.NewForwarding(false, validHop), + nil, + }, + { + "valid forwarding with max hops", + types.NewForwarding(false, generateHops(types.MaximumNumberOfForwardingHops)...), + nil, + }, + { + "invalid forwarding with too many hops", + types.NewForwarding(false, generateHops(types.MaximumNumberOfForwardingHops+1)...), + types.ErrInvalidForwarding, + }, + { + "invalid forwarding with too short hop port ID", + types.NewForwarding( + false, + types.Hop{ + PortId: invalidShortPort, + ChannelId: ibctesting.FirstChannelID, + }, + ), + host.ErrInvalidID, + }, + { + "invalid forwarding with too long hop port ID", + types.NewForwarding( + false, + types.Hop{ + PortId: invalidLongPort, + ChannelId: ibctesting.FirstChannelID, + }, + ), + host.ErrInvalidID, + }, + { + "invalid forwarding with non-alpha hop port ID", + types.NewForwarding( + false, + types.Hop{ + PortId: invalidPort, + ChannelId: ibctesting.FirstChannelID, + }, + ), + host.ErrInvalidID, + }, + { + "invalid forwarding with too long hop channel ID", + types.NewForwarding( + false, + types.Hop{ + PortId: types.PortID, + ChannelId: invalidLongChannel, + }, + ), + host.ErrInvalidID, + }, + { + "invalid forwarding with too short hop channel ID", + types.NewForwarding( + false, + types.Hop{ + PortId: types.PortID, + ChannelId: invalidShortChannel, + }, + ), + host.ErrInvalidID, + }, + { + "invalid forwarding with non-alpha hop channel ID", + types.NewForwarding( + false, + types.Hop{ + PortId: types.PortID, + ChannelId: invalidChannel, + }, + ), + host.ErrInvalidID, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tc := tc + + err := tc.forwarding.Validate() + + expPass := tc.expError == nil + if expPass { + require.NoError(t, err) + } else { + require.ErrorIs(t, err, tc.expError) + } + }) + } +} + +func TestForwardingPacketData_Validate(t *testing.T) { + tests := []struct { + name string + forwarding types.ForwardingPacketData + expError error + }{ + { + "valid forwarding with no hops", + types.NewForwardingPacketData(""), + nil, + }, + { + "valid forwarding with hops", + types.NewForwardingPacketData("", validHop), nil, }, { "valid forwarding with memo", - types.NewForwarding(testMemo1, validHop, validHop), + types.NewForwardingPacketData(testMemo1, validHop, validHop), nil, }, { "valid forwarding with max hops", - types.NewForwarding("", generateHops(types.MaximumNumberOfForwardingHops)...), + types.NewForwardingPacketData("", generateHops(types.MaximumNumberOfForwardingHops)...), nil, }, { "valid forwarding with max memo length", - types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength), validHop), + types.NewForwardingPacketData(ibctesting.GenerateString(types.MaximumMemoLength), validHop), nil, }, { "invalid forwarding with too many hops", - types.NewForwarding("", generateHops(types.MaximumNumberOfForwardingHops+1)...), + types.NewForwardingPacketData("", generateHops(types.MaximumNumberOfForwardingHops+1)...), types.ErrInvalidForwarding, }, { "invalid forwarding with too long memo", - types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), + types.NewForwardingPacketData(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), types.ErrInvalidMemo, }, { "invalid forwarding with empty hops and specified memo", - types.NewForwarding("memo"), + types.NewForwardingPacketData("memo"), types.ErrInvalidForwarding, }, { "invalid forwarding with too short hop port ID", - types.NewForwarding( + types.NewForwardingPacketData( "", types.Hop{ PortId: invalidShortPort, @@ -74,7 +183,7 @@ func TestForwarding_Validate(t *testing.T) { }, { "invalid forwarding with too long hop port ID", - types.NewForwarding( + types.NewForwardingPacketData( "", types.Hop{ PortId: invalidLongPort, @@ -85,7 +194,7 @@ func TestForwarding_Validate(t *testing.T) { }, { "invalid forwarding with non-alpha hop port ID", - types.NewForwarding( + types.NewForwardingPacketData( "", types.Hop{ PortId: invalidPort, @@ -96,7 +205,7 @@ func TestForwarding_Validate(t *testing.T) { }, { "invalid forwarding with too long hop channel ID", - types.NewForwarding( + types.NewForwardingPacketData( "", types.Hop{ PortId: types.PortID, @@ -107,7 +216,7 @@ func TestForwarding_Validate(t *testing.T) { }, { "invalid forwarding with too short hop channel ID", - types.NewForwarding( + types.NewForwardingPacketData( "", types.Hop{ PortId: types.PortID, @@ -118,7 +227,7 @@ func TestForwarding_Validate(t *testing.T) { }, { "invalid forwarding with non-alpha hop channel ID", - types.NewForwarding( + types.NewForwardingPacketData( "", types.Hop{ PortId: types.PortID, @@ -144,6 +253,7 @@ func TestForwarding_Validate(t *testing.T) { } } +// generateHops generates a slice of n correctly initialized hops. func generateHops(n int) []types.Hop { hops := make([]types.Hop, n) for i := 0; i < n; i++ { diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 2e6bf3d5ba6..01289ff42eb 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -111,11 +111,6 @@ func (msg MsgTransfer) ValidateBasic() error { if !msg.TimeoutHeight.IsZero() { return errorsmod.Wrapf(ErrInvalidPacketTimeout, "timeout height must not be set if forwarding path hops is not empty: %s, %s", msg.TimeoutHeight, msg.Forwarding.Hops) } - - // when forwarding, the memo must be empty - if msg.Memo != "" { - return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", msg.Memo, msg.Forwarding.Hops) - } } for _, coin := range msg.GetCoins() { @@ -140,7 +135,7 @@ func (msg MsgTransfer) GetCoins() sdk.Coins { // ShouldBeForwarded determines if the transfer should be forwarded to the next hop. func (msg MsgTransfer) ShouldBeForwarded() bool { - return len(msg.Forwarding.Hops) > 0 + return len(msg.Forwarding.Hops) > 0 || msg.Forwarding.Unwind } // isValidIBCCoin returns true if the token provided is valid, diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index 03fc39f61fb..b09992f57a2 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -61,6 +61,8 @@ func TestMsgTransferValidation(t *testing.T) { {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), nil}, {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), nil}, {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), nil}, + {"memo with forwarding path hops not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "memo", types.NewForwarding(false, validHop)), nil}, + {"memo with forwarding unwind set to true", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "memo", types.NewForwarding(true)), nil}, {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), host.ErrInvalidID}, {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), host.ErrInvalidID}, @@ -80,12 +82,10 @@ func TestMsgTransferValidation(t *testing.T) { {"multidenom: zero coins", types.NewMsgTransfer(validPort, validChannel, zeroCoins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, {"multidenom: too many coins", types.NewMsgTransfer(validPort, validChannel, make([]sdk.Coin, types.MaximumTokensLength+1), sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, {"multidenom: both token and tokens are set", &types.MsgTransfer{validPort, validChannel, coin, sender, receiver, clienttypes.ZeroHeight(), 100, "", coins, emptyForwarding}, ibcerrors.ErrInvalidCoins}, - {"timeout height must be zero if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 100, "memo", types.NewForwarding("", validHop)), types.ErrInvalidPacketTimeout}, - {"memo must be empty if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "memo", types.NewForwarding("", validHop)), types.ErrInvalidMemo}, - {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding("", types.Hop{PortId: invalidPort, ChannelId: validChannel})), host.ErrInvalidID}, - {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding("", types.Hop{PortId: validPort, ChannelId: invalidChannel})), host.ErrInvalidID}, - {"invalid forwarding info too many hops", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding("", generateHops(types.MaximumNumberOfForwardingHops+1)...)), types.ErrInvalidForwarding}, - {"invalid forwarding info too long memo", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop)), types.ErrInvalidMemo}, + {"timeout height must be zero if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 100, "memo", types.NewForwarding(false, validHop)), types.ErrInvalidPacketTimeout}, + {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, types.Hop{PortId: invalidPort, ChannelId: validChannel})), host.ErrInvalidID}, + {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, types.Hop{PortId: validPort, ChannelId: invalidChannel})), host.ErrInvalidID}, + {"invalid forwarding info too many hops", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, generateHops(types.MaximumNumberOfForwardingHops+1)...)), types.ErrInvalidForwarding}, } for _, tc := range testCases { diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index 6f8a34a4e24..c75d31b5fc2 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -103,7 +103,7 @@ func NewFungibleTokenPacketDataV2( tokens []Token, sender, receiver string, memo string, - forwarding Forwarding, + forwarding ForwardingPacketData, ) FungibleTokenPacketDataV2 { return FungibleTokenPacketDataV2{ Tokens: tokens, diff --git a/modules/apps/transfer/types/packet.pb.go b/modules/apps/transfer/types/packet.pb.go index fd02225dc97..2622fc514bd 100644 --- a/modules/apps/transfer/types/packet.pb.go +++ b/modules/apps/transfer/types/packet.pb.go @@ -120,7 +120,7 @@ type FungibleTokenPacketDataV2 struct { // optional memo Memo string `protobuf:"bytes,4,opt,name=memo,proto3" json:"memo,omitempty"` // optional forwarding information - Forwarding Forwarding `protobuf:"bytes,5,opt,name=forwarding,proto3" json:"forwarding"` + Forwarding ForwardingPacketData `protobuf:"bytes,5,opt,name=forwarding,proto3" json:"forwarding"` } func (m *FungibleTokenPacketDataV2) Reset() { *m = FungibleTokenPacketDataV2{} } @@ -184,16 +184,74 @@ func (m *FungibleTokenPacketDataV2) GetMemo() string { return "" } -func (m *FungibleTokenPacketDataV2) GetForwarding() Forwarding { +func (m *FungibleTokenPacketDataV2) GetForwarding() ForwardingPacketData { if m != nil { return m.Forwarding } - return Forwarding{} + return ForwardingPacketData{} +} + +// ForwardingPacketData defines a list of port ID, channel ID pairs determining the path +// through which a packet must be forwarded, and the destination memo string to be used in the +// final destination of the tokens. +type ForwardingPacketData struct { + // optional memo consumed by final destination chain + DestinationMemo string `protobuf:"bytes,1,opt,name=destination_memo,json=destinationMemo,proto3" json:"destination_memo,omitempty"` + // optional intermediate path through which packet will be forwarded. + Hops []Hop `protobuf:"bytes,2,rep,name=hops,proto3" json:"hops"` +} + +func (m *ForwardingPacketData) Reset() { *m = ForwardingPacketData{} } +func (m *ForwardingPacketData) String() string { return proto.CompactTextString(m) } +func (*ForwardingPacketData) ProtoMessage() {} +func (*ForwardingPacketData) Descriptor() ([]byte, []int) { + return fileDescriptor_653ca2ce9a5ca313, []int{2} +} +func (m *ForwardingPacketData) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ForwardingPacketData) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ForwardingPacketData.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 *ForwardingPacketData) XXX_Merge(src proto.Message) { + xxx_messageInfo_ForwardingPacketData.Merge(m, src) +} +func (m *ForwardingPacketData) XXX_Size() int { + return m.Size() +} +func (m *ForwardingPacketData) XXX_DiscardUnknown() { + xxx_messageInfo_ForwardingPacketData.DiscardUnknown(m) +} + +var xxx_messageInfo_ForwardingPacketData proto.InternalMessageInfo + +func (m *ForwardingPacketData) GetDestinationMemo() string { + if m != nil { + return m.DestinationMemo + } + return "" +} + +func (m *ForwardingPacketData) GetHops() []Hop { + if m != nil { + return m.Hops + } + return nil } func init() { proto.RegisterType((*FungibleTokenPacketData)(nil), "ibc.applications.transfer.v2.FungibleTokenPacketData") proto.RegisterType((*FungibleTokenPacketDataV2)(nil), "ibc.applications.transfer.v2.FungibleTokenPacketDataV2") + proto.RegisterType((*ForwardingPacketData)(nil), "ibc.applications.transfer.v2.ForwardingPacketData") } func init() { @@ -201,30 +259,34 @@ func init() { } var fileDescriptor_653ca2ce9a5ca313 = []byte{ - // 365 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xb1, 0xae, 0xd3, 0x30, - 0x18, 0x85, 0xe3, 0x36, 0xad, 0xc0, 0xdd, 0xac, 0x0a, 0x42, 0x85, 0x42, 0x55, 0x96, 0x20, 0x84, - 0xad, 0x86, 0x01, 0x56, 0x2a, 0xd4, 0x11, 0x41, 0x85, 0x18, 0xd8, 0x1c, 0xc7, 0x0d, 0x56, 0x1b, - 0x3b, 0xb2, 0x9d, 0x20, 0x9e, 0x02, 0x1e, 0xab, 0x63, 0x47, 0xa6, 0xab, 0xab, 0xf6, 0x1d, 0xee, - 0x7c, 0x15, 0x27, 0xb7, 0x37, 0x4b, 0xb3, 0xfd, 0xe7, 0xe4, 0xf8, 0xe8, 0xcb, 0xff, 0xc3, 0x37, - 0x22, 0x61, 0x84, 0x16, 0xc5, 0x5e, 0x30, 0x6a, 0x85, 0x92, 0x86, 0x58, 0x4d, 0xa5, 0xd9, 0x72, - 0x4d, 0xaa, 0x98, 0x14, 0x94, 0xed, 0xb8, 0xc5, 0x85, 0x56, 0x56, 0xa1, 0x97, 0x22, 0x61, 0xb8, - 0x1b, 0xc5, 0x0f, 0x51, 0x5c, 0xc5, 0xb3, 0xa8, 0xb7, 0xc8, 0xaa, 0x1d, 0x97, 0x4d, 0xcf, 0x6c, - 0x9a, 0xa9, 0x4c, 0xb9, 0x91, 0xd4, 0x53, 0xeb, 0xbe, 0xed, 0x79, 0xbf, 0xbc, 0xcc, 0x4d, 0x78, - 0xf1, 0x17, 0xc0, 0xe7, 0xeb, 0x52, 0x66, 0x22, 0xd9, 0xf3, 0xef, 0x75, 0xf5, 0x57, 0x07, 0xfa, - 0x99, 0x5a, 0x8a, 0xa6, 0x70, 0x94, 0x72, 0xa9, 0xf2, 0x00, 0xcc, 0x41, 0xf4, 0x74, 0xd3, 0x08, - 0xf4, 0x0c, 0x8e, 0x69, 0xae, 0x4a, 0x69, 0x83, 0x81, 0xb3, 0x5b, 0x55, 0xfb, 0x86, 0xcb, 0x94, - 0xeb, 0x60, 0xd8, 0xf8, 0x8d, 0x42, 0x33, 0xf8, 0x44, 0x73, 0xc6, 0x45, 0xc5, 0x75, 0xe0, 0xbb, - 0x2f, 0x17, 0x8d, 0x10, 0xf4, 0x73, 0x9e, 0xab, 0x60, 0xe4, 0x7c, 0x37, 0x2f, 0xee, 0x00, 0x7c, - 0x71, 0x85, 0xe8, 0x47, 0x8c, 0x3e, 0xc1, 0xb1, 0xdb, 0x80, 0x09, 0xc0, 0x7c, 0x18, 0x4d, 0xe2, - 0xd7, 0xb8, 0x6f, 0x97, 0xd8, 0x15, 0xac, 0xfc, 0xc3, 0xcd, 0x2b, 0x6f, 0xd3, 0x3e, 0xec, 0x80, - 0x0e, 0xae, 0x82, 0x0e, 0xaf, 0x80, 0xfa, 0x8f, 0xa0, 0xe8, 0x0b, 0x84, 0x5b, 0xa5, 0x7f, 0x53, - 0x9d, 0x0a, 0x99, 0xb9, 0x5f, 0x98, 0xc4, 0x51, 0x1f, 0xce, 0x12, 0xaf, 0x2f, 0xf9, 0x96, 0xa9, - 0xd3, 0xb0, 0xfa, 0x76, 0x38, 0x85, 0xe0, 0x78, 0x0a, 0xc1, 0xed, 0x29, 0x04, 0xff, 0xce, 0xa1, - 0x77, 0x3c, 0x87, 0xde, 0xff, 0x73, 0xe8, 0xfd, 0xfc, 0x90, 0x09, 0xfb, 0xab, 0x4c, 0x30, 0x53, - 0x39, 0x61, 0xca, 0xe4, 0xca, 0x10, 0x91, 0xb0, 0x77, 0x99, 0x22, 0xd5, 0x47, 0x92, 0xab, 0xb4, - 0xdc, 0x73, 0x53, 0x5f, 0xbc, 0x73, 0x69, 0xfb, 0xa7, 0xe0, 0x26, 0x19, 0xbb, 0x23, 0xbf, 0xbf, - 0x0f, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xa2, 0xd3, 0x30, 0x9c, 0x02, 0x00, 0x00, + // 418 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0x41, 0x8b, 0xd3, 0x40, + 0x14, 0xc7, 0x93, 0x34, 0x5b, 0x74, 0xf6, 0xa0, 0x0c, 0x45, 0x63, 0x91, 0xb8, 0xd6, 0x4b, 0x17, + 0x71, 0x86, 0x8d, 0x07, 0x05, 0x4f, 0x2e, 0xb2, 0x78, 0x11, 0x74, 0x11, 0x11, 0x2f, 0x32, 0x99, + 0xcc, 0x66, 0x87, 0x36, 0xf3, 0xc2, 0xcc, 0x24, 0xe2, 0x45, 0xfc, 0x06, 0xfa, 0xb1, 0x7a, 0xec, + 0xd1, 0x93, 0x48, 0xfb, 0x45, 0x24, 0x93, 0xd8, 0xe6, 0x60, 0x73, 0x7b, 0xef, 0x9f, 0xff, 0xfb, + 0xf3, 0x9b, 0x97, 0x87, 0x4e, 0x65, 0xca, 0x29, 0x2b, 0xcb, 0xa5, 0xe4, 0xcc, 0x4a, 0x50, 0x86, + 0x5a, 0xcd, 0x94, 0xb9, 0x12, 0x9a, 0xd6, 0x09, 0x2d, 0x19, 0x5f, 0x08, 0x4b, 0x4a, 0x0d, 0x16, + 0xf0, 0x7d, 0x99, 0x72, 0xd2, 0xb7, 0x92, 0x7f, 0x56, 0x52, 0x27, 0xd3, 0xf9, 0x60, 0x90, 0x85, + 0x85, 0x50, 0x6d, 0xce, 0x74, 0x92, 0x43, 0x0e, 0xae, 0xa4, 0x4d, 0xd5, 0xa9, 0x8f, 0x07, 0xe6, + 0xcf, 0x76, 0x75, 0x6b, 0x9e, 0xfd, 0xf0, 0xd1, 0xdd, 0x8b, 0x4a, 0xe5, 0x32, 0x5d, 0x8a, 0xf7, + 0x4d, 0xf4, 0x5b, 0x07, 0xfa, 0x8a, 0x59, 0x86, 0x27, 0xe8, 0x28, 0x13, 0x0a, 0x8a, 0xc8, 0x3f, + 0xf1, 0xe7, 0x37, 0x2f, 0xdb, 0x06, 0xdf, 0x41, 0x63, 0x56, 0x40, 0xa5, 0x6c, 0x14, 0x38, 0xb9, + 0xeb, 0x1a, 0xdd, 0x08, 0x95, 0x09, 0x1d, 0x8d, 0x5a, 0xbd, 0xed, 0xf0, 0x14, 0xdd, 0xd0, 0x82, + 0x0b, 0x59, 0x0b, 0x1d, 0x85, 0xee, 0xcb, 0xae, 0xc7, 0x18, 0x85, 0x85, 0x28, 0x20, 0x3a, 0x72, + 0xba, 0xab, 0x67, 0xdf, 0x03, 0x74, 0xef, 0x00, 0xd1, 0x87, 0x04, 0xbf, 0x44, 0x63, 0xb7, 0x01, + 0x13, 0xf9, 0x27, 0xa3, 0xf9, 0x71, 0xf2, 0x88, 0x0c, 0xed, 0x92, 0xb8, 0x80, 0xf3, 0x70, 0xf5, + 0xfb, 0x81, 0x77, 0xd9, 0x0d, 0xf6, 0x40, 0x83, 0x83, 0xa0, 0xa3, 0x03, 0xa0, 0xe1, 0x1e, 0x14, + 0x7f, 0x44, 0xe8, 0x0a, 0xf4, 0x17, 0xa6, 0x33, 0xa9, 0x72, 0xf7, 0x84, 0xe3, 0x24, 0x19, 0xc6, + 0xb9, 0xd8, 0xf9, 0xf7, 0x8f, 0xea, 0xe8, 0x7a, 0x59, 0xb3, 0x6f, 0x68, 0xf2, 0x3f, 0x27, 0x3e, + 0x45, 0xb7, 0x33, 0x61, 0xac, 0x54, 0x2e, 0xfa, 0xb3, 0x23, 0x6a, 0xff, 0xcd, 0xad, 0x9e, 0xfe, + 0xa6, 0x81, 0x7b, 0x81, 0xc2, 0x6b, 0x28, 0x4d, 0x14, 0xb8, 0x2d, 0x3d, 0x1c, 0xc2, 0x3a, 0x23, + 0xaf, 0xa1, 0xec, 0x28, 0xdc, 0xd0, 0xf9, 0xbb, 0xd5, 0x26, 0xf6, 0xd7, 0x9b, 0xd8, 0xff, 0xb3, + 0x89, 0xfd, 0x9f, 0xdb, 0xd8, 0x5b, 0x6f, 0x63, 0xef, 0xd7, 0x36, 0xf6, 0x3e, 0x3d, 0xcb, 0xa5, + 0xbd, 0xae, 0x52, 0xc2, 0xa1, 0xa0, 0x1c, 0x4c, 0x01, 0x86, 0xca, 0x94, 0x3f, 0xc9, 0x81, 0xd6, + 0xcf, 0x69, 0x01, 0x59, 0xb5, 0x14, 0xa6, 0xb9, 0xbd, 0xde, 0xcd, 0xd9, 0xaf, 0xa5, 0x30, 0xe9, + 0xd8, 0x9d, 0xdb, 0xd3, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x64, 0x17, 0xb6, 0x26, 0x03, + 0x00, 0x00, } func (m *FungibleTokenPacketData) Marshal() (dAtA []byte, err error) { @@ -353,6 +415,50 @@ func (m *FungibleTokenPacketDataV2) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } +func (m *ForwardingPacketData) 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 *ForwardingPacketData) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ForwardingPacketData) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Hops) > 0 { + for iNdEx := len(m.Hops) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Hops[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPacket(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.DestinationMemo) > 0 { + i -= len(m.DestinationMemo) + copy(dAtA[i:], m.DestinationMemo) + i = encodeVarintPacket(dAtA, i, uint64(len(m.DestinationMemo))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintPacket(dAtA []byte, offset int, v uint64) int { offset -= sovPacket(v) base := offset @@ -422,6 +528,25 @@ func (m *FungibleTokenPacketDataV2) Size() (n int) { return n } +func (m *ForwardingPacketData) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DestinationMemo) + if l > 0 { + n += 1 + l + sovPacket(uint64(l)) + } + if len(m.Hops) > 0 { + for _, e := range m.Hops { + l = e.Size() + n += 1 + l + sovPacket(uint64(l)) + } + } + return n +} + func sovPacket(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -851,6 +976,122 @@ func (m *FungibleTokenPacketDataV2) Unmarshal(dAtA []byte) error { } return nil } +func (m *ForwardingPacketData) 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 ErrIntOverflowPacket + } + 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: ForwardingPacketData: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ForwardingPacketData: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DestinationMemo", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + 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 ErrInvalidLengthPacket + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DestinationMemo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hops", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPacket + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPacket + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPacket + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hops = append(m.Hops, Hop{}) + if err := m.Hops[len(m.Hops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPacket(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPacket + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipPacket(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 69b7a30068b..3e1cfbe8e46 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -20,6 +20,8 @@ const ( invalidLargeAmount = "115792089237316195423570985008687907853269984665640564039457584007913129639936" // 2^256 ) +var emptyForwardingPacketData = types.ForwardingPacketData{} + // TestFungibleTokenPacketDataValidateBasic tests ValidateBasic for FungibleTokenPacketData func TestFungibleTokenPacketDataValidateBasic(t *testing.T) { testCases := []struct { @@ -183,7 +185,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - emptyForwarding, + emptyForwardingPacketData, ), nil, }, @@ -199,7 +201,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "memo", - emptyForwarding, + emptyForwardingPacketData, ), nil, }, @@ -215,7 +217,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "memo", - emptyForwarding, + emptyForwardingPacketData, ), nil, }, @@ -231,7 +233,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwarding("", validHop, validHop), + types.NewForwardingPacketData("", validHop, validHop), ), nil, }, @@ -247,7 +249,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwarding("memo", validHop), + types.NewForwardingPacketData("memo", validHop), ), nil, }, @@ -263,7 +265,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - emptyForwarding, + emptyForwardingPacketData, ), types.ErrInvalidDenomForTransfer, }, @@ -279,7 +281,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - emptyForwarding, + emptyForwardingPacketData, ), types.ErrInvalidAmount, }, @@ -290,7 +292,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - emptyForwarding, + emptyForwardingPacketData, ), types.ErrInvalidAmount, }, @@ -306,7 +308,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - emptyForwarding, + emptyForwardingPacketData, ), types.ErrInvalidAmount, }, @@ -322,7 +324,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - emptyForwarding, + emptyForwardingPacketData, ), types.ErrInvalidAmount, }, @@ -338,7 +340,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "memo", - emptyForwarding, + emptyForwardingPacketData, ), types.ErrInvalidAmount, }, @@ -354,7 +356,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { "", receiver, "memo", - emptyForwarding, + emptyForwardingPacketData, ), ibcerrors.ErrInvalidAddress, }, @@ -370,7 +372,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, "", "", - emptyForwarding, + emptyForwardingPacketData, ), ibcerrors.ErrInvalidAddress, }, @@ -386,7 +388,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, ibctesting.GenerateString(types.MaximumMemoLength+1), - emptyForwarding, + emptyForwardingPacketData, ), types.ErrInvalidMemo, }, @@ -402,7 +404,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "memo", - types.NewForwarding("", validHop), + types.NewForwardingPacketData("", validHop), ), types.ErrInvalidMemo, }, @@ -418,7 +420,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwarding( + types.NewForwardingPacketData( "", types.Hop{ PortId: invalidPort, @@ -440,7 +442,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwarding( + types.NewForwardingPacketData( "", types.Hop{ PortId: "transfer", @@ -462,7 +464,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwarding("", generateHops(types.MaximumNumberOfForwardingHops+1)...), + types.NewForwardingPacketData("", generateHops(types.MaximumNumberOfForwardingHops+1)...), ), types.ErrInvalidForwarding, }, @@ -478,7 +480,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { sender, receiver, "", - types.NewForwarding(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), + types.NewForwardingPacketData(ibctesting.GenerateString(types.MaximumMemoLength+1), validHop), ), types.ErrInvalidMemo, }, @@ -516,7 +518,7 @@ func TestGetPacketSender(t *testing.T) { sender, receiver, "", - emptyForwarding, + emptyForwardingPacketData, ), sender, }, @@ -532,7 +534,7 @@ func TestGetPacketSender(t *testing.T) { "", receiver, "abc", - emptyForwarding, + emptyForwardingPacketData, ), "", }, @@ -563,7 +565,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, receiver), - emptyForwarding, + emptyForwardingPacketData, ), map[string]interface{}{ @@ -582,7 +584,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, fmt.Sprintf(`{"src_callback": {"address": "%s", "gas_limit": "200000"}}`, receiver), - emptyForwarding, + emptyForwardingPacketData, ), map[string]interface{}{ "address": receiver, @@ -601,7 +603,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, `{"src_callback": "string"}`, - emptyForwarding, + emptyForwardingPacketData, ), "string", }, @@ -617,7 +619,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, fmt.Sprintf(`{"dest_callback": {"address": "%s", "min_gas": "200000"}}`, receiver), - emptyForwarding, + emptyForwardingPacketData, ), nil, }, @@ -633,7 +635,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, "", - emptyForwarding, + emptyForwardingPacketData, ), nil, }, @@ -649,7 +651,7 @@ func TestPacketDataProvider(t *testing.T) { sender, receiver, "invalid", - emptyForwarding, + emptyForwardingPacketData, ), nil, }, @@ -681,7 +683,7 @@ func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { sender, receiver, "", - emptyForwarding, + emptyForwardingPacketData, ), false, }, @@ -697,7 +699,7 @@ func TestFungibleTokenPacketDataOmitEmpty(t *testing.T) { sender, receiver, "abc", - emptyForwarding, + emptyForwardingPacketData, ), true, }, diff --git a/modules/apps/transfer/types/transfer.pb.go b/modules/apps/transfer/types/transfer.pb.go index 7311d98c072..f2825d90088 100644 --- a/modules/apps/transfer/types/transfer.pb.go +++ b/modules/apps/transfer/types/transfer.pb.go @@ -84,11 +84,13 @@ func (m *Params) GetReceiveEnabled() bool { } // Forwarding defines a list of port ID, channel ID pairs determining the path -// through which a packet must be forwarded, and the memo string to be used in the -// final destination of the tokens. +// through which a packet must be forwarded, and an unwind boolean indicating if +// the coin should be unwinded to its native chain before forwarding. type Forwarding struct { - Hops []Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops"` - Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"` + // optional unwinding for the token transfered + Unwind bool `protobuf:"varint,1,opt,name=unwind,proto3" json:"unwind,omitempty"` + // optional intermediate path through which packet will be forwarded + Hops []Hop `protobuf:"bytes,2,rep,name=hops,proto3" json:"hops"` } func (m *Forwarding) Reset() { *m = Forwarding{} } @@ -124,18 +126,18 @@ func (m *Forwarding) XXX_DiscardUnknown() { var xxx_messageInfo_Forwarding proto.InternalMessageInfo -func (m *Forwarding) GetHops() []Hop { +func (m *Forwarding) GetUnwind() bool { if m != nil { - return m.Hops + return m.Unwind } - return nil + return false } -func (m *Forwarding) GetMemo() string { +func (m *Forwarding) GetHops() []Hop { if m != nil { - return m.Memo + return m.Hops } - return "" + return nil } // Hop defines a port ID, channel ID pair specifying where tokens must be forwarded @@ -203,28 +205,28 @@ func init() { } var fileDescriptor_5041673e96e97901 = []byte{ - // 324 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0x4b, 0xf3, 0x30, - 0x18, 0xc7, 0xdb, 0x77, 0x63, 0xaf, 0x7b, 0x26, 0x0a, 0x41, 0x70, 0x88, 0xd6, 0x6d, 0x17, 0x07, - 0x62, 0xc3, 0xf4, 0xa0, 0x20, 0x5e, 0x06, 0xca, 0x76, 0xd3, 0xe2, 0x49, 0x90, 0x91, 0xa6, 0xb1, - 0x0b, 0xb4, 0x79, 0x42, 0xd2, 0x55, 0xfc, 0x16, 0x7e, 0xac, 0x1d, 0x77, 0xf4, 0x24, 0xb2, 0x7d, - 0x11, 0x69, 0x3b, 0xc6, 0x4e, 0xde, 0xfe, 0xf9, 0xe5, 0xf7, 0x27, 0x0f, 0x79, 0xe0, 0x5c, 0x86, - 0x9c, 0x32, 0xad, 0x13, 0xc9, 0x59, 0x26, 0x51, 0x59, 0x9a, 0x19, 0xa6, 0xec, 0x9b, 0x30, 0x34, - 0x1f, 0x6c, 0xb2, 0xaf, 0x0d, 0x66, 0x48, 0x8e, 0x65, 0xc8, 0xfd, 0x6d, 0xd9, 0xdf, 0x08, 0xf9, - 0xe0, 0xe8, 0x20, 0xc6, 0x18, 0x4b, 0x91, 0x16, 0xa9, 0xea, 0xf4, 0x9e, 0xa1, 0xf1, 0xc8, 0x0c, - 0x4b, 0x2d, 0xe9, 0xc2, 0xae, 0x15, 0x2a, 0x9a, 0x08, 0xc5, 0xc2, 0x44, 0x44, 0x6d, 0xb7, 0xe3, - 0xf6, 0x77, 0x82, 0x56, 0xc1, 0xee, 0x2b, 0x44, 0xce, 0x60, 0xdf, 0x08, 0x2e, 0x64, 0x2e, 0x36, - 0xd6, 0xbf, 0xd2, 0xda, 0x5b, 0xe3, 0xb5, 0xd8, 0x7b, 0x05, 0x78, 0x40, 0xf3, 0xce, 0x4c, 0x24, - 0x55, 0x4c, 0x6e, 0xa1, 0x3e, 0x45, 0x6d, 0xdb, 0x6e, 0xa7, 0xd6, 0x6f, 0x5d, 0x76, 0xfd, 0xbf, - 0xc6, 0xf4, 0x47, 0xa8, 0x87, 0xf5, 0xf9, 0xf7, 0xa9, 0x13, 0x94, 0x25, 0x42, 0xa0, 0x9e, 0x8a, - 0x14, 0xcb, 0x87, 0x9a, 0x41, 0x99, 0x7b, 0x77, 0x50, 0x1b, 0xa1, 0x26, 0x87, 0xf0, 0x5f, 0xa3, - 0xc9, 0x26, 0xb2, 0x1a, 0xb6, 0x19, 0x34, 0x8a, 0xe3, 0x38, 0x22, 0x27, 0x00, 0x7c, 0xca, 0x94, - 0x12, 0x49, 0x71, 0x57, 0x35, 0x9b, 0x6b, 0x32, 0x8e, 0x86, 0x4f, 0xf3, 0xa5, 0xe7, 0x2e, 0x96, - 0x9e, 0xfb, 0xb3, 0xf4, 0xdc, 0xcf, 0x95, 0xe7, 0x2c, 0x56, 0x9e, 0xf3, 0xb5, 0xf2, 0x9c, 0x97, - 0xeb, 0x58, 0x66, 0xd3, 0x59, 0xe8, 0x73, 0x4c, 0x29, 0x47, 0x9b, 0xa2, 0xa5, 0x32, 0xe4, 0x17, - 0x31, 0xd2, 0xfc, 0x86, 0xa6, 0x18, 0xcd, 0x12, 0x61, 0x8b, 0x75, 0x6c, 0xad, 0x21, 0xfb, 0xd0, - 0xc2, 0x86, 0x8d, 0xf2, 0x37, 0xaf, 0x7e, 0x03, 0x00, 0x00, 0xff, 0xff, 0x95, 0xd0, 0x0d, 0xf6, - 0xb0, 0x01, 0x00, 0x00, + // 323 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x41, 0x4b, 0xc3, 0x30, + 0x14, 0xc7, 0xdb, 0x6d, 0x54, 0x97, 0x89, 0x42, 0x10, 0x1d, 0xa2, 0x75, 0xdb, 0xc5, 0x81, 0xd8, + 0x30, 0x3d, 0x28, 0x88, 0x97, 0x81, 0xb2, 0xdd, 0x74, 0x78, 0xf2, 0x32, 0xd2, 0x34, 0x76, 0x81, + 0x36, 0x2f, 0x24, 0x59, 0x87, 0xdf, 0xc2, 0x8f, 0xb5, 0xe3, 0x8e, 0x9e, 0x44, 0xb6, 0x2f, 0x22, + 0xed, 0xea, 0xd8, 0xc9, 0xdb, 0x7b, 0xbf, 0xf7, 0x7b, 0x8f, 0x90, 0x3f, 0xba, 0x14, 0x21, 0x23, + 0x54, 0xa9, 0x44, 0x30, 0x6a, 0x05, 0x48, 0x43, 0xac, 0xa6, 0xd2, 0xbc, 0x73, 0x4d, 0xb2, 0xde, + 0xa6, 0x0e, 0x94, 0x06, 0x0b, 0xf8, 0x54, 0x84, 0x2c, 0xd8, 0x96, 0x83, 0x8d, 0x90, 0xf5, 0x4e, + 0x0e, 0x63, 0x88, 0xa1, 0x10, 0x49, 0x5e, 0xad, 0x77, 0x3a, 0xaf, 0xc8, 0x7b, 0xa6, 0x9a, 0xa6, + 0x06, 0xb7, 0xd1, 0x9e, 0xe1, 0x32, 0x1a, 0x73, 0x49, 0xc3, 0x84, 0x47, 0x4d, 0xb7, 0xe5, 0x76, + 0x77, 0x47, 0x8d, 0x9c, 0x3d, 0xae, 0x11, 0xbe, 0x40, 0x07, 0x9a, 0x33, 0x2e, 0x32, 0xbe, 0xb1, + 0x2a, 0x85, 0xb5, 0x5f, 0xe2, 0x52, 0xec, 0x50, 0x84, 0x9e, 0x40, 0xcf, 0xa8, 0x8e, 0x84, 0x8c, + 0xf1, 0x11, 0xf2, 0xa6, 0x72, 0x26, 0xe4, 0xdf, 0xcd, 0xb2, 0xc3, 0xf7, 0xa8, 0x36, 0x01, 0x65, + 0x9a, 0x95, 0x56, 0xb5, 0xdb, 0xb8, 0x6e, 0x07, 0xff, 0x3d, 0x3f, 0x18, 0x80, 0xea, 0xd7, 0xe6, + 0xdf, 0xe7, 0xce, 0xa8, 0x58, 0xea, 0x3c, 0xa0, 0xea, 0x00, 0x14, 0x3e, 0x46, 0x3b, 0x0a, 0xb4, + 0x1d, 0x8b, 0xf5, 0xf1, 0xfa, 0xc8, 0xcb, 0xdb, 0x61, 0x84, 0xcf, 0x10, 0x62, 0x13, 0x2a, 0x25, + 0x4f, 0xf2, 0x59, 0xa5, 0x98, 0xd5, 0x4b, 0x32, 0x8c, 0xfa, 0x2f, 0xf3, 0xa5, 0xef, 0x2e, 0x96, + 0xbe, 0xfb, 0xb3, 0xf4, 0xdd, 0xcf, 0x95, 0xef, 0x2c, 0x56, 0xbe, 0xf3, 0xb5, 0xf2, 0x9d, 0xb7, + 0xdb, 0x58, 0xd8, 0xc9, 0x34, 0x0c, 0x18, 0xa4, 0x84, 0x81, 0x49, 0xc1, 0x10, 0x11, 0xb2, 0xab, + 0x18, 0x48, 0x76, 0x47, 0x52, 0x88, 0xa6, 0x09, 0x37, 0x79, 0x24, 0x5b, 0x51, 0xd8, 0x0f, 0xc5, + 0x4d, 0xe8, 0x15, 0x3f, 0x7a, 0xf3, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x94, 0x05, 0x3d, 0x15, 0xb4, + 0x01, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -290,13 +292,6 @@ func (m *Forwarding) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.Memo) > 0 { - i -= len(m.Memo) - copy(dAtA[i:], m.Memo) - i = encodeVarintTransfer(dAtA, i, uint64(len(m.Memo))) - i-- - dAtA[i] = 0x12 - } if len(m.Hops) > 0 { for iNdEx := len(m.Hops) - 1; iNdEx >= 0; iNdEx-- { { @@ -308,8 +303,18 @@ func (m *Forwarding) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintTransfer(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0xa + dAtA[i] = 0x12 + } + } + if m.Unwind { + i-- + if m.Unwind { + dAtA[i] = 1 + } else { + dAtA[i] = 0 } + i-- + dAtA[i] = 0x8 } return len(dAtA) - i, nil } @@ -383,16 +388,15 @@ func (m *Forwarding) Size() (n int) { } var l int _ = l + if m.Unwind { + n += 2 + } if len(m.Hops) > 0 { for _, e := range m.Hops { l = e.Size() n += 1 + l + sovTransfer(uint64(l)) } } - l = len(m.Memo) - if l > 0 { - n += 1 + l + sovTransfer(uint64(l)) - } return n } @@ -539,10 +543,10 @@ func (m *Forwarding) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Hops", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Unwind", wireType) } - var msglen int + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTransfer @@ -552,31 +556,17 @@ func (m *Forwarding) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { - return ErrInvalidLengthTransfer - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTransfer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Hops = append(m.Hops, Hop{}) - if err := m.Hops[len(m.Hops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex + m.Unwind = bool(v != 0) case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Memo", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Hops", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTransfer @@ -586,23 +576,25 @@ func (m *Forwarding) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthTransfer } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTransfer } if postIndex > l { return io.ErrUnexpectedEOF } - m.Memo = string(dAtA[iNdEx:postIndex]) + m.Hops = append(m.Hops, Hop{}) + if err := m.Hops[len(m.Hops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index 5419b503512..bac1092e02f 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -58,13 +58,7 @@ func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) return authz.AcceptResponse{}, errorsmod.Wrap(ibcerrors.ErrInvalidAddress, "not allowed receiver address for transfer") } - memo := msgTransfer.Memo - // in the case of forwarded transfers, the actual memo is stored in the forwarding path until the final destination - if msgTransfer.ShouldBeForwarded() { - memo = msgTransfer.Forwarding.Memo - } - - if err := validateMemo(ctx, memo, a.Allocations[index].AllowedPacketData); err != nil { + if err := validateMemo(ctx, msgTransfer.Memo, a.Allocations[index].AllowedPacketData); err != nil { return authz.AcceptResponse{}, err } diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index 0b108525709..14b7c7c1ad6 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -104,7 +104,8 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { func() { allowedList := []string{} transferAuthz.Allocations[0].AllowedPacketData = allowedList - msgTransfer.Forwarding = types.NewForwarding("", validHop) + + msgTransfer.Forwarding = types.NewForwarding(false, validHop) }, func(res authz.AcceptResponse, err error) { suite.Require().NoError(err) @@ -134,7 +135,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { func() { allowedList := []string{"*"} transferAuthz.Allocations[0].AllowedPacketData = allowedList - msgTransfer.Forwarding = types.NewForwarding(testMemo1, validHop) + msgTransfer.Forwarding = types.NewForwarding(false, validHop) }, func(res authz.AcceptResponse, err error) { suite.Require().NoError(err) @@ -159,21 +160,6 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Nil(res.Updated) }, }, - { - "success: transfer memo allowed in forwarding path", - func() { - allowedList := []string{testMemo1, testMemo2} - transferAuthz.Allocations[0].AllowedPacketData = allowedList - msgTransfer.Forwarding = types.NewForwarding(testMemo1, validHop) - }, - func(res authz.AcceptResponse, err error) { - suite.Require().NoError(err) - - suite.Require().True(res.Accept) - suite.Require().True(res.Delete) - suite.Require().Nil(res.Updated) - }, - }, { "empty AllowedPacketData but not empty memo", func() { @@ -185,17 +171,6 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Error(err) }, }, - { - "empty AllowedPacketData but not empty memo in forwarding path", - func() { - allowedList := []string{} - transferAuthz.Allocations[0].AllowedPacketData = allowedList - msgTransfer.Forwarding = types.NewForwarding(testMemo1, validHop) - }, - func(res authz.AcceptResponse, err error) { - suite.Require().Error(err) - }, - }, { "memo not allowed", func() { @@ -208,18 +183,6 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().ErrorContains(err, fmt.Sprintf("not allowed memo: %s", testMemo2)) }, }, - { - "memo not allowed in forwarding path", - func() { - allowedList := []string{testMemo1} - transferAuthz.Allocations[0].AllowedPacketData = allowedList - msgTransfer.Forwarding = types.NewForwarding(testMemo2, validHop) - }, - func(res authz.AcceptResponse, err error) { - suite.Require().Error(err) - suite.Require().ErrorContains(err, fmt.Sprintf("not allowed memo: %s", testMemo2)) - }, - }, { "test multiple coins does not overspend", func() { diff --git a/proto/ibc/applications/transfer/v1/transfer.proto b/proto/ibc/applications/transfer/v1/transfer.proto index 8e3456e3a29..2c0b942e554 100644 --- a/proto/ibc/applications/transfer/v1/transfer.proto +++ b/proto/ibc/applications/transfer/v1/transfer.proto @@ -20,11 +20,13 @@ message Params { } // Forwarding defines a list of port ID, channel ID pairs determining the path -// through which a packet must be forwarded, and the memo string to be used in the -// final destination of the tokens. +// through which a packet must be forwarded, and an unwind boolean indicating if +// the coin should be unwinded to its native chain before forwarding. message Forwarding { - repeated Hop hops = 1 [(gogoproto.nullable) = false]; - string memo = 2; + // optional unwinding for the token transfered + bool unwind = 1; + // optional intermediate path through which packet will be forwarded + repeated Hop hops = 2 [(gogoproto.nullable) = false]; } // Hop defines a port ID, channel ID pair specifying where tokens must be forwarded diff --git a/proto/ibc/applications/transfer/v2/packet.proto b/proto/ibc/applications/transfer/v2/packet.proto index 9999e7ea87c..162833ce4e1 100644 --- a/proto/ibc/applications/transfer/v2/packet.proto +++ b/proto/ibc/applications/transfer/v2/packet.proto @@ -37,5 +37,15 @@ message FungibleTokenPacketDataV2 { // optional memo string memo = 4; // optional forwarding information - ibc.applications.transfer.v1.Forwarding forwarding = 5 [(gogoproto.nullable) = false]; + ForwardingPacketData forwarding = 5 [(gogoproto.nullable) = false]; +} + +// ForwardingPacketData defines a list of port ID, channel ID pairs determining the path +// through which a packet must be forwarded, and the destination memo string to be used in the +// final destination of the tokens. +message ForwardingPacketData { + // optional memo consumed by final destination chain + string destination_memo = 1; + // optional intermediate path through which packet will be forwarded. + repeated ibc.applications.transfer.v1.Hop hops = 2 [(gogoproto.nullable) = false]; } From ef6d22f7e231c5d34991b6d099d48864dc52d616 Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Fri, 21 Jun 2024 10:02:28 +0100 Subject: [PATCH 091/141] feat: allow authz granters to specify forwarding info for token transfer (#6661) * First attempt to modify proto and validation. * Fmt * Make it compile * Proto * Add basic validation * Added tests * Fix nil check and remove redundant code. * Move "forwarding" to non-pointer * Added one test case. * Moved error and changed method name. * PR Feedback. * Add nullable=false * Added test and fixed test names * Run make proto-all * Change pointer to non-pointer * Change Yet Another Pointer * More pointers * Comments and naming * Reintroduce brace removed while merging * Remove accidentally reintroduced tests --- modules/apps/transfer/types/authz.pb.go | 310 ++++++++++++++++-- .../transfer/types/transfer_authorization.go | 22 +- .../types/transfer_authorization_test.go | 116 ++++++- .../ibc/applications/transfer/v1/authz.proto | 9 + 4 files changed, 425 insertions(+), 32 deletions(-) diff --git a/modules/apps/transfer/types/authz.pb.go b/modules/apps/transfer/types/authz.pb.go index 01928af5ac8..f0db4502e32 100644 --- a/modules/apps/transfer/types/authz.pb.go +++ b/modules/apps/transfer/types/authz.pb.go @@ -39,6 +39,9 @@ type Allocation struct { // allow list of memo strings, an empty list prohibits all memo strings; // a list only with "*" permits any memo string AllowedPacketData []string `protobuf:"bytes,5,rep,name=allowed_packet_data,json=allowedPacketData,proto3" json:"allowed_packet_data,omitempty"` + // a list of allowed source port ID/channel ID pairs through which the packet is allowed to be forwarded until final + // destination + AllowedForwardingHops []Hops `protobuf:"bytes,6,rep,name=allowed_forwarding_hops,json=allowedForwardingHops,proto3" json:"allowed_forwarding_hops"` } func (m *Allocation) Reset() { *m = Allocation{} } @@ -109,6 +112,58 @@ func (m *Allocation) GetAllowedPacketData() []string { return nil } +func (m *Allocation) GetAllowedForwardingHops() []Hops { + if m != nil { + return m.AllowedForwardingHops + } + return nil +} + +// Hops represent a list of Hop +type Hops struct { + Hops []Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops"` +} + +func (m *Hops) Reset() { *m = Hops{} } +func (m *Hops) String() string { return proto.CompactTextString(m) } +func (*Hops) ProtoMessage() {} +func (*Hops) Descriptor() ([]byte, []int) { + return fileDescriptor_b1a28b55d17325aa, []int{1} +} +func (m *Hops) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Hops) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Hops.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 *Hops) XXX_Merge(src proto.Message) { + xxx_messageInfo_Hops.Merge(m, src) +} +func (m *Hops) XXX_Size() int { + return m.Size() +} +func (m *Hops) XXX_DiscardUnknown() { + xxx_messageInfo_Hops.DiscardUnknown(m) +} + +var xxx_messageInfo_Hops proto.InternalMessageInfo + +func (m *Hops) GetHops() []Hop { + if m != nil { + return m.Hops + } + return nil +} + // TransferAuthorization allows the grantee to spend up to spend_limit coins from // the granter's account for ibc transfer on a specific channel type TransferAuthorization struct { @@ -120,7 +175,7 @@ func (m *TransferAuthorization) Reset() { *m = TransferAuthorization{} } func (m *TransferAuthorization) String() string { return proto.CompactTextString(m) } func (*TransferAuthorization) ProtoMessage() {} func (*TransferAuthorization) Descriptor() ([]byte, []int) { - return fileDescriptor_b1a28b55d17325aa, []int{1} + return fileDescriptor_b1a28b55d17325aa, []int{2} } func (m *TransferAuthorization) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -158,6 +213,7 @@ func (m *TransferAuthorization) GetAllocations() []Allocation { func init() { proto.RegisterType((*Allocation)(nil), "ibc.applications.transfer.v1.Allocation") + proto.RegisterType((*Hops)(nil), "ibc.applications.transfer.v1.Hops") proto.RegisterType((*TransferAuthorization)(nil), "ibc.applications.transfer.v1.TransferAuthorization") } @@ -166,35 +222,39 @@ func init() { } var fileDescriptor_b1a28b55d17325aa = []byte{ - // 436 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xcf, 0x8e, 0xd3, 0x30, - 0x10, 0xc6, 0x9b, 0xed, 0x82, 0x54, 0x57, 0x20, 0x11, 0x40, 0xca, 0xae, 0x20, 0xad, 0x2a, 0x81, - 0x72, 0xa9, 0x4d, 0xe1, 0x00, 0xe2, 0xb6, 0x5d, 0x8e, 0x7b, 0x28, 0x15, 0x27, 0x2e, 0x91, 0xe3, - 0x98, 0xd6, 0x5a, 0x27, 0x13, 0xc5, 0x93, 0x20, 0xf6, 0x29, 0xd8, 0xd7, 0xe0, 0xcc, 0x43, 0xac, - 0x38, 0xed, 0x91, 0x13, 0xa0, 0xf6, 0x45, 0x50, 0x6c, 0x17, 0x8a, 0x90, 0xf6, 0x94, 0xf8, 0x9b, - 0xcf, 0xf3, 0xe7, 0xe7, 0x21, 0x89, 0xca, 0x04, 0xe3, 0x55, 0xa5, 0x95, 0xe0, 0xa8, 0xa0, 0x34, - 0x0c, 0x6b, 0x5e, 0x9a, 0x0f, 0xb2, 0x66, 0xed, 0x8c, 0xf1, 0x06, 0xd7, 0x17, 0xb4, 0xaa, 0x01, - 0x21, 0x7c, 0xa4, 0x32, 0x41, 0xf7, 0x9d, 0x74, 0xe7, 0xa4, 0xed, 0xec, 0xf8, 0x48, 0x80, 0x29, - 0xc0, 0xa4, 0xd6, 0xcb, 0xdc, 0xc1, 0x5d, 0x3c, 0x7e, 0xb0, 0x82, 0x15, 0x38, 0xbd, 0xfb, 0xf3, - 0x6a, 0xec, 0x3c, 0x2c, 0xe3, 0x46, 0xb2, 0x76, 0x96, 0x49, 0xe4, 0x33, 0x26, 0x40, 0x95, 0x2e, - 0x3e, 0xb9, 0x3c, 0x20, 0xe4, 0x44, 0x6b, 0x70, 0xc5, 0xc2, 0x11, 0x19, 0x1a, 0x68, 0x6a, 0x21, - 0xd3, 0x0a, 0x6a, 0x8c, 0x82, 0x71, 0x90, 0x0c, 0x96, 0xc4, 0x49, 0x0b, 0xa8, 0x31, 0x7c, 0x42, - 0xee, 0x7a, 0x83, 0x58, 0xf3, 0xb2, 0x94, 0x3a, 0x3a, 0xb0, 0x9e, 0x3b, 0x4e, 0x3d, 0x75, 0x62, - 0xa8, 0xc9, 0xd0, 0x54, 0xb2, 0xcc, 0x53, 0xad, 0x0a, 0x85, 0x51, 0x7f, 0xdc, 0x4f, 0x86, 0xcf, - 0x8f, 0xa8, 0x6f, 0xb8, 0x6b, 0x86, 0xfa, 0x66, 0xe8, 0x29, 0xa8, 0x72, 0xfe, 0xec, 0xea, 0xc7, - 0xa8, 0xf7, 0xe5, 0xe7, 0x28, 0x59, 0x29, 0x5c, 0x37, 0x19, 0x15, 0x50, 0xf8, 0xe9, 0xfc, 0x67, - 0x6a, 0xf2, 0x73, 0x86, 0x9f, 0x2a, 0x69, 0xec, 0x05, 0xb3, 0x24, 0x36, 0xff, 0x59, 0x97, 0x3e, - 0x7c, 0x4c, 0x08, 0xd7, 0x1a, 0x3e, 0xa6, 0x5a, 0x19, 0x8c, 0x0e, 0xc7, 0xfd, 0x64, 0xb0, 0x1c, - 0x58, 0xe5, 0x4c, 0x19, 0x0c, 0x29, 0xb9, 0x6f, 0x0f, 0x32, 0x4f, 0x2b, 0x2e, 0xce, 0x25, 0xa6, - 0x39, 0x47, 0x1e, 0xdd, 0xb2, 0xbe, 0x7b, 0x3e, 0xb4, 0xb0, 0x91, 0x37, 0x1c, 0xf9, 0xe4, 0x32, - 0x20, 0x0f, 0xdf, 0x79, 0xe8, 0x27, 0x0d, 0xae, 0xa1, 0x56, 0x17, 0x0e, 0xcf, 0x82, 0x0c, 0xf9, - 0x1f, 0x58, 0x26, 0x0a, 0xec, 0x58, 0x09, 0xbd, 0xe9, 0xc9, 0xe8, 0x5f, 0xba, 0xf3, 0xc3, 0x6e, - 0xca, 0xe5, 0x7e, 0x8a, 0xd7, 0x4f, 0xbf, 0x7d, 0x9d, 0x4e, 0x3c, 0x16, 0xb7, 0x06, 0x3b, 0x2e, - 0xff, 0x54, 0x9e, 0xbf, 0xbd, 0xda, 0xc4, 0xc1, 0xf5, 0x26, 0x0e, 0x7e, 0x6d, 0xe2, 0xe0, 0xf3, - 0x36, 0xee, 0x5d, 0x6f, 0xe3, 0xde, 0xf7, 0x6d, 0xdc, 0x7b, 0xff, 0xf2, 0x7f, 0x64, 0x2a, 0x13, - 0xd3, 0x15, 0xb0, 0xf6, 0x15, 0x2b, 0x20, 0x6f, 0xb4, 0x34, 0xdd, 0xea, 0xed, 0xad, 0x9c, 0xe5, - 0x98, 0xdd, 0xb6, 0x1b, 0xf0, 0xe2, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcc, 0xb7, 0x0f, 0x97, - 0x9c, 0x02, 0x00, 0x00, + // 501 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xc1, 0x8e, 0xd3, 0x3c, + 0x14, 0x85, 0x9b, 0x69, 0xff, 0x91, 0xea, 0xea, 0x47, 0x22, 0x30, 0x22, 0x33, 0x82, 0xb4, 0x54, + 0x02, 0x45, 0x42, 0xb5, 0x29, 0x2c, 0x40, 0xb0, 0x9a, 0x16, 0x21, 0x16, 0xb3, 0x28, 0x15, 0x2b, + 0x36, 0xc1, 0x71, 0x3c, 0x8d, 0x35, 0x6e, 0x6e, 0x14, 0x3b, 0x1d, 0x31, 0x4f, 0x01, 0xaf, 0xc1, + 0x9a, 0x87, 0x18, 0xb1, 0x9a, 0x25, 0x2b, 0x40, 0xed, 0x23, 0xf0, 0x02, 0x28, 0xb6, 0x5b, 0x8a, + 0x90, 0xca, 0xca, 0xf1, 0xb9, 0xc7, 0x9f, 0x7d, 0x73, 0x2e, 0x8a, 0x44, 0xc2, 0x08, 0x2d, 0x0a, + 0x29, 0x18, 0xd5, 0x02, 0x72, 0x45, 0x74, 0x49, 0x73, 0x75, 0xca, 0x4b, 0xb2, 0x18, 0x12, 0x5a, + 0xe9, 0xec, 0x02, 0x17, 0x25, 0x68, 0xf0, 0x6f, 0x8b, 0x84, 0xe1, 0x6d, 0x27, 0x5e, 0x3b, 0xf1, + 0x62, 0x78, 0x74, 0xc8, 0x40, 0xcd, 0x41, 0xc5, 0xc6, 0x4b, 0xec, 0xc6, 0x1e, 0x3c, 0xba, 0x39, + 0x83, 0x19, 0x58, 0xbd, 0xfe, 0x72, 0x6a, 0x68, 0x3d, 0x24, 0xa1, 0x8a, 0x93, 0xc5, 0x30, 0xe1, + 0x9a, 0x0e, 0x09, 0x03, 0x91, 0xbb, 0xfa, 0x83, 0x9d, 0x0f, 0xdb, 0x5c, 0x6d, 0xcc, 0xfd, 0x9f, + 0x7b, 0x08, 0x1d, 0x4b, 0x09, 0xd6, 0xea, 0x77, 0x51, 0x47, 0x41, 0x55, 0x32, 0x1e, 0x17, 0x50, + 0xea, 0xc0, 0xeb, 0x79, 0x51, 0x7b, 0x8a, 0xac, 0x34, 0x81, 0x52, 0xfb, 0xf7, 0xd0, 0x35, 0x67, + 0x60, 0x19, 0xcd, 0x73, 0x2e, 0x83, 0x3d, 0xe3, 0xf9, 0xdf, 0xaa, 0x63, 0x2b, 0xfa, 0x12, 0x75, + 0x54, 0xc1, 0xf3, 0x34, 0x96, 0x62, 0x2e, 0x74, 0xd0, 0xec, 0x35, 0xa3, 0xce, 0xa3, 0x43, 0xec, + 0xba, 0xab, 0x5f, 0x8e, 0xdd, 0xcb, 0xf1, 0x18, 0x44, 0x3e, 0x7a, 0x78, 0xf9, 0xad, 0xdb, 0xf8, + 0xf4, 0xbd, 0x1b, 0xcd, 0x84, 0xce, 0xaa, 0x04, 0x33, 0x98, 0xbb, 0x5f, 0xe1, 0x96, 0x81, 0x4a, + 0xcf, 0x88, 0x7e, 0x5f, 0x70, 0x65, 0x0e, 0xa8, 0x29, 0x32, 0xfc, 0x93, 0x1a, 0xef, 0xdf, 0x41, + 0x88, 0x4a, 0x09, 0xe7, 0xb1, 0x14, 0x4a, 0x07, 0xad, 0x5e, 0x33, 0x6a, 0x4f, 0xdb, 0x46, 0x39, + 0x11, 0x4a, 0xfb, 0x18, 0xdd, 0x30, 0x1b, 0x9e, 0xc6, 0x05, 0x65, 0x67, 0x5c, 0xc7, 0x29, 0xd5, + 0x34, 0xf8, 0xcf, 0xf8, 0xae, 0xbb, 0xd2, 0xc4, 0x54, 0x5e, 0x50, 0x4d, 0xfd, 0x77, 0xe8, 0xd6, + 0xda, 0x7f, 0x0a, 0xe5, 0x39, 0x2d, 0x53, 0x91, 0xcf, 0xe2, 0x0c, 0x0a, 0x15, 0xec, 0x9b, 0x46, + 0xfa, 0x78, 0x57, 0xa2, 0xf8, 0x15, 0x14, 0x6a, 0xd4, 0xaa, 0x3b, 0x9a, 0x1e, 0x38, 0xd0, 0xcb, + 0x0d, 0xa7, 0x2e, 0xf6, 0xc7, 0xa8, 0x55, 0xaf, 0xfe, 0x73, 0xd4, 0x32, 0x58, 0xcf, 0x60, 0xef, + 0xfe, 0x13, 0xeb, 0xa8, 0xe6, 0x50, 0xff, 0xa3, 0x87, 0x0e, 0xde, 0xb8, 0xfa, 0x71, 0xa5, 0x33, + 0x28, 0xc5, 0x85, 0x4d, 0x71, 0x82, 0x3a, 0x74, 0x93, 0xe9, 0x9a, 0x1e, 0xed, 0xa6, 0xff, 0x1e, + 0x02, 0x77, 0xc9, 0x36, 0xe2, 0xd9, 0xfd, 0x2f, 0x9f, 0x07, 0x7d, 0x97, 0x9e, 0x1d, 0xed, 0x75, + 0x7c, 0x7f, 0xdc, 0x3c, 0x7a, 0x7d, 0xb9, 0x0c, 0xbd, 0xab, 0x65, 0xe8, 0xfd, 0x58, 0x86, 0xde, + 0x87, 0x55, 0xd8, 0xb8, 0x5a, 0x85, 0x8d, 0xaf, 0xab, 0xb0, 0xf1, 0xf6, 0xc9, 0xdf, 0xc9, 0x8a, + 0x84, 0x0d, 0x66, 0x40, 0x16, 0x4f, 0xc9, 0x1c, 0xd2, 0x4a, 0x72, 0x55, 0x4f, 0xed, 0xd6, 0xb4, + 0x9a, 0xb8, 0x93, 0x7d, 0x33, 0xa8, 0x8f, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x61, 0xe1, 0x76, + 0x97, 0x70, 0x03, 0x00, 0x00, } func (m *Allocation) Marshal() (dAtA []byte, err error) { @@ -217,6 +277,20 @@ func (m *Allocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.AllowedForwardingHops) > 0 { + for iNdEx := len(m.AllowedForwardingHops) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AllowedForwardingHops[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } if len(m.AllowedPacketData) > 0 { for iNdEx := len(m.AllowedPacketData) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.AllowedPacketData[iNdEx]) @@ -266,6 +340,43 @@ func (m *Allocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *Hops) 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 *Hops) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Hops) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Hops) > 0 { + for iNdEx := len(m.Hops) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Hops[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *TransferAuthorization) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -346,6 +457,27 @@ func (m *Allocation) Size() (n int) { n += 1 + l + sovAuthz(uint64(l)) } } + if len(m.AllowedForwardingHops) > 0 { + for _, e := range m.AllowedForwardingHops { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *Hops) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Hops) > 0 { + for _, e := range m.Hops { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } return n } @@ -561,6 +693,124 @@ func (m *Allocation) Unmarshal(dAtA []byte) error { } m.AllowedPacketData = append(m.AllowedPacketData, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowedForwardingHops", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AllowedForwardingHops = append(m.AllowedForwardingHops, Hops{}) + if err := m.AllowedForwardingHops[len(m.AllowedForwardingHops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Hops) 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 ErrIntOverflowAuthz + } + 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: Hops: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Hops: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hops", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hops = append(m.Hops, Hop{}) + if err := m.Hops[len(m.Hops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipAuthz(dAtA[iNdEx:]) diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index bac1092e02f..e12173401fb 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -3,6 +3,7 @@ package types import ( "context" "math/big" + "reflect" "slices" "strings" @@ -49,7 +50,11 @@ func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) index := getAllocationIndex(*msgTransfer, a.Allocations) if index == allocationNotFound { - return authz.AcceptResponse{}, errorsmod.Wrapf(ibcerrors.ErrNotFound, "requested port and channel allocation does not exist") + return authz.AcceptResponse{}, errorsmod.Wrap(ibcerrors.ErrNotFound, "requested port and channel allocation does not exist") + } + + if !isAllowedForwarding(msgTransfer.Forwarding.Hops, a.Allocations[index].AllowedForwardingHops) { + return authz.AcceptResponse{}, errorsmod.Wrap(ErrInvalidForwarding, "not allowed forwarding hops") } ctx := sdk.UnwrapSDKContext(goCtx) @@ -165,6 +170,21 @@ func isAllowedAddress(ctx sdk.Context, receiver string, allowedAddrs []string) b return false } +// isAllowedForwarding returns whether the provided slice of Hop matches one of the allowed ones. +func isAllowedForwarding(hops []Hop, allowed []Hops) bool { + if len(hops) == 0 { + return true + } + + for _, allowedHops := range allowed { + if reflect.DeepEqual(hops, allowedHops.Hops) { + return true + } + } + + return false +} + // validateMemo returns a nil error indicating if the memo is valid for transfer. func validateMemo(ctx sdk.Context, memo string, allowedMemos []string) error { // if the allow list is empty, then the memo must be an empty string diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index 14b7c7c1ad6..0303482f7dc 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -19,6 +19,8 @@ const ( testMemo2 = `{"forward":{"channel":"channel-11","port":"transfer","receiver":"stars1twfv52yxcyykx2lcvgl42svw46hsm5dd4ww6xy","retries":2,"timeout":1712146014542131200}}` ) +var forwardingWithValidHop = []types.Hops{{Hops: []types.Hop{validHop}}} + func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { var ( msgTransfer *types.MsgTransfer @@ -104,7 +106,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { func() { allowedList := []string{} transferAuthz.Allocations[0].AllowedPacketData = allowedList - + transferAuthz.Allocations[0].AllowedForwardingHops = forwardingWithValidHop msgTransfer.Forwarding = types.NewForwarding(false, validHop) }, func(res authz.AcceptResponse, err error) { @@ -135,6 +137,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { func() { allowedList := []string{"*"} transferAuthz.Allocations[0].AllowedPacketData = allowedList + transferAuthz.Allocations[0].AllowedForwardingHops = forwardingWithValidHop msgTransfer.Forwarding = types.NewForwarding(false, validHop) }, func(res authz.AcceptResponse, err error) { @@ -278,6 +281,41 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Len(updatedAuthz.Allocations, 1) }, }, + { + "success: allowed forwarding hops", + func() { + msgTransfer.Forwarding = types.NewForwarding(false, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}) + transferAuthz.Allocations[0].AllowedForwardingHops = []types.Hops{ + { + Hops: []types.Hop{ + {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, + {PortId: ibctesting.MockPort, ChannelId: "channel-2"}, + }, + }, + } + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + suite.Require().True(res.Accept) + }, + }, + { + "success: Allocation specify hops but msgTransfer does not have hops", + func() { + transferAuthz.Allocations[0].AllowedForwardingHops = []types.Hops{ + { + Hops: []types.Hop{ + {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, + {PortId: ibctesting.MockPort, ChannelId: "channel-2"}, + }, + }, + } + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + suite.Require().True(res.Accept) + }, + }, { "failure: multidenom transfer spend limit is exceeded", func() { @@ -352,6 +390,82 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().Nil(res.Updated) }, }, + { + "failure: allowed forwarding hops contains more hops", + func() { + msgTransfer.Forwarding = types.NewForwarding(false, + types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, + types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}, + types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-3"}, + ) + transferAuthz.Allocations[0].AllowedForwardingHops = []types.Hops{ + { + Hops: []types.Hop{ + {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, + {PortId: ibctesting.MockPort, ChannelId: "channel-2"}, + }, + }, + } + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + suite.Require().False(res.Accept) + }, + }, + { + "failure: allowed forwarding hops contains one different hop", + func() { + msgTransfer.Forwarding = types.NewForwarding(false, + types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, + types.Hop{PortId: "3", ChannelId: "channel-3"}, + ) + transferAuthz.Allocations[0].AllowedForwardingHops = []types.Hops{ + { + Hops: []types.Hop{ + {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, + {PortId: ibctesting.MockPort, ChannelId: "channel-2"}, + }, + }, + } + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + suite.Require().False(res.Accept) + }, + }, + { + "failure: allowed forwarding hops is empty but hops are present", + func() { + msgTransfer.Forwarding = types.NewForwarding(false, + types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, + ) + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + suite.Require().False(res.Accept) + }, + }, + { + "failure: order of hops is different", + func() { + msgTransfer.Forwarding = types.NewForwarding(false, + types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, + types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}, + ) + transferAuthz.Allocations[0].AllowedForwardingHops = []types.Hops{ + { + Hops: []types.Hop{ + {PortId: ibctesting.MockPort, ChannelId: "channel-2"}, + {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, + }, + }, + } + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + suite.Require().False(res.Accept) + }, + }, } for _, tc := range testCases { diff --git a/proto/ibc/applications/transfer/v1/authz.proto b/proto/ibc/applications/transfer/v1/authz.proto index 5c4b71d3479..ede9b6dda6c 100644 --- a/proto/ibc/applications/transfer/v1/authz.proto +++ b/proto/ibc/applications/transfer/v1/authz.proto @@ -7,6 +7,7 @@ option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; import "cosmos/base/v1beta1/coin.proto"; +import "ibc/applications/transfer/v1/transfer.proto"; // Allocation defines the spend limit for a particular port and channel message Allocation { @@ -22,6 +23,14 @@ message Allocation { // allow list of memo strings, an empty list prohibits all memo strings; // a list only with "*" permits any memo string repeated string allowed_packet_data = 5; + // a list of allowed source port ID/channel ID pairs through which the packet is allowed to be forwarded until final + // destination + repeated Hops allowed_forwarding_hops = 6 [(gogoproto.nullable) = false]; +} + +// Hops represent a list of Hop +message Hops { + repeated ibc.applications.transfer.v1.Hop hops = 1 [(gogoproto.nullable) = false]; } // TransferAuthorization allows the grantee to spend up to spend_limit coins from From da2f9f637198dc5cee45a95d1c2987ea3cc0c1fb Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Fri, 21 Jun 2024 10:58:05 +0100 Subject: [PATCH 092/141] feat: delete forwarded packet when it is not needed anymore (#6621) * Create ontimeoutpacket test for forwarding * Propagate ack on A * Refactoring * Minor changes * Added comments * Fix type name. * Gofumpt * Update modules/apps/transfer/keeper/relay_forwarding_test.go Co-authored-by: Carlos Rodriguez * Update modules/apps/transfer/keeper/relay_forwarding_test.go Co-authored-by: Carlos Rodriguez * Update modules/apps/transfer/keeper/relay_forwarding_test.go Co-authored-by: Carlos Rodriguez * Update modules/apps/transfer/keeper/relay_forwarding_test.go Co-authored-by: Carlos Rodriguez * Add godoc to test. * Changed trace construction * Update modules/apps/transfer/keeper/relay_forwarding_test.go Co-authored-by: Carlos Rodriguez * remove error msg parameter from helper function * Add test for forwarded packet * Delete packet when not needed anymore. * Move deletion of packet in a single place. * Reintroduce newline * Do not ignore error. * PR feedback. * Construct packet for B ack check. * PR feedback * Pass packet to acknowledgeforwardedpacket * revert unwanted change * Another unwanted change * Better signature and fix source/dest * Added one more test. --------- Co-authored-by: Carlos Rodriguez Co-authored-by: Gjermund Garaba --- modules/apps/transfer/keeper/forwarding.go | 21 ++++++++++++------- modules/apps/transfer/keeper/keeper.go | 8 +++++++ modules/apps/transfer/keeper/relay.go | 6 +++--- .../transfer/keeper/relay_forwarding_test.go | 8 +++++++ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index c33dc58f460..1029d6369a8 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -44,13 +44,13 @@ func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDat } // ackForwardPacketSuccess writes a successful async acknowledgement for the prevPacket -func (k Keeper) ackForwardPacketSuccess(ctx sdk.Context, prevPacket channeltypes.Packet) error { +func (k Keeper) ackForwardPacketSuccess(ctx sdk.Context, prevPacket, forwardedPacket channeltypes.Packet) error { forwardAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) + return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardedPacket, forwardAck) } // ackForwardPacketError reverts the receive packet logic that occurs in the middle chain and writes the async ack for the prevPacket -func (k Keeper) ackForwardPacketError(ctx sdk.Context, prevPacket channeltypes.Packet, failedPacketData types.FungibleTokenPacketDataV2) error { +func (k Keeper) ackForwardPacketError(ctx sdk.Context, prevPacket, forwardedPacket channeltypes.Packet, failedPacketData types.FungibleTokenPacketDataV2) error { // the forwarded packet has failed, thus the funds have been refunded to the intermediate address. // we must revert the changes that came from successfully receiving the tokens on our chain // before propagating the error acknowledgement back to original sender chain @@ -59,27 +59,32 @@ func (k Keeper) ackForwardPacketError(ctx sdk.Context, prevPacket channeltypes.P } forwardAck := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketFailed) - return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) + return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardedPacket, forwardAck) } // ackForwardPacketTimeout reverts the receive packet logic that occurs in the middle chain and writes a failed async ack for the prevPacket -func (k Keeper) ackForwardPacketTimeout(ctx sdk.Context, prevPacket channeltypes.Packet, timeoutPacketData types.FungibleTokenPacketDataV2) error { +func (k Keeper) ackForwardPacketTimeout(ctx sdk.Context, prevPacket, forwardedPacket channeltypes.Packet, timeoutPacketData types.FungibleTokenPacketDataV2) error { if err := k.revertForwardedPacket(ctx, prevPacket, timeoutPacketData); err != nil { return err } forwardAck := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketTimedOut) - return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardAck) + return k.acknowledgeForwardedPacket(ctx, prevPacket, forwardedPacket, forwardAck) } // acknowledgeForwardedPacket writes the async acknowledgement for packet -func (k Keeper) acknowledgeForwardedPacket(ctx sdk.Context, packet channeltypes.Packet, ack channeltypes.Acknowledgement) error { +func (k Keeper) acknowledgeForwardedPacket(ctx sdk.Context, packet, forwardedPacket channeltypes.Packet, ack channeltypes.Acknowledgement) error { capability, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(packet.DestinationPort, packet.DestinationChannel)) if !ok { return errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") } - return k.ics4Wrapper.WriteAcknowledgement(ctx, capability, packet, ack) + if err := k.ics4Wrapper.WriteAcknowledgement(ctx, capability, packet, ack); err != nil { + return err + } + + k.deleteForwardedPacket(ctx, forwardedPacket.SourcePort, forwardedPacket.SourceChannel, forwardedPacket.Sequence) + return nil } // revertForwardedPacket reverts the logic of receive packet that occurs in the middle chains during a packet forwarding. diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index 2fd82e639a3..d9d8d60b546 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -328,3 +328,11 @@ func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, se return storedPacket, true } + +// deleteForwardedPacket deletes the forwarded packet from the store. +func (k Keeper) deleteForwardedPacket(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := ctx.KVStore(k.storeKey) + packetKey := types.PacketForwardKey(portID, channelID, sequence) + + store.Delete(packetKey) +} diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index ce65244452e..6d2d8d1e5e5 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -285,7 +285,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac switch ack.Response.(type) { case *channeltypes.Acknowledgement_Result: if isForwarded { - return k.ackForwardPacketSuccess(ctx, prevPacket) + return k.ackForwardPacketSuccess(ctx, prevPacket, packet) } // the acknowledgement succeeded on the receiving chain so nothing @@ -297,7 +297,7 @@ func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Pac return err } if isForwarded { - return k.ackForwardPacketError(ctx, prevPacket, data) + return k.ackForwardPacketError(ctx, prevPacket, packet, data) } return nil @@ -316,7 +316,7 @@ func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, dat prevPacket, isForwarded := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) if isForwarded { - return k.ackForwardPacketTimeout(ctx, prevPacket, data) + return k.ackForwardPacketTimeout(ctx, prevPacket, packet, data) } return nil diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 591321db516..b36f6e28a49 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -317,6 +317,10 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { err = path2.EndpointB.UpdateClient() suite.Require().NoError(err) + // B should now have deleted the forwarded packet. + _, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), packetFromAtoB.DestinationPort, packetFromAtoB.DestinationChannel, packetFromAtoB.Sequence) + suite.Require().False(found, "Chain B should have deleted its forwarded packet") + result, err = path2.EndpointB.RecvPacketWithResult(packetFromBtoC) suite.Require().NoError(err) suite.Require().NotNil(result) @@ -562,6 +566,10 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { err = path1.EndpointB.AcknowledgePacket(packetFromBtoA, errorAckOnA.Acknowledgement()) suite.Require().NoError(err) + // Check that B deleted the forwarded packet. + _, found = suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), forwardedPacket.SourcePort, forwardedPacket.SourceChannel, forwardedPacket.Sequence) + suite.Require().False(found, "chain B should have deleted the forwarded packet mapping") + // Check that Escrow B has been refunded amount coin = sdk.NewCoin(denomAB.IBCDenom(), amount) totalEscrowChainB = suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) From e68143b28b22f5207df2b22128e604b94c5f2b79 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Fri, 21 Jun 2024 13:46:16 +0200 Subject: [PATCH 093/141] test(transfer): forwarding acknowledgment errors in middle hop (#6659) * test(transfer): forwarding where middle chaind is source for receive and send * Fix errors after merge * Finish up the test * Update some out-of-date comments * test(transfer): multi-hop ack failure with middle chain NOT being source * Fix tests after height change * Fix tests after height change * Fix test after #6586 * Rename tests to not use scenario numbers * Rename test * address self-review comments * use boolean in NewForwarding parameter * some more review comments --------- Co-authored-by: Carlos Rodriguez --- .../transfer/keeper/relay_forwarding_test.go | 320 +++++++++++++++++- 1 file changed, 318 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index b36f6e28a49..c5bd15daa23 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -356,8 +356,324 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { suite.Require().NoError(err) } -// This test replicates the Acknowledgement Failure Scenario 5 -func (suite *KeeperTestSuite) TestAcknowledgementFailureScenario5Forwarding() { +// TestAcknowledgementFailureWithMiddleChainAsNativeTokenSource tests a failure in the last hop where the +// middle chain is native source when receiving and sending the packet. In other words, the middle chain's native +// token has been sent to chain C, and the multi-hop transfer from C -> B -> A has chain B being the source of +// the token both when receiving and forwarding (sending). +func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeTokenSource() { + amount := sdkmath.NewInt(100) + /* + Given the following topology: + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-0) chain C + stake transfer/channel-0/stake transfer/channel-0/transfer/channel-0/stake + We want to trigger: + 1. Transfer from B to C + 2. Single transfer forwarding token from C -> B -> A + 2.1 The ack fails on the last hop (chain A) + 2.2 Propagate the error back to C + 3. Verify all the balances are updated as expected + */ + + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) + path2.Setup() + + coinOnB := sdk.NewCoin(sdk.DefaultBondDenom, amount) + setupSender := suite.chainB.SenderAccounts[0].SenderAccount + setupReceiver := suite.chainC.SenderAccounts[0].SenderAccount + + setupTransferMsg := types.NewMsgTransfer( + path2.EndpointA.ChannelConfig.PortID, + path2.EndpointA.ChannelID, + sdk.NewCoins(coinOnB), + setupSender.GetAddress().String(), + setupReceiver.GetAddress().String(), + suite.chainB.GetTimeoutHeight(), + 0, "", + types.Forwarding{}, + ) + + result, err := suite.chainB.SendMsgs(setupTransferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainC + packetFromBToC, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetFromBToC) + + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointB.RecvPacketWithResult(packetFromBToC) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that EscrowBtoC has amount + escrowAddressBtoC := types.GetEscrowAddress(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID) + escrowBalancBtoC := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), escrowAddressBtoC, coinOnB.GetDenom()) + suite.Require().Equal(amount, escrowBalancBtoC.Amount) + + // Check that receiver has the expected tokens + denomOnC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID)) + coinOnC := sdk.NewCoin(denomOnC.IBCDenom(), amount) + balanceOnC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), setupReceiver.GetAddress(), coinOnC.GetDenom()) + suite.Require().Equal(amount, balanceOnC.Amount) + + // Now we start the transfer from C -> B -> A + sender := suite.chainC.SenderAccounts[0].SenderAccount + receiver := suite.chainA.SenderAccounts[0].SenderAccount + + forwarding := types.NewForwarding(false, types.Hop{ + PortId: path1.EndpointB.ChannelConfig.PortID, + ChannelId: path1.EndpointB.ChannelID, + }) + + forwardTransfer := types.NewMsgTransfer( + path2.EndpointB.ChannelConfig.PortID, + path2.EndpointB.ChannelID, + sdk.NewCoins(coinOnC), + sender.GetAddress().String(), + receiver.GetAddress().String(), + clienttypes.ZeroHeight(), + suite.chainA.GetTimeoutTimestamp(), + "", + forwarding, + ) + + result, err = suite.chainC.SendMsgs(forwardTransfer) + suite.Require().NoError(err) // message committed + + // Check that Escrow C has unescrowed the amount + totalEscrowChainC := suite.chainC.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainC.GetContext(), coinOnC.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), totalEscrowChainC.Amount) + + // parse the packet from result events and recv packet on chainB + packetFromCtoB, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetFromCtoB) + + err = path2.EndpointA.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointA.RecvPacketWithResult(packetFromCtoB) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that escrow has been moved from EscrowBtoC to EscrowBtoA + escrowBalancBtoC = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), escrowAddressBtoC, coinOnB.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), escrowBalancBtoC.Amount) + + escrowAddressBtoA := types.GetEscrowAddress(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID) + escrowBalanceBtoA := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), escrowAddressBtoA, coinOnB.GetDenom()) + suite.Require().Equal(amount, escrowBalanceBtoA.Amount) + + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packetFromCtoB.Sequence) + suite.Require().True(found) + suite.Require().Equal(packetFromCtoB, forwardedPacket) + + // Now we can receive the packet on A where we want to trigger an error + packetFromBtoA, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetFromBtoA) + + // turn off receive on chain A to trigger an error + suite.chainA.GetSimApp().TransferKeeper.SetParams(suite.chainA.GetContext(), types.Params{ + SendEnabled: true, + ReceiveEnabled: false, + }) + + err = path1.EndpointA.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointA.RecvPacketWithResult(packetFromBtoA) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // An error ack is now written on chainA + // Now we need to propagate the error to B and C + errorAckOnA := channeltypes.NewErrorAcknowledgement(types.ErrReceiveDisabled) + errorAckCommitmentOnA := channeltypes.CommitAcknowledgement(errorAckOnA.Acknowledgement()) + ackOnA := suite.chainA.GetAcknowledgement(packetFromBtoA) + suite.Require().Equal(errorAckCommitmentOnA, ackOnA) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + + err = path1.EndpointB.AcknowledgePacket(packetFromBtoA, errorAckOnA.Acknowledgement()) + suite.Require().NoError(err) + + errorAckOnB := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketFailed) + errorAckCommitmentOnB := channeltypes.CommitAcknowledgement(errorAckOnB.Acknowledgement()) + ackOnB := suite.chainB.GetAcknowledgement(packetFromCtoB) + suite.Require().Equal(errorAckCommitmentOnB, ackOnB) + + // Check that escrow has been moved back from EscrowBtoA to EscrowBtoC + escrowBalanceBtoA = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), escrowAddressBtoA, coinOnB.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), escrowBalanceBtoA.Amount) + + escrowBalancBtoC = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), escrowAddressBtoC, coinOnB.GetDenom()) + suite.Require().Equal(amount, escrowBalancBtoC.Amount) + + // Check the status of account on chain C before executing ack. + balanceOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), setupReceiver.GetAddress(), coinOnC.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), balanceOnC.Amount) + + // Propagate the error to C + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) + + err = path2.EndpointB.AcknowledgePacket(packetFromCtoB, errorAckOnB.Acknowledgement()) + suite.Require().NoError(err) + + // Check that everything has been reverted + // + // Check the vouchers have been refunded on C + balanceOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), setupReceiver.GetAddress(), coinOnC.GetDenom()) + suite.Require().Equal(amount, balanceOnC.Amount, "final receiver balance has not increased") +} + +// TestAcknowledgementFailureWithMiddleChainAsNotBeingTokenSource tests a failure in the last hop where the middle chain +// is not source of the token when receiving or sending the packet. In other words, the middle chain's is sent +// (and forwarding) someone else's native token (in this case chain C). +func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNotBeingTokenSource() { + amount := sdkmath.NewInt(100) + /* + Given the following topology: + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-0) chain C + stake transfer/channel-0/stake transfer/channel-0/transfer/channel-0/stake + We want to trigger: + 1. Single transfer forwarding token from C -> B -> A + 1.1 The ack fails on the last hop + 1.2 Propagate the error back to C + 2. Verify all the balances are updated as expected + */ + + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path1.Setup() + + path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) + path2.Setup() + + // Now we start the transfer from C -> B -> A + coinOnC := sdk.NewCoin(sdk.DefaultBondDenom, amount) + sender := suite.chainC.SenderAccounts[0].SenderAccount + receiver := suite.chainA.SenderAccounts[0].SenderAccount + + forwarding := types.NewForwarding(false, types.Hop{ + PortId: path1.EndpointB.ChannelConfig.PortID, + ChannelId: path1.EndpointB.ChannelID, + }) + + forwardTransfer := types.NewMsgTransfer( + path2.EndpointB.ChannelConfig.PortID, + path2.EndpointB.ChannelID, + sdk.NewCoins(coinOnC), + sender.GetAddress().String(), + receiver.GetAddress().String(), + clienttypes.ZeroHeight(), + suite.chainA.GetTimeoutTimestamp(), + "", + forwarding, + ) + + balanceOnCBefore := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), sender.GetAddress(), coinOnC.GetDenom()) + + result, err := suite.chainC.SendMsgs(forwardTransfer) + suite.Require().NoError(err) // message committed + + // Check that Escrow C has amount + totalEscrowChainC := suite.chainC.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainC.GetContext(), coinOnC.GetDenom()) + suite.Require().Equal(amount, totalEscrowChainC.Amount) + + packetFromCtoB, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetFromCtoB) + + err = path2.EndpointA.UpdateClient() + suite.Require().NoError(err) + + result, err = path2.EndpointA.RecvPacketWithResult(packetFromCtoB) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that Escrow B has amount + denomOnB := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID)) + coinOnB := sdk.NewCoin(denomOnB.IBCDenom(), amount) + totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coinOnB.GetDenom()) + suite.Require().Equal(amount, totalEscrowChainB.Amount) + + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packetFromCtoB.Sequence) + suite.Require().True(found) + suite.Require().Equal(packetFromCtoB, forwardedPacket) + + // Now we can receive the packet on A where we want to trigger an error + packetFromBtoA, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetFromBtoA) + + // turn off receive on chain A to trigger an error + suite.chainA.GetSimApp().TransferKeeper.SetParams(suite.chainA.GetContext(), types.Params{ + SendEnabled: true, + ReceiveEnabled: false, + }) + + err = path1.EndpointA.UpdateClient() + suite.Require().NoError(err) + + result, err = path1.EndpointA.RecvPacketWithResult(packetFromBtoA) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // An error ack is now written on chainA + // Now we need to propagate the error to B and C + errorAckOnA := channeltypes.NewErrorAcknowledgement(types.ErrReceiveDisabled) + errorAckCommitmentOnA := channeltypes.CommitAcknowledgement(errorAckOnA.Acknowledgement()) + ackOnA := suite.chainA.GetAcknowledgement(packetFromBtoA) + suite.Require().Equal(errorAckCommitmentOnA, ackOnA) + + err = path1.EndpointB.UpdateClient() + suite.Require().NoError(err) + + err = path1.EndpointB.AcknowledgePacket(packetFromBtoA, errorAckOnA.Acknowledgement()) + suite.Require().NoError(err) + + errorAckOnB := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketFailed) + errorAckCommitmentOnB := channeltypes.CommitAcknowledgement(errorAckOnB.Acknowledgement()) + ackOnB := suite.chainB.GetAcknowledgement(packetFromCtoB) + suite.Require().Equal(errorAckCommitmentOnB, ackOnB) + + // Check that escrow has been burnt on B + totalEscrowChainB = suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coinOnB.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), totalEscrowChainB.Amount) + + // Check the status of account on chain C before executing ack. + balanceOnC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), sender.GetAddress(), coinOnC.GetDenom()) + suite.Require().Equal(balanceOnCBefore.SubAmount(amount).Amount, balanceOnC.Amount) + + // Propagate the error to C + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) + + err = path2.EndpointB.AcknowledgePacket(packetFromCtoB, errorAckOnB.Acknowledgement()) + suite.Require().NoError(err) + + // Check that everything has been reverted + // + // Check the token has been returned to the sender on C + totalEscrowChainC = suite.chainC.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainC.GetContext(), coinOnC.GetDenom()) + suite.Require().Equal(sdkmath.NewInt(0), totalEscrowChainC.Amount) + + balanceOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), sender.GetAddress(), coinOnC.GetDenom()) + suite.Require().Equal(balanceOnCBefore.Amount, balanceOnC.Amount, "final receiver balance has not increased") +} + +// This tests a failure in the last hop where the middle chain as IBC denom source when receiving and sending the packet. +// In other words, an IBC denom from the middle chain's sent to chain C, and the multi-hop +// transfer from C -> B -> A has chain B being the source of the token both when receiving and forwarding (sending). +// Previously referenced as Acknowledgement Failure Scenario 5 +func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsIBCTokenSource() { amount := sdkmath.NewInt(100) /* Given the following topolgy: From 6619821c739891ff132e42eb1c1a49f5e0791e7c Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Fri, 21 Jun 2024 17:55:53 +0200 Subject: [PATCH 094/141] test(transfer): last chain in forwarding packet is ICS20 v1 (#6622) * test(transfer): last chain in forwarding being ICS20 v1 * Finish TestForwarding_WithLastChainBeingICS20v1_Succeeds * Update CreateNewPath signature Co-authored-by: Nikolas De Giorgis * Fix PR review comments --------- Co-authored-by: Nikolas De Giorgis --- e2e/tests/transfer/forwarding_test.go | 70 +++++++++++++++++++++++++ e2e/testsuite/testsuite.go | 74 ++++++++++++++++----------- 2 files changed, 114 insertions(+), 30 deletions(-) diff --git a/e2e/tests/transfer/forwarding_test.go b/e2e/tests/transfer/forwarding_test.go index 79ee19f6391..8b4f6c0c461 100644 --- a/e2e/tests/transfer/forwarding_test.go +++ b/e2e/tests/transfer/forwarding_test.go @@ -5,12 +5,16 @@ package transfer import ( "context" "testing" + "time" + "github.com/strangelove-ventures/interchaintest/v8/ibc" testifysuite "github.com/stretchr/testify/suite" "github.com/cosmos/ibc-go/e2e/testsuite" "github.com/cosmos/ibc-go/e2e/testsuite/query" "github.com/cosmos/ibc-go/e2e/testvalues" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" ) func TestTransferForwardingTestSuite(t *testing.T) { @@ -95,3 +99,69 @@ func (s *TransferForwardingTestSuite) TestThreeChainSetup() { s.Require().Equal(expected, actualBalance.Int64()) }) } + +func (s *TransferForwardingTestSuite) TestForwarding_WithLastChainBeingICS20v1_Succeeds() { + ctx := context.TODO() + t := s.T() + + relayer, chains := s.GetRelayer(), s.GetAllChains() + + chainA, chainB, chainC := chains[0], chains[1], chains[2] + + channelAtoB := s.GetChainAChannel() + + // Creating a new path between chain B and chain C with a ICS20-v1 channel + opts := s.TransferChannelOptions() + opts.Version = transfertypes.V1 + channelBtoC, _ := s.CreateNewPath(ctx, chainB, chainC, ibc.DefaultClientOpts(), opts) + s.Require().Equal(transfertypes.V1, channelBtoC.Version, "the channel version is not ics20-1") + + chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) + chainAAddress := chainAWallet.FormattedAddress() + chainADenom := chainA.Config().Denom + + chainCWallet := s.CreateUserOnChainC(ctx, testvalues.StartingTokenAmount) + chainCAddress := chainCWallet.FormattedAddress() + + t.Run("IBC transfer from A to C with forwarding through B", func(t *testing.T) { + inFiveMinutes := time.Now().Add(5 * time.Minute).UnixNano() + forwarding := transfertypes.NewForwarding(false, transfertypes.Hop{ + PortId: channelBtoC.PortID, + ChannelId: channelBtoC.ChannelID, + }) + + msgTransfer := testsuite.GetMsgTransfer( + channelAtoB.PortID, + channelAtoB.ChannelID, + transfertypes.V2, + testvalues.DefaultTransferCoins(chainADenom), + chainAAddress, + chainCAddress, + clienttypes.ZeroHeight(), + uint64(inFiveMinutes), + "", + forwarding) + resp := s.BroadcastMessages(ctx, chainA, chainAWallet, msgTransfer) + s.AssertTxSuccess(resp) + }) + + t.Run("start relayer", func(t *testing.T) { + s.StartRelayer(relayer) + }) + + t.Run("packets are relayed from A to B to C", func(t *testing.T) { + chainCDenom := transfertypes.NewDenom(chainADenom, + transfertypes.NewTrace(channelBtoC.Counterparty.PortID, channelBtoC.Counterparty.ChannelID), + transfertypes.NewTrace(channelAtoB.Counterparty.PortID, channelAtoB.Counterparty.ChannelID), + ) + + s.AssertPacketRelayed(ctx, chainA, channelAtoB.PortID, channelAtoB.ChannelID, 1) + s.AssertPacketRelayed(ctx, chainB, channelBtoC.PortID, channelBtoC.ChannelID, 1) + + actualBalance, err := query.Balance(ctx, chainC, chainCAddress, chainCDenom.IBCDenom()) + s.Require().NoError(err) + + expected := testvalues.IBCTransferAmount + s.Require().Equal(expected, actualBalance.Int64()) + }) +} diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index 1a24eb2e142..5ae47a5b8df 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -177,52 +177,66 @@ func (s *E2ETestSuite) SetupTest() { s.SetupPath(ibc.DefaultClientOpts(), defaultChannelOpts(s.GetAllChains())) } -// SetupPath creates a path between the chains using the provided client and channel options. +// SetupPath creates paths between the all chains using the provided client and channel options. func (s *E2ETestSuite) SetupPath(clientOpts ibc.CreateClientOptions, channelOpts ibc.CreateChannelOptions) { s.T().Logf("Setting up path for: %s", s.T().Name()) - r := s.relayer ctx := context.TODO() allChains := s.GetAllChains() for i := 0; i < len(allChains)-1; i++ { chainA, chainB := allChains[i], allChains[i+1] - pathName := s.generatePathName() - s.T().Logf("establishing path between %s and %s on path %s", chainA.Config().ChainID, chainB.Config().ChainID, pathName) + _, _ = s.CreateNewPath(ctx, chainA, chainB, clientOpts, channelOpts) + } +} + +func (s *E2ETestSuite) CreateNewPath( + ctx context.Context, + chainA ibc.Chain, + chainB ibc.Chain, + clientOpts ibc.CreateClientOptions, + channelOpts ibc.CreateChannelOptions, +) (chainAChannel ibc.ChannelOutput, chainBChannel ibc.ChannelOutput) { + r := s.relayer - err := r.GeneratePath(ctx, s.GetRelayerExecReporter(), chainA.Config().ChainID, chainB.Config().ChainID, pathName) - s.Require().NoError(err) + pathName := s.generatePathName() + s.T().Logf("establishing path between %s and %s on path %s", chainA.Config().ChainID, chainB.Config().ChainID, pathName) - // Create new clients - err = r.CreateClients(ctx, s.GetRelayerExecReporter(), pathName, clientOpts) - s.Require().NoError(err) - err = test.WaitForBlocks(ctx, 1, chainA, chainB) - s.Require().NoError(err) + err := r.GeneratePath(ctx, s.GetRelayerExecReporter(), chainA.Config().ChainID, chainB.Config().ChainID, pathName) + s.Require().NoError(err) - err = r.CreateConnections(ctx, s.GetRelayerExecReporter(), pathName) - s.Require().NoError(err) - err = test.WaitForBlocks(ctx, 1, chainA, chainB) - s.Require().NoError(err) + // Create new clients + err = r.CreateClients(ctx, s.GetRelayerExecReporter(), pathName, clientOpts) + s.Require().NoError(err) + err = test.WaitForBlocks(ctx, 1, chainA, chainB) + s.Require().NoError(err) - err = r.CreateChannel(ctx, s.GetRelayerExecReporter(), pathName, channelOpts) - s.Require().NoError(err) - err = test.WaitForBlocks(ctx, 1, chainA, chainB) - s.Require().NoError(err) + err = r.CreateConnections(ctx, s.GetRelayerExecReporter(), pathName) + s.Require().NoError(err) + err = test.WaitForBlocks(ctx, 1, chainA, chainB) + s.Require().NoError(err) - channelsA, err := r.GetChannels(ctx, s.GetRelayerExecReporter(), chainA.Config().ChainID) - s.Require().NoError(err) + err = r.CreateChannel(ctx, s.GetRelayerExecReporter(), pathName, channelOpts) + s.Require().NoError(err) + err = test.WaitForBlocks(ctx, 1, chainA, chainB) + s.Require().NoError(err) - channelsB, err := r.GetChannels(ctx, s.GetRelayerExecReporter(), chainB.Config().ChainID) - s.Require().NoError(err) + channelsA, err := r.GetChannels(ctx, s.GetRelayerExecReporter(), chainA.Config().ChainID) + s.Require().NoError(err) - if s.channels[s.T().Name()] == nil { - s.channels[s.T().Name()] = make(map[ibc.Chain][]ibc.ChannelOutput) - } + channelsB, err := r.GetChannels(ctx, s.GetRelayerExecReporter(), chainB.Config().ChainID) + s.Require().NoError(err) - // keep track of channels associated with a given chain for access within the tests. - s.channels[s.T().Name()][chainA] = channelsA - s.channels[s.T().Name()][chainB] = channelsB - s.testPaths[s.T().Name()] = append(s.testPaths[s.T().Name()], pathName) + if s.channels[s.T().Name()] == nil { + s.channels[s.T().Name()] = make(map[ibc.Chain][]ibc.ChannelOutput) } + + // keep track of channels associated with a given chain for access within the tests. + s.channels[s.T().Name()][chainA] = channelsA + s.channels[s.T().Name()][chainB] = channelsB + + s.testPaths[s.T().Name()] = append(s.testPaths[s.T().Name()], pathName) + + return channelsA[len(channelsA)-1], channelsB[len(channelsB)-1] } // GetChainAChannel returns the ibc.ChannelOutput for the current test. From 43eceedba9802e55512a56898db56d626b24ab15 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Mon, 24 Jun 2024 09:28:43 +0200 Subject: [PATCH 095/141] refactor: rename SetupPath to SetupPaths (#6674) --- e2e/tests/core/03-connection/connection_test.go | 2 +- e2e/tests/transfer/authz_test.go | 2 +- e2e/tests/transfer/base_test.go | 2 +- e2e/tests/transfer/forwarding_test.go | 2 +- e2e/tests/transfer/incentivized_test.go | 2 +- e2e/tests/transfer/upgradesv1_test.go | 2 +- e2e/tests/transfer/upgradesv2_test.go | 2 +- e2e/tests/upgrades/upgrade_test.go | 2 +- e2e/testsuite/testsuite.go | 11 ++++++----- 9 files changed, 14 insertions(+), 13 deletions(-) diff --git a/e2e/tests/core/03-connection/connection_test.go b/e2e/tests/core/03-connection/connection_test.go index 9caeb4a302b..93dbcd98004 100644 --- a/e2e/tests/core/03-connection/connection_test.go +++ b/e2e/tests/core/03-connection/connection_test.go @@ -34,7 +34,7 @@ type ConnectionTestSuite struct { } func (s *ConnectionTestSuite) SetupTest() { - s.SetupPath(ibc.DefaultClientOpts(), s.TransferChannelOptions()) + s.SetupPaths(ibc.DefaultClientOpts(), s.TransferChannelOptions()) } // QueryMaxExpectedTimePerBlockParam queries the on-chain max expected time per block param for 03-connection diff --git a/e2e/tests/transfer/authz_test.go b/e2e/tests/transfer/authz_test.go index 6829bbd35ed..2a1d9b7c1fc 100644 --- a/e2e/tests/transfer/authz_test.go +++ b/e2e/tests/transfer/authz_test.go @@ -33,7 +33,7 @@ type AuthzTransferTestSuite struct { } func (suite *AuthzTransferTestSuite) SetupTest() { - suite.SetupPath(ibc.DefaultClientOpts(), suite.TransferChannelOptions()) + suite.SetupPaths(ibc.DefaultClientOpts(), suite.TransferChannelOptions()) } // QueryGranterGrants returns all GrantAuthorizations for the given granterAddress. diff --git a/e2e/tests/transfer/base_test.go b/e2e/tests/transfer/base_test.go index 5993f92862e..7acafea833f 100644 --- a/e2e/tests/transfer/base_test.go +++ b/e2e/tests/transfer/base_test.go @@ -34,7 +34,7 @@ type TransferTestSuite struct { } func (s *TransferTestSuite) SetupTest() { - s.SetupPath(ibc.DefaultClientOpts(), s.TransferChannelOptions()) + s.SetupPaths(ibc.DefaultClientOpts(), s.TransferChannelOptions()) } // QueryTransferParams queries the on-chain send enabled param for the transfer module diff --git a/e2e/tests/transfer/forwarding_test.go b/e2e/tests/transfer/forwarding_test.go index 8b4f6c0c461..1c96b978f9d 100644 --- a/e2e/tests/transfer/forwarding_test.go +++ b/e2e/tests/transfer/forwarding_test.go @@ -113,7 +113,7 @@ func (s *TransferForwardingTestSuite) TestForwarding_WithLastChainBeingICS20v1_S // Creating a new path between chain B and chain C with a ICS20-v1 channel opts := s.TransferChannelOptions() opts.Version = transfertypes.V1 - channelBtoC, _ := s.CreateNewPath(ctx, chainB, chainC, ibc.DefaultClientOpts(), opts) + channelBtoC, _ := s.CreatePath(ctx, chainB, chainC, ibc.DefaultClientOpts(), opts) s.Require().Equal(transfertypes.V1, channelBtoC.Version, "the channel version is not ics20-1") chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) diff --git a/e2e/tests/transfer/incentivized_test.go b/e2e/tests/transfer/incentivized_test.go index 463b4fcfb62..350d0ccaa37 100644 --- a/e2e/tests/transfer/incentivized_test.go +++ b/e2e/tests/transfer/incentivized_test.go @@ -39,7 +39,7 @@ func TestIncentivizedTransferTestSuite(t *testing.T) { // SetupTest explicitly enables fee middleware in the channel options. func (s *IncentivizedTransferTestSuite) SetupTest() { - s.SetupPath(ibc.DefaultClientOpts(), s.FeeTransferChannelOptions()) + s.SetupPaths(ibc.DefaultClientOpts(), s.FeeTransferChannelOptions()) } func (s *IncentivizedTransferTestSuite) TestMsgPayPacketFee_AsyncSingleSender_Succeeds() { diff --git a/e2e/tests/transfer/upgradesv1_test.go b/e2e/tests/transfer/upgradesv1_test.go index 11f6b656879..31bcaf7faa2 100644 --- a/e2e/tests/transfer/upgradesv1_test.go +++ b/e2e/tests/transfer/upgradesv1_test.go @@ -33,7 +33,7 @@ type TransferChannelUpgradesV1TestSuite struct { func (s *TransferChannelUpgradesV1TestSuite) SetupTest() { opts := s.TransferChannelOptions() opts.Version = transfertypes.V1 - s.SetupPath(ibc.DefaultClientOpts(), opts) + s.SetupPaths(ibc.DefaultClientOpts(), opts) } // TestChannelUpgrade_WithICS20v2_Succeeds tests upgrading a transfer channel to ICS20 v2. diff --git a/e2e/tests/transfer/upgradesv2_test.go b/e2e/tests/transfer/upgradesv2_test.go index 0f7a95f152e..8a505fef560 100644 --- a/e2e/tests/transfer/upgradesv2_test.go +++ b/e2e/tests/transfer/upgradesv2_test.go @@ -32,7 +32,7 @@ type TransferChannelUpgradesTestSuite struct { } func (s *TransferChannelUpgradesTestSuite) SetupTest() { - s.SetupPath(ibc.DefaultClientOpts(), s.TransferChannelOptions()) + s.SetupPaths(ibc.DefaultClientOpts(), s.TransferChannelOptions()) } // TestChannelUpgrade_WithFeeMiddleware_Succeeds tests upgrading a transfer channel to wire up fee middleware diff --git a/e2e/tests/upgrades/upgrade_test.go b/e2e/tests/upgrades/upgrade_test.go index 998f4bcd747..bbfa2567915 100644 --- a/e2e/tests/upgrades/upgrade_test.go +++ b/e2e/tests/upgrades/upgrade_test.go @@ -63,7 +63,7 @@ func (s *UpgradeTestSuite) SetupTest() { if strings.HasSuffix(s.T().Name(), "TestV8ToV8_1ChainUpgrade") { channelOpts = s.FeeTransferChannelOptions() } - s.SetupPath(ibc.DefaultClientOpts(), channelOpts) + s.SetupPaths(ibc.DefaultClientOpts(), channelOpts) } // UpgradeChain upgrades a chain to a specific version using the planName provided. diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index 5ae47a5b8df..bc430786106 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -174,22 +174,23 @@ func (s *E2ETestSuite) SetupChains(ctx context.Context, channelOptionsModifier C // SetupTest will by default use the default channel options to create a path between the chains. // if non default channel options are required, the test suite must override the `SetupTest` function. func (s *E2ETestSuite) SetupTest() { - s.SetupPath(ibc.DefaultClientOpts(), defaultChannelOpts(s.GetAllChains())) + s.SetupPaths(ibc.DefaultClientOpts(), defaultChannelOpts(s.GetAllChains())) } -// SetupPath creates paths between the all chains using the provided client and channel options. -func (s *E2ETestSuite) SetupPath(clientOpts ibc.CreateClientOptions, channelOpts ibc.CreateChannelOptions) { +// SetupPaths creates paths between the chains using the provided client and channel options. +// The paths are created such that ChainA is connected to ChainB, ChainB is connected to ChainC etc. +func (s *E2ETestSuite) SetupPaths(clientOpts ibc.CreateClientOptions, channelOpts ibc.CreateChannelOptions) { s.T().Logf("Setting up path for: %s", s.T().Name()) ctx := context.TODO() allChains := s.GetAllChains() for i := 0; i < len(allChains)-1; i++ { chainA, chainB := allChains[i], allChains[i+1] - _, _ = s.CreateNewPath(ctx, chainA, chainB, clientOpts, channelOpts) + _, _ = s.CreatePath(ctx, chainA, chainB, clientOpts, channelOpts) } } -func (s *E2ETestSuite) CreateNewPath( +func (s *E2ETestSuite) CreatePath( ctx context.Context, chainA ibc.Chain, chainB ibc.Chain, From aa860ac295c968e1b0e9573d1925b61d59596ba0 Mon Sep 17 00:00:00 2001 From: Dzung Do | Decentrio Date: Mon, 24 Jun 2024 17:19:51 +0700 Subject: [PATCH 096/141] chore: add flag for unwind in transfer cli (#6680) * add flag for unwind in transfer cli * update long description of cli --------- Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/client/cli/tx.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index 550f5c34620..84f83a886a0 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -24,6 +24,7 @@ const ( flagAbsoluteTimeouts = "absolute-timeouts" flagMemo = "memo" flagForwarding = "forwarding" + flagUnwind = "unwind" ) // defaultRelativePacketTimeoutTimestamp is the default packet timeout timestamp (in nanoseconds) @@ -41,7 +42,11 @@ func NewTransferTxCmd() *cobra.Command { packet if the coins list is a comma-separated string (e.g. 100uatom,100uosmo). Timeouts can be specified as absolute using the {absolute-timeouts} flag. Timeout height can be set by passing in the height string in the form {revision}-{height} using the {packet-timeout-height} flag. Note, relative timeout height is not supported. Relative timeout timestamp is added to the value of the user's local system clock time -using the {packet-timeout-timestamp} flag. If no timeout value is set then a default relative timeout value of 10 minutes is used.`), +using the {packet-timeout-timestamp} flag. If no timeout value is set then a default relative timeout value of 10 minutes is used. IBC tokens +can be automatically unwound to their native chain using the {unwind} flag. Please note that if the {unwind} flag used, then the transfer should contain only +tokens for a single denomination. Tokens can also be automatically forwarded through multiple chains using the {fowarding} flag and specifying +a comma-separated list of source portID/channelID pairs for each intermediary chain. {unwind} and {forwarding} flags can be used together +to unwind IBC tokens to their native chain and forward them to the final destination.`), Example: fmt.Sprintf("%s tx ibc-transfer transfer [src-port] [src-channel] [receiver] [coins]", version.AppName), Args: cobra.ExactArgs(4), RunE: func(cmd *cobra.Command, args []string) error { @@ -129,6 +134,8 @@ using the {packet-timeout-timestamp} flag. If no timeout value is set then a def cmd.Flags().Bool(flagAbsoluteTimeouts, false, "Timeout flags are used as absolute timeouts.") cmd.Flags().String(flagMemo, "", "Memo to be sent along with the packet.") cmd.Flags().String(flagForwarding, "", "Forwarding information in the form of a comma separated list of portID/channelID pairs, denoting the intermediary hops. If forwarding is specified any memo set will be included in the forwarding information created.") + cmd.Flags().Bool(flagUnwind, false, "Flag to indicate if the coin should be unwound to its native chain before forwarding.") + flags.AddTxFlagsToCmd(cmd) return cmd @@ -158,6 +165,10 @@ func parseForwarding(cmd *cobra.Command) (types.Forwarding, error) { hops = append(hops, hop) } - // TODO(jim): Add flag for unwind value - return types.NewForwarding(false, hops...), nil + unwind, err := cmd.Flags().GetBool(flagUnwind) + if err != nil { + return types.Forwarding{}, err + } + + return types.NewForwarding(unwind, hops...), nil } From 2b4d24b7741a38ee63a89cd8b0cf4ae6b92d1817 Mon Sep 17 00:00:00 2001 From: Maintain Date: Mon, 24 Jun 2024 22:01:47 +0700 Subject: [PATCH 097/141] feat: impl check reject transfer if len(hops) > 0 and ics20-1 (#6675) * impl check reject transfer if len(hops) > 0 and ics20-1 * add test case hops is not empty with ics20-2 * address review comments * reorder variable declaration --------- Co-authored-by: Carlos Rodriguez Co-authored-by: Gjermund Garaba --- modules/apps/transfer/keeper/relay.go | 13 +++++-- modules/apps/transfer/keeper/relay_test.go | 43 +++++++++++++++++++++- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 6d2d8d1e5e5..7cff4bc333c 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -76,9 +76,16 @@ func (k Keeper) sendTransfer( return 0, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "application version not found for source port: %s and source channel: %s", sourcePort, sourceChannel) } - // ics20-1 only supports a single coin, so if that is the current version, we must only process a single coin. - if appVersion == types.V1 && len(coins) > 1 { - return 0, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "cannot transfer multiple coins with ics20-1") + 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(coins) > 1 { + return 0, 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 len(forwarding.Hops) > 0 { + return 0, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "cannot forward coins with %s", types.V1) + } } destinationPort := channel.Counterparty.PortId diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 937815d9344..c739d21187c 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -35,8 +35,8 @@ func (suite *KeeperTestSuite) TestSendTransfer() { sender sdk.AccAddress timeoutHeight clienttypes.Height memo string + forwarding types.Forwarding expEscrowAmount sdkmath.Int // total amount in escrow for denom on receiving chain - ) testCases := []struct { @@ -80,6 +80,29 @@ func (suite *KeeperTestSuite) TestSendTransfer() { }, nil, }, + { + "successful transfer with empty forwarding hops and ics20-1", + func() { + expEscrowAmount = sdkmath.NewInt(100) + + // Set version to isc20-1. + path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { + channel.Version = types.V1 + }) + }, + nil, + }, + { + "successful transfer with non-empty forwarding hops and ics20-2", + func() { + expEscrowAmount = sdkmath.NewInt(100) + forwarding = types.NewForwarding(false, types.Hop{ + PortId: path.EndpointA.ChannelConfig.PortID, + ChannelId: path.EndpointA.ChannelID, + }) + }, + nil, + }, { "successful transfer of IBC token with memo", func() { @@ -146,6 +169,21 @@ func (suite *KeeperTestSuite) TestSendTransfer() { }, channeltypes.ErrInvalidPacket, }, + { + "failure: forwarding hops is not empty with ics20-1", + func() { + // Set version to isc20-1. + path.EndpointA.UpdateChannel(func(channel *channeltypes.Channel) { + channel.Version = types.V1 + }) + + forwarding = types.NewForwarding(false, types.Hop{ + PortId: path.EndpointA.ChannelConfig.PortID, + ChannelId: path.EndpointA.ChannelID, + }) + }, + ibcerrors.ErrInvalidRequest, + }, } for _, tc := range testCases { @@ -162,6 +200,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { memo = "" timeoutHeight = suite.chainB.GetTimeoutHeight() expEscrowAmount = sdkmath.ZeroInt() + forwarding = emptyForwarding // create IBC token on chainA transferMsg := types.NewMsgTransfer(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, sdk.NewCoins(coin), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainA.GetTimeoutHeight(), 0, "", emptyForwarding) @@ -184,7 +223,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, // only use timeout height memo, - emptyForwarding, + forwarding, ) res, err := suite.chainA.GetSimApp().TransferKeeper.Transfer(suite.chainA.GetContext(), msg) From 59e3df74ba7cb0728bdba004f4d527213706dfbd Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Tue, 25 Jun 2024 10:57:10 +0300 Subject: [PATCH 098/141] feat(transfer): add unwinding ability (#6656) * Create ontimeoutpacket test for forwarding * Propagate ack on A * Refactoring * Minor changes * Added comments * Fix type name. * Gofumpt * Update modules/apps/transfer/keeper/relay_forwarding_test.go Co-authored-by: Carlos Rodriguez * Update modules/apps/transfer/keeper/relay_forwarding_test.go Co-authored-by: Carlos Rodriguez * Update modules/apps/transfer/keeper/relay_forwarding_test.go Co-authored-by: Carlos Rodriguez * Update modules/apps/transfer/keeper/relay_forwarding_test.go Co-authored-by: Carlos Rodriguez * Add godoc to test. * Changed trace construction * Update modules/apps/transfer/keeper/relay_forwarding_test.go Co-authored-by: Carlos Rodriguez * remove error msg parameter from helper function * Add test for forwarded packet * Construct packet for B ack check. * PR feedback * feat(transfer): add unwind, refactor proto structure. gen-all * tests(transfer/types): fix test failures in types tests. * tests(transfer/keeper): fix test failures in keeper tests. * cli(transfer): fix cli usage. pending flag for unwind. * tests(callbacks): fix failing tests in callbacks. * tests(transfer/internal): fix failures in internal package. * tests(transfer): fix test failures in top level tranfer package. * tests(ica/host/keeper): fix repr of msg transfer in ica host msg execution. * lint(all): lint this bad boy * chore(transfer/types): amend validation for MsgTransfer's ShouldBeForwarded, add tests for ForwardedPacketData, minor nits. * nit(self): only pass relevant fields to create packet data; minor comment improvement. * Apply suggestions from code review Co-authored-by: Carlos Rodriguez * chore(merge): fix merge issues. * chore(proto): mention optional nature of fields. * memo: do not drop it * validation: drop requirement on memo being empty on msg transfer. * feat(transfer): add unwinding ability, wip. * Added unwind to allocation forwarding. * Add tests and move some validation * Missing import * Fixed validation and added test * PR Feedback * Return nil when returning an error. * Cleaner comment * Add test case for multiple hos --------- Co-authored-by: bznein Co-authored-by: Nikolas De Giorgis Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/keeper/export_test.go | 5 + modules/apps/transfer/keeper/msg_server.go | 36 ++ .../apps/transfer/keeper/msg_server_test.go | 120 +++++++ modules/apps/transfer/types/authz.pb.go | 332 +++++++++++++++--- modules/apps/transfer/types/msgs.go | 36 +- modules/apps/transfer/types/msgs_test.go | 6 +- .../transfer/types/transfer_authorization.go | 17 +- .../types/transfer_authorization_test.go | 37 +- .../ibc/applications/transfer/v1/authz.proto | 10 +- 9 files changed, 526 insertions(+), 73 deletions(-) diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index b5fbc235504..fa86b405e86 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -33,6 +33,11 @@ func (k Keeper) TokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro return k.tokenFromCoin(ctx, coin) } +// UnwindHops is a wrapper around unwindToken for testing purposes. +func (k Keeper) UnwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgTransfer, error) { + return k.unwindHops(ctx, msg) +} + // CreatePacketDataBytesFromVersion is a wrapper around createPacketDataBytesFromVersion for testing purposes func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, hops []types.Hop) []byte { return createPacketDataBytesFromVersion(appVersion, sender, receiver, memo, tokens, hops) diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 507dc2c7b62..2be27e0f776 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -36,6 +36,13 @@ 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) } + if msg.Forwarding.Unwind { + msg, err = k.unwindHops(ctx, msg) + if err != nil { + return nil, err + } + } + sequence, err := k.sendTransfer( ctx, msg.SourcePort, msg.SourceChannel, coins, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, msg.Memo, msg.Forwarding) @@ -59,3 +66,32 @@ func (k Keeper) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParams) return &types.MsgUpdateParamsResponse{}, nil } + +// 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) { + coins := msg.GetCoins() + token, err := k.tokenFromCoin(ctx, coins[0]) + if err != nil { + return nil, err + } + + if token.Denom.IsNative() { + return nil, errorsmod.Wrap(types.ErrInvalidForwarding, "cannot unwind a native token") + } + var unwindHops []types.Hop + for _, trace := range token.Denom.Trace[1:] { + unwindHops = append(unwindHops, types.Hop{PortId: trace.PortId, ChannelId: trace.ChannelId}) //nolint: gosimple + } + + // Update message fields. + msg.SourcePort, msg.SourceChannel = token.Denom.Trace[0].PortId, token.Denom.Trace[0].ChannelId + msg.Forwarding.Hops = append(unwindHops, msg.Forwarding.Hops...) + msg.Forwarding.Unwind = false + + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + return msg, nil +} diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 2a9be02aed7..95e1734d209 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -13,6 +13,7 @@ import ( abci "github.com/cometbft/cometbft/abci/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" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -238,3 +239,122 @@ func (suite *KeeperTestSuite) TestUpdateParams() { }) } } + +func (suite *KeeperTestSuite) TestUnwindHops() { + var msg *types.MsgTransfer + var path *ibctesting.Path + denom := types.NewDenom(ibctesting.TestCoin.Denom, types.NewTrace(ibctesting.MockPort, "channel-0"), types.NewTrace(ibctesting.MockPort, "channel-1")) + coins := sdk.NewCoins(sdk.NewCoin(denom.IBCDenom(), ibctesting.TestCoin.Amount)) + testCases := []struct { + name string + malleate func() + assertResult func(modified *types.MsgTransfer, err error) + }{ + { + "success", + func() { + suite.chainA.GetSimApp().TransferKeeper.SetDenom(suite.chainA.GetContext(), denom) + }, + func(modified *types.MsgTransfer, err error) { + suite.Require().NoError(err, "got unexpected error from unwindHops") + msg.SourceChannel = denom.Trace[0].PortId + msg.SourcePort = denom.Trace[0].ChannelId + msg.Forwarding = types.NewForwarding(false, types.Hop{PortId: denom.Trace[1].PortId, ChannelId: denom.Trace[1].ChannelId}) + suite.Require().Equal(*msg, *modified, "expected msg and modified msg are different") + }, + }, + { + "success: multiple unwind hops", + func() { + denom.Trace = append(denom.Trace, types.NewTrace(ibctesting.MockPort, "channel-2"), types.NewTrace(ibctesting.MockPort, "channel-3")) + coins = sdk.NewCoins(sdk.NewCoin(denom.IBCDenom(), ibctesting.TestCoin.Amount)) + suite.chainA.GetSimApp().TransferKeeper.SetDenom(suite.chainA.GetContext(), denom) + msg.Tokens = coins + }, + func(modified *types.MsgTransfer, err error) { + suite.Require().NoError(err, "got unexpected error from unwindHops") + msg.SourceChannel = denom.Trace[0].PortId + msg.SourcePort = denom.Trace[0].ChannelId + msg.Forwarding = types.NewForwarding(false, + types.Hop{PortId: denom.Trace[3].PortId, ChannelId: denom.Trace[3].ChannelId}, + types.Hop{PortId: denom.Trace[2].PortId, ChannelId: denom.Trace[2].ChannelId}, + types.Hop{PortId: denom.Trace[1].PortId, ChannelId: denom.Trace[1].ChannelId}, + ) + suite.Require().Equal(*msg, *modified, "expected msg and modified msg are different") + }, + }, + { + "success - unwind hops are added to existing hops", + func() { + suite.chainA.GetSimApp().TransferKeeper.SetDenom(suite.chainA.GetContext(), denom) + msg.Forwarding = types.NewForwarding(true, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}) + }, + func(modified *types.MsgTransfer, err error) { + suite.Require().NoError(err, "got unexpected error from unwindHops") + msg.SourceChannel = denom.Trace[0].PortId + msg.SourcePort = denom.Trace[0].ChannelId + msg.Forwarding = types.NewForwarding(false, + types.Hop{PortId: denom.Trace[1].PortId, ChannelId: denom.Trace[1].ChannelId}, + types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}, + ) + 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() { + denom.Trace[0].ChannelId = "channel/0" + coins = sdk.NewCoins(sdk.NewCoin(denom.IBCDenom(), ibctesting.TestCoin.Amount)) + msg.Tokens = coins + suite.chainA.GetSimApp().TransferKeeper.SetDenom(suite.chainA.GetContext(), denom) + }, + func(modified *types.MsgTransfer, err error) { + suite.Require().ErrorContains(err, "invalid source channel ID") + }, + }, + { + "failure: denom is native", + func() { + denom.Trace = nil + coins = sdk.NewCoins(sdk.NewCoin(denom.IBCDenom(), ibctesting.TestCoin.Amount)) + msg.Tokens = coins + suite.chainA.GetSimApp().TransferKeeper.SetDenom(suite.chainA.GetContext(), denom) + }, + func(modified *types.MsgTransfer, err error) { + suite.Require().ErrorIs(err, types.ErrInvalidForwarding) + }, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path.Setup() + + msg = types.NewMsgTransfer( + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + coins, + suite.chainA.SenderAccount.GetAddress().String(), + suite.chainB.SenderAccount.GetAddress().String(), + clienttypes.ZeroHeight(), + suite.chainA.GetTimeoutTimestamp(), + "memo", + types.NewForwarding(true), + ) + + tc.malleate() + gotMsg, err := suite.chainA.GetSimApp().TransferKeeper.UnwindHops(suite.chainA.GetContext(), msg) + tc.assertResult(gotMsg, err) + }) + } +} diff --git a/modules/apps/transfer/types/authz.pb.go b/modules/apps/transfer/types/authz.pb.go index f0db4502e32..51de34c0ae4 100644 --- a/modules/apps/transfer/types/authz.pb.go +++ b/modules/apps/transfer/types/authz.pb.go @@ -39,9 +39,8 @@ type Allocation struct { // allow list of memo strings, an empty list prohibits all memo strings; // a list only with "*" permits any memo string AllowedPacketData []string `protobuf:"bytes,5,rep,name=allowed_packet_data,json=allowedPacketData,proto3" json:"allowed_packet_data,omitempty"` - // a list of allowed source port ID/channel ID pairs through which the packet is allowed to be forwarded until final - // destination - AllowedForwardingHops []Hops `protobuf:"bytes,6,rep,name=allowed_forwarding_hops,json=allowedForwardingHops,proto3" json:"allowed_forwarding_hops"` + // Forwarding options that are allowed. + AllowedForwarding AllowedForwarding `protobuf:"bytes,6,opt,name=allowed_forwarding,json=allowedForwarding,proto3" json:"allowed_forwarding"` } func (m *Allocation) Reset() { *m = Allocation{} } @@ -112,13 +111,69 @@ func (m *Allocation) GetAllowedPacketData() []string { return nil } -func (m *Allocation) GetAllowedForwardingHops() []Hops { +func (m *Allocation) GetAllowedForwarding() AllowedForwarding { + if m != nil { + return m.AllowedForwarding + } + return AllowedForwarding{} +} + +// AllowedForwarding defines which options are allowed for forwarding. +type AllowedForwarding struct { + // a list of allowed source port ID/channel ID pairs through which the packet is allowed to be forwarded until final + // destination + AllowedHops []Hops `protobuf:"bytes,1,rep,name=allowed_hops,json=allowedHops,proto3" json:"allowed_hops"` + // Whether to allow automatic unwinding of tokens to the original chain. + AllowUnwind bool `protobuf:"varint,2,opt,name=allow_unwind,json=allowUnwind,proto3" json:"allow_unwind,omitempty"` +} + +func (m *AllowedForwarding) Reset() { *m = AllowedForwarding{} } +func (m *AllowedForwarding) String() string { return proto.CompactTextString(m) } +func (*AllowedForwarding) ProtoMessage() {} +func (*AllowedForwarding) Descriptor() ([]byte, []int) { + return fileDescriptor_b1a28b55d17325aa, []int{1} +} +func (m *AllowedForwarding) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AllowedForwarding) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AllowedForwarding.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 *AllowedForwarding) XXX_Merge(src proto.Message) { + xxx_messageInfo_AllowedForwarding.Merge(m, src) +} +func (m *AllowedForwarding) XXX_Size() int { + return m.Size() +} +func (m *AllowedForwarding) XXX_DiscardUnknown() { + xxx_messageInfo_AllowedForwarding.DiscardUnknown(m) +} + +var xxx_messageInfo_AllowedForwarding proto.InternalMessageInfo + +func (m *AllowedForwarding) GetAllowedHops() []Hops { if m != nil { - return m.AllowedForwardingHops + return m.AllowedHops } return nil } +func (m *AllowedForwarding) GetAllowUnwind() bool { + if m != nil { + return m.AllowUnwind + } + return false +} + // Hops represent a list of Hop type Hops struct { Hops []Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops"` @@ -128,7 +183,7 @@ func (m *Hops) Reset() { *m = Hops{} } func (m *Hops) String() string { return proto.CompactTextString(m) } func (*Hops) ProtoMessage() {} func (*Hops) Descriptor() ([]byte, []int) { - return fileDescriptor_b1a28b55d17325aa, []int{1} + return fileDescriptor_b1a28b55d17325aa, []int{2} } func (m *Hops) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -175,7 +230,7 @@ func (m *TransferAuthorization) Reset() { *m = TransferAuthorization{} } func (m *TransferAuthorization) String() string { return proto.CompactTextString(m) } func (*TransferAuthorization) ProtoMessage() {} func (*TransferAuthorization) Descriptor() ([]byte, []int) { - return fileDescriptor_b1a28b55d17325aa, []int{2} + return fileDescriptor_b1a28b55d17325aa, []int{3} } func (m *TransferAuthorization) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -213,6 +268,7 @@ func (m *TransferAuthorization) GetAllocations() []Allocation { func init() { proto.RegisterType((*Allocation)(nil), "ibc.applications.transfer.v1.Allocation") + proto.RegisterType((*AllowedForwarding)(nil), "ibc.applications.transfer.v1.AllowedForwarding") proto.RegisterType((*Hops)(nil), "ibc.applications.transfer.v1.Hops") proto.RegisterType((*TransferAuthorization)(nil), "ibc.applications.transfer.v1.TransferAuthorization") } @@ -222,39 +278,41 @@ func init() { } var fileDescriptor_b1a28b55d17325aa = []byte{ - // 501 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0xc1, 0x8e, 0xd3, 0x3c, - 0x14, 0x85, 0x9b, 0x69, 0xff, 0x91, 0xea, 0xea, 0x47, 0x22, 0x30, 0x22, 0x33, 0x82, 0xb4, 0x54, - 0x02, 0x45, 0x42, 0xb5, 0x29, 0x2c, 0x40, 0xb0, 0x9a, 0x16, 0x21, 0x16, 0xb3, 0x28, 0x15, 0x2b, - 0x36, 0xc1, 0x71, 0x3c, 0x8d, 0x35, 0x6e, 0x6e, 0x14, 0x3b, 0x1d, 0x31, 0x4f, 0x01, 0xaf, 0xc1, - 0x9a, 0x87, 0x18, 0xb1, 0x9a, 0x25, 0x2b, 0x40, 0xed, 0x23, 0xf0, 0x02, 0x28, 0xb6, 0x5b, 0x8a, - 0x90, 0xca, 0xca, 0xf1, 0xb9, 0xc7, 0x9f, 0x7d, 0x73, 0x2e, 0x8a, 0x44, 0xc2, 0x08, 0x2d, 0x0a, - 0x29, 0x18, 0xd5, 0x02, 0x72, 0x45, 0x74, 0x49, 0x73, 0x75, 0xca, 0x4b, 0xb2, 0x18, 0x12, 0x5a, - 0xe9, 0xec, 0x02, 0x17, 0x25, 0x68, 0xf0, 0x6f, 0x8b, 0x84, 0xe1, 0x6d, 0x27, 0x5e, 0x3b, 0xf1, - 0x62, 0x78, 0x74, 0xc8, 0x40, 0xcd, 0x41, 0xc5, 0xc6, 0x4b, 0xec, 0xc6, 0x1e, 0x3c, 0xba, 0x39, - 0x83, 0x19, 0x58, 0xbd, 0xfe, 0x72, 0x6a, 0x68, 0x3d, 0x24, 0xa1, 0x8a, 0x93, 0xc5, 0x30, 0xe1, - 0x9a, 0x0e, 0x09, 0x03, 0x91, 0xbb, 0xfa, 0x83, 0x9d, 0x0f, 0xdb, 0x5c, 0x6d, 0xcc, 0xfd, 0x9f, - 0x7b, 0x08, 0x1d, 0x4b, 0x09, 0xd6, 0xea, 0x77, 0x51, 0x47, 0x41, 0x55, 0x32, 0x1e, 0x17, 0x50, - 0xea, 0xc0, 0xeb, 0x79, 0x51, 0x7b, 0x8a, 0xac, 0x34, 0x81, 0x52, 0xfb, 0xf7, 0xd0, 0x35, 0x67, - 0x60, 0x19, 0xcd, 0x73, 0x2e, 0x83, 0x3d, 0xe3, 0xf9, 0xdf, 0xaa, 0x63, 0x2b, 0xfa, 0x12, 0x75, - 0x54, 0xc1, 0xf3, 0x34, 0x96, 0x62, 0x2e, 0x74, 0xd0, 0xec, 0x35, 0xa3, 0xce, 0xa3, 0x43, 0xec, - 0xba, 0xab, 0x5f, 0x8e, 0xdd, 0xcb, 0xf1, 0x18, 0x44, 0x3e, 0x7a, 0x78, 0xf9, 0xad, 0xdb, 0xf8, - 0xf4, 0xbd, 0x1b, 0xcd, 0x84, 0xce, 0xaa, 0x04, 0x33, 0x98, 0xbb, 0x5f, 0xe1, 0x96, 0x81, 0x4a, - 0xcf, 0x88, 0x7e, 0x5f, 0x70, 0x65, 0x0e, 0xa8, 0x29, 0x32, 0xfc, 0x93, 0x1a, 0xef, 0xdf, 0x41, - 0x88, 0x4a, 0x09, 0xe7, 0xb1, 0x14, 0x4a, 0x07, 0xad, 0x5e, 0x33, 0x6a, 0x4f, 0xdb, 0x46, 0x39, - 0x11, 0x4a, 0xfb, 0x18, 0xdd, 0x30, 0x1b, 0x9e, 0xc6, 0x05, 0x65, 0x67, 0x5c, 0xc7, 0x29, 0xd5, - 0x34, 0xf8, 0xcf, 0xf8, 0xae, 0xbb, 0xd2, 0xc4, 0x54, 0x5e, 0x50, 0x4d, 0xfd, 0x77, 0xe8, 0xd6, - 0xda, 0x7f, 0x0a, 0xe5, 0x39, 0x2d, 0x53, 0x91, 0xcf, 0xe2, 0x0c, 0x0a, 0x15, 0xec, 0x9b, 0x46, - 0xfa, 0x78, 0x57, 0xa2, 0xf8, 0x15, 0x14, 0x6a, 0xd4, 0xaa, 0x3b, 0x9a, 0x1e, 0x38, 0xd0, 0xcb, - 0x0d, 0xa7, 0x2e, 0xf6, 0xc7, 0xa8, 0x55, 0xaf, 0xfe, 0x73, 0xd4, 0x32, 0x58, 0xcf, 0x60, 0xef, - 0xfe, 0x13, 0xeb, 0xa8, 0xe6, 0x50, 0xff, 0xa3, 0x87, 0x0e, 0xde, 0xb8, 0xfa, 0x71, 0xa5, 0x33, - 0x28, 0xc5, 0x85, 0x4d, 0x71, 0x82, 0x3a, 0x74, 0x93, 0xe9, 0x9a, 0x1e, 0xed, 0xa6, 0xff, 0x1e, - 0x02, 0x77, 0xc9, 0x36, 0xe2, 0xd9, 0xfd, 0x2f, 0x9f, 0x07, 0x7d, 0x97, 0x9e, 0x1d, 0xed, 0x75, - 0x7c, 0x7f, 0xdc, 0x3c, 0x7a, 0x7d, 0xb9, 0x0c, 0xbd, 0xab, 0x65, 0xe8, 0xfd, 0x58, 0x86, 0xde, - 0x87, 0x55, 0xd8, 0xb8, 0x5a, 0x85, 0x8d, 0xaf, 0xab, 0xb0, 0xf1, 0xf6, 0xc9, 0xdf, 0xc9, 0x8a, - 0x84, 0x0d, 0x66, 0x40, 0x16, 0x4f, 0xc9, 0x1c, 0xd2, 0x4a, 0x72, 0x55, 0x4f, 0xed, 0xd6, 0xb4, - 0x9a, 0xb8, 0x93, 0x7d, 0x33, 0xa8, 0x8f, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x61, 0xe1, 0x76, - 0x97, 0x70, 0x03, 0x00, 0x00, + // 541 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0xc7, 0xe3, 0x26, 0x54, 0x64, 0x03, 0x48, 0x35, 0x20, 0xb9, 0x15, 0x38, 0xa9, 0x25, 0x90, + 0x25, 0x94, 0x5d, 0x52, 0x0e, 0x20, 0x38, 0x25, 0x41, 0x08, 0x89, 0x1e, 0x42, 0x04, 0x17, 0x2e, + 0xd6, 0xfa, 0xa3, 0xf1, 0xaa, 0xce, 0x8e, 0xe5, 0x5d, 0x27, 0xa2, 0x57, 0x5e, 0x00, 0x5e, 0x83, + 0x33, 0x0f, 0x51, 0x71, 0xea, 0x91, 0x13, 0xa0, 0xe4, 0x21, 0xb8, 0x22, 0xef, 0x6e, 0x42, 0x50, + 0xa5, 0xf4, 0x64, 0xef, 0x7f, 0x7e, 0x33, 0xff, 0xfd, 0x98, 0x41, 0x3e, 0x0b, 0x23, 0x42, 0xf3, + 0x3c, 0x63, 0x11, 0x95, 0x0c, 0xb8, 0x20, 0xb2, 0xa0, 0x5c, 0x9c, 0x24, 0x05, 0x99, 0xf5, 0x08, + 0x2d, 0x65, 0x7a, 0x86, 0xf3, 0x02, 0x24, 0xd8, 0xf7, 0x58, 0x18, 0xe1, 0x4d, 0x12, 0xaf, 0x48, + 0x3c, 0xeb, 0x1d, 0xec, 0x47, 0x20, 0xa6, 0x20, 0x02, 0xc5, 0x12, 0xbd, 0xd0, 0x89, 0x07, 0x77, + 0x26, 0x30, 0x01, 0xad, 0x57, 0x7f, 0x46, 0x75, 0x35, 0x43, 0x42, 0x2a, 0x12, 0x32, 0xeb, 0x85, + 0x89, 0xa4, 0x3d, 0x12, 0x01, 0xe3, 0x26, 0xfe, 0x68, 0xeb, 0xc6, 0xd6, 0xd6, 0x0a, 0xf6, 0xfe, + 0xec, 0x20, 0xd4, 0xcf, 0x32, 0xd0, 0xa8, 0xdd, 0x46, 0x2d, 0x01, 0x65, 0x11, 0x25, 0x41, 0x0e, + 0x85, 0x74, 0xac, 0x8e, 0xe5, 0x37, 0xc7, 0x48, 0x4b, 0x23, 0x28, 0xa4, 0xfd, 0x00, 0xdd, 0x32, + 0x40, 0x94, 0x52, 0xce, 0x93, 0xcc, 0xd9, 0x51, 0xcc, 0x4d, 0xad, 0x0e, 0xb5, 0x68, 0x67, 0xa8, + 0x25, 0xf2, 0x84, 0xc7, 0x41, 0xc6, 0xa6, 0x4c, 0x3a, 0xf5, 0x4e, 0xdd, 0x6f, 0x1d, 0xed, 0x63, + 0x73, 0xba, 0x6a, 0xe7, 0xd8, 0xec, 0x1c, 0x0f, 0x81, 0xf1, 0xc1, 0xe3, 0xf3, 0x9f, 0xed, 0xda, + 0xd7, 0x5f, 0x6d, 0x7f, 0xc2, 0x64, 0x5a, 0x86, 0x38, 0x82, 0xa9, 0xb9, 0x0a, 0xf3, 0xe9, 0x8a, + 0xf8, 0x94, 0xc8, 0x8f, 0x79, 0x22, 0x54, 0x82, 0x18, 0x23, 0x55, 0xff, 0xb8, 0x2a, 0x6f, 0xdf, + 0x47, 0x88, 0x66, 0x19, 0xcc, 0x83, 0x8c, 0x09, 0xe9, 0x34, 0x3a, 0x75, 0xbf, 0x39, 0x6e, 0x2a, + 0xe5, 0x98, 0x09, 0x69, 0x63, 0x74, 0x5b, 0x2d, 0x92, 0x38, 0xc8, 0x69, 0x74, 0x9a, 0xc8, 0x20, + 0xa6, 0x92, 0x3a, 0xd7, 0x14, 0xb7, 0x67, 0x42, 0x23, 0x15, 0x79, 0x49, 0x25, 0xb5, 0x63, 0x64, + 0xaf, 0xf8, 0x13, 0x28, 0xe6, 0xb4, 0x88, 0x19, 0x9f, 0x38, 0xbb, 0x1d, 0xcb, 0x6f, 0x1d, 0x11, + 0xbc, 0xed, 0x31, 0x71, 0x5f, 0xe7, 0xbd, 0x5a, 0xa7, 0x0d, 0x1a, 0xd5, 0xc9, 0xd6, 0x2e, 0xff, + 0x02, 0xde, 0x27, 0x0b, 0xed, 0x5d, 0xc2, 0xed, 0x37, 0xe8, 0xc6, 0xca, 0x3b, 0x85, 0x5c, 0x38, + 0x96, 0xba, 0x39, 0x6f, 0xbb, 0xeb, 0x6b, 0xc8, 0x85, 0x31, 0x6a, 0x99, 0xec, 0x4a, 0xb2, 0x0f, + 0x4d, 0xb1, 0xa0, 0xe4, 0x73, 0xc6, 0x63, 0xf5, 0x54, 0xd7, 0x0d, 0xf2, 0x5e, 0x49, 0xde, 0x10, + 0x35, 0x14, 0xfa, 0x02, 0x35, 0x36, 0xfc, 0x0e, 0xaf, 0xf4, 0x33, 0x76, 0x2a, 0xc9, 0xfb, 0x62, + 0xa1, 0xbb, 0xef, 0x4c, 0xbc, 0x5f, 0xca, 0x14, 0x0a, 0x76, 0xa6, 0xfb, 0x69, 0x84, 0x94, 0x9b, + 0x29, 0x62, 0xaa, 0xfb, 0x57, 0xdf, 0xa1, 0xd6, 0x37, 0xcf, 0x64, 0xc8, 0xe7, 0x0f, 0xbf, 0x7f, + 0xeb, 0x7a, 0xa6, 0x8f, 0xf4, 0x90, 0xad, 0x1a, 0xe9, 0x3f, 0xe7, 0xc1, 0xdb, 0xf3, 0x85, 0x6b, + 0x5d, 0x2c, 0x5c, 0xeb, 0xf7, 0xc2, 0xb5, 0x3e, 0x2f, 0xdd, 0xda, 0xc5, 0xd2, 0xad, 0xfd, 0x58, + 0xba, 0xb5, 0x0f, 0x4f, 0x2f, 0xf7, 0x18, 0x0b, 0xa3, 0xee, 0x04, 0xc8, 0xec, 0x19, 0x99, 0x42, + 0x5c, 0x66, 0x89, 0xa8, 0xe6, 0x67, 0x63, 0x6e, 0x54, 0xe3, 0x85, 0xbb, 0x6a, 0x64, 0x9e, 0xfc, + 0x0d, 0x00, 0x00, 0xff, 0xff, 0x08, 0x47, 0x9b, 0x9b, 0xfa, 0x03, 0x00, 0x00, } func (m *Allocation) Marshal() (dAtA []byte, err error) { @@ -277,20 +335,16 @@ func (m *Allocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.AllowedForwardingHops) > 0 { - for iNdEx := len(m.AllowedForwardingHops) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.AllowedForwardingHops[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintAuthz(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x32 + { + size, err := m.AllowedForwarding.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x32 if len(m.AllowedPacketData) > 0 { for iNdEx := len(m.AllowedPacketData) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.AllowedPacketData[iNdEx]) @@ -340,6 +394,53 @@ func (m *Allocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *AllowedForwarding) 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 *AllowedForwarding) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AllowedForwarding) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.AllowUnwind { + i-- + if m.AllowUnwind { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if len(m.AllowedHops) > 0 { + for iNdEx := len(m.AllowedHops) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AllowedHops[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *Hops) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -457,12 +558,26 @@ func (m *Allocation) Size() (n int) { n += 1 + l + sovAuthz(uint64(l)) } } - if len(m.AllowedForwardingHops) > 0 { - for _, e := range m.AllowedForwardingHops { + l = m.AllowedForwarding.Size() + n += 1 + l + sovAuthz(uint64(l)) + return n +} + +func (m *AllowedForwarding) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.AllowedHops) > 0 { + for _, e := range m.AllowedHops { l = e.Size() n += 1 + l + sovAuthz(uint64(l)) } } + if m.AllowUnwind { + n += 2 + } return n } @@ -695,7 +810,7 @@ func (m *Allocation) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AllowedForwardingHops", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AllowedForwarding", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -722,8 +837,7 @@ func (m *Allocation) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.AllowedForwardingHops = append(m.AllowedForwardingHops, Hops{}) - if err := m.AllowedForwardingHops[len(m.AllowedForwardingHops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.AllowedForwarding.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -748,6 +862,110 @@ func (m *Allocation) Unmarshal(dAtA []byte) error { } return nil } +func (m *AllowedForwarding) 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 ErrIntOverflowAuthz + } + 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: AllowedForwarding: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AllowedForwarding: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowedHops", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AllowedHops = append(m.AllowedHops, Hops{}) + if err := m.AllowedHops[len(m.AllowedHops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowUnwind", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AllowUnwind = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Hops) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 01289ff42eb..231bc108ddd 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -69,11 +69,8 @@ func NewMsgTransfer( // NOTE: The recipient addresses format is not validated as the format defined by // the chain is not known to IBC. func (msg MsgTransfer) ValidateBasic() error { - if err := host.PortIdentifierValidator(msg.SourcePort); err != nil { - return errorsmod.Wrap(err, "invalid source port ID") - } - if err := host.ChannelIdentifierValidator(msg.SourceChannel); err != nil { - return errorsmod.Wrap(err, "invalid source channel ID") + if err := validateSourcePortAndChannel(msg); err != nil { + return err // The actual error and its message are already wrapped in the called function. } if len(msg.Tokens) == 0 && !isValidIBCCoin(msg.Token) { @@ -113,6 +110,13 @@ func (msg MsgTransfer) ValidateBasic() error { } } + if msg.Forwarding.Unwind { + // When unwinding, we must have at most one token. + if len(msg.GetCoins()) > 1 { + return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, "cannot unwind more that one token") + } + } + for _, coin := range msg.GetCoins() { if err := validateIBCCoin(coin); err != nil { return errorsmod.Wrapf(ibcerrors.ErrInvalidCoins, "%s: %s", err.Error(), coin.String()) @@ -160,3 +164,25 @@ func validateIBCCoin(coin sdk.Coin) error { return nil } + +func validateSourcePortAndChannel(msg MsgTransfer) error { + // If unwind is set, we want to ensure that port and channel are empty. + if msg.Forwarding.Unwind { + if msg.SourcePort != "" { + return errorsmod.Wrapf(ErrInvalidForwarding, "source port must be empty when unwind is set, got %s instead", msg.SourcePort) + } + if msg.SourceChannel != "" { + return errorsmod.Wrapf(ErrInvalidForwarding, "source channel must be empty when unwind is set, got %s instead", msg.SourceChannel) + } + return nil + } + + // Otherwise, we just do the usual validation of the port and channel identifiers. + if err := host.PortIdentifierValidator(msg.SourcePort); err != nil { + return errorsmod.Wrap(err, "invalid source port ID") + } + if err := host.ChannelIdentifierValidator(msg.SourceChannel); err != nil { + return errorsmod.Wrap(err, "invalid source channel ID") + } + return nil +} diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index b09992f57a2..a7d837ae741 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -59,10 +59,11 @@ func TestMsgTransferValidation(t *testing.T) { expError error }{ {"valid msg with base denom", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), nil}, + {"valid msg with unwind", types.NewMsgTransfer("", "", coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(true)), nil}, {"valid msg with trace hash", types.NewMsgTransfer(validPort, validChannel, ibcCoins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), nil}, {"multidenom", types.NewMsgTransfer(validPort, validChannel, coins.Add(ibcCoins...), sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), nil}, {"memo with forwarding path hops not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "memo", types.NewForwarding(false, validHop)), nil}, - {"memo with forwarding unwind set to true", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "memo", types.NewForwarding(true)), nil}, + {"memo with forwarding unwind set to true", types.NewMsgTransfer("", "", coins, sender, receiver, clienttypes.ZeroHeight(), 100, "memo", types.NewForwarding(true)), nil}, {"invalid ibc denom", types.NewMsgTransfer(validPort, validChannel, invalidIBCCoins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, {"too short port id", types.NewMsgTransfer(invalidShortPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), host.ErrInvalidID}, {"too long port id", types.NewMsgTransfer(invalidLongPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), host.ErrInvalidID}, @@ -86,6 +87,9 @@ func TestMsgTransferValidation(t *testing.T) { {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, types.Hop{PortId: invalidPort, ChannelId: validChannel})), host.ErrInvalidID}, {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, types.Hop{PortId: validPort, ChannelId: invalidChannel})), host.ErrInvalidID}, {"invalid forwarding info too many hops", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, generateHops(types.MaximumNumberOfForwardingHops+1)...)), types.ErrInvalidForwarding}, + {"unwind specified but source port is not empty", types.NewMsgTransfer(validPort, "", coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(true)), types.ErrInvalidForwarding}, + {"unwind specified but source channel is not empty", types.NewMsgTransfer("", validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(true)), types.ErrInvalidForwarding}, + {"unwind specified but more than one coin in the message", types.NewMsgTransfer("", "", coins.Add(sdk.NewCoin("atom", ibctesting.TestCoin.Amount)), sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(true)), ibcerrors.ErrInvalidCoins}, } for _, tc := range testCases { diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index e12173401fb..a7605bf306f 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -53,8 +53,8 @@ func (a TransferAuthorization) Accept(goCtx context.Context, msg proto.Message) return authz.AcceptResponse{}, errorsmod.Wrap(ibcerrors.ErrNotFound, "requested port and channel allocation does not exist") } - if !isAllowedForwarding(msgTransfer.Forwarding.Hops, a.Allocations[index].AllowedForwardingHops) { - return authz.AcceptResponse{}, errorsmod.Wrap(ErrInvalidForwarding, "not allowed forwarding hops") + if err := validateForwarding(msgTransfer.Forwarding, a.Allocations[index].AllowedForwarding); err != nil { + return authz.AcceptResponse{}, err } ctx := sdk.UnwrapSDKContext(goCtx) @@ -170,6 +170,19 @@ func isAllowedAddress(ctx sdk.Context, receiver string, allowedAddrs []string) b return false } +// validateForwarding performs the validation of forwarding info. +func validateForwarding(forwarding Forwarding, allowedForwarding AllowedForwarding) error { + if forwarding.Unwind && !allowedForwarding.AllowUnwind { + return errorsmod.Wrap(ErrInvalidForwarding, "not allowed unwind") + } + + if !isAllowedForwarding(forwarding.Hops, allowedForwarding.AllowedHops) { + return errorsmod.Wrap(ErrInvalidForwarding, "not allowed hops") + } + + return nil +} + // isAllowedForwarding returns whether the provided slice of Hop matches one of the allowed ones. func isAllowedForwarding(hops []Hop, allowed []Hops) bool { if len(hops) == 0 { diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index 0303482f7dc..f2cb16e6fd1 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -106,7 +106,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { func() { allowedList := []string{} transferAuthz.Allocations[0].AllowedPacketData = allowedList - transferAuthz.Allocations[0].AllowedForwardingHops = forwardingWithValidHop + transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = forwardingWithValidHop msgTransfer.Forwarding = types.NewForwarding(false, validHop) }, func(res authz.AcceptResponse, err error) { @@ -137,7 +137,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { func() { allowedList := []string{"*"} transferAuthz.Allocations[0].AllowedPacketData = allowedList - transferAuthz.Allocations[0].AllowedForwardingHops = forwardingWithValidHop + transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = forwardingWithValidHop msgTransfer.Forwarding = types.NewForwarding(false, validHop) }, func(res authz.AcceptResponse, err error) { @@ -285,7 +285,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { "success: allowed forwarding hops", func() { msgTransfer.Forwarding = types.NewForwarding(false, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}) - transferAuthz.Allocations[0].AllowedForwardingHops = []types.Hops{ + transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = []types.Hops{ { Hops: []types.Hop{ {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, @@ -302,7 +302,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { { "success: Allocation specify hops but msgTransfer does not have hops", func() { - transferAuthz.Allocations[0].AllowedForwardingHops = []types.Hops{ + transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = []types.Hops{ { Hops: []types.Hop{ {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, @@ -316,6 +316,17 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().True(res.Accept) }, }, + { + "success: Allocation allows unwind and msgTransfer specifies unwind", + func() { + transferAuthz.Allocations[0].AllowedForwarding.AllowUnwind = true + msgTransfer.Forwarding.Unwind = true + }, + func(res authz.AcceptResponse, err error) { + suite.Require().NoError(err) + suite.Require().True(res.Accept) + }, + }, { "failure: multidenom transfer spend limit is exceeded", func() { @@ -398,7 +409,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-3"}, ) - transferAuthz.Allocations[0].AllowedForwardingHops = []types.Hops{ + transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = []types.Hops{ { Hops: []types.Hop{ {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, @@ -419,7 +430,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, types.Hop{PortId: "3", ChannelId: "channel-3"}, ) - transferAuthz.Allocations[0].AllowedForwardingHops = []types.Hops{ + transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = []types.Hops{ { Hops: []types.Hop{ {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, @@ -452,7 +463,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}, ) - transferAuthz.Allocations[0].AllowedForwardingHops = []types.Hops{ + transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = []types.Hops{ { Hops: []types.Hop{ {PortId: ibctesting.MockPort, ChannelId: "channel-2"}, @@ -466,6 +477,18 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().False(res.Accept) }, }, + + { + "failure: unwind is not allowed", + func() { + msgTransfer.Forwarding.Unwind = true + transferAuthz.Allocations[0].AllowedForwarding.AllowUnwind = false + }, + func(res authz.AcceptResponse, err error) { + suite.Require().Error(err) + suite.Require().False(res.Accept) + }, + }, } for _, tc := range testCases { diff --git a/proto/ibc/applications/transfer/v1/authz.proto b/proto/ibc/applications/transfer/v1/authz.proto index ede9b6dda6c..dfa2399199c 100644 --- a/proto/ibc/applications/transfer/v1/authz.proto +++ b/proto/ibc/applications/transfer/v1/authz.proto @@ -23,9 +23,17 @@ message Allocation { // allow list of memo strings, an empty list prohibits all memo strings; // a list only with "*" permits any memo string repeated string allowed_packet_data = 5; + // Forwarding options that are allowed. + AllowedForwarding allowed_forwarding = 6 [(gogoproto.nullable) = false]; +} + +// AllowedForwarding defines which options are allowed for forwarding. +message AllowedForwarding { + // Whether to allow automatic unwinding of tokens to the original chain. + bool allow_unwind = 1; // a list of allowed source port ID/channel ID pairs through which the packet is allowed to be forwarded until final // destination - repeated Hops allowed_forwarding_hops = 6 [(gogoproto.nullable) = false]; + repeated Hops allowed_hops = 2 [(gogoproto.nullable) = false]; } // Hops represent a list of Hop From 9c5ae038c5e49052d61fe3d8234b880c6ba635da Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 25 Jun 2024 13:16:21 +0200 Subject: [PATCH 099/141] fix typo --- modules/apps/transfer/types/msgs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index 231bc108ddd..eafb6abd59e 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -113,7 +113,7 @@ func (msg MsgTransfer) ValidateBasic() error { if msg.Forwarding.Unwind { // When unwinding, we must have at most one token. if len(msg.GetCoins()) > 1 { - return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, "cannot unwind more that one token") + return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, "cannot unwind more than one token") } } From c2a6bc60f5d4c1a0d925cf7aba1718abcae6fec9 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 25 Jun 2024 16:13:42 +0200 Subject: [PATCH 100/141] remove unnecessary wrapping of function --- modules/apps/transfer/ibc_module.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 45a56ec6dc9..666d956c0e5 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -191,9 +191,7 @@ func (im IBCModule) OnRecvPacket( ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - defer func() { - events.EmitOnRecvPacketEvent(ctx, data, ack, ackErr) - }() + defer events.EmitOnRecvPacketEvent(ctx, data, ack, ackErr) data, ackErr = im.getICS20PacketData(ctx, packet.GetData(), packet.GetDestPort(), packet.GetDestChannel()) if ackErr != nil { From c3ccbfc10390617aeed4336ea2b123c23d3ab2a6 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 25 Jun 2024 16:45:16 +0200 Subject: [PATCH 101/141] Revert "remove unnecessary wrapping of function" This reverts commit c2a6bc60f5d4c1a0d925cf7aba1718abcae6fec9. --- modules/apps/transfer/ibc_module.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 666d956c0e5..45a56ec6dc9 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -191,7 +191,9 @@ func (im IBCModule) OnRecvPacket( ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) - defer events.EmitOnRecvPacketEvent(ctx, data, ack, ackErr) + defer func() { + events.EmitOnRecvPacketEvent(ctx, data, ack, ackErr) + }() data, ackErr = im.getICS20PacketData(ctx, packet.GetData(), packet.GetDestPort(), packet.GetDestChannel()) if ackErr != nil { From 53457766523ea5ef236755d07f7d839dd7b417f7 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 25 Jun 2024 17:03:26 +0200 Subject: [PATCH 102/141] fix usage of function --- e2e/tests/wasm/grandpa_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/tests/wasm/grandpa_test.go b/e2e/tests/wasm/grandpa_test.go index 845a5c7bfe8..8543fb5d4cb 100644 --- a/e2e/tests/wasm/grandpa_test.go +++ b/e2e/tests/wasm/grandpa_test.go @@ -154,7 +154,7 @@ func (s *GrandpaTestSuite) SetupTest() { channelOpts := ibc.DefaultChannelOpts() channelOpts.Version = transfertypes.V1 - s.SetupPath(ibc.DefaultClientOpts(), channelOpts) + s.SetupPaths(ibc.DefaultClientOpts(), channelOpts) } // TestMsgTransfer_Succeeds_GrandpaContract features From 74088ba6b7d3b31bfd287257ff577d99ae49b358 Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Tue, 25 Jun 2024 16:43:45 +0100 Subject: [PATCH 103/141] (chore) replace reflect.DeepEqual with slices.Equal (#6697) * Replace reflect.DeepEqual with slices.Equal * Nit formatting --- modules/apps/transfer/types/transfer_authorization.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index a7605bf306f..4dfe20eafb2 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -3,7 +3,6 @@ package types import ( "context" "math/big" - "reflect" "slices" "strings" @@ -189,8 +188,12 @@ func isAllowedForwarding(hops []Hop, allowed []Hops) bool { return true } + // We want to ensure that at least one of the Hops in "allowed" + // is equal to "hops". + // Note that we can't use slices.Contains() as that is a generic + // function that requires the type Hop to satisfy the "comparable" constraint. for _, allowedHops := range allowed { - if reflect.DeepEqual(hops, allowedHops.Hops) { + if slices.Equal(hops, allowedHops.Hops) { return true } } From 272c12bf96e43783fb09152415b7207b38287d5a Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Tue, 25 Jun 2024 19:02:41 +0200 Subject: [PATCH 104/141] chore: comment hop slicing for clarity (#6702) Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/keeper/forwarding.go | 1 + modules/apps/transfer/keeper/msg_server.go | 1 + 2 files changed, 2 insertions(+) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 1029d6369a8..09dd15ebd9d 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -16,6 +16,7 @@ import ( func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDataV2, packet channeltypes.Packet, receivedCoins sdk.Coins) error { var nextForwardingPath types.Forwarding if len(data.Forwarding.Hops) > 1 { + // remove the first hop since it has been completed (this chain has received the packet) nextForwardingPath = types.NewForwarding(false, data.Forwarding.Hops[1:]...) } diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 2be27e0f776..55202574157 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -81,6 +81,7 @@ func (k Keeper) unwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgT return nil, errorsmod.Wrap(types.ErrInvalidForwarding, "cannot unwind a native token") } var unwindHops []types.Hop + // remove the first hop in denom as it is the current port/channel on this chain for _, trace := range token.Denom.Trace[1:] { unwindHops = append(unwindHops, types.Hop{PortId: trace.PortId, ChannelId: trace.ChannelId}) //nolint: gosimple } From 4349a1d03f9399cd116362716908b4e2b2703d77 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 26 Jun 2024 09:29:22 +0200 Subject: [PATCH 105/141] chore: cleanup forwarding tests (#6691) * chore: cleanup forwarding tests * lint * fix --------- Co-authored-by: Nikolas De Giorgis Co-authored-by: Gjermund Garaba --- .../transfer/keeper/relay_forwarding_test.go | 818 ++++++------------ 1 file changed, 264 insertions(+), 554 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index c5bd15daa23..181d1299317 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -14,28 +14,65 @@ import ( ibctesting "github.com/cosmos/ibc-go/v8/testing" ) -func (suite *KeeperTestSuite) TestPathForwarding() { - amount := sdkmath.NewInt(100) +func (suite *KeeperTestSuite) setupForwardingPaths() (pathAtoB, pathBtoC *ibctesting.Path) { + pathAtoB = ibctesting.NewTransferPath(suite.chainA, suite.chainB) + pathBtoC = ibctesting.NewTransferPath(suite.chainB, suite.chainC) + pathAtoB.Setup() + pathBtoC.Setup() + return pathAtoB, pathBtoC +} - // setup - // 2 transfer channels between chain A and chain B - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() +type amountType int - path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path2.Setup() +const ( + escrow amountType = iota + balance +) + +func (suite *KeeperTestSuite) assertAmountOnChain(chain *ibctesting.TestChain, balanceType amountType, amount sdkmath.Int, denom string) { + var total sdk.Coin + switch balanceType { + case escrow: + total = chain.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(chain.GetContext(), denom) + case balance: + total = chain.GetSimApp().BankKeeper.GetBalance(chain.GetContext(), chain.SenderAccounts[0].SenderAccount.GetAddress(), denom) + default: + suite.Fail("invalid amountType %s", balanceType) + } + suite.Require().Equal(amount, total.Amount, fmt.Sprintf("Chain %s: got balance of %d, wanted %d", chain.Name(), total.Amount, amount)) +} - coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) +// TestStoredForwardedPacketAndEscrowAfterFirstHop tests that the forwarded packet +// from chain A to chain B is stored after when the packet is received on chain B +// and then forwarded to chain C, and checks the balance of the escrow accounts +// in chain A nad B. +func (suite *KeeperTestSuite) TestStoredForwardedPacketAndEscrowAfterFirstHop() { + /* + Given the following topology: + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-0) chain A + stake transfer/channel-0/stake transfer/channel-0/transfer/channel-0/stake + We want to trigger: + 1. A sends B over channel-0. + 2. Receive on B. + At this point we want to assert: + A: escrowA = amount,stake AND packet A to B is stored in forwarded packet + B: escrowB = amount,transfer/channel-0/stake + */ + + amount := sdkmath.NewInt(100) + pathAtoB, pathBtoC := suite.setupForwardingPaths() + + coin := ibctesting.TestCoin sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainA.SenderAccounts[1].SenderAccount + receiver := suite.chainC.SenderAccounts[0].SenderAccount forwarding := types.NewForwarding(false, types.Hop{ - PortId: path2.EndpointA.ChannelConfig.PortID, - ChannelId: path2.EndpointA.ChannelID, + PortId: pathBtoC.EndpointA.ChannelConfig.PortID, + ChannelId: pathBtoC.EndpointA.ChannelID, }) transferMsg := types.NewMsgTransfer( - path1.EndpointA.ChannelConfig.PortID, - path1.EndpointA.ChannelID, + pathAtoB.EndpointA.ChannelConfig.PortID, + pathAtoB.EndpointA.ChannelID, sdk.NewCoins(coin), sender.GetAddress().String(), receiver.GetAddress().String(), @@ -51,49 +88,61 @@ func (suite *KeeperTestSuite) TestPathForwarding() { suite.Require().NoError(err) suite.Require().NotNil(packet) - err = path1.EndpointB.UpdateClient() + err = pathAtoB.EndpointB.UpdateClient() suite.Require().NoError(err) - result, err = path1.EndpointB.RecvPacketWithResult(packet) + result, err = pathAtoB.EndpointB.RecvPacketWithResult(packet) suite.Require().NoError(err) suite.Require().NotNil(result) - forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, packet.Sequence) + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID, packet.Sequence) suite.Require().True(found) suite.Require().Equal(packet, forwardedPacket) + + suite.assertAmountOnChain(suite.chainA, escrow, amount, sdk.DefaultBondDenom) + + // denom path: transfer/channel-0 + denom := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID)) + suite.assertAmountOnChain(suite.chainB, escrow, amount, denom.IBCDenom()) } -func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { - amount := sdkmath.NewInt(100) +// TestSuccessfulPathForwarding tests a successful transfer from A to C through B. +func (suite *KeeperTestSuite) TestSuccessfulForward() { /* - Given the following topolgy: - chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A - stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake + Given the following topology: + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-0) chain C + stake transfer/channel-0/stake transfer/channel-0/transfer/channel-0/stake We want to trigger: - 1. A sends B over channel0. - 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions + 1. A sends B over channel-0. + 2. Receive on B. + 2.1 B sends C over channel-1 + 3. Receive on C. At this point we want to assert: - A: escrowA = amount,denom - B: escrowB = amount,transfer/channel-0/denom + A: escrowA = amount,stake + B: escrowB = amount,transfer/channel-0/denom + C: finalReceiver = amount,transfer/channel-0/transfer/channel-0/denom */ + amount := sdkmath.NewInt(100) + path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) path1.Setup() - path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) path2.Setup() - coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + + coinOnA := ibctesting.TestCoin sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainA.SenderAccounts[1].SenderAccount + receiver := suite.chainC.SenderAccounts[0].SenderAccount forwarding := types.NewForwarding(false, types.Hop{ - PortId: path2.EndpointB.ChannelConfig.PortID, - ChannelId: path2.EndpointB.ChannelID, + PortId: path2.EndpointA.ChannelConfig.PortID, + ChannelId: path2.EndpointA.ChannelID, }) transferMsg := types.NewMsgTransfer( path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, - sdk.NewCoins(coin), + sdk.NewCoins(coinOnA), sender.GetAddress().String(), receiver.GetAddress().String(), clienttypes.ZeroHeight(), @@ -105,255 +154,216 @@ func (suite *KeeperTestSuite) TestEscrowsAreSetAfterForwarding() { suite.Require().NoError(err) // message committed // parse the packet from result events and recv packet on chainB - packet, err := ibctesting.ParsePacketFromEvents(result.Events) + packetFromAtoB, err := ibctesting.ParsePacketFromEvents(result.Events) suite.Require().NoError(err) - suite.Require().NotNil(packet) + suite.Require().NotNil(packetFromAtoB) err = path1.EndpointB.UpdateClient() suite.Require().NoError(err) - result, err = path1.EndpointB.RecvPacketWithResult(packet) + result, err = path1.EndpointB.RecvPacketWithResult(packetFromAtoB) suite.Require().NoError(err) suite.Require().NotNil(result) - totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) + // Check that Escrow A has amount + suite.assertAmountOnChain(suite.chainA, escrow, amount, sdk.DefaultBondDenom) // denom path: transfer/channel-0 denom := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + suite.assertAmountOnChain(suite.chainB, escrow, amount, denom.IBCDenom()) - // Check that Escrow B has amount - coin = sdk.NewCoin(denom.IBCDenom(), amount) - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) -} - -// This test is probably overcomplicated. Could have used RecvPacketWithResult directly. -func (suite *KeeperTestSuite) TestHappyPathForwarding() { - amount := sdkmath.NewInt(100) - /* - Given the following topolgy: - chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain A - stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake - We want to trigger: - 1. A sends B over channel0. - 2. B onRecv . 2.1(B sends A over channel1) Atomic Actions - At this point we want to assert: - A: escrowA = amount,denom - B: escrowB = amount,transfer/channel-0/denom - 3. A OnRecv - At this point we want to assert: - C: finalReceiver = amount,transfer/channel-1/transfer/channel-0/denom - */ - - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() - - path2 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path2.Setup() - - // transfer/channel-1/transfer/channel-0/denom - denomABA := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID), types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) - - // Check that initially the final receiver address has 0 ABA coins - coin := sdk.NewCoin(denomABA.IBCDenom(), amount) - preCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(0), preCoinOnA.Amount, "final receiver has not zero balance") + packetFromBtoC, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetFromBtoC) - coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) - sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainA.SenderAccounts[1].SenderAccount - forwarding := types.NewForwarding(false, types.Hop{ - PortId: path2.EndpointB.ChannelConfig.PortID, - ChannelId: path2.EndpointB.ChannelID, - }) + err = path2.EndpointA.UpdateClient() + suite.Require().NoError(err) - transferMsg := types.NewMsgTransfer( - path1.EndpointA.ChannelConfig.PortID, - path1.EndpointA.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - clienttypes.ZeroHeight(), - suite.chainA.GetTimeoutTimestamp(), "", - forwarding, - ) + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) - result, err := suite.chainA.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed + // B should have stored the forwarded packet. + _, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), packetFromBtoC.SourcePort, packetFromBtoC.SourceChannel, packetFromBtoC.Sequence) + suite.Require().True(found, "Chain B should have stored the forwarded packet") - // parse the packet from result events and recv packet on chainB - packet, err := ibctesting.ParsePacketFromEvents(result.Events) + result, err = path2.EndpointB.RecvPacketWithResult(packetFromBtoC) suite.Require().NoError(err) - suite.Require().NotNil(packet) + suite.Require().NotNil(result) - forwardingPacketData := types.NewForwardingPacketData("", forwarding.Hops...) - denom := types.Denom{Base: sdk.DefaultBondDenom} - data := types.NewFungibleTokenPacketDataV2( - []types.Token{ - { - Denom: denom, - Amount: amount.String(), - }, - }, sender.GetAddress().String(), receiver.GetAddress().String(), "", forwardingPacketData) - packetRecv := channeltypes.NewPacket(data.GetBytes(), 2, path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, clienttypes.ZeroHeight(), suite.chainA.GetTimeoutTimestamp()) + // transfer/channel-0/transfer/channel-0/denom + // Check that the final receiver has received the expected tokens. + denomABC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID), types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + // Check that the final receiver has received the expected tokens. + suite.assertAmountOnChain(suite.chainC, balance, amount, denomABC.IBCDenom()) - err = suite.chainB.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packetRecv, data) - // If forwarding has been triggered then the async must be true. - suite.Require().Nil(err) + successAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + successAckBz := channeltypes.CommitAcknowledgement(successAck.Acknowledgement()) + ackOnC := suite.chainC.GetAcknowledgement(packetFromBtoC) + suite.Require().Equal(successAckBz, ackOnC) - // denomTrace path: transfer/channel-0 - denom = types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + // Ack back to B + err = path2.EndpointB.UpdateClient() + suite.Require().NoError(err) - // Check that Escrow B has amount - coin = sdk.NewCoin(denom.IBCDenom(), amount) - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) - suite.Require().Equal(amount, totalEscrowChainB.Amount, "escrow account on B is different than amount") + err = path2.EndpointA.AcknowledgePacket(packetFromBtoC, successAck.Acknowledgement()) + suite.Require().NoError(err) - // Check that Escrow A has amount - coin = sdk.NewCoin(sdk.DefaultBondDenom, amount) - totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - suite.Require().Equal(amount, totalEscrowChainA.Amount, "escrow account on A is different than amount") + ackOnB := suite.chainB.GetAcknowledgement(packetFromAtoB) + suite.Require().Equal(successAckBz, ackOnB) - // Now during the onRecvPacket above a new msgTransfer has been sent - // We need to receive the packet on the final hand + // B should now have deleted the forwarded packet. + _, found = suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), packetFromBtoC.SourcePort, packetFromBtoC.SourceChannel, packetFromBtoC.Sequence) + suite.Require().False(found, "Chain B should have deleted the forwarded packet") - packet, err = ibctesting.ParsePacketFromEvents(result.Events) + // Ack back to A + err = path1.EndpointA.UpdateClient() suite.Require().NoError(err) - suite.Require().NotNil(packet) - data = types.NewFungibleTokenPacketDataV2( - []types.Token{ - { - Denom: denom, - Amount: amount.String(), - }, - }, types.GetForwardAddress(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID).String(), receiver.GetAddress().String(), "", types.ForwardingPacketData{}) - packetRecv = channeltypes.NewPacket(data.GetBytes(), 3, path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID, path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID, clienttypes.NewHeight(1, 100), 0) - - // execute onRecvPacket, when chaninA receives the tokens the escrow amount on B should increase to amount - err = suite.chainA.GetSimApp().TransferKeeper.OnRecvPacket(suite.chainA.GetContext(), packetRecv, data) + err = path1.EndpointA.AcknowledgePacket(packetFromAtoB, successAck.Acknowledgement()) suite.Require().NoError(err) - - // Check that the final receiver has received the expected tokens. - coin = sdk.NewCoin(denomABA.IBCDenom(), amount) - postCoinOnA := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccounts[1].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnA.Amount, "final receiver balance has not increased") } -// Simplification of the above test. -func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { - amount := sdkmath.NewInt(100) +// TestSuccessfulUnwind tests unwinding of tokens sent from A -> B -> C by +// forwarding the tokens back from C -> B -> A. +func (suite *KeeperTestSuite) TestSuccessfulUnwind() { /* Given the following topolgy: - chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain C - stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-0) chain C + stake transfer/channel-0/stake transfer/channel-0/transfer/channel-0/stake We want to trigger: - 1. Single transfer forwarding token from A -> B -> C - 2. B onRecv . 2.1(B sends C over channel1) Atomic Actions - At this point we want to assert: - A: escrowA = amount,denom - B: escrowB = amount,transfer/channel-0/denom + 1. Send vouchers from C to B. + 2. Receive on B. + 2.1 B sends B over channel-0 + 3. Receive on A. + At this point we want to assert: + - escrow on B and C is zero + - receiver on A has amount,stake */ - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() + amount := sdkmath.NewInt(100) + + pathAtoB, pathBtoC := suite.setupForwardingPaths() + + sender := suite.chainC.SenderAccount + receiver := suite.chainA.SenderAccount + + // set sender and escrow accounts with the right balances to set up an initial state + // that should have been the same as sending token from A -> B -> C + denomA := types.NewDenom(sdk.DefaultBondDenom) + denomAB := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID)) + denomABC := types.NewDenom(sdk.DefaultBondDenom, append([]types.Trace{types.NewTrace(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID)}, denomAB.Trace...)...) + + coinOnA := sdk.NewCoin(denomA.IBCDenom(), amount) + err := suite.chainA.GetSimApp().BankKeeper.MintCoins(suite.chainA.GetContext(), types.ModuleName, sdk.NewCoins(coinOnA)) + suite.Require().NoError(err) + escrowAddressAtoB := types.GetEscrowAddress(pathAtoB.EndpointA.ChannelConfig.PortID, pathAtoB.EndpointA.ChannelID) + err = suite.chainA.GetSimApp().BankKeeper.MintCoins(suite.chainA.GetContext(), types.ModuleName, sdk.NewCoins(coinOnA)) + suite.Require().NoError(err) + err = suite.chainA.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainA.GetContext(), types.ModuleName, escrowAddressAtoB, sdk.NewCoins(coinOnA)) + suite.Require().NoError(err) + suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), coinOnA) + + coinOnB := sdk.NewCoin(denomAB.IBCDenom(), amount) + err = suite.chainB.GetSimApp().BankKeeper.MintCoins(suite.chainB.GetContext(), types.ModuleName, sdk.NewCoins(coinOnB)) + suite.Require().NoError(err) + escrowAddressBtoC := types.GetEscrowAddress(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID) + err = suite.chainB.GetSimApp().BankKeeper.MintCoins(suite.chainB.GetContext(), types.ModuleName, sdk.NewCoins(coinOnB)) + suite.Require().NoError(err) + err = suite.chainB.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainB.GetContext(), types.ModuleName, escrowAddressBtoC, sdk.NewCoins(coinOnB)) + suite.Require().NoError(err) + suite.chainB.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainB.GetContext(), coinOnB) + suite.chainB.GetSimApp().TransferKeeper.SetDenom(suite.chainB.GetContext(), denomAB) + + coinOnC := sdk.NewCoin(denomABC.IBCDenom(), amount) + err = suite.chainC.GetSimApp().BankKeeper.MintCoins(suite.chainC.GetContext(), types.ModuleName, sdk.NewCoins(coinOnC)) + suite.Require().NoError(err) + err = suite.chainC.GetSimApp().BankKeeper.SendCoinsFromModuleToAccount(suite.chainC.GetContext(), types.ModuleName, sender.GetAddress(), sdk.NewCoins(coinOnC)) + suite.Require().NoError(err) + suite.chainC.GetSimApp().TransferKeeper.SetDenom(suite.chainC.GetContext(), denomABC) + + originalABalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), receiver.GetAddress(), coinOnA.Denom) - path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) - path2.Setup() - coinOnA := sdk.NewCoin(sdk.DefaultBondDenom, amount) - sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainC.SenderAccounts[0].SenderAccount forwarding := types.NewForwarding(false, types.Hop{ - PortId: path2.EndpointA.ChannelConfig.PortID, - ChannelId: path2.EndpointA.ChannelID, + PortId: pathAtoB.EndpointB.ChannelConfig.PortID, + ChannelId: pathAtoB.EndpointB.ChannelID, }) transferMsg := types.NewMsgTransfer( - path1.EndpointA.ChannelConfig.PortID, - path1.EndpointA.ChannelID, - sdk.NewCoins(coinOnA), + pathBtoC.EndpointB.ChannelConfig.PortID, + pathBtoC.EndpointB.ChannelID, + sdk.NewCoins(coinOnC), sender.GetAddress().String(), receiver.GetAddress().String(), clienttypes.ZeroHeight(), - suite.chainA.GetTimeoutTimestamp(), "", + suite.chainC.GetTimeoutTimestamp(), "", forwarding, ) - result, err := suite.chainA.SendMsgs(transferMsg) + result, err := suite.chainC.SendMsgs(transferMsg) suite.Require().NoError(err) // message committed + // Sender's balance for vouchers is 0 + suite.assertAmountOnChain(suite.chainC, balance, sdkmath.NewInt(0), denomABC.IBCDenom()) + // parse the packet from result events and recv packet on chainB - packetFromAtoB, err := ibctesting.ParsePacketFromEvents(result.Events) + packetFromCtoB, err := ibctesting.ParsePacketFromEvents(result.Events) suite.Require().NoError(err) - suite.Require().NotNil(packetFromAtoB) + suite.Require().NotNil(packetFromCtoB) - err = path1.EndpointB.UpdateClient() + err = pathBtoC.EndpointA.UpdateClient() suite.Require().NoError(err) - result, err = path1.EndpointB.RecvPacketWithResult(packetFromAtoB) + result, err = pathBtoC.EndpointA.RecvPacketWithResult(packetFromCtoB) suite.Require().NoError(err) suite.Require().NotNil(result) - // Check that Escrow A has amount - totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coinOnA.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) - - // denomTrace path: transfer/channel-0 - denomTrace := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) - - // Check that Escrow B has amount - coinOnB := sdk.NewCoin(denomTrace.IBCDenom(), amount) - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coinOnB.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - - packetFromBtoC, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packetFromBtoC) + // Vouchers have been burned on chain B + suite.assertAmountOnChain(suite.chainB, escrow, sdkmath.NewInt(0), denomAB.IBCDenom()) - err = path2.EndpointA.UpdateClient() + // parse the packet from result events and recv packet on chainA + packetFromBtoA, err := ibctesting.ParsePacketFromEvents(result.Events) suite.Require().NoError(err) + suite.Require().NotNil(packetFromBtoA) - err = path2.EndpointB.UpdateClient() + err = pathAtoB.EndpointA.UpdateClient() suite.Require().NoError(err) - // B should now have deleted the forwarded packet. - _, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), packetFromAtoB.DestinationPort, packetFromAtoB.DestinationChannel, packetFromAtoB.Sequence) - suite.Require().False(found, "Chain B should have deleted its forwarded packet") + // B should have stored the forwarded packet. + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), packetFromBtoA.SourcePort, packetFromBtoA.SourceChannel, packetFromBtoA.Sequence) + suite.Require().True(found) + suite.Require().Equal(packetFromCtoB, forwardedPacket) - result, err = path2.EndpointB.RecvPacketWithResult(packetFromBtoC) + result, err = pathAtoB.EndpointA.RecvPacketWithResult(packetFromBtoA) suite.Require().NoError(err) suite.Require().NotNil(result) - // transfer/channel-1/transfer/channel-0/denom - denomTraceABC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID), types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) - - // Check that the final receiver has received the expected tokens. - coinOnC := sdk.NewCoin(denomTraceABC.IBCDenom(), amount) - balanceOnC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), receiver.GetAddress(), coinOnC.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), balanceOnC.Amount, "final receiver balance has not increased") - successAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) successAckBz := channeltypes.CommitAcknowledgement(successAck.Acknowledgement()) - ackOnC := suite.chainC.GetAcknowledgement(packetFromBtoC) - suite.Require().Equal(successAckBz, ackOnC) // Ack back to B - err = path2.EndpointB.UpdateClient() + err = pathAtoB.EndpointB.UpdateClient() suite.Require().NoError(err) - err = path2.EndpointA.AcknowledgePacket(packetFromBtoC, successAck.Acknowledgement()) + err = pathAtoB.EndpointB.AcknowledgePacket(packetFromBtoA, successAck.Acknowledgement()) suite.Require().NoError(err) - ackOnB := suite.chainB.GetAcknowledgement(packetFromAtoB) + ackOnB := suite.chainB.GetAcknowledgement(packetFromCtoB) suite.Require().Equal(successAckBz, ackOnB) - // Ack back to A - err = path1.EndpointA.UpdateClient() + // Ack back to C + err = pathBtoC.EndpointB.UpdateClient() suite.Require().NoError(err) - err = path1.EndpointA.AcknowledgePacket(packetFromAtoB, successAck.Acknowledgement()) + err = pathBtoC.EndpointB.AcknowledgePacket(packetFromCtoB, successAck.Acknowledgement()) suite.Require().NoError(err) + + // Check that B deleted the forwarded packet. + _, found = suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), packetFromBtoA.SourcePort, packetFromBtoA.SourceChannel, packetFromBtoA.Sequence) + suite.Require().False(found, "chain B should have deleted the forwarded packet mapping") + + // Check that tokens have been unescrowed and receiver got the tokens + suite.assertAmountOnChain(suite.chainA, escrow, sdkmath.NewInt(0), denomA.IBCDenom()) + suite.assertAmountOnChain(suite.chainA, balance, originalABalance.Amount.Add(amount), denomA.IBCDenom()) } // TestAcknowledgementFailureWithMiddleChainAsNativeTokenSource tests a failure in the last hop where the @@ -361,7 +371,6 @@ func (suite *KeeperTestSuite) TestSimplifiedHappyPathForwarding() { // token has been sent to chain C, and the multi-hop transfer from C -> B -> A has chain B being the source of // the token both when receiving and forwarding (sending). func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeTokenSource() { - amount := sdkmath.NewInt(100) /* Given the following topology: chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-0) chain C @@ -374,19 +383,17 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeT 3. Verify all the balances are updated as expected */ - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() + amount := sdkmath.NewInt(100) - path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) - path2.Setup() + pathAtoB, pathBtoC := suite.setupForwardingPaths() - coinOnB := sdk.NewCoin(sdk.DefaultBondDenom, amount) + coinOnB := ibctesting.TestCoin setupSender := suite.chainB.SenderAccounts[0].SenderAccount setupReceiver := suite.chainC.SenderAccounts[0].SenderAccount setupTransferMsg := types.NewMsgTransfer( - path2.EndpointA.ChannelConfig.PortID, - path2.EndpointA.ChannelID, + pathBtoC.EndpointA.ChannelConfig.PortID, + pathBtoC.EndpointA.ChannelID, sdk.NewCoins(coinOnB), setupSender.GetAddress().String(), setupReceiver.GetAddress().String(), @@ -403,20 +410,20 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeT suite.Require().NoError(err) suite.Require().NotNil(packetFromBToC) - err = path2.EndpointB.UpdateClient() + err = pathBtoC.EndpointB.UpdateClient() suite.Require().NoError(err) - result, err = path2.EndpointB.RecvPacketWithResult(packetFromBToC) + result, err = pathBtoC.EndpointB.RecvPacketWithResult(packetFromBToC) suite.Require().NoError(err) suite.Require().NotNil(result) // Check that EscrowBtoC has amount - escrowAddressBtoC := types.GetEscrowAddress(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID) + escrowAddressBtoC := types.GetEscrowAddress(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID) escrowBalancBtoC := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), escrowAddressBtoC, coinOnB.GetDenom()) suite.Require().Equal(amount, escrowBalancBtoC.Amount) // Check that receiver has the expected tokens - denomOnC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID)) + denomOnC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID)) coinOnC := sdk.NewCoin(denomOnC.IBCDenom(), amount) balanceOnC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), setupReceiver.GetAddress(), coinOnC.GetDenom()) suite.Require().Equal(amount, balanceOnC.Amount) @@ -426,13 +433,13 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeT receiver := suite.chainA.SenderAccounts[0].SenderAccount forwarding := types.NewForwarding(false, types.Hop{ - PortId: path1.EndpointB.ChannelConfig.PortID, - ChannelId: path1.EndpointB.ChannelID, + PortId: pathAtoB.EndpointB.ChannelConfig.PortID, + ChannelId: pathAtoB.EndpointB.ChannelID, }) forwardTransfer := types.NewMsgTransfer( - path2.EndpointB.ChannelConfig.PortID, - path2.EndpointB.ChannelID, + pathBtoC.EndpointB.ChannelConfig.PortID, + pathBtoC.EndpointB.ChannelID, sdk.NewCoins(coinOnC), sender.GetAddress().String(), receiver.GetAddress().String(), @@ -454,10 +461,10 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeT suite.Require().NoError(err) suite.Require().NotNil(packetFromCtoB) - err = path2.EndpointA.UpdateClient() + err = pathBtoC.EndpointA.UpdateClient() suite.Require().NoError(err) - result, err = path2.EndpointA.RecvPacketWithResult(packetFromCtoB) + result, err = pathBtoC.EndpointA.RecvPacketWithResult(packetFromCtoB) suite.Require().NoError(err) suite.Require().NotNil(result) @@ -465,11 +472,11 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeT escrowBalancBtoC = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), escrowAddressBtoC, coinOnB.GetDenom()) suite.Require().Equal(sdkmath.NewInt(0), escrowBalancBtoC.Amount) - escrowAddressBtoA := types.GetEscrowAddress(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID) + escrowAddressBtoA := types.GetEscrowAddress(pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID) escrowBalanceBtoA := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), escrowAddressBtoA, coinOnB.GetDenom()) suite.Require().Equal(amount, escrowBalanceBtoA.Amount) - forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packetFromCtoB.Sequence) + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID, packetFromCtoB.Sequence) suite.Require().True(found) suite.Require().Equal(packetFromCtoB, forwardedPacket) @@ -484,10 +491,10 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeT ReceiveEnabled: false, }) - err = path1.EndpointA.UpdateClient() + err = pathAtoB.EndpointA.UpdateClient() suite.Require().NoError(err) - result, err = path1.EndpointA.RecvPacketWithResult(packetFromBtoA) + result, err = pathAtoB.EndpointA.RecvPacketWithResult(packetFromBtoA) suite.Require().NoError(err) suite.Require().NotNil(result) @@ -498,10 +505,10 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeT ackOnA := suite.chainA.GetAcknowledgement(packetFromBtoA) suite.Require().Equal(errorAckCommitmentOnA, ackOnA) - err = path1.EndpointB.UpdateClient() + err = pathAtoB.EndpointB.UpdateClient() suite.Require().NoError(err) - err = path1.EndpointB.AcknowledgePacket(packetFromBtoA, errorAckOnA.Acknowledgement()) + err = pathAtoB.EndpointB.AcknowledgePacket(packetFromBtoA, errorAckOnA.Acknowledgement()) suite.Require().NoError(err) errorAckOnB := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketFailed) @@ -521,10 +528,10 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeT suite.Require().Equal(sdkmath.NewInt(0), balanceOnC.Amount) // Propagate the error to C - err = path2.EndpointB.UpdateClient() + err = pathBtoC.EndpointB.UpdateClient() suite.Require().NoError(err) - err = path2.EndpointB.AcknowledgePacket(packetFromCtoB, errorAckOnB.Acknowledgement()) + err = pathBtoC.EndpointB.AcknowledgePacket(packetFromCtoB, errorAckOnB.Acknowledgement()) suite.Require().NoError(err) // Check that everything has been reverted @@ -538,37 +545,34 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNativeT // is not source of the token when receiving or sending the packet. In other words, the middle chain's is sent // (and forwarding) someone else's native token (in this case chain C). func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNotBeingTokenSource() { - amount := sdkmath.NewInt(100) /* Given the following topology: - chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-0) chain C - stake transfer/channel-0/stake transfer/channel-0/transfer/channel-0/stake + chain A (channel 0) <- (channel-0) chain B (channel-1) <- (channel-0) chain C + transfer/channel-0/transfer/channel-1/stake transfer/channel-1/stake stake We want to trigger: 1. Single transfer forwarding token from C -> B -> A - 1.1 The ack fails on the last hop - 1.2 Propagate the error back to C + 1.1 The ack fails on the last hop + 1.2 Propagate the error back to C 2. Verify all the balances are updated as expected */ - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() + amount := sdkmath.NewInt(100) - path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) - path2.Setup() + pathAtoB, pathBtoC := suite.setupForwardingPaths() // Now we start the transfer from C -> B -> A - coinOnC := sdk.NewCoin(sdk.DefaultBondDenom, amount) + coinOnC := ibctesting.TestCoin sender := suite.chainC.SenderAccounts[0].SenderAccount receiver := suite.chainA.SenderAccounts[0].SenderAccount forwarding := types.NewForwarding(false, types.Hop{ - PortId: path1.EndpointB.ChannelConfig.PortID, - ChannelId: path1.EndpointB.ChannelID, + PortId: pathAtoB.EndpointB.ChannelConfig.PortID, + ChannelId: pathAtoB.EndpointB.ChannelID, }) forwardTransfer := types.NewMsgTransfer( - path2.EndpointB.ChannelConfig.PortID, - path2.EndpointB.ChannelID, + pathBtoC.EndpointB.ChannelConfig.PortID, + pathBtoC.EndpointB.ChannelID, sdk.NewCoins(coinOnC), sender.GetAddress().String(), receiver.GetAddress().String(), @@ -591,20 +595,18 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNotBein suite.Require().NoError(err) suite.Require().NotNil(packetFromCtoB) - err = path2.EndpointA.UpdateClient() + err = pathBtoC.EndpointA.UpdateClient() suite.Require().NoError(err) - result, err = path2.EndpointA.RecvPacketWithResult(packetFromCtoB) + result, err = pathBtoC.EndpointA.RecvPacketWithResult(packetFromCtoB) suite.Require().NoError(err) suite.Require().NotNil(result) // Check that Escrow B has amount - denomOnB := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointA.ChannelConfig.PortID, path2.EndpointA.ChannelID)) - coinOnB := sdk.NewCoin(denomOnB.IBCDenom(), amount) - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coinOnB.GetDenom()) - suite.Require().Equal(amount, totalEscrowChainB.Amount) + denomOnB := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(pathBtoC.EndpointA.ChannelConfig.PortID, pathBtoC.EndpointA.ChannelID)) + suite.assertAmountOnChain(suite.chainB, escrow, amount, denomOnB.IBCDenom()) - forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packetFromCtoB.Sequence) + forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID, packetFromCtoB.Sequence) suite.Require().True(found) suite.Require().Equal(packetFromCtoB, forwardedPacket) @@ -619,10 +621,10 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNotBein ReceiveEnabled: false, }) - err = path1.EndpointA.UpdateClient() + err = pathAtoB.EndpointA.UpdateClient() suite.Require().NoError(err) - result, err = path1.EndpointA.RecvPacketWithResult(packetFromBtoA) + result, err = pathAtoB.EndpointA.RecvPacketWithResult(packetFromBtoA) suite.Require().NoError(err) suite.Require().NotNil(result) @@ -633,10 +635,10 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNotBein ackOnA := suite.chainA.GetAcknowledgement(packetFromBtoA) suite.Require().Equal(errorAckCommitmentOnA, ackOnA) - err = path1.EndpointB.UpdateClient() + err = pathAtoB.EndpointB.UpdateClient() suite.Require().NoError(err) - err = path1.EndpointB.AcknowledgePacket(packetFromBtoA, errorAckOnA.Acknowledgement()) + err = pathAtoB.EndpointB.AcknowledgePacket(packetFromBtoA, errorAckOnA.Acknowledgement()) suite.Require().NoError(err) errorAckOnB := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketFailed) @@ -645,316 +647,24 @@ func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsNotBein suite.Require().Equal(errorAckCommitmentOnB, ackOnB) // Check that escrow has been burnt on B - totalEscrowChainB = suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coinOnB.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(0), totalEscrowChainB.Amount) + suite.assertAmountOnChain(suite.chainB, escrow, sdkmath.NewInt(0), denomOnB.IBCDenom()) // Check the status of account on chain C before executing ack. balanceOnC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), sender.GetAddress(), coinOnC.GetDenom()) suite.Require().Equal(balanceOnCBefore.SubAmount(amount).Amount, balanceOnC.Amount) // Propagate the error to C - err = path2.EndpointB.UpdateClient() + err = pathBtoC.EndpointB.UpdateClient() suite.Require().NoError(err) - err = path2.EndpointB.AcknowledgePacket(packetFromCtoB, errorAckOnB.Acknowledgement()) + err = pathBtoC.EndpointB.AcknowledgePacket(packetFromCtoB, errorAckOnB.Acknowledgement()) suite.Require().NoError(err) // Check that everything has been reverted // // Check the token has been returned to the sender on C - totalEscrowChainC = suite.chainC.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainC.GetContext(), coinOnC.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(0), totalEscrowChainC.Amount) - - balanceOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), sender.GetAddress(), coinOnC.GetDenom()) - suite.Require().Equal(balanceOnCBefore.Amount, balanceOnC.Amount, "final receiver balance has not increased") -} - -// This tests a failure in the last hop where the middle chain as IBC denom source when receiving and sending the packet. -// In other words, an IBC denom from the middle chain's sent to chain C, and the multi-hop -// transfer from C -> B -> A has chain B being the source of the token both when receiving and forwarding (sending). -// Previously referenced as Acknowledgement Failure Scenario 5 -func (suite *KeeperTestSuite) TestAcknowledgementFailureWithMiddleChainAsIBCTokenSource() { - amount := sdkmath.NewInt(100) - /* - Given the following topolgy: - chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-1) chain C - stake transfer/channel-0/stake transfer/channel-1/transfer/channel-0/stake - We want to trigger: - 0. A sends B over channel0 [path1] - 1. B sends C over channel1 [path2]. - 2. C recvs - This represent the checkpoint we will need to verify at the of the test - 3. C --> [path2] B --> [path1] A. - 4. OnRecv in B works properly and trigger the packet forwarding to A - 5. Modify the balance of escrowA to cause an error during the onRecv - 6. OnRecv on A fails. Error Ack is written in A, relayed to B and finally to C. - At this point we want to assert: - Everything has been reverted at checkpoint values. - - C has amount of transfer/channel-1/transfer/channel-0/stake - - B totalEscrow has amount of transfer/channel-0/stake - */ - - // Testing Topology - - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() - - path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) - path2.Setup() - - // First we want to execute 0. - - coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) - sender := suite.chainA.SenderAccounts[0].SenderAccount - receiver := suite.chainB.SenderAccounts[0].SenderAccount - - transferMsg := types.NewMsgTransfer( - path1.EndpointA.ChannelConfig.PortID, - path1.EndpointA.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", - types.Forwarding{}, - ) - - result, err := suite.chainA.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - // parse the packet from result events and recv packet on chainB - packetFromAtoB, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packetFromAtoB) - - err = path1.EndpointB.UpdateClient() - suite.Require().NoError(err) - - result, err = path1.EndpointB.RecvPacketWithResult(packetFromAtoB) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - // Check that Escrow B has amount - totalEscrowChainA := suite.chainA.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainA.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainA.Amount) - - // transfer/channel-0/denom - denomAB := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) - - // Check the coins have been received on B - coin = sdk.NewCoin(denomAB.IBCDenom(), amount) - postCoinOnB := suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnB.Amount, "final receiver balance has not increased") - - // A --> B Simple transfer happened properly. - - // Now we want to trigger B -> C - sender = suite.chainB.SenderAccounts[0].SenderAccount - receiver = suite.chainC.SenderAccounts[0].SenderAccount - - transferMsg = types.NewMsgTransfer( - path2.EndpointA.ChannelConfig.PortID, - path2.EndpointA.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - suite.chainA.GetTimeoutHeight(), - 0, "", - types.Forwarding{}, - ) - - result, err = suite.chainB.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - // parse the packet from result events and recv packet on chainB - packetFromBtoC, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packetFromBtoC) - - err = path2.EndpointB.UpdateClient() - suite.Require().NoError(err) - - result, err = path2.EndpointB.RecvPacketWithResult(packetFromBtoC) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - // Check that Escrow B has amount - totalEscrowChainB := suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - - // transfer/channel-1/transfer/channel-0/denom - denomABC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID), types.NewTrace(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID)) - - // Check the coins have been received on C - coin = sdk.NewCoin(denomABC.IBCDenom(), amount) - postCoinOnC := suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnC.Amount, "final receiver balance has not increased") - - // B -> C Simple transfer happened properly. - - // Now we want to trigger C -> B -> A - // The coin we want to send out is exactly the one we received on C - coin = sdk.NewCoin(denomABC.IBCDenom(), amount) - - sender = suite.chainC.SenderAccounts[0].SenderAccount - receiver = suite.chainA.SenderAccounts[0].SenderAccount // Receiver is the A chain account - - forwarding := types.NewForwarding(false, types.Hop{ - PortId: path1.EndpointB.ChannelConfig.PortID, - ChannelId: path1.EndpointB.ChannelID, - }) - - transferMsg = types.NewMsgTransfer( - path2.EndpointB.ChannelConfig.PortID, - path2.EndpointB.ChannelID, - sdk.NewCoins(coin), - sender.GetAddress().String(), - receiver.GetAddress().String(), - clienttypes.ZeroHeight(), - suite.chainA.GetTimeoutTimestamp(), "", - forwarding, - ) - - result, err = suite.chainC.SendMsgs(transferMsg) - suite.Require().NoError(err) // message committed - - // Voucher have been burned on chain C - postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Vouchers have not been burned") - - // parse the packet from result events and recv packet on chainB - packetFromCtoB, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packetFromCtoB) - - err = path2.EndpointA.UpdateClient() - suite.Require().NoError(err) - - result, err = path2.EndpointA.RecvPacketWithResult(packetFromCtoB) - suite.Require().NoError(err) - suite.Require().NotNil(result) - - // We have successfully received the packet on B and forwarded it to A. - // Lets try to retrieve it in order to save it - forwardedPacket, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID, packetFromCtoB.Sequence) - suite.Require().True(found) - suite.Require().Equal(packetFromCtoB, forwardedPacket) - - // Voucher have been burned on chain B - coin = sdk.NewCoin(denomAB.IBCDenom(), amount) - postCoinOnB = suite.chainB.GetSimApp().BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(0), postCoinOnB.Amount, "Vouchers have not been burned") - - // Now we can receive the packet on A. - // To trigger an error during the OnRecv, we have to manipulate the balance present in the escrow of A - // of denom - - // parse the packet from result events and recv packet on chainA - packetFromBtoA, err := ibctesting.ParsePacketFromEvents(result.Events) - suite.Require().NoError(err) - suite.Require().NotNil(packetFromBtoA) - - // turn off receive on chain A to trigger an error - suite.chainA.GetSimApp().TransferKeeper.SetParams(suite.chainA.GetContext(), types.Params{ - SendEnabled: true, - ReceiveEnabled: false, - }) - - err = path1.EndpointA.UpdateClient() - suite.Require().NoError(err) - - result, err = path1.EndpointA.RecvPacketWithResult(packetFromBtoA) - suite.Require().NoError(err) - - // An error ack has been written on chainA - // Now we need to propagate it back to chainB and chainC - packetSequenceOnA, err := ibctesting.ParsePacketSequenceFromEvents(result.Events) - suite.Require().NoError(err) - - errorAckOnA := channeltypes.NewErrorAcknowledgement(types.ErrReceiveDisabled) - errorAckCommitmentOnA := channeltypes.CommitAcknowledgement(errorAckOnA.Acknowledgement()) - ackOnC, found := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(suite.chainA.GetContext(), path1.EndpointA.ChannelConfig.PortID, path1.EndpointA.ChannelID, packetSequenceOnA) - suite.Require().True(found) - suite.Require().Equal(errorAckCommitmentOnA, ackOnC) - - err = path1.EndpointB.UpdateClient() - suite.Require().NoError(err) - - err = path1.EndpointB.AcknowledgePacket(packetFromBtoA, errorAckOnA.Acknowledgement()) - suite.Require().NoError(err) - - // Check that B deleted the forwarded packet. - _, found = suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), forwardedPacket.SourcePort, forwardedPacket.SourceChannel, forwardedPacket.Sequence) - suite.Require().False(found, "chain B should have deleted the forwarded packet mapping") - - // Check that Escrow B has been refunded amount - coin = sdk.NewCoin(denomAB.IBCDenom(), amount) - totalEscrowChainB = suite.chainB.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(suite.chainB.GetContext(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), totalEscrowChainB.Amount) - - err = path2.EndpointB.UpdateClient() - suite.Require().NoError(err) - - errorAckOnB := channeltypes.NewErrorAcknowledgement(types.ErrForwardedPacketFailed) - errorAckCommitmentOnB := channeltypes.CommitAcknowledgement(errorAckOnB.Acknowledgement()) - ackOnB := suite.chainB.GetAcknowledgement(packetFromCtoB) - suite.Require().Equal(errorAckCommitmentOnB, ackOnB) - - // Check the status of account on chain C before executing ack. - coin = sdk.NewCoin(denomABC.IBCDenom(), amount) - postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(0), postCoinOnC.Amount, "Final Hop balance has been refunded before Ack execution") - - // Execute ack - err = path2.EndpointB.AcknowledgePacket(packetFromCtoB, errorAckOnB.Acknowledgement()) - suite.Require().NoError(err) - - // Check that everything has been reverted - // - // Check the vouchers transfer/channel-1/transfer/channel-0/denom have been refunded on C - coin = sdk.NewCoin(denomABC.IBCDenom(), amount) - postCoinOnC = suite.chainC.GetSimApp().BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccounts[0].SenderAccount.GetAddress(), coin.GetDenom()) - suite.Require().Equal(sdkmath.NewInt(100), postCoinOnC.Amount, "final receiver balance has not increased") - - err = path1.EndpointB.UpdateClient() - suite.Require().NoError(err) -} - -/* -// TODO - Test scenarios for failures ack -Check out the notion page: https://www.notion.so/interchain/ICS20-v2-path-forwarding-091f1ac788e84a538261c5a247cb5924 -// TODO -Test async ack is properly relayed to middle hop after forwarding transfer completition -// TODO -Tiemout during forwarding after middle hop execution reverts properly the state changes -*/ - -func (suite *KeeperTestSuite) setupForwardingPaths() (pathAtoB, pathBtoC *ibctesting.Path) { - pathAtoB = ibctesting.NewTransferPath(suite.chainA, suite.chainB) - pathBtoC = ibctesting.NewTransferPath(suite.chainB, suite.chainC) - pathAtoB.Setup() - pathBtoC.Setup() - return pathAtoB, pathBtoC -} - -type amountType int - -const ( - escrow amountType = iota - balance -) - -func (suite *KeeperTestSuite) assertAmountOnChain(chain *ibctesting.TestChain, balanceType amountType, amount sdkmath.Int, denom string) { - var total sdk.Coin - switch balanceType { - case escrow: - total = chain.GetSimApp().TransferKeeper.GetTotalEscrowForDenom(chain.GetContext(), denom) - case balance: - total = chain.GetSimApp().BankKeeper.GetBalance(chain.GetContext(), chain.SenderAccounts[0].SenderAccount.GetAddress(), denom) - default: - suite.Fail("invalid amountType %s", balanceType) - } - suite.Require().Equal(amount, total.Amount, fmt.Sprintf("Chain %s: got balance of %d, wanted %d", chain.Name(), total.Amount, amount)) + suite.assertAmountOnChain(suite.chainC, escrow, sdkmath.NewInt(0), coinOnC.GetDenom()) + suite.assertAmountOnChain(suite.chainC, balance, balanceOnCBefore.Amount, coinOnC.GetDenom()) } // TestOnTimeoutPacketForwarding tests the scenario in which a packet goes from @@ -964,13 +674,13 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketForwarding() { pathAtoB, pathBtoC := suite.setupForwardingPaths() amount := sdkmath.NewInt(100) - coin := sdk.NewCoin(sdk.DefaultBondDenom, amount) + coin := ibctesting.TestCoin sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainC.SenderAccounts[0].SenderAccount denomA := types.NewDenom(coin.Denom) denomAB := types.NewDenom(coin.Denom, types.NewTrace(pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID)) - denomABC := types.NewDenom(coin.Denom, append(denomAB.Trace, types.NewTrace(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID))...) + denomABC := types.NewDenom(coin.Denom, append([]types.Trace{types.NewTrace(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID)}, denomAB.Trace...)...) originalABalance := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), sender.GetAddress(), coin.Denom) From 24cd07f537a48c8992997214300ed16f9148e3c6 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Wed, 26 Jun 2024 09:41:36 +0200 Subject: [PATCH 106/141] chore: pull out hop validation and consolidate for transfer+packet (#6695) * chore: pull out hop validation and consolidate transfer+packet * Update modules/apps/transfer/types/forwarding_test.go Co-authored-by: Carlos Rodriguez * cr fixes --------- Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/types/forwarding.go | 49 +++++---- .../apps/transfer/types/forwarding_test.go | 100 +++++++++++++++--- modules/apps/transfer/types/msgs_test.go | 4 +- modules/apps/transfer/types/packet_test.go | 5 +- 4 files changed, 122 insertions(+), 36 deletions(-) diff --git a/modules/apps/transfer/types/forwarding.go b/modules/apps/transfer/types/forwarding.go index 895bfb9e286..d202ebde9f9 100644 --- a/modules/apps/transfer/types/forwarding.go +++ b/modules/apps/transfer/types/forwarding.go @@ -18,17 +18,8 @@ func NewForwarding(unwind bool, hops ...Hop) Forwarding { // Validate performs a basic validation of the Forwarding fields. func (fi Forwarding) Validate() error { - if len(fi.Hops) > MaximumNumberOfForwardingHops { - return errorsmod.Wrapf(ErrInvalidForwarding, "number of hops in forwarding cannot exceed %d", MaximumNumberOfForwardingHops) - } - - for _, hop := range fi.Hops { - if err := host.PortIdentifierValidator(hop.PortId); err != nil { - return errorsmod.Wrapf(err, "invalid hop source port ID %s", hop.PortId) - } - if err := host.ChannelIdentifierValidator(hop.ChannelId); err != nil { - return errorsmod.Wrapf(err, "invalid source channel ID %s", hop.ChannelId) - } + if err := validateHops(fi.Hops); err != nil { + return errorsmod.Wrapf(ErrInvalidForwarding, "invalid hops in forwarding") } return nil @@ -44,8 +35,8 @@ func NewForwardingPacketData(destinationMemo string, hops ...Hop) ForwardingPack // Validate performs a basic validation of the ForwardingPacketData fields. func (fi ForwardingPacketData) Validate() error { - if len(fi.Hops) > MaximumNumberOfForwardingHops { - return errorsmod.Wrapf(ErrInvalidForwarding, "number of hops in forwarding packet data cannot exceed %d", MaximumNumberOfForwardingHops) + if err := validateHops(fi.Hops); err != nil { + return errorsmod.Wrapf(ErrInvalidForwarding, "invalid hops in forwarding packet data") } if len(fi.DestinationMemo) > MaximumMemoLength { @@ -56,12 +47,32 @@ func (fi ForwardingPacketData) Validate() error { return errorsmod.Wrap(ErrInvalidForwarding, "memo specified when forwarding packet data hops is empty") } - for _, hop := range fi.Hops { - if err := host.PortIdentifierValidator(hop.PortId); err != nil { - return errorsmod.Wrapf(err, "invalid source port ID %s", hop.PortId) - } - if err := host.ChannelIdentifierValidator(hop.ChannelId); err != nil { - return errorsmod.Wrapf(err, "invalid source channel ID %s", hop.ChannelId) + return nil +} + +// Validate performs a basic validation of the Hop fields. +func (h Hop) Validate() error { + if err := host.PortIdentifierValidator(h.PortId); err != nil { + return errorsmod.Wrapf(err, "invalid hop source port ID %s", h.PortId) + } + if err := host.ChannelIdentifierValidator(h.ChannelId); err != nil { + return errorsmod.Wrapf(err, "invalid source channel ID %s", h.ChannelId) + } + + return nil +} + +// validateHops performs a basic validation of the hops. +// It checks that the number of hops does not exceed the maximum allowed and that each hop is valid. +// It will not return any errors if hops is empty. +func validateHops(hops []Hop) error { + if len(hops) > MaximumNumberOfForwardingHops { + return errorsmod.Wrapf(ErrInvalidForwarding, "number of hops cannot exceed %d", MaximumNumberOfForwardingHops) + } + + for _, hop := range hops { + if err := hop.Validate(); err != nil { + return err } } diff --git a/modules/apps/transfer/types/forwarding_test.go b/modules/apps/transfer/types/forwarding_test.go index c8633c7f72f..357291ee735 100644 --- a/modules/apps/transfer/types/forwarding_test.go +++ b/modules/apps/transfer/types/forwarding_test.go @@ -50,7 +50,7 @@ func TestForwarding_Validate(t *testing.T) { ChannelId: ibctesting.FirstChannelID, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "invalid forwarding with too long hop port ID", @@ -61,7 +61,7 @@ func TestForwarding_Validate(t *testing.T) { ChannelId: ibctesting.FirstChannelID, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "invalid forwarding with non-alpha hop port ID", @@ -72,7 +72,7 @@ func TestForwarding_Validate(t *testing.T) { ChannelId: ibctesting.FirstChannelID, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "invalid forwarding with too long hop channel ID", @@ -83,7 +83,7 @@ func TestForwarding_Validate(t *testing.T) { ChannelId: invalidLongChannel, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "invalid forwarding with too short hop channel ID", @@ -94,7 +94,7 @@ func TestForwarding_Validate(t *testing.T) { ChannelId: invalidShortChannel, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "invalid forwarding with non-alpha hop channel ID", @@ -105,7 +105,7 @@ func TestForwarding_Validate(t *testing.T) { ChannelId: invalidChannel, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, } for _, tc := range tests { @@ -179,7 +179,7 @@ func TestForwardingPacketData_Validate(t *testing.T) { ChannelId: ibctesting.FirstChannelID, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "invalid forwarding with too long hop port ID", @@ -190,7 +190,7 @@ func TestForwardingPacketData_Validate(t *testing.T) { ChannelId: ibctesting.FirstChannelID, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "invalid forwarding with non-alpha hop port ID", @@ -201,7 +201,7 @@ func TestForwardingPacketData_Validate(t *testing.T) { ChannelId: ibctesting.FirstChannelID, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "invalid forwarding with too long hop channel ID", @@ -212,7 +212,7 @@ func TestForwardingPacketData_Validate(t *testing.T) { ChannelId: invalidLongChannel, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "invalid forwarding with too short hop channel ID", @@ -223,7 +223,7 @@ func TestForwardingPacketData_Validate(t *testing.T) { ChannelId: invalidShortChannel, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "invalid forwarding with non-alpha hop channel ID", @@ -234,7 +234,7 @@ func TestForwardingPacketData_Validate(t *testing.T) { ChannelId: invalidChannel, }, ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, } for _, tc := range tests { @@ -253,6 +253,82 @@ func TestForwardingPacketData_Validate(t *testing.T) { } } +func TestValidateHop(t *testing.T) { + tests := []struct { + name string + hop types.Hop + expError error + }{ + { + "valid hop", + validHop, + nil, + }, + { + "invalid hop with too short port ID", + types.Hop{ + PortId: invalidShortPort, + ChannelId: ibctesting.FirstChannelID, + }, + host.ErrInvalidID, + }, + { + "invalid hop with too long port ID", + types.Hop{ + PortId: invalidLongPort, + ChannelId: ibctesting.FirstChannelID, + }, + host.ErrInvalidID, + }, + { + "invalid hop with non-alpha port ID", + types.Hop{ + PortId: invalidPort, + ChannelId: ibctesting.FirstChannelID, + }, + host.ErrInvalidID, + }, + { + "invalid hop with too long channel ID", + types.Hop{ + PortId: types.PortID, + ChannelId: invalidLongChannel, + }, + host.ErrInvalidID, + }, + { + "invalid hop with too short channel ID", + types.Hop{ + PortId: types.PortID, + ChannelId: invalidShortChannel, + }, + host.ErrInvalidID, + }, + { + "invalid hop with non-alpha channel ID", + types.Hop{ + PortId: types.PortID, + ChannelId: invalidChannel, + }, + host.ErrInvalidID, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tc := tc + + err := tc.hop.Validate() + + expPass := tc.expError == nil + if expPass { + require.NoError(t, err) + } else { + require.ErrorIs(t, err, tc.expError) + } + }) + } +} + // generateHops generates a slice of n correctly initialized hops. func generateHops(n int) []types.Hop { hops := make([]types.Hop, n) diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index a7d837ae741..b0ccbb611bf 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -84,8 +84,8 @@ func TestMsgTransferValidation(t *testing.T) { {"multidenom: too many coins", types.NewMsgTransfer(validPort, validChannel, make([]sdk.Coin, types.MaximumTokensLength+1), sender, receiver, clienttypes.ZeroHeight(), 100, "", emptyForwarding), ibcerrors.ErrInvalidCoins}, {"multidenom: both token and tokens are set", &types.MsgTransfer{validPort, validChannel, coin, sender, receiver, clienttypes.ZeroHeight(), 100, "", coins, emptyForwarding}, ibcerrors.ErrInvalidCoins}, {"timeout height must be zero if forwarding path hops is not empty", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, timeoutHeight, 100, "memo", types.NewForwarding(false, validHop)), types.ErrInvalidPacketTimeout}, - {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, types.Hop{PortId: invalidPort, ChannelId: validChannel})), host.ErrInvalidID}, - {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, types.Hop{PortId: validPort, ChannelId: invalidChannel})), host.ErrInvalidID}, + {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, types.Hop{PortId: invalidPort, ChannelId: validChannel})), types.ErrInvalidForwarding}, + {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, types.Hop{PortId: validPort, ChannelId: invalidChannel})), types.ErrInvalidForwarding}, {"invalid forwarding info too many hops", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, generateHops(types.MaximumNumberOfForwardingHops+1)...)), types.ErrInvalidForwarding}, {"unwind specified but source port is not empty", types.NewMsgTransfer(validPort, "", coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(true)), types.ErrInvalidForwarding}, {"unwind specified but source channel is not empty", types.NewMsgTransfer("", validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(true)), types.ErrInvalidForwarding}, diff --git a/modules/apps/transfer/types/packet_test.go b/modules/apps/transfer/types/packet_test.go index 3e1cfbe8e46..6a70b8d72a3 100644 --- a/modules/apps/transfer/types/packet_test.go +++ b/modules/apps/transfer/types/packet_test.go @@ -8,7 +8,6 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -428,7 +427,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { }, ), ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "failure: invalid forwarding path channel ID", @@ -450,7 +449,7 @@ func TestFungibleTokenPacketDataV2ValidateBasic(t *testing.T) { }, ), ), - host.ErrInvalidID, + types.ErrInvalidForwarding, }, { "failure: invalid forwarding path too many hops", From 37d7335a095dc981fdda821f880baf759f61475f Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 26 Jun 2024 10:41:08 +0100 Subject: [PATCH 107/141] Remove unwind field in authz (#6701) * chore: remove unwind field in authz * chore: remove duplicate test * Update modules/apps/transfer/types/transfer_authorization.go Co-authored-by: Carlos Rodriguez --------- Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/types/authz.pb.go | 328 +++--------------- .../transfer/types/transfer_authorization.go | 10 +- .../types/transfer_authorization_test.go | 28 +- .../ibc/applications/transfer/v1/authz.proto | 9 +- 4 files changed, 69 insertions(+), 306 deletions(-) diff --git a/modules/apps/transfer/types/authz.pb.go b/modules/apps/transfer/types/authz.pb.go index 51de34c0ae4..e71fcc8dc6f 100644 --- a/modules/apps/transfer/types/authz.pb.go +++ b/modules/apps/transfer/types/authz.pb.go @@ -40,7 +40,7 @@ type Allocation struct { // a list only with "*" permits any memo string AllowedPacketData []string `protobuf:"bytes,5,rep,name=allowed_packet_data,json=allowedPacketData,proto3" json:"allowed_packet_data,omitempty"` // Forwarding options that are allowed. - AllowedForwarding AllowedForwarding `protobuf:"bytes,6,opt,name=allowed_forwarding,json=allowedForwarding,proto3" json:"allowed_forwarding"` + AllowedForwarding []AllowedForwarding `protobuf:"bytes,6,rep,name=allowed_forwarding,json=allowedForwarding,proto3" json:"allowed_forwarding"` } func (m *Allocation) Reset() { *m = Allocation{} } @@ -111,20 +111,18 @@ func (m *Allocation) GetAllowedPacketData() []string { return nil } -func (m *Allocation) GetAllowedForwarding() AllowedForwarding { +func (m *Allocation) GetAllowedForwarding() []AllowedForwarding { if m != nil { return m.AllowedForwarding } - return AllowedForwarding{} + return nil } // AllowedForwarding defines which options are allowed for forwarding. type AllowedForwarding struct { // a list of allowed source port ID/channel ID pairs through which the packet is allowed to be forwarded until final // destination - AllowedHops []Hops `protobuf:"bytes,1,rep,name=allowed_hops,json=allowedHops,proto3" json:"allowed_hops"` - // Whether to allow automatic unwinding of tokens to the original chain. - AllowUnwind bool `protobuf:"varint,2,opt,name=allow_unwind,json=allowUnwind,proto3" json:"allow_unwind,omitempty"` + Hops []Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops"` } func (m *AllowedForwarding) Reset() { *m = AllowedForwarding{} } @@ -160,59 +158,7 @@ func (m *AllowedForwarding) XXX_DiscardUnknown() { var xxx_messageInfo_AllowedForwarding proto.InternalMessageInfo -func (m *AllowedForwarding) GetAllowedHops() []Hops { - if m != nil { - return m.AllowedHops - } - return nil -} - -func (m *AllowedForwarding) GetAllowUnwind() bool { - if m != nil { - return m.AllowUnwind - } - return false -} - -// Hops represent a list of Hop -type Hops struct { - Hops []Hop `protobuf:"bytes,1,rep,name=hops,proto3" json:"hops"` -} - -func (m *Hops) Reset() { *m = Hops{} } -func (m *Hops) String() string { return proto.CompactTextString(m) } -func (*Hops) ProtoMessage() {} -func (*Hops) Descriptor() ([]byte, []int) { - return fileDescriptor_b1a28b55d17325aa, []int{2} -} -func (m *Hops) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Hops) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Hops.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 *Hops) XXX_Merge(src proto.Message) { - xxx_messageInfo_Hops.Merge(m, src) -} -func (m *Hops) XXX_Size() int { - return m.Size() -} -func (m *Hops) XXX_DiscardUnknown() { - xxx_messageInfo_Hops.DiscardUnknown(m) -} - -var xxx_messageInfo_Hops proto.InternalMessageInfo - -func (m *Hops) GetHops() []Hop { +func (m *AllowedForwarding) GetHops() []Hop { if m != nil { return m.Hops } @@ -230,7 +176,7 @@ func (m *TransferAuthorization) Reset() { *m = TransferAuthorization{} } func (m *TransferAuthorization) String() string { return proto.CompactTextString(m) } func (*TransferAuthorization) ProtoMessage() {} func (*TransferAuthorization) Descriptor() ([]byte, []int) { - return fileDescriptor_b1a28b55d17325aa, []int{3} + return fileDescriptor_b1a28b55d17325aa, []int{2} } func (m *TransferAuthorization) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -269,7 +215,6 @@ func (m *TransferAuthorization) GetAllocations() []Allocation { func init() { proto.RegisterType((*Allocation)(nil), "ibc.applications.transfer.v1.Allocation") proto.RegisterType((*AllowedForwarding)(nil), "ibc.applications.transfer.v1.AllowedForwarding") - proto.RegisterType((*Hops)(nil), "ibc.applications.transfer.v1.Hops") proto.RegisterType((*TransferAuthorization)(nil), "ibc.applications.transfer.v1.TransferAuthorization") } @@ -278,41 +223,38 @@ func init() { } var fileDescriptor_b1a28b55d17325aa = []byte{ - // 541 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0xcd, 0x6e, 0xd3, 0x40, - 0x10, 0xc7, 0xe3, 0x26, 0x54, 0x64, 0x03, 0x48, 0x35, 0x20, 0xb9, 0x15, 0x38, 0xa9, 0x25, 0x90, - 0x25, 0x94, 0x5d, 0x52, 0x0e, 0x20, 0x38, 0x25, 0x41, 0x08, 0x89, 0x1e, 0x42, 0x04, 0x17, 0x2e, - 0xd6, 0xfa, 0xa3, 0xf1, 0xaa, 0xce, 0x8e, 0xe5, 0x5d, 0x27, 0xa2, 0x57, 0x5e, 0x00, 0x5e, 0x83, - 0x33, 0x0f, 0x51, 0x71, 0xea, 0x91, 0x13, 0xa0, 0xe4, 0x21, 0xb8, 0x22, 0xef, 0x6e, 0x42, 0x50, - 0xa5, 0xf4, 0x64, 0xef, 0x7f, 0x7e, 0x33, 0xff, 0xfd, 0x98, 0x41, 0x3e, 0x0b, 0x23, 0x42, 0xf3, - 0x3c, 0x63, 0x11, 0x95, 0x0c, 0xb8, 0x20, 0xb2, 0xa0, 0x5c, 0x9c, 0x24, 0x05, 0x99, 0xf5, 0x08, - 0x2d, 0x65, 0x7a, 0x86, 0xf3, 0x02, 0x24, 0xd8, 0xf7, 0x58, 0x18, 0xe1, 0x4d, 0x12, 0xaf, 0x48, - 0x3c, 0xeb, 0x1d, 0xec, 0x47, 0x20, 0xa6, 0x20, 0x02, 0xc5, 0x12, 0xbd, 0xd0, 0x89, 0x07, 0x77, - 0x26, 0x30, 0x01, 0xad, 0x57, 0x7f, 0x46, 0x75, 0x35, 0x43, 0x42, 0x2a, 0x12, 0x32, 0xeb, 0x85, - 0x89, 0xa4, 0x3d, 0x12, 0x01, 0xe3, 0x26, 0xfe, 0x68, 0xeb, 0xc6, 0xd6, 0xd6, 0x0a, 0xf6, 0xfe, - 0xec, 0x20, 0xd4, 0xcf, 0x32, 0xd0, 0xa8, 0xdd, 0x46, 0x2d, 0x01, 0x65, 0x11, 0x25, 0x41, 0x0e, - 0x85, 0x74, 0xac, 0x8e, 0xe5, 0x37, 0xc7, 0x48, 0x4b, 0x23, 0x28, 0xa4, 0xfd, 0x00, 0xdd, 0x32, - 0x40, 0x94, 0x52, 0xce, 0x93, 0xcc, 0xd9, 0x51, 0xcc, 0x4d, 0xad, 0x0e, 0xb5, 0x68, 0x67, 0xa8, - 0x25, 0xf2, 0x84, 0xc7, 0x41, 0xc6, 0xa6, 0x4c, 0x3a, 0xf5, 0x4e, 0xdd, 0x6f, 0x1d, 0xed, 0x63, - 0x73, 0xba, 0x6a, 0xe7, 0xd8, 0xec, 0x1c, 0x0f, 0x81, 0xf1, 0xc1, 0xe3, 0xf3, 0x9f, 0xed, 0xda, - 0xd7, 0x5f, 0x6d, 0x7f, 0xc2, 0x64, 0x5a, 0x86, 0x38, 0x82, 0xa9, 0xb9, 0x0a, 0xf3, 0xe9, 0x8a, - 0xf8, 0x94, 0xc8, 0x8f, 0x79, 0x22, 0x54, 0x82, 0x18, 0x23, 0x55, 0xff, 0xb8, 0x2a, 0x6f, 0xdf, - 0x47, 0x88, 0x66, 0x19, 0xcc, 0x83, 0x8c, 0x09, 0xe9, 0x34, 0x3a, 0x75, 0xbf, 0x39, 0x6e, 0x2a, - 0xe5, 0x98, 0x09, 0x69, 0x63, 0x74, 0x5b, 0x2d, 0x92, 0x38, 0xc8, 0x69, 0x74, 0x9a, 0xc8, 0x20, - 0xa6, 0x92, 0x3a, 0xd7, 0x14, 0xb7, 0x67, 0x42, 0x23, 0x15, 0x79, 0x49, 0x25, 0xb5, 0x63, 0x64, - 0xaf, 0xf8, 0x13, 0x28, 0xe6, 0xb4, 0x88, 0x19, 0x9f, 0x38, 0xbb, 0x1d, 0xcb, 0x6f, 0x1d, 0x11, - 0xbc, 0xed, 0x31, 0x71, 0x5f, 0xe7, 0xbd, 0x5a, 0xa7, 0x0d, 0x1a, 0xd5, 0xc9, 0xd6, 0x2e, 0xff, - 0x02, 0xde, 0x27, 0x0b, 0xed, 0x5d, 0xc2, 0xed, 0x37, 0xe8, 0xc6, 0xca, 0x3b, 0x85, 0x5c, 0x38, - 0x96, 0xba, 0x39, 0x6f, 0xbb, 0xeb, 0x6b, 0xc8, 0x85, 0x31, 0x6a, 0x99, 0xec, 0x4a, 0xb2, 0x0f, - 0x4d, 0xb1, 0xa0, 0xe4, 0x73, 0xc6, 0x63, 0xf5, 0x54, 0xd7, 0x0d, 0xf2, 0x5e, 0x49, 0xde, 0x10, - 0x35, 0x14, 0xfa, 0x02, 0x35, 0x36, 0xfc, 0x0e, 0xaf, 0xf4, 0x33, 0x76, 0x2a, 0xc9, 0xfb, 0x62, - 0xa1, 0xbb, 0xef, 0x4c, 0xbc, 0x5f, 0xca, 0x14, 0x0a, 0x76, 0xa6, 0xfb, 0x69, 0x84, 0x94, 0x9b, - 0x29, 0x62, 0xaa, 0xfb, 0x57, 0xdf, 0xa1, 0xd6, 0x37, 0xcf, 0x64, 0xc8, 0xe7, 0x0f, 0xbf, 0x7f, - 0xeb, 0x7a, 0xa6, 0x8f, 0xf4, 0x90, 0xad, 0x1a, 0xe9, 0x3f, 0xe7, 0xc1, 0xdb, 0xf3, 0x85, 0x6b, - 0x5d, 0x2c, 0x5c, 0xeb, 0xf7, 0xc2, 0xb5, 0x3e, 0x2f, 0xdd, 0xda, 0xc5, 0xd2, 0xad, 0xfd, 0x58, - 0xba, 0xb5, 0x0f, 0x4f, 0x2f, 0xf7, 0x18, 0x0b, 0xa3, 0xee, 0x04, 0xc8, 0xec, 0x19, 0x99, 0x42, - 0x5c, 0x66, 0x89, 0xa8, 0xe6, 0x67, 0x63, 0x6e, 0x54, 0xe3, 0x85, 0xbb, 0x6a, 0x64, 0x9e, 0xfc, - 0x0d, 0x00, 0x00, 0xff, 0xff, 0x08, 0x47, 0x9b, 0x9b, 0xfa, 0x03, 0x00, 0x00, + // 496 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0x4f, 0x8b, 0xd3, 0x40, + 0x18, 0xc6, 0x9b, 0x6d, 0x5d, 0xe8, 0x14, 0x85, 0x8d, 0x0a, 0xd9, 0x45, 0xd3, 0x5a, 0x50, 0x02, + 0xd2, 0x19, 0xab, 0x07, 0x45, 0x4f, 0xed, 0x8a, 0x78, 0xd8, 0x43, 0x2d, 0x9e, 0xbc, 0x84, 0xc9, + 0x64, 0xb6, 0x19, 0x76, 0x9a, 0x37, 0x64, 0x26, 0x5d, 0xdc, 0x4f, 0xa1, 0x5f, 0xc3, 0xb3, 0x1f, + 0x62, 0xf1, 0xb4, 0x47, 0x4f, 0x2a, 0xed, 0x87, 0xf0, 0x2a, 0x99, 0x99, 0xd6, 0xca, 0x42, 0x3d, + 0xb5, 0xf3, 0xbc, 0xbf, 0xf7, 0x5f, 0x9e, 0x17, 0x45, 0x22, 0x61, 0x84, 0x16, 0x85, 0x14, 0x8c, + 0x6a, 0x01, 0xb9, 0x22, 0xba, 0xa4, 0xb9, 0x3a, 0xe5, 0x25, 0x59, 0x0c, 0x09, 0xad, 0x74, 0x76, + 0x81, 0x8b, 0x12, 0x34, 0xf8, 0xf7, 0x44, 0xc2, 0xf0, 0x36, 0x89, 0xd7, 0x24, 0x5e, 0x0c, 0x8f, + 0x0e, 0x19, 0xa8, 0x39, 0xa8, 0xd8, 0xb0, 0xc4, 0x3e, 0x6c, 0xe2, 0xd1, 0x9d, 0x19, 0xcc, 0xc0, + 0xea, 0xf5, 0x3f, 0xa7, 0x86, 0x96, 0x21, 0x09, 0x55, 0x9c, 0x2c, 0x86, 0x09, 0xd7, 0x74, 0x48, + 0x18, 0x88, 0xdc, 0xc5, 0x1f, 0xef, 0x1c, 0x6c, 0xd3, 0xda, 0xc0, 0xfd, 0xdf, 0x7b, 0x08, 0x8d, + 0xa4, 0x04, 0x8b, 0xfa, 0x5d, 0xd4, 0x51, 0x50, 0x95, 0x8c, 0xc7, 0x05, 0x94, 0x3a, 0xf0, 0x7a, + 0x5e, 0xd4, 0x9e, 0x22, 0x2b, 0x4d, 0xa0, 0xd4, 0xfe, 0x43, 0x74, 0xcb, 0x01, 0x2c, 0xa3, 0x79, + 0xce, 0x65, 0xb0, 0x67, 0x98, 0x9b, 0x56, 0x3d, 0xb6, 0xa2, 0x2f, 0x51, 0x47, 0x15, 0x3c, 0x4f, + 0x63, 0x29, 0xe6, 0x42, 0x07, 0xcd, 0x5e, 0x33, 0xea, 0x3c, 0x3d, 0xc4, 0x6e, 0xbb, 0x7a, 0x72, + 0xec, 0x26, 0xc7, 0xc7, 0x20, 0xf2, 0xf1, 0x93, 0xcb, 0x1f, 0xdd, 0xc6, 0x97, 0x9f, 0xdd, 0x68, + 0x26, 0x74, 0x56, 0x25, 0x98, 0xc1, 0xdc, 0x7d, 0x0a, 0xf7, 0x33, 0x50, 0xe9, 0x19, 0xd1, 0x1f, + 0x0b, 0xae, 0x4c, 0x82, 0x9a, 0x22, 0x53, 0xff, 0xa4, 0x2e, 0xef, 0xdf, 0x47, 0x88, 0x4a, 0x09, + 0xe7, 0xb1, 0x14, 0x4a, 0x07, 0xad, 0x5e, 0x33, 0x6a, 0x4f, 0xdb, 0x46, 0x39, 0x11, 0x4a, 0xfb, + 0x18, 0xdd, 0x36, 0x0f, 0x9e, 0xc6, 0x05, 0x65, 0x67, 0x5c, 0xc7, 0x29, 0xd5, 0x34, 0xb8, 0x61, + 0xb8, 0x03, 0x17, 0x9a, 0x98, 0xc8, 0x6b, 0xaa, 0xa9, 0x9f, 0x22, 0x7f, 0xcd, 0x9f, 0x42, 0x79, + 0x4e, 0xcb, 0x54, 0xe4, 0xb3, 0x60, 0xdf, 0xec, 0x40, 0xf0, 0x2e, 0x33, 0xf1, 0xc8, 0xe6, 0xbd, + 0xd9, 0xa4, 0x8d, 0x5b, 0xf5, 0x66, 0x9b, 0x2e, 0x7f, 0x03, 0xfd, 0x09, 0x3a, 0xb8, 0x46, 0xfb, + 0xaf, 0x50, 0x2b, 0x83, 0x42, 0x05, 0x9e, 0x69, 0xf6, 0x60, 0x77, 0xb3, 0xb7, 0x50, 0xb8, 0xf2, + 0x26, 0xa9, 0xff, 0xd9, 0x43, 0x77, 0xdf, 0xbb, 0xf8, 0xa8, 0xd2, 0x19, 0x94, 0xe2, 0xc2, 0xda, + 0x3a, 0x41, 0x1d, 0xba, 0x31, 0x79, 0x5d, 0x3d, 0xfa, 0xff, 0x2a, 0x56, 0x77, 0x4d, 0xb6, 0x4b, + 0xbc, 0x7c, 0xf4, 0xed, 0xeb, 0xa0, 0xef, 0xec, 0xb4, 0xb7, 0xbe, 0xf6, 0xf3, 0x9f, 0xce, 0xe3, + 0x77, 0x97, 0xcb, 0xd0, 0xbb, 0x5a, 0x86, 0xde, 0xaf, 0x65, 0xe8, 0x7d, 0x5a, 0x85, 0x8d, 0xab, + 0x55, 0xd8, 0xf8, 0xbe, 0x0a, 0x1b, 0x1f, 0x9e, 0x5f, 0xb7, 0x5a, 0x24, 0x6c, 0x30, 0x03, 0xb2, + 0x78, 0x41, 0xe6, 0x90, 0x56, 0x92, 0xab, 0xfa, 0x8c, 0xb7, 0xce, 0xd7, 0xf8, 0x9f, 0xec, 0x9b, + 0xcb, 0x7d, 0xf6, 0x27, 0x00, 0x00, 0xff, 0xff, 0x79, 0x59, 0xb5, 0xa3, 0x81, 0x03, 0x00, 0x00, } func (m *Allocation) Marshal() (dAtA []byte, err error) { @@ -335,16 +277,20 @@ func (m *Allocation) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - { - size, err := m.AllowedForwarding.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if len(m.AllowedForwarding) > 0 { + for iNdEx := len(m.AllowedForwarding) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AllowedForwarding[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 } - i -= size - i = encodeVarintAuthz(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x32 if len(m.AllowedPacketData) > 0 { for iNdEx := len(m.AllowedPacketData) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.AllowedPacketData[iNdEx]) @@ -410,53 +356,6 @@ func (m *AllowedForwarding) MarshalTo(dAtA []byte) (int, error) { } func (m *AllowedForwarding) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.AllowUnwind { - i-- - if m.AllowUnwind { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x10 - } - if len(m.AllowedHops) > 0 { - for iNdEx := len(m.AllowedHops) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.AllowedHops[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintAuthz(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *Hops) 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 *Hops) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Hops) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -558,30 +457,16 @@ func (m *Allocation) Size() (n int) { n += 1 + l + sovAuthz(uint64(l)) } } - l = m.AllowedForwarding.Size() - n += 1 + l + sovAuthz(uint64(l)) - return n -} - -func (m *AllowedForwarding) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.AllowedHops) > 0 { - for _, e := range m.AllowedHops { + if len(m.AllowedForwarding) > 0 { + for _, e := range m.AllowedForwarding { l = e.Size() n += 1 + l + sovAuthz(uint64(l)) } } - if m.AllowUnwind { - n += 2 - } return n } -func (m *Hops) Size() (n int) { +func (m *AllowedForwarding) Size() (n int) { if m == nil { return 0 } @@ -837,7 +722,8 @@ func (m *Allocation) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.AllowedForwarding.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.AllowedForwarding = append(m.AllowedForwarding, AllowedForwarding{}) + if err := m.AllowedForwarding[len(m.AllowedForwarding)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -891,110 +777,6 @@ func (m *AllowedForwarding) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: AllowedForwarding: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AllowedHops", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAuthz - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthAuthz - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthAuthz - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AllowedHops = append(m.AllowedHops, Hops{}) - if err := m.AllowedHops[len(m.AllowedHops)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field AllowUnwind", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowAuthz - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.AllowUnwind = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := skipAuthz(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthAuthz - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Hops) 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 ErrIntOverflowAuthz - } - 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: Hops: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Hops: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Hops", wireType) diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index 4dfe20eafb2..2a08097345b 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -170,12 +170,12 @@ func isAllowedAddress(ctx sdk.Context, receiver string, allowedAddrs []string) b } // validateForwarding performs the validation of forwarding info. -func validateForwarding(forwarding Forwarding, allowedForwarding AllowedForwarding) error { - if forwarding.Unwind && !allowedForwarding.AllowUnwind { - return errorsmod.Wrap(ErrInvalidForwarding, "not allowed unwind") +func validateForwarding(forwarding Forwarding, allowedForwarding []AllowedForwarding) error { + if forwarding.Unwind { + return errorsmod.Wrap(ErrInvalidForwarding, "not allowed automatic unwind") } - if !isAllowedForwarding(forwarding.Hops, allowedForwarding.AllowedHops) { + if !isAllowedForwarding(forwarding.Hops, allowedForwarding) { return errorsmod.Wrap(ErrInvalidForwarding, "not allowed hops") } @@ -183,7 +183,7 @@ func validateForwarding(forwarding Forwarding, allowedForwarding AllowedForwardi } // isAllowedForwarding returns whether the provided slice of Hop matches one of the allowed ones. -func isAllowedForwarding(hops []Hop, allowed []Hops) bool { +func isAllowedForwarding(hops []Hop, allowed []AllowedForwarding) bool { if len(hops) == 0 { return true } diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index f2cb16e6fd1..74d84086e1c 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -19,7 +19,7 @@ const ( testMemo2 = `{"forward":{"channel":"channel-11","port":"transfer","receiver":"stars1twfv52yxcyykx2lcvgl42svw46hsm5dd4ww6xy","retries":2,"timeout":1712146014542131200}}` ) -var forwardingWithValidHop = []types.Hops{{Hops: []types.Hop{validHop}}} +var forwardingWithValidHop = []types.AllowedForwarding{{Hops: []types.Hop{validHop}}} func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { var ( @@ -106,7 +106,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { func() { allowedList := []string{} transferAuthz.Allocations[0].AllowedPacketData = allowedList - transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = forwardingWithValidHop + transferAuthz.Allocations[0].AllowedForwarding = forwardingWithValidHop msgTransfer.Forwarding = types.NewForwarding(false, validHop) }, func(res authz.AcceptResponse, err error) { @@ -137,7 +137,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { func() { allowedList := []string{"*"} transferAuthz.Allocations[0].AllowedPacketData = allowedList - transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = forwardingWithValidHop + transferAuthz.Allocations[0].AllowedForwarding = forwardingWithValidHop msgTransfer.Forwarding = types.NewForwarding(false, validHop) }, func(res authz.AcceptResponse, err error) { @@ -285,7 +285,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { "success: allowed forwarding hops", func() { msgTransfer.Forwarding = types.NewForwarding(false, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}) - transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = []types.Hops{ + transferAuthz.Allocations[0].AllowedForwarding = []types.AllowedForwarding{ { Hops: []types.Hop{ {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, @@ -302,7 +302,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { { "success: Allocation specify hops but msgTransfer does not have hops", func() { - transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = []types.Hops{ + transferAuthz.Allocations[0].AllowedForwarding = []types.AllowedForwarding{ { Hops: []types.Hop{ {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, @@ -316,17 +316,6 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { suite.Require().True(res.Accept) }, }, - { - "success: Allocation allows unwind and msgTransfer specifies unwind", - func() { - transferAuthz.Allocations[0].AllowedForwarding.AllowUnwind = true - msgTransfer.Forwarding.Unwind = true - }, - func(res authz.AcceptResponse, err error) { - suite.Require().NoError(err) - suite.Require().True(res.Accept) - }, - }, { "failure: multidenom transfer spend limit is exceeded", func() { @@ -409,7 +398,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-3"}, ) - transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = []types.Hops{ + transferAuthz.Allocations[0].AllowedForwarding = []types.AllowedForwarding{ { Hops: []types.Hop{ {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, @@ -430,7 +419,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, types.Hop{PortId: "3", ChannelId: "channel-3"}, ) - transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = []types.Hops{ + transferAuthz.Allocations[0].AllowedForwarding = []types.AllowedForwarding{ { Hops: []types.Hop{ {PortId: ibctesting.MockPort, ChannelId: "channel-1"}, @@ -463,7 +452,7 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-1"}, types.Hop{PortId: ibctesting.MockPort, ChannelId: "channel-2"}, ) - transferAuthz.Allocations[0].AllowedForwarding.AllowedHops = []types.Hops{ + transferAuthz.Allocations[0].AllowedForwarding = []types.AllowedForwarding{ { Hops: []types.Hop{ {PortId: ibctesting.MockPort, ChannelId: "channel-2"}, @@ -482,7 +471,6 @@ func (suite *TypesTestSuite) TestTransferAuthorizationAccept() { "failure: unwind is not allowed", func() { msgTransfer.Forwarding.Unwind = true - transferAuthz.Allocations[0].AllowedForwarding.AllowUnwind = false }, func(res authz.AcceptResponse, err error) { suite.Require().Error(err) diff --git a/proto/ibc/applications/transfer/v1/authz.proto b/proto/ibc/applications/transfer/v1/authz.proto index dfa2399199c..c8f9ca1cc66 100644 --- a/proto/ibc/applications/transfer/v1/authz.proto +++ b/proto/ibc/applications/transfer/v1/authz.proto @@ -24,20 +24,13 @@ message Allocation { // a list only with "*" permits any memo string repeated string allowed_packet_data = 5; // Forwarding options that are allowed. - AllowedForwarding allowed_forwarding = 6 [(gogoproto.nullable) = false]; + repeated AllowedForwarding allowed_forwarding = 6 [(gogoproto.nullable) = false]; } // AllowedForwarding defines which options are allowed for forwarding. message AllowedForwarding { - // Whether to allow automatic unwinding of tokens to the original chain. - bool allow_unwind = 1; // a list of allowed source port ID/channel ID pairs through which the packet is allowed to be forwarded until final // destination - repeated Hops allowed_hops = 2 [(gogoproto.nullable) = false]; -} - -// Hops represent a list of Hop -message Hops { repeated ibc.applications.transfer.v1.Hop hops = 1 [(gogoproto.nullable) = false]; } From 6e1a082015396b68ee296a1b3da93af4ecfe937d Mon Sep 17 00:00:00 2001 From: Cian Hatton Date: Wed, 26 Jun 2024 11:24:45 +0100 Subject: [PATCH 108/141] chore: add packet data validation back (#6704) --- modules/apps/transfer/ibc_module.go | 2 + modules/apps/transfer/keeper/export_test.go | 2 +- modules/apps/transfer/keeper/relay.go | 24 +++++--- modules/apps/transfer/keeper/relay_test.go | 61 +++++++++++++++++---- 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 45a56ec6dc9..c9014bf4f76 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -191,6 +191,8 @@ func (im IBCModule) OnRecvPacket( ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + // we are explicitly wrapping this emit event call in an anonymous function so that + // the packet data is evaluated after it has been assigned a value. defer func() { events.EmitOnRecvPacketEvent(ctx, data, ack, ackErr) }() diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index fa86b405e86..5b7348c5f98 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -39,6 +39,6 @@ func (k Keeper) UnwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgT } // CreatePacketDataBytesFromVersion is a wrapper around createPacketDataBytesFromVersion for testing purposes -func CreatePacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, hops []types.Hop) []byte { +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/relay.go b/modules/apps/transfer/keeper/relay.go index 7cff4bc333c..6c9d67c041b 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -147,7 +147,10 @@ func (k Keeper) sendTransfer( tokens = append(tokens, token) } - packetDataBytes := createPacketDataBytesFromVersion(appVersion, sender.String(), receiver, memo, tokens, forwarding.Hops) + packetDataBytes, err := createPacketDataBytesFromVersion(appVersion, sender.String(), receiver, memo, tokens, forwarding.Hops) + if err != nil { + return 0, err + } sequence, err := k.ics4Wrapper.SendPacket(ctx, channelCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, packetDataBytes) if err != nil { @@ -438,8 +441,7 @@ func (k Keeper) tokenFromCoin(ctx sdk.Context, coin sdk.Coin) (types.Token, erro } // createPacketDataBytesFromVersion creates the packet data bytes to be sent based on the application version. -func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, hops []types.Hop) []byte { - var packetDataBytes []byte +func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, tokens types.Tokens, hops []types.Hop) ([]byte, error) { switch appVersion { case types.V1: // Sanity check, tokens must always be of length 1 if using app version V1. @@ -449,7 +451,12 @@ func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, token := tokens[0] packetData := types.NewFungibleTokenPacketData(token.Denom.Path(), token.Amount, sender, receiver, memo) - packetDataBytes = packetData.GetBytes() + + if err := packetData.ValidateBasic(); err != nil { + return nil, errorsmod.Wrapf(err, "failed to validate %s packet data", types.V1) + } + + return packetData.GetBytes(), nil case types.V2: // If forwarding is needed, move memo to forwarding packet data and set packet.Memo to empty string. var forwardingPacketData types.ForwardingPacketData @@ -459,12 +466,15 @@ func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, } packetData := types.NewFungibleTokenPacketDataV2(tokens, sender, receiver, memo, forwardingPacketData) - packetDataBytes = packetData.GetBytes() + + if err := packetData.ValidateBasic(); err != nil { + return nil, errorsmod.Wrapf(err, "failed to validate %s packet data", types.V2) + } + + return packetData.GetBytes(), nil default: panic(fmt.Errorf("app version must be one of %s", types.SupportedVersions)) } - - return packetDataBytes } // burnCoin sends coins from the account to the transfer module account and then burn them. diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index c739d21187c..390d8530c33 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -1287,24 +1287,26 @@ func (suite *KeeperTestSuite) TestPacketForwardsCompatibility() { func (suite *KeeperTestSuite) TestCreatePacketDataBytesFromVersion() { var ( - bz []byte - tokens types.Tokens + bz []byte + tokens types.Tokens + sender, receiver string ) testCases := []struct { name string appVersion string malleate func() - expResult func(bz []byte) + expResult func(bz []byte, err error) expPanicErr error }{ { "success", types.V1, func() {}, - func(bz []byte) { - expPacketData := types.NewFungibleTokenPacketData("", "", "", "", "") + func(bz []byte, err error) { + expPacketData := types.NewFungibleTokenPacketData(ibctesting.TestCoin.Denom, ibctesting.TestCoin.Amount.String(), sender, receiver, "") suite.Require().Equal(bz, expPacketData.GetBytes()) + suite.Require().NoError(err) }, nil, }, @@ -1312,9 +1314,34 @@ func (suite *KeeperTestSuite) TestCreatePacketDataBytesFromVersion() { "success: version 2", types.V2, func() {}, - func(bz []byte) { - expPacketData := types.NewFungibleTokenPacketDataV2(types.Tokens{types.Token{}}, "", "", "", emptyForwardingPacketData) + func(bz []byte, err error) { + expPacketData := types.NewFungibleTokenPacketDataV2(tokens, sender, receiver, "", emptyForwardingPacketData) suite.Require().Equal(bz, expPacketData.GetBytes()) + suite.Require().NoError(err) + }, + nil, + }, + { + "failure: fails v1 validation", + types.V1, + func() { + sender = "" + }, + func(bz []byte, err error) { + suite.Require().Nil(bz) + suite.Require().ErrorIs(err, ibcerrors.ErrInvalidAddress) + }, + nil, + }, + { + "failure: fails v2 validation", + types.V2, + func() { + sender = "" + }, + func(bz []byte, err error) { + suite.Require().Nil(bz) + suite.Require().ErrorIs(err, ibcerrors.ErrInvalidAddress) }, nil, }, @@ -1338,12 +1365,26 @@ func (suite *KeeperTestSuite) TestCreatePacketDataBytesFromVersion() { for _, tc := range testCases { suite.Run(tc.name, func() { - tokens = types.Tokens{types.Token{}} + suite.SetupTest() + + path := ibctesting.NewTransferPath(suite.chainA, suite.chainB) + path.Setup() + + tokens = types.Tokens{ + { + Amount: ibctesting.TestCoin.Amount.String(), + Denom: types.NewDenom(ibctesting.TestCoin.Denom), + }, + } + + sender = suite.chainA.SenderAccount.GetAddress().String() + receiver = suite.chainB.SenderAccount.GetAddress().String() tc.malleate() + var err error createFunc := func() { - bz = transferkeeper.CreatePacketDataBytesFromVersion(tc.appVersion, "", "", "", tokens, nil) + bz, err = transferkeeper.CreatePacketDataBytesFromVersion(tc.appVersion, sender, receiver, "", tokens, nil) } expPanic := tc.expPanicErr != nil @@ -1351,7 +1392,7 @@ func (suite *KeeperTestSuite) TestCreatePacketDataBytesFromVersion() { suite.Require().PanicsWithError(tc.expPanicErr.Error(), createFunc) } else { createFunc() - tc.expResult(bz) + tc.expResult(bz, err) } }) } From 8f9691fd709c2b652c6a0408cd0ab8f3cee6a4c1 Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Wed, 26 Jun 2024 13:30:41 +0100 Subject: [PATCH 109/141] (chore) Refactor code around forwarding validation (#6706) * Refactor validation * Fixed verification logic, added two tests * Fix check for unwind * removed unneeded indirection * Update modules/apps/transfer/types/msgs.go Co-authored-by: DimitrisJim * Add docstring. --------- Co-authored-by: Gjermund Garaba Co-authored-by: DimitrisJim --- modules/apps/transfer/types/msgs.go | 72 ++++++++++++------------ modules/apps/transfer/types/msgs_test.go | 2 + 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index eafb6abd59e..be3420d233f 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -69,10 +69,22 @@ func NewMsgTransfer( // NOTE: The recipient addresses format is not validated as the format defined by // the chain is not known to IBC. func (msg MsgTransfer) ValidateBasic() error { - if err := validateSourcePortAndChannel(msg); err != nil { - return err // The actual error and its message are already wrapped in the called function. + if err := msg.validateForwarding(); err != nil { + return err } + if !msg.Forwarding.Unwind { + // We verify that portID and channelID are valid IDs only if + // we are not setting unwind to true. + // In that case, validation that they are empty is performed in + // validateForwarding(). + if err := host.PortIdentifierValidator(msg.SourcePort); err != nil { + return errorsmod.Wrap(err, "invalid source port ID") + } + if err := host.ChannelIdentifierValidator(msg.SourceChannel); err != nil { + return errorsmod.Wrap(err, "invalid source channel ID") + } + } if len(msg.Tokens) == 0 && !isValidIBCCoin(msg.Token) { return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, "either token or token array must be filled") } @@ -99,30 +111,42 @@ func (msg MsgTransfer) ValidateBasic() error { return errorsmod.Wrapf(ErrInvalidMemo, "memo must not exceed %d bytes", MaximumMemoLength) } + for _, coin := range msg.GetCoins() { + if err := validateIBCCoin(coin); err != nil { + return errorsmod.Wrapf(ibcerrors.ErrInvalidCoins, "%s: %s", err.Error(), coin.String()) + } + } + + return nil +} + +// validateForwarding ensures that forwarding is set up correctly. +func (msg MsgTransfer) validateForwarding() error { + if !msg.ShouldBeForwarded() { + return nil + } if err := msg.Forwarding.Validate(); err != nil { return err } - if msg.ShouldBeForwarded() { + if !msg.TimeoutHeight.IsZero() { // when forwarding, the timeout height must not be set - if !msg.TimeoutHeight.IsZero() { - return errorsmod.Wrapf(ErrInvalidPacketTimeout, "timeout height must not be set if forwarding path hops is not empty: %s, %s", msg.TimeoutHeight, msg.Forwarding.Hops) - } + return errorsmod.Wrapf(ErrInvalidPacketTimeout, "timeout height must be zero if forwarding path hops is not empty: %s, %s", msg.TimeoutHeight, msg.Forwarding.Hops) } if msg.Forwarding.Unwind { - // When unwinding, we must have at most one token. + if msg.SourcePort != "" { + return errorsmod.Wrapf(ErrInvalidForwarding, "source port must be empty when unwind is set, got %s instead", msg.SourcePort) + } + if msg.SourceChannel != "" { + return errorsmod.Wrapf(ErrInvalidForwarding, "source channel must be empty when unwind is set, got %s instead", msg.SourceChannel) + } if len(msg.GetCoins()) > 1 { + // When unwinding, we must have at most one token. return errorsmod.Wrap(ibcerrors.ErrInvalidCoins, "cannot unwind more than one token") } } - for _, coin := range msg.GetCoins() { - if err := validateIBCCoin(coin); err != nil { - return errorsmod.Wrapf(ibcerrors.ErrInvalidCoins, "%s: %s", err.Error(), coin.String()) - } - } - return nil } @@ -164,25 +188,3 @@ func validateIBCCoin(coin sdk.Coin) error { return nil } - -func validateSourcePortAndChannel(msg MsgTransfer) error { - // If unwind is set, we want to ensure that port and channel are empty. - if msg.Forwarding.Unwind { - if msg.SourcePort != "" { - return errorsmod.Wrapf(ErrInvalidForwarding, "source port must be empty when unwind is set, got %s instead", msg.SourcePort) - } - if msg.SourceChannel != "" { - return errorsmod.Wrapf(ErrInvalidForwarding, "source channel must be empty when unwind is set, got %s instead", msg.SourceChannel) - } - return nil - } - - // Otherwise, we just do the usual validation of the port and channel identifiers. - if err := host.PortIdentifierValidator(msg.SourcePort); err != nil { - return errorsmod.Wrap(err, "invalid source port ID") - } - if err := host.ChannelIdentifierValidator(msg.SourceChannel); err != nil { - return errorsmod.Wrap(err, "invalid source channel ID") - } - return nil -} diff --git a/modules/apps/transfer/types/msgs_test.go b/modules/apps/transfer/types/msgs_test.go index b0ccbb611bf..2fea4f4a5b2 100644 --- a/modules/apps/transfer/types/msgs_test.go +++ b/modules/apps/transfer/types/msgs_test.go @@ -87,6 +87,8 @@ func TestMsgTransferValidation(t *testing.T) { {"invalid forwarding info port", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, types.Hop{PortId: invalidPort, ChannelId: validChannel})), types.ErrInvalidForwarding}, {"invalid forwarding info channel", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, types.Hop{PortId: validPort, ChannelId: invalidChannel})), types.ErrInvalidForwarding}, {"invalid forwarding info too many hops", types.NewMsgTransfer(validPort, validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, generateHops(types.MaximumNumberOfForwardingHops+1)...)), types.ErrInvalidForwarding}, + {"invalid portID when forwarding is set but unwind is not", types.NewMsgTransfer("", validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, validHop)), host.ErrInvalidID}, + {"invalid channelID when forwarding is set but unwind is not", types.NewMsgTransfer(validPort, "", coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(false, validHop)), host.ErrInvalidID}, {"unwind specified but source port is not empty", types.NewMsgTransfer(validPort, "", coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(true)), types.ErrInvalidForwarding}, {"unwind specified but source channel is not empty", types.NewMsgTransfer("", validChannel, coins, sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(true)), types.ErrInvalidForwarding}, {"unwind specified but more than one coin in the message", types.NewMsgTransfer("", "", coins.Add(sdk.NewCoin("atom", ibctesting.TestCoin.Amount)), sender, receiver, clienttypes.ZeroHeight(), 100, "", types.NewForwarding(true)), ibcerrors.ErrInvalidCoins}, From c505243e7b8b01e8fe754ad31c31ce75c60a6cf6 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 26 Jun 2024 14:59:56 +0200 Subject: [PATCH 110/141] use setupForwardingPaths in test --- .../transfer/keeper/relay_forwarding_test.go | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 181d1299317..d162dc96b6d 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -125,23 +125,19 @@ func (suite *KeeperTestSuite) TestSuccessfulForward() { amount := sdkmath.NewInt(100) - path1 := ibctesting.NewTransferPath(suite.chainA, suite.chainB) - path1.Setup() - - path2 := ibctesting.NewTransferPath(suite.chainB, suite.chainC) - path2.Setup() + pathAtoB, pathBtoC := suite.setupForwardingPaths() coinOnA := ibctesting.TestCoin sender := suite.chainA.SenderAccounts[0].SenderAccount receiver := suite.chainC.SenderAccounts[0].SenderAccount forwarding := types.NewForwarding(false, types.Hop{ - PortId: path2.EndpointA.ChannelConfig.PortID, - ChannelId: path2.EndpointA.ChannelID, + PortId: pathBtoC.EndpointA.ChannelConfig.PortID, + ChannelId: pathBtoC.EndpointA.ChannelID, }) transferMsg := types.NewMsgTransfer( - path1.EndpointA.ChannelConfig.PortID, - path1.EndpointA.ChannelID, + pathAtoB.EndpointA.ChannelConfig.PortID, + pathAtoB.EndpointA.ChannelID, sdk.NewCoins(coinOnA), sender.GetAddress().String(), receiver.GetAddress().String(), @@ -158,10 +154,10 @@ func (suite *KeeperTestSuite) TestSuccessfulForward() { suite.Require().NoError(err) suite.Require().NotNil(packetFromAtoB) - err = path1.EndpointB.UpdateClient() + err = pathAtoB.EndpointB.UpdateClient() suite.Require().NoError(err) - result, err = path1.EndpointB.RecvPacketWithResult(packetFromAtoB) + result, err = pathAtoB.EndpointB.RecvPacketWithResult(packetFromAtoB) suite.Require().NoError(err) suite.Require().NotNil(result) @@ -169,30 +165,30 @@ func (suite *KeeperTestSuite) TestSuccessfulForward() { suite.assertAmountOnChain(suite.chainA, escrow, amount, sdk.DefaultBondDenom) // denom path: transfer/channel-0 - denom := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + denom := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID)) suite.assertAmountOnChain(suite.chainB, escrow, amount, denom.IBCDenom()) packetFromBtoC, err := ibctesting.ParsePacketFromEvents(result.Events) suite.Require().NoError(err) suite.Require().NotNil(packetFromBtoC) - err = path2.EndpointA.UpdateClient() + err = pathBtoC.EndpointA.UpdateClient() suite.Require().NoError(err) - err = path2.EndpointB.UpdateClient() + err = pathBtoC.EndpointB.UpdateClient() suite.Require().NoError(err) // B should have stored the forwarded packet. _, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), packetFromBtoC.SourcePort, packetFromBtoC.SourceChannel, packetFromBtoC.Sequence) suite.Require().True(found, "Chain B should have stored the forwarded packet") - result, err = path2.EndpointB.RecvPacketWithResult(packetFromBtoC) + result, err = pathBtoC.EndpointB.RecvPacketWithResult(packetFromBtoC) suite.Require().NoError(err) suite.Require().NotNil(result) // transfer/channel-0/transfer/channel-0/denom // Check that the final receiver has received the expected tokens. - denomABC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(path2.EndpointB.ChannelConfig.PortID, path2.EndpointB.ChannelID), types.NewTrace(path1.EndpointB.ChannelConfig.PortID, path1.EndpointB.ChannelID)) + denomABC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID), types.NewTrace(pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID)) // Check that the final receiver has received the expected tokens. suite.assertAmountOnChain(suite.chainC, balance, amount, denomABC.IBCDenom()) @@ -202,10 +198,10 @@ func (suite *KeeperTestSuite) TestSuccessfulForward() { suite.Require().Equal(successAckBz, ackOnC) // Ack back to B - err = path2.EndpointB.UpdateClient() + err = pathBtoC.EndpointB.UpdateClient() suite.Require().NoError(err) - err = path2.EndpointA.AcknowledgePacket(packetFromBtoC, successAck.Acknowledgement()) + err = pathBtoC.EndpointA.AcknowledgePacket(packetFromBtoC, successAck.Acknowledgement()) suite.Require().NoError(err) ackOnB := suite.chainB.GetAcknowledgement(packetFromAtoB) @@ -216,10 +212,10 @@ func (suite *KeeperTestSuite) TestSuccessfulForward() { suite.Require().False(found, "Chain B should have deleted the forwarded packet") // Ack back to A - err = path1.EndpointA.UpdateClient() + err = pathAtoB.EndpointA.UpdateClient() suite.Require().NoError(err) - err = path1.EndpointA.AcknowledgePacket(packetFromAtoB, successAck.Acknowledgement()) + err = pathAtoB.EndpointA.AcknowledgePacket(packetFromAtoB, successAck.Acknowledgement()) suite.Require().NoError(err) } From d715455f2d95e10d1899499cdf80476089d2b9ea Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Wed, 26 Jun 2024 15:59:44 +0200 Subject: [PATCH 111/141] feat(transfer): allow non-cosmos-sdk AccAddress in final receiver for forwarded packets (#6709) * allow non-cosmos-sdk AccAddress for forwarded packets * cr fixes --- modules/apps/transfer/keeper/forwarding.go | 9 ++- .../transfer/keeper/relay_forwarding_test.go | 79 +++++++++++++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 09dd15ebd9d..4934dea7072 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -134,14 +134,15 @@ func (k Keeper) revertForwardedPacket(ctx sdk.Context, prevPacket channeltypes.P // getReceiverFromPacketData returns either the sender specified in the packet data or the forwarding address // if there are still hops left to perform. func getReceiverFromPacketData(data types.FungibleTokenPacketDataV2, portID, channelID string) (sdk.AccAddress, error) { + if data.ShouldBeForwarded() { + // since data.Receiver can potentially be a non-CosmosSDK AccAddress, we return early if the packet should be forwarded + return types.GetForwardAddress(portID, channelID), nil + } + receiver, err := sdk.AccAddressFromBech32(data.Receiver) if err != nil { return nil, errorsmod.Wrapf(ibcerrors.ErrInvalidAddress, "failed to decode receiver address %s: %v", data.Receiver, err) } - if data.ShouldBeForwarded() { - receiver = types.GetForwardAddress(portID, channelID) - } - return receiver, nil } diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index d162dc96b6d..f5796f47988 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -219,6 +219,85 @@ func (suite *KeeperTestSuite) TestSuccessfulForward() { suite.Require().NoError(err) } +// TestSuccessfulPathForwarding tests that a packet is successfully forwarded with a non-Cosmos account address. +// The test stops before verifying the final receive, because we don't have a non-cosmos chain to test with. +func (suite *KeeperTestSuite) TestSuccessfulForwardWithNonCosmosAccAddress() { + /* + Given the following topology: + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-0) chain C + stake transfer/channel-0/stake transfer/channel-0/transfer/channel-0/stake + We want to trigger: + 1. A sends B over channel-0. + 2. Receive on B. + 2.1 B sends C over channel-1 + 3. Receive on C. + At this point we want to assert: + A: packet gets relayed properly with final receiver intact + B: packet arrives and is forwarded with final receiver intact + C: no assertions as we don't have a non-cosmos chain to test with, so this would fail here + */ + + amount := sdkmath.NewInt(100) + + pathAtoB, pathBtoC := suite.setupForwardingPaths() + + sender := suite.chainA.SenderAccounts[0].SenderAccount + nonCosmosReceiver := "0x42069163Ac5919fD49e6A67e6c211E0C86397fa2" + forwarding := types.NewForwarding(false, types.Hop{ + PortId: pathBtoC.EndpointA.ChannelConfig.PortID, + ChannelId: pathBtoC.EndpointA.ChannelID, + }) + + transferMsg := types.NewMsgTransfer( + pathAtoB.EndpointA.ChannelConfig.PortID, + pathAtoB.EndpointA.ChannelID, + sdk.NewCoins(ibctesting.TestCoin), + sender.GetAddress().String(), + nonCosmosReceiver, + clienttypes.ZeroHeight(), + suite.chainA.GetTimeoutTimestamp(), "", + forwarding, + ) + + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packetFromAtoB, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetFromAtoB) + + // Check that the token sent from A has final receiver intact + var tokenPacketOnA types.FungibleTokenPacketDataV2 + err = suite.chainA.Codec.UnmarshalJSON(packetFromAtoB.Data, &tokenPacketOnA) + suite.Require().NoError(err) + suite.Require().Equal(nonCosmosReceiver, tokenPacketOnA.Receiver) + + err = pathAtoB.EndpointB.UpdateClient() + suite.Require().NoError(err) + + result, err = pathAtoB.EndpointB.RecvPacketWithResult(packetFromAtoB) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that Escrow A has amount + suite.assertAmountOnChain(suite.chainA, escrow, amount, sdk.DefaultBondDenom) + + packetFromBtoC, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetFromBtoC) + + // Check that the token sent from B has final receiver intact + var tokenPacketOnB types.FungibleTokenPacketDataV2 + err = suite.chainB.Codec.UnmarshalJSON(packetFromBtoC.Data, &tokenPacketOnB) + suite.Require().NoError(err) + suite.Require().Equal(nonCosmosReceiver, tokenPacketOnB.Receiver) + + // B should have stored the forwarded packet. + _, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), packetFromBtoC.SourcePort, packetFromBtoC.SourceChannel, packetFromBtoC.Sequence) + suite.Require().True(found, "Chain B should have stored the forwarded packet") +} + // TestSuccessfulUnwind tests unwinding of tokens sent from A -> B -> C by // forwarding the tokens back from C -> B -> A. func (suite *KeeperTestSuite) TestSuccessfulUnwind() { From 4e61ea93faff92682d805f42f4237b1b18ed2592 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Wed, 26 Jun 2024 16:38:50 +0200 Subject: [PATCH 112/141] chore: pass only hops to sendTransfer + events rename (#6703) Co-authored-by: Carlos Rodriguez --- modules/apps/transfer/ibc_module_test.go | 15 ++++++--------- .../apps/transfer/internal/events/events.go | 18 +++++++++--------- modules/apps/transfer/keeper/msg_server.go | 2 +- .../apps/transfer/keeper/msg_server_test.go | 4 ++-- modules/apps/transfer/keeper/relay.go | 8 ++++---- modules/apps/transfer/types/events.go | 2 +- 6 files changed, 23 insertions(+), 26 deletions(-) diff --git a/modules/apps/transfer/ibc_module_test.go b/modules/apps/transfer/ibc_module_test.go index 327009b0ef4..c524bb42cc5 100644 --- a/modules/apps/transfer/ibc_module_test.go +++ b/modules/apps/transfer/ibc_module_test.go @@ -307,11 +307,11 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { ) packet.Data = packetData.GetBytes() - forwardingBz, err := json.Marshal(packetData.Forwarding) + forwardingHopsBz, err := json.Marshal(packetData.Forwarding.Hops) suite.Require().NoError(err) for i, attr := range expectedAttributes { - if attr.Key == types.AttributeKeyForwarding { - expectedAttributes[i].Value = string(forwardingBz) + if attr.Key == types.AttributeKeyForwardingHops { + expectedAttributes[i].Value = string(forwardingHopsBz) break } } @@ -325,15 +325,12 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { packet.Data = []byte("invalid data") // Override expected attributes because this fails on unmarshaling packet data (so can't get the attributes) - forwardingBz, err := json.Marshal(types.Forwarding{}) - suite.Require().NoError(err) - expectedAttributes = []sdk.Attribute{ sdk.NewAttribute(types.AttributeKeySender, ""), sdk.NewAttribute(types.AttributeKeyReceiver, ""), sdk.NewAttribute(types.AttributeKeyTokens, "null"), sdk.NewAttribute(types.AttributeKeyMemo, ""), - sdk.NewAttribute(types.AttributeKeyForwarding, string(forwardingBz)), + sdk.NewAttribute(types.AttributeKeyForwardingHops, "null"), sdk.NewAttribute(types.AttributeKeyAckSuccess, "false"), sdk.NewAttribute(types.AttributeKeyAckError, "cannot unmarshal ICS20-V2 transfer packet data: invalid character 'i' looking for beginning of value: invalid type: invalid type"), } @@ -373,7 +370,7 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { tokensBz, err := json.Marshal(packetData.Tokens) suite.Require().NoError(err) - forwardingBz, err := json.Marshal(packetData.Forwarding) + forwardingHopsBz, err := json.Marshal(packetData.Forwarding.Hops) suite.Require().NoError(err) expectedAttributes = []sdk.Attribute{ @@ -381,7 +378,7 @@ func (suite *TransferTestSuite) TestOnRecvPacket() { sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver), sdk.NewAttribute(types.AttributeKeyTokens, string(tokensBz)), sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), - sdk.NewAttribute(types.AttributeKeyForwarding, string(forwardingBz)), + sdk.NewAttribute(types.AttributeKeyForwardingHops, string(forwardingHopsBz)), } if tc.expAck == nil || tc.expAck.Success() { expectedAttributes = append(expectedAttributes, sdk.NewAttribute(types.AttributeKeyAckSuccess, "true")) diff --git a/modules/apps/transfer/internal/events/events.go b/modules/apps/transfer/internal/events/events.go index 70556ab5c97..8bcbf49bb6d 100644 --- a/modules/apps/transfer/internal/events/events.go +++ b/modules/apps/transfer/internal/events/events.go @@ -11,9 +11,9 @@ import ( ) // EmitTransferEvent emits a ibc transfer event on successful transfers. -func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.Tokens, memo string, forwarding types.Forwarding) { +func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.Tokens, memo string, forwardingHops []types.Hop) { tokensStr := mustMarshalType[types.Tokens](tokens) - forwardingStr := mustMarshalType[types.Forwarding](forwarding) + forwardingHopsStr := mustMarshalType[[]types.Hop](forwardingHops) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( @@ -22,7 +22,7 @@ func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.To sdk.NewAttribute(types.AttributeKeyReceiver, receiver), sdk.NewAttribute(types.AttributeKeyTokens, tokensStr), sdk.NewAttribute(types.AttributeKeyMemo, memo), - sdk.NewAttribute(types.AttributeKeyForwarding, forwardingStr), + sdk.NewAttribute(types.AttributeKeyForwardingHops, forwardingHopsStr), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -34,14 +34,14 @@ func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.To // EmitOnRecvPacketEvent emits a fungible token packet event in the OnRecvPacket callback func EmitOnRecvPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement, ackErr error) { tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) - forwardingStr := mustMarshalType[types.ForwardingPacketData](packetData.Forwarding) + forwardingHopStr := mustMarshalType[[]types.Hop](packetData.Forwarding.Hops) eventAttributes := []sdk.Attribute{ sdk.NewAttribute(types.AttributeKeySender, packetData.Sender), sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver), sdk.NewAttribute(types.AttributeKeyTokens, tokensStr), sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), - sdk.NewAttribute(types.AttributeKeyForwarding, forwardingStr), + sdk.NewAttribute(types.AttributeKeyForwardingHops, forwardingHopStr), sdk.NewAttribute(types.AttributeKeyAckSuccess, strconv.FormatBool(ack.Success())), } @@ -64,7 +64,7 @@ func EmitOnRecvPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacket // EmitOnAcknowledgementPacketEvent emits a fungible token packet event in the OnAcknowledgementPacket callback func EmitOnAcknowledgementPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) { tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) - forwardingStr := mustMarshalType[types.ForwardingPacketData](packetData.Forwarding) + forwardingHopsStr := mustMarshalType[[]types.Hop](packetData.Forwarding.Hops) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( @@ -73,7 +73,7 @@ func EmitOnAcknowledgementPacketEvent(ctx sdk.Context, packetData types.Fungible sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver), sdk.NewAttribute(types.AttributeKeyTokens, tokensStr), sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), - sdk.NewAttribute(types.AttributeKeyForwarding, forwardingStr), + sdk.NewAttribute(types.AttributeKeyForwardingHops, forwardingHopsStr), sdk.NewAttribute(types.AttributeKeyAck, ack.String()), ), sdk.NewEvent( @@ -103,7 +103,7 @@ func EmitOnAcknowledgementPacketEvent(ctx sdk.Context, packetData types.Fungible // EmitOnTimeoutEvent emits a fungible token packet event in the OnTimeoutPacket callback func EmitOnTimeoutEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2) { tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) - forwardingStr := mustMarshalType[types.ForwardingPacketData](packetData.Forwarding) + forwardingHopsStr := mustMarshalType[[]types.Hop](packetData.Forwarding.Hops) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( @@ -111,7 +111,7 @@ func EmitOnTimeoutEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDat sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Sender), sdk.NewAttribute(types.AttributeKeyRefundTokens, tokensStr), sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo), - sdk.NewAttribute(types.AttributeKeyForwarding, forwardingStr), + sdk.NewAttribute(types.AttributeKeyForwardingHops, forwardingHopsStr), ), sdk.NewEvent( sdk.EventTypeMessage, diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 55202574157..689b44084d5 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -45,7 +45,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. sequence, err := k.sendTransfer( ctx, msg.SourcePort, msg.SourceChannel, coins, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp, - msg.Memo, msg.Forwarding) + msg.Memo, msg.Forwarding.Hops) if err != nil { return nil, err } diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 95e1734d209..0d17738263e 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -153,7 +153,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { tokensBz, err := json.Marshal(types.Tokens(tokens)) suite.Require().NoError(err) - forwardingBz, err := json.Marshal(msg.Forwarding) + forwardingHopsBz, err := json.Marshal(msg.Forwarding.Hops) suite.Require().NoError(err) res, err := suite.chainA.GetSimApp().TransferKeeper.Transfer(ctx, msg) @@ -168,7 +168,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), sdk.NewAttribute(types.AttributeKeyTokens, string(tokensBz)), sdk.NewAttribute(types.AttributeKeyMemo, msg.Memo), - sdk.NewAttribute(types.AttributeKeyForwarding, string(forwardingBz)), + sdk.NewAttribute(types.AttributeKeyForwardingHops, string(forwardingHopsBz)), ), sdk.NewEvent( sdk.EventTypeMessage, diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 6c9d67c041b..a4712c12f58 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -64,7 +64,7 @@ func (k Keeper) sendTransfer( timeoutHeight clienttypes.Height, timeoutTimestamp uint64, memo string, - forwarding types.Forwarding, + hops []types.Hop, ) (uint64, error) { channel, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) if !found { @@ -83,7 +83,7 @@ func (k Keeper) sendTransfer( } // ics20-1 does not support forwarding, so if that is the current version, we must reject the transfer. - if len(forwarding.Hops) > 0 { + if len(hops) > 0 { return 0, errorsmod.Wrapf(ibcerrors.ErrInvalidRequest, "cannot forward coins with %s", types.V1) } } @@ -147,7 +147,7 @@ func (k Keeper) sendTransfer( tokens = append(tokens, token) } - packetDataBytes, err := createPacketDataBytesFromVersion(appVersion, sender.String(), receiver, memo, tokens, forwarding.Hops) + packetDataBytes, err := createPacketDataBytesFromVersion(appVersion, sender.String(), receiver, memo, tokens, hops) if err != nil { return 0, err } @@ -157,7 +157,7 @@ func (k Keeper) sendTransfer( return 0, err } - events.EmitTransferEvent(ctx, sender.String(), receiver, tokens, memo, forwarding) + events.EmitTransferEvent(ctx, sender.String(), receiver, tokens, memo, hops) defer internaltelemetry.ReportTransferTelemetry(tokens, labels) diff --git a/modules/apps/transfer/types/events.go b/modules/apps/transfer/types/events.go index 90f2137d11f..f5ad7210431 100644 --- a/modules/apps/transfer/types/events.go +++ b/modules/apps/transfer/types/events.go @@ -19,5 +19,5 @@ const ( AttributeKeyAck = "acknowledgement" AttributeKeyAckError = "error" AttributeKeyMemo = "memo" - AttributeKeyForwarding = "forwarding" + AttributeKeyForwardingHops = "forwarding_hops" ) From 3e2a5fa97186ecd6ac9ad46ffe16c46c24c83984 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Wed, 26 Jun 2024 16:59:26 +0200 Subject: [PATCH 113/141] test: forwarding test that verifies forwarded memo (#6707) * test: forwarding with memo * fix test * cr fixes --- .../transfer/keeper/relay_forwarding_test.go | 140 ++++++++++++++++++ testing/events.go | 19 ++- testing/events_test.go | 2 +- 3 files changed, 156 insertions(+), 5 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index f5796f47988..f34c527aeb5 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -219,6 +219,146 @@ func (suite *KeeperTestSuite) TestSuccessfulForward() { suite.Require().NoError(err) } +// TestSuccessfulPathForwarding tests a successful transfer from A to C through B with a memo that should arrive at C. +func (suite *KeeperTestSuite) TestSuccessfulForwardWithMemo() { + /* + Given the following topology: + chain A (channel 0) -> (channel-0) chain B (channel-1) -> (channel-0) chain C + stake transfer/channel-0/stake transfer/channel-0/transfer/channel-0/stake + We want to trigger: + 1. A sends B over channel-0. + 2. Receive on B. + 2.1 B sends C over channel-1 + 3. Receive on C. + At this point we want to assert: + A: escrowA = amount,stake + B: escrowB = amount,transfer/channel-0/denom + C: finalReceiver = amount,transfer/channel-0/transfer/channel-0/denom,memo + */ + + amount := sdkmath.NewInt(100) + testMemo := "test forwarding memo" + + pathAtoB, pathBtoC := suite.setupForwardingPaths() + + coinOnA := ibctesting.TestCoin + sender := suite.chainA.SenderAccounts[0].SenderAccount + receiver := suite.chainC.SenderAccounts[0].SenderAccount + forwarding := types.NewForwarding(false, types.Hop{ + PortId: pathBtoC.EndpointA.ChannelConfig.PortID, + ChannelId: pathBtoC.EndpointA.ChannelID, + }) + + transferMsg := types.NewMsgTransfer( + pathAtoB.EndpointA.ChannelConfig.PortID, + pathAtoB.EndpointA.ChannelID, + sdk.NewCoins(coinOnA), + sender.GetAddress().String(), + receiver.GetAddress().String(), + clienttypes.ZeroHeight(), + suite.chainA.GetTimeoutTimestamp(), + testMemo, + forwarding, + ) + + result, err := suite.chainA.SendMsgs(transferMsg) + suite.Require().NoError(err) // message committed + + // parse the packet from result events and recv packet on chainB + packetFromAtoB, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetFromAtoB) + + err = pathAtoB.EndpointB.UpdateClient() + suite.Require().NoError(err) + + // Check that the memo is stored correctly in the packet sent from A + var tokenPacketOnA types.FungibleTokenPacketDataV2 + err = suite.chainA.Codec.UnmarshalJSON(packetFromAtoB.Data, &tokenPacketOnA) + suite.Require().NoError(err) + suite.Require().Equal("", tokenPacketOnA.Memo) + suite.Require().Equal(testMemo, tokenPacketOnA.Forwarding.DestinationMemo) + + result, err = pathAtoB.EndpointB.RecvPacketWithResult(packetFromAtoB) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + // Check that Escrow A has amount + suite.assertAmountOnChain(suite.chainA, escrow, amount, sdk.DefaultBondDenom) + + // denom path: transfer/channel-0 + denom := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID)) + suite.assertAmountOnChain(suite.chainB, escrow, amount, denom.IBCDenom()) + + packetFromBtoC, err := ibctesting.ParsePacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetFromBtoC) + + // Check that the memo is stored correctly in the packet sent from B + var tokenPacketOnB types.FungibleTokenPacketDataV2 + err = suite.chainB.Codec.UnmarshalJSON(packetFromBtoC.Data, &tokenPacketOnB) + suite.Require().NoError(err) + suite.Require().Equal(testMemo, tokenPacketOnB.Memo) + suite.Require().Equal("", tokenPacketOnB.Forwarding.DestinationMemo) + + err = pathBtoC.EndpointA.UpdateClient() + suite.Require().NoError(err) + + err = pathBtoC.EndpointB.UpdateClient() + suite.Require().NoError(err) + + // B should have stored the forwarded packet. + _, found := suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), packetFromBtoC.SourcePort, packetFromBtoC.SourceChannel, packetFromBtoC.Sequence) + suite.Require().True(found, "Chain B should have stored the forwarded packet") + + result, err = pathBtoC.EndpointB.RecvPacketWithResult(packetFromBtoC) + suite.Require().NoError(err) + suite.Require().NotNil(result) + + packetOnC, err := ibctesting.ParseRecvPacketFromEvents(result.Events) + suite.Require().NoError(err) + suite.Require().NotNil(packetOnC) + + // Check that the memo is stored directly in the memo field on C + var tokenPacketOnC types.FungibleTokenPacketDataV2 + err = suite.chainC.Codec.UnmarshalJSON(packetOnC.Data, &tokenPacketOnC) + suite.Require().NoError(err) + suite.Require().Equal("", tokenPacketOnC.Forwarding.DestinationMemo) + suite.Require().Equal(testMemo, tokenPacketOnC.Memo) + + // transfer/channel-0/transfer/channel-0/denom + // Check that the final receiver has received the expected tokens. + denomABC := types.NewDenom(sdk.DefaultBondDenom, types.NewTrace(pathBtoC.EndpointB.ChannelConfig.PortID, pathBtoC.EndpointB.ChannelID), types.NewTrace(pathAtoB.EndpointB.ChannelConfig.PortID, pathAtoB.EndpointB.ChannelID)) + // Check that the final receiver has received the expected tokens. + suite.assertAmountOnChain(suite.chainC, balance, amount, denomABC.IBCDenom()) + + successAck := channeltypes.NewResultAcknowledgement([]byte{byte(1)}) + successAckBz := channeltypes.CommitAcknowledgement(successAck.Acknowledgement()) + ackOnC := suite.chainC.GetAcknowledgement(packetFromBtoC) + suite.Require().Equal(successAckBz, ackOnC) + + // Ack back to B + err = pathBtoC.EndpointB.UpdateClient() + suite.Require().NoError(err) + + err = pathBtoC.EndpointA.AcknowledgePacket(packetFromBtoC, successAck.Acknowledgement()) + suite.Require().NoError(err) + + ackOnB := suite.chainB.GetAcknowledgement(packetFromAtoB) + suite.Require().Equal(successAckBz, ackOnB) + + // B should now have deleted the forwarded packet. + _, found = suite.chainB.GetSimApp().TransferKeeper.GetForwardedPacket(suite.chainB.GetContext(), packetFromBtoC.SourcePort, packetFromBtoC.SourceChannel, packetFromBtoC.Sequence) + suite.Require().False(found, "Chain B should have deleted the forwarded packet") + + // Ack back to A + err = pathAtoB.EndpointA.UpdateClient() + suite.Require().NoError(err) + + err = pathAtoB.EndpointA.AcknowledgePacket(packetFromAtoB, successAck.Acknowledgement()) + suite.Require().NoError(err) +} + // TestSuccessfulPathForwarding tests that a packet is successfully forwarded with a non-Cosmos account address. // The test stops before verifying the final receive, because we don't have a non-cosmos chain to test with. func (suite *KeeperTestSuite) TestSuccessfulForwardWithNonCosmosAccAddress() { diff --git a/testing/events.go b/testing/events.go index 5954b5b4b51..3e1db55ee6a 100644 --- a/testing/events.go +++ b/testing/events.go @@ -62,10 +62,21 @@ func ParseChannelIDFromEvents(events []abci.Event) (string, error) { } // ParsePacketFromEvents parses events emitted from a MsgRecvPacket and returns -// the first packet found. +// the first EventTypeSendPacket packet found. // Returns an error if no packet is found. func ParsePacketFromEvents(events []abci.Event) (channeltypes.Packet, error) { - packets, err := ParsePacketsFromEvents(events) + packets, err := ParsePacketsFromEvents(channeltypes.EventTypeSendPacket, events) + if err != nil { + return channeltypes.Packet{}, err + } + return packets[0], nil +} + +// ParseRecvPacketFromEvents parses events emitted from a MsgRecvPacket and returns +// the first EventTypeRecvPacket packet found. +// Returns an error if no packet is found. +func ParseRecvPacketFromEvents(events []abci.Event) (channeltypes.Packet, error) { + packets, err := ParsePacketsFromEvents(channeltypes.EventTypeRecvPacket, events) if err != nil { return channeltypes.Packet{}, err } @@ -75,13 +86,13 @@ func ParsePacketFromEvents(events []abci.Event) (channeltypes.Packet, error) { // ParsePacketsFromEvents parses events emitted from a MsgRecvPacket and returns // all the packets found. // Returns an error if no packet is found. -func ParsePacketsFromEvents(events []abci.Event) ([]channeltypes.Packet, error) { +func ParsePacketsFromEvents(eventType string, events []abci.Event) ([]channeltypes.Packet, error) { ferr := func(err error) ([]channeltypes.Packet, error) { return nil, fmt.Errorf("ibctesting.ParsePacketsFromEvents: %w", err) } var packets []channeltypes.Packet for _, ev := range events { - if ev.Type == channeltypes.EventTypeSendPacket { + if ev.Type == eventType { var packet channeltypes.Packet for _, attr := range ev.Attributes { switch attr.Key { diff --git a/testing/events_test.go b/testing/events_test.go index a9cf524c68a..c99eceec00c 100644 --- a/testing/events_test.go +++ b/testing/events_test.go @@ -199,7 +199,7 @@ func TestParsePacketsFromEvents(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - allPackets, err := ibctesting.ParsePacketsFromEvents(tc.events) + allPackets, err := ibctesting.ParsePacketsFromEvents(channeltypes.EventTypeSendPacket, tc.events) if tc.expectedError == "" { require.NoError(t, err) From 5ea9d7982ce0890f3f0fa3bb68e8f2a72618e453 Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Wed, 26 Jun 2024 17:15:53 +0200 Subject: [PATCH 114/141] chore: update godoc for relay forwarding tests --- modules/apps/transfer/keeper/relay_forwarding_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index f34c527aeb5..70145734d3a 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -106,7 +106,7 @@ func (suite *KeeperTestSuite) TestStoredForwardedPacketAndEscrowAfterFirstHop() suite.assertAmountOnChain(suite.chainB, escrow, amount, denom.IBCDenom()) } -// TestSuccessfulPathForwarding tests a successful transfer from A to C through B. +// TestSuccessfulForward tests a successful transfer from A to C through B. func (suite *KeeperTestSuite) TestSuccessfulForward() { /* Given the following topology: @@ -219,7 +219,7 @@ func (suite *KeeperTestSuite) TestSuccessfulForward() { suite.Require().NoError(err) } -// TestSuccessfulPathForwarding tests a successful transfer from A to C through B with a memo that should arrive at C. +// TestSuccessfulForwardWithMemo tests a successful transfer from A to C through B with a memo that should arrive at C. func (suite *KeeperTestSuite) TestSuccessfulForwardWithMemo() { /* Given the following topology: @@ -359,7 +359,7 @@ func (suite *KeeperTestSuite) TestSuccessfulForwardWithMemo() { suite.Require().NoError(err) } -// TestSuccessfulPathForwarding tests that a packet is successfully forwarded with a non-Cosmos account address. +// TestSuccessfulForwardWithNonCosmosAccAddress tests that a packet is successfully forwarded with a non-Cosmos account address. // The test stops before verifying the final receive, because we don't have a non-cosmos chain to test with. func (suite *KeeperTestSuite) TestSuccessfulForwardWithNonCosmosAccAddress() { /* From 100ccc7934acccfc7204005e48e6c707670ec26b Mon Sep 17 00:00:00 2001 From: Gjermund Garaba Date: Wed, 26 Jun 2024 17:28:07 +0200 Subject: [PATCH 115/141] chore: use module account instead of custom forward address (#6688) * chore: use module account instead of custom forward address * pull blocked addr checker into keeper method * lint * clean up IsBlockedAddr --- modules/apps/transfer/keeper/forwarding.go | 10 +++--- modules/apps/transfer/keeper/keeper.go | 11 ++++++ modules/apps/transfer/keeper/keeper_test.go | 35 +++++++++++++++++++ modules/apps/transfer/keeper/msg_server.go | 2 +- .../apps/transfer/keeper/msg_server_test.go | 3 +- modules/apps/transfer/keeper/relay.go | 22 +++++++++--- .../transfer/keeper/relay_forwarding_test.go | 2 +- modules/apps/transfer/keeper/relay_test.go | 9 ++--- modules/apps/transfer/types/keys.go | 17 --------- 9 files changed, 77 insertions(+), 34 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 4934dea7072..ef103671cd3 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -20,8 +20,8 @@ func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDat nextForwardingPath = types.NewForwarding(false, data.Forwarding.Hops[1:]...) } - // sending from the forward escrow address to the original receiver address. - sender := types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel) + // sending from module account (used as a temporary forward escrow) to the original receiver address. + sender := k.authKeeper.GetModuleAddress(types.ModuleName) msg := types.NewMsgTransfer( data.Forwarding.Hops[0].PortId, @@ -101,7 +101,7 @@ func (k Keeper) revertForwardedPacket(ctx sdk.Context, prevPacket channeltypes.P 2. Burning voucher tokens if the funds are foreign */ - forwardingAddr := types.GetForwardAddress(prevPacket.DestinationPort, prevPacket.DestinationChannel) + forwardingAddr := k.authKeeper.GetModuleAddress(types.ModuleName) escrow := types.GetEscrowAddress(prevPacket.DestinationPort, prevPacket.DestinationChannel) // we can iterate over the received tokens of prevPacket by iterating over the sent tokens of failedPacketData @@ -133,10 +133,10 @@ func (k Keeper) revertForwardedPacket(ctx sdk.Context, prevPacket channeltypes.P // getReceiverFromPacketData returns either the sender specified in the packet data or the forwarding address // if there are still hops left to perform. -func getReceiverFromPacketData(data types.FungibleTokenPacketDataV2, portID, channelID string) (sdk.AccAddress, error) { +func (k Keeper) getReceiverFromPacketData(data types.FungibleTokenPacketDataV2) (sdk.AccAddress, error) { if data.ShouldBeForwarded() { // since data.Receiver can potentially be a non-CosmosSDK AccAddress, we return early if the packet should be forwarded - return types.GetForwardAddress(portID, channelID), nil + return k.authKeeper.GetModuleAddress(types.ModuleName), nil } receiver, err := sdk.AccAddressFromBech32(data.Receiver) diff --git a/modules/apps/transfer/keeper/keeper.go b/modules/apps/transfer/keeper/keeper.go index d9d8d60b546..2af2697ba7b 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -336,3 +336,14 @@ func (k Keeper) deleteForwardedPacket(ctx sdk.Context, portID, channelID string, store.Delete(packetKey) } + +// 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 { + moduleAddr := k.authKeeper.GetModuleAddress(types.ModuleName) + if addr.Equals(moduleAddr) { + return false + } + + return k.bankKeeper.BlockedAddr(addr) +} diff --git a/modules/apps/transfer/keeper/keeper_test.go b/modules/apps/transfer/keeper/keeper_test.go index f9f0e658f15..b37592d85d2 100644 --- a/modules/apps/transfer/keeper/keeper_test.go +++ b/modules/apps/transfer/keeper/keeper_test.go @@ -13,6 +13,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" @@ -350,3 +351,37 @@ func (suite *KeeperTestSuite) TestWithICS4Wrapper() { suite.Require().IsType((*channelkeeper.Keeper)(nil), ics4Wrapper) } + +func (suite *KeeperTestSuite) TestIsBlockedAddr() { + suite.SetupTest() + + testCases := []struct { + name string + addr sdk.AccAddress + expBlock bool + }{ + { + "transfer module account address", + suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName), + false, + }, + { + "regular address", + suite.chainA.SenderAccount.GetAddress(), + false, + }, + { + "blocked address", + suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(minttypes.ModuleName), + true, + }, + } + + for _, tc := range testCases { + tc := tc + + suite.Run(tc.name, func() { + suite.Require().Equal(tc.expBlock, suite.chainA.GetSimApp().TransferKeeper.IsBlockedAddr(tc.addr)) + }) + } +} diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 689b44084d5..555217d5191 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -32,7 +32,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. return nil, errorsmod.Wrapf(types.ErrSendDisabled, err.Error()) } - if k.bankKeeper.BlockedAddr(sender) { + if k.IsBlockedAddr(sender) { return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to send funds", sender) } diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 0d17738263e..0f7c41971fb 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" abci "github.com/cometbft/cometbft/abci/types" @@ -80,7 +81,7 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { { "failure: sender is a blocked address", func() { - msg.Sender = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName).String() + msg.Sender = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(minttypes.ModuleName).String() }, ibcerrors.ErrUnauthorized, }, diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index a4712c12f58..d5d6cb2b13d 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/events" internaltelemetry "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/telemetry" @@ -179,7 +180,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return types.ErrReceiveDisabled } - receiver, err := getReceiverFromPacketData(data, packet.DestinationPort, packet.DestinationChannel) + receiver, err := k.getReceiverFromPacketData(data) if err != nil { return err } @@ -212,7 +213,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t coin := sdk.NewCoin(token.Denom.IBCDenom(), transferAmount) - if k.bankKeeper.BlockedAddr(receiver) { + if k.IsBlockedAddr(receiver) { return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) } @@ -259,8 +260,15 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t } // send to receiver - if err := k.bankKeeper.SendCoinsFromModuleToAccount( - ctx, types.ModuleName, receiver, sdk.NewCoins(voucher), + if k.IsBlockedAddr(receiver) { + return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) + } + moduleAddr := k.authKeeper.GetModuleAddress(types.ModuleName) + if moduleAddr == nil { + return errorsmod.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", types.ModuleName) + } + if err := k.bankKeeper.SendCoins( + ctx, moduleAddr, receiver, sdk.NewCoins(voucher), ); err != nil { return errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()) } @@ -339,6 +347,7 @@ func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, dat func (k Keeper) refundPacketTokens(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2) error { // NOTE: packet data type already checked in handler.go + moduleAccountAddr := k.authKeeper.GetModuleAddress(types.ModuleName) for _, token := range data.Tokens { coin, err := token.ToCoin() if err != nil { @@ -368,7 +377,10 @@ func (k Keeper) refundPacketTokens(ctx sdk.Context, packet channeltypes.Packet, return err } - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, sdk.NewCoins(coin)); err != nil { + if k.IsBlockedAddr(sender) { + return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to send funds", sender) + } + if err := k.bankKeeper.SendCoins(ctx, moduleAccountAddr, sender, sdk.NewCoins(coin)); err != nil { panic(fmt.Errorf("unable to send coins from module to account despite previously minting coins to module account: %v", err)) } } diff --git a/modules/apps/transfer/keeper/relay_forwarding_test.go b/modules/apps/transfer/keeper/relay_forwarding_test.go index 70145734d3a..292cd88ed5f 100644 --- a/modules/apps/transfer/keeper/relay_forwarding_test.go +++ b/modules/apps/transfer/keeper/relay_forwarding_test.go @@ -951,7 +951,7 @@ func (suite *KeeperTestSuite) TestOnTimeoutPacketForwarding() { suite.Require().True(found, "Chain B has no forwarded packet") suite.Require().Equal(packet, forwardedPacket, "ForwardedPacket stored in ChainB is not the same that was sent") - address := types.GetForwardAddress(packet.DestinationPort, packet.DestinationChannel).String() + address := suite.chainB.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName).String() data := types.NewFungibleTokenPacketDataV2( []types.Token{ { diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index 390d8530c33..d6ddbbd3aec 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -11,6 +11,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" transferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" @@ -124,7 +125,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() { { "failure: sender account is blocked", func() { - sender = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName) + sender = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(minttypes.ModuleName) }, ibcerrors.ErrUnauthorized, }, @@ -364,9 +365,9 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsNotSource() { { "failure: receiver is module account", func() { - receiver = suite.chainB.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName).String() + receiver = suite.chainB.GetSimApp().AccountKeeper.GetModuleAddress(minttypes.ModuleName).String() }, - sdkerrors.ErrUnauthorized, + ibcerrors.ErrUnauthorized, }, { "failure: receive is disabled", @@ -522,7 +523,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsSource() { { "failure: receiver is module account", func() { - receiver = suite.chainB.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName).String() + receiver = suite.chainB.GetSimApp().AccountKeeper.GetModuleAddress(minttypes.ModuleName).String() expEscrowAmount = sdkmath.NewInt(100) }, ibcerrors.ErrUnauthorized, diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index fac10003053..8975db4e893 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -49,9 +49,6 @@ const ( // this address has been reasoned about to avoid collisions with other addresses // https://github.com/cosmos/cosmos-sdk/issues/7737#issuecomment-735671951 escrowAddressVersion = V1 - - // this new address is introduced specifically with ics20-2. - forwardAddressVersion = "forwardingAddress" ) var ( @@ -82,20 +79,6 @@ func GetEscrowAddress(portID, channelID string) sdk.AccAddress { return hash[:20] } -// GetForwardAddress returns the escrow address for the specified channel. -func GetForwardAddress(portID, channelID string) sdk.AccAddress { - // a slash is used to create domain separation between port and channel identifiers to - // prevent address collisions between escrow addresses created for different channels - contents := fmt.Sprintf("%s/%s", portID, channelID) - - // ADR 028 AddressHash construction - preImage := []byte(forwardAddressVersion) - preImage = append(preImage, 0) - preImage = append(preImage, contents...) - hash := sha256.Sum256(preImage) - return hash[:20] -} - // TotalEscrowForDenomKey returns the store key of under which the total amount of // source chain tokens in escrow is stored. func TotalEscrowForDenomKey(denom string) []byte { From 13d3ac6d474f66e7113c9026a8ea09658fbe588e Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Wed, 26 Jun 2024 21:10:03 +0200 Subject: [PATCH 116/141] chore: replace continue with if/else (#6700) Co-authored-by: Nikolas De Giorgis --- modules/apps/transfer/keeper/relay.go | 77 +++++++++++++-------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index d5d6cb2b13d..66d7359585e 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -228,56 +228,53 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t // Appending token. The new denom has been computed receivedCoins = append(receivedCoins, coin) + } else { + // sender chain is the source, mint vouchers - // Continue processing rest of tokens in packet data. - continue - } + // since SendPacket did not prefix the denomination, we must add the destination port and channel to the trace + trace := []types.Trace{types.NewTrace(packet.DestinationPort, packet.DestinationChannel)} + token.Denom.Trace = append(trace, token.Denom.Trace...) - // sender chain is the source, mint vouchers + if !k.HasDenom(ctx, token.Denom.Hash()) { + k.SetDenom(ctx, token.Denom) + } - // since SendPacket did not prefix the denomination, we must add the destination port and channel to the trace - trace := []types.Trace{types.NewTrace(packet.DestinationPort, packet.DestinationChannel)} - token.Denom.Trace = append(trace, token.Denom.Trace...) + voucherDenom := token.Denom.IBCDenom() + if !k.bankKeeper.HasDenomMetaData(ctx, voucherDenom) { + k.setDenomMetadata(ctx, token.Denom) + } - if !k.HasDenom(ctx, token.Denom.Hash()) { - k.SetDenom(ctx, token.Denom) - } + events.EmitDenomEvent(ctx, token) - voucherDenom := token.Denom.IBCDenom() - if !k.bankKeeper.HasDenomMetaData(ctx, voucherDenom) { - k.setDenomMetadata(ctx, token.Denom) - } + voucher := sdk.NewCoin(voucherDenom, transferAmount) - events.EmitDenomEvent(ctx, token) + // mint new tokens if the source of the transfer is the same chain + if err := k.bankKeeper.MintCoins( + ctx, types.ModuleName, sdk.NewCoins(voucher), + ); err != nil { + return errorsmod.Wrap(err, "failed to mint IBC tokens") + } - voucher := sdk.NewCoin(voucherDenom, transferAmount) + // send to receiver + if k.IsBlockedAddr(receiver) { + return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) + } + moduleAddr := k.authKeeper.GetModuleAddress(types.ModuleName) + if moduleAddr == nil { + return errorsmod.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", types.ModuleName) + } + if err := k.bankKeeper.SendCoins( + ctx, moduleAddr, receiver, sdk.NewCoins(voucher), + ); err != nil { + return errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()) + } - // mint new tokens if the source of the transfer is the same chain - if err := k.bankKeeper.MintCoins( - ctx, types.ModuleName, sdk.NewCoins(voucher), - ); err != nil { - return errorsmod.Wrap(err, "failed to mint IBC tokens") - } + denomPath := token.Denom.Path() + labels = append(labels, telemetry.NewLabel(coretypes.LabelSource, "false")) + defer internaltelemetry.ReportOnRecvPacketTelemetry(transferAmount, denomPath, labels) - // send to receiver - if k.IsBlockedAddr(receiver) { - return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) - } - moduleAddr := k.authKeeper.GetModuleAddress(types.ModuleName) - if moduleAddr == nil { - return errorsmod.Wrapf(sdkerrors.ErrUnknownAddress, "module account %s does not exist", types.ModuleName) - } - if err := k.bankKeeper.SendCoins( - ctx, moduleAddr, receiver, sdk.NewCoins(voucher), - ); err != nil { - return errorsmod.Wrapf(err, "failed to send coins to receiver %s", receiver.String()) + receivedCoins = append(receivedCoins, voucher) } - - denomPath := token.Denom.Path() - labels = append(labels, telemetry.NewLabel(coretypes.LabelSource, "false")) - defer internaltelemetry.ReportOnRecvPacketTelemetry(transferAmount, denomPath, labels) - - receivedCoins = append(receivedCoins, voucher) } if data.ShouldBeForwarded() { From 4d19be15a5a4156ea85dbec1e1b9df5b8604dba5 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 10:07:08 +0200 Subject: [PATCH 117/141] add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87f8373c29b..476dc961f69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features * (apps/transfer) [\#6492](https://github.com/cosmos/ibc-go/pull/6492) Added new `Tokens` field to `MsgTransfer` to enable sending of multiple denoms, and deprecated the `Token` field. +* (apps/transfer) [\#6693](https://github.com/cosmos/ibc-go/pull/6693) Added new `Forwarding` field to `MsgTransfer` to enable forwarding tokens through multiple intermediary chains with a signle transaction. This also enables automatic unwinding of tokens to their native chain. ### Bug Fixes From 2838aef386cdb1dc2da143b6d509504e6957a2c7 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 11:23:35 +0200 Subject: [PATCH 118/141] add test for invalid receiver address --- modules/apps/transfer/keeper/relay_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/apps/transfer/keeper/relay_test.go b/modules/apps/transfer/keeper/relay_test.go index d6ddbbd3aec..e9824c05ace 100644 --- a/modules/apps/transfer/keeper/relay_test.go +++ b/modules/apps/transfer/keeper/relay_test.go @@ -369,6 +369,13 @@ func (suite *KeeperTestSuite) TestOnRecvPacket_ReceiverIsNotSource() { }, ibcerrors.ErrUnauthorized, }, + { + "failure: receiver is invalid", + func() { + receiver = "invalid-address" + }, + ibcerrors.ErrInvalidAddress, + }, { "failure: receive is disabled", func() { From 7afb7f6fd6c9e1a17d46cb8c0fd341f96f4dbe7f Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 12:33:24 +0200 Subject: [PATCH 119/141] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 476dc961f69..58928588a9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,7 +73,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features * (apps/transfer) [\#6492](https://github.com/cosmos/ibc-go/pull/6492) Added new `Tokens` field to `MsgTransfer` to enable sending of multiple denoms, and deprecated the `Token` field. -* (apps/transfer) [\#6693](https://github.com/cosmos/ibc-go/pull/6693) Added new `Forwarding` field to `MsgTransfer` to enable forwarding tokens through multiple intermediary chains with a signle transaction. This also enables automatic unwinding of tokens to their native chain. +* (apps/transfer) [\#6693](https://github.com/cosmos/ibc-go/pull/6693) Added new `Forwarding` field to `MsgTransfer` to enable forwarding tokens through multiple intermediary chains with a single transaction. This also enables automatic unwinding of tokens to their native chain. ### Bug Fixes From 0221c6bf35ce71f8d162bc9a91513791de8a0364 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 12:35:08 +0200 Subject: [PATCH 120/141] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58928588a9e..ee7e462a3d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,7 +73,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features * (apps/transfer) [\#6492](https://github.com/cosmos/ibc-go/pull/6492) Added new `Tokens` field to `MsgTransfer` to enable sending of multiple denoms, and deprecated the `Token` field. -* (apps/transfer) [\#6693](https://github.com/cosmos/ibc-go/pull/6693) Added new `Forwarding` field to `MsgTransfer` to enable forwarding tokens through multiple intermediary chains with a single transaction. This also enables automatic unwinding of tokens to their native chain. +* (apps/transfer) [\#6693](https://github.com/cosmos/ibc-go/pull/6693) Added new `Forwarding` field to `MsgTransfer` to enable forwarding tokens through multiple intermediary chains with a single transaction. This also enables automatic unwinding of tokens to their native chain. `x/authz` support for transfer allows granters to specify a set of possible forwarding hops that are allowed for grantees. ### Bug Fixes From cc46a63ea6e0644082b25761efbef0abfd759d91 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 13:14:30 +0200 Subject: [PATCH 121/141] make getForwardedPacket private --- modules/apps/transfer/keeper/export_test.go | 6 ++++++ modules/apps/transfer/keeper/keeper.go | 4 ++-- modules/apps/transfer/keeper/relay.go | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index 5b7348c5f98..b6e09c02392 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -5,6 +5,7 @@ import ( internaltypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/internal/types" "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ) // SetDenomTraces is a wrapper around iterateDenomTraces for testing purposes. @@ -38,6 +39,11 @@ func (k Keeper) UnwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgT return k.unwindHops(ctx, msg) } +// UnwindHops is a wrapper around unwindToken for testing purposes. +func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, sequence uint64) (channeltypes.Packet, bool) { + return k.getForwardedPacket(ctx, portID, channelID, sequence) +} + // 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 2af2697ba7b..799e4493d46 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -315,8 +315,8 @@ func (k Keeper) setForwardedPacket(ctx sdk.Context, portID, channelID string, se store.Set(types.PacketForwardKey(portID, channelID, sequence), bz) } -// GetForwardedPacket gets the forwarded packet from the store. -func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, sequence uint64) (channeltypes.Packet, bool) { +// getForwardedPacket gets the forwarded packet from the store. +func (k Keeper) getForwardedPacket(ctx sdk.Context, portID, channelID string, sequence uint64) (channeltypes.Packet, bool) { store := ctx.KVStore(k.storeKey) bz := store.Get(types.PacketForwardKey(portID, channelID, sequence)) if bz == nil { diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 66d7359585e..a38ab861e0c 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -295,7 +295,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t // acknowledgement was a success then nothing occurs. If the acknowledgement failed, // then the sender is refunded their tokens using the refundPacketToken function. func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) error { - prevPacket, isForwarded := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) + prevPacket, isForwarded := k.getForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) switch ack.Response.(type) { case *channeltypes.Acknowledgement_Result: @@ -329,7 +329,7 @@ func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, dat return err } - prevPacket, isForwarded := k.GetForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) + prevPacket, isForwarded := k.getForwardedPacket(ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence) if isForwarded { return k.ackForwardPacketTimeout(ctx, prevPacket, packet, data) } From e67aeaf997dffa5928650ef041a4148f4d939927 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 13:27:46 +0200 Subject: [PATCH 122/141] remove auxiliary burn coins function --- modules/apps/transfer/keeper/forwarding.go | 2 +- modules/apps/transfer/keeper/relay.go | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index ef103671cd3..48f9b9ce858 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -124,7 +124,7 @@ func (k Keeper) revertForwardedPacket(ctx sdk.Context, prevPacket channeltypes.P continue } - if err := k.burnCoin(ctx, forwardingAddr, coin); err != nil { + if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(coin)); err != nil { return err } } diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index a38ab861e0c..98b4affac6a 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -485,20 +485,3 @@ func createPacketDataBytesFromVersion(appVersion, sender, receiver, memo string, panic(fmt.Errorf("app version must be one of %s", types.SupportedVersions)) } } - -// burnCoin sends coins from the account to the transfer module account and then burn them. -// We do this because bankKeeper.BurnCoins only works with a module account in SDK v0.50, -// the next version of the SDK will allow burning coins from any account. -// TODO: remove this function once we switch forwarding address to a module account (#6561) -func (k Keeper) burnCoin(ctx sdk.Context, account sdk.AccAddress, coin sdk.Coin) error { - coins := sdk.NewCoins(coin) - if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, account, types.ModuleName, coins); err != nil { - return err - } - - if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins); err != nil { - return err - } - - return nil -} From 966a644dee11c75f701fb38b61c7beaf7ac83061 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 27 Jun 2024 13:39:27 +0200 Subject: [PATCH 123/141] nit: rename func method recv args in types/forwarding.go --- modules/apps/transfer/types/forwarding.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/apps/transfer/types/forwarding.go b/modules/apps/transfer/types/forwarding.go index d202ebde9f9..6c5cd330d65 100644 --- a/modules/apps/transfer/types/forwarding.go +++ b/modules/apps/transfer/types/forwarding.go @@ -17,8 +17,8 @@ func NewForwarding(unwind bool, hops ...Hop) Forwarding { } // Validate performs a basic validation of the Forwarding fields. -func (fi Forwarding) Validate() error { - if err := validateHops(fi.Hops); err != nil { +func (f Forwarding) Validate() error { + if err := validateHops(f.Hops); err != nil { return errorsmod.Wrapf(ErrInvalidForwarding, "invalid hops in forwarding") } @@ -34,16 +34,16 @@ func NewForwardingPacketData(destinationMemo string, hops ...Hop) ForwardingPack } // Validate performs a basic validation of the ForwardingPacketData fields. -func (fi ForwardingPacketData) Validate() error { - if err := validateHops(fi.Hops); err != nil { +func (fpd ForwardingPacketData) Validate() error { + if err := validateHops(fpd.Hops); err != nil { return errorsmod.Wrapf(ErrInvalidForwarding, "invalid hops in forwarding packet data") } - if len(fi.DestinationMemo) > MaximumMemoLength { + if len(fpd.DestinationMemo) > MaximumMemoLength { return errorsmod.Wrapf(ErrInvalidMemo, "memo length cannot exceed %d", MaximumMemoLength) } - if len(fi.Hops) == 0 && fi.DestinationMemo != "" { + if len(fpd.Hops) == 0 && fpd.DestinationMemo != "" { return errorsmod.Wrap(ErrInvalidForwarding, "memo specified when forwarding packet data hops is empty") } From e92e086dcb01e3a1e8bdec9e08f5b704ac495d87 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 27 Jun 2024 13:41:40 +0200 Subject: [PATCH 124/141] chore: rename ShouldBeForwarded to HasFowarding --- modules/apps/transfer/ibc_module.go | 2 +- modules/apps/transfer/keeper/forwarding.go | 2 +- modules/apps/transfer/keeper/relay.go | 2 +- modules/apps/transfer/types/msgs.go | 6 +++--- modules/apps/transfer/types/packet.go | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index c9014bf4f76..7d832f78aef 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -213,7 +213,7 @@ func (im IBCModule) OnRecvPacket( im.keeper.Logger(ctx).Info("successfully handled ICS-20 packet", "sequence", packet.Sequence) - if data.ShouldBeForwarded() { + if data.HasForwarding() { // NOTE: acknowledgement will be written asynchronously return nil } diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 48f9b9ce858..2ebf0ecdeef 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -134,7 +134,7 @@ func (k Keeper) revertForwardedPacket(ctx sdk.Context, prevPacket channeltypes.P // getReceiverFromPacketData returns either the sender specified in the packet data or the forwarding address // if there are still hops left to perform. func (k Keeper) getReceiverFromPacketData(data types.FungibleTokenPacketDataV2) (sdk.AccAddress, error) { - if data.ShouldBeForwarded() { + if data.HasForwarding() { // since data.Receiver can potentially be a non-CosmosSDK AccAddress, we return early if the packet should be forwarded return k.authKeeper.GetModuleAddress(types.ModuleName), nil } diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 98b4affac6a..fbaba594e9f 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -277,7 +277,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t } } - if data.ShouldBeForwarded() { + if data.HasForwarding() { // we are now sending from the forward escrow address to the final receiver address. if err := k.forwardPacket(ctx, data, packet, receivedCoins); err != nil { return err diff --git a/modules/apps/transfer/types/msgs.go b/modules/apps/transfer/types/msgs.go index be3420d233f..6b036e491c3 100644 --- a/modules/apps/transfer/types/msgs.go +++ b/modules/apps/transfer/types/msgs.go @@ -122,7 +122,7 @@ func (msg MsgTransfer) ValidateBasic() error { // validateForwarding ensures that forwarding is set up correctly. func (msg MsgTransfer) validateForwarding() error { - if !msg.ShouldBeForwarded() { + if !msg.HasForwarding() { return nil } if err := msg.Forwarding.Validate(); err != nil { @@ -161,8 +161,8 @@ func (msg MsgTransfer) GetCoins() sdk.Coins { return coins } -// ShouldBeForwarded determines if the transfer should be forwarded to the next hop. -func (msg MsgTransfer) ShouldBeForwarded() bool { +// HasForwarding determines if the transfer should be forwarded to the next hop. +func (msg MsgTransfer) HasForwarding() bool { return len(msg.Forwarding.Hops) > 0 || msg.Forwarding.Unwind } diff --git a/modules/apps/transfer/types/packet.go b/modules/apps/transfer/types/packet.go index c75d31b5fc2..7a182b8598e 100644 --- a/modules/apps/transfer/types/packet.go +++ b/modules/apps/transfer/types/packet.go @@ -145,7 +145,7 @@ func (ftpd FungibleTokenPacketDataV2) ValidateBasic() error { } // We cannot have non-empty memo and non-empty forwarding path hops at the same time. - if ftpd.ShouldBeForwarded() && ftpd.Memo != "" { + if ftpd.HasForwarding() && ftpd.Memo != "" { return errorsmod.Wrapf(ErrInvalidMemo, "memo must be empty if forwarding path hops is not empty: %s, %s", ftpd.Memo, ftpd.Forwarding.Hops) } @@ -195,7 +195,7 @@ func (ftpd FungibleTokenPacketDataV2) GetPacketSender(sourcePortID string) strin return ftpd.Sender } -// ShouldBeForwarded determines if the packet should be forwarded to the next hop. -func (ftpd FungibleTokenPacketDataV2) ShouldBeForwarded() bool { +// HasForwarding determines if the packet should be forwarded to the next hop. +func (ftpd FungibleTokenPacketDataV2) HasForwarding() bool { return len(ftpd.Forwarding.Hops) > 0 } From 6ea614f5b25a93577fa04f2f0db141e3155c8c93 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 27 Jun 2024 14:27:10 +0300 Subject: [PATCH 125/141] e2e: remove template test for three chain setup. --- e2e/tests/transfer/forwarding_test.go | 73 --------------------------- 1 file changed, 73 deletions(-) diff --git a/e2e/tests/transfer/forwarding_test.go b/e2e/tests/transfer/forwarding_test.go index caed6eae537..5037421f275 100644 --- a/e2e/tests/transfer/forwarding_test.go +++ b/e2e/tests/transfer/forwarding_test.go @@ -30,79 +30,6 @@ func (s *TransferForwardingTestSuite) SetupSuite() { s.SetupChains(context.TODO(), nil, testsuite.ThreeChainSetup()) } -// TODO: replace this with actual tests https://github.com/cosmos/ibc-go/issues/6578 -// this test verifies that three chains can be set up, and the relayer will relay -// packets between them as configured in the newInterchain function. -func (s *TransferForwardingTestSuite) TestThreeChainSetup() { - ctx := context.TODO() - t := s.T() - - relayer, chains := s.GetRelayer(), s.GetAllChains() - - chainA, chainB, chainC := chains[0], chains[1], chains[2] - - chainAChannels, err := relayer.GetChannels(ctx, s.GetRelayerExecReporter(), chainA.Config().ChainID) - s.Require().NoError(err) - chainBChannels, err := relayer.GetChannels(ctx, s.GetRelayerExecReporter(), chainB.Config().ChainID) - s.Require().NoError(err) - chainCChannels, err := relayer.GetChannels(ctx, s.GetRelayerExecReporter(), chainC.Config().ChainID) - s.Require().NoError(err) - - s.Require().Len(chainAChannels, 1, "expected 1 channels on chain A") - s.Require().Len(chainBChannels, 2, "expected 2 channels on chain B") - s.Require().Len(chainCChannels, 1, "expected 1 channels on chain C") - - channelAToB := chainAChannels[0] - channelBToC := chainBChannels[1] - - chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount) - chainAAddress := chainAWallet.FormattedAddress() - chainADenom := chainA.Config().Denom - - chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount) - chainBAddress := chainBWallet.FormattedAddress() - chainBDenom := chainB.Config().Denom - - chainCWallet := s.CreateUserOnChainC(ctx, testvalues.StartingTokenAmount) - chainCAddress := chainCWallet.FormattedAddress() - - t.Run("IBC transfer from A to B", func(t *testing.T) { - transferTxResp := s.Transfer(ctx, chainA, chainAWallet, channelAToB.PortID, channelAToB.ChannelID, testvalues.DefaultTransferCoins(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "") - s.AssertTxSuccess(transferTxResp) - }) - - t.Run("IBC transfer from B to C", func(t *testing.T) { - transferTxResp := s.Transfer(ctx, chainB, chainBWallet, channelBToC.PortID, channelBToC.ChannelID, testvalues.DefaultTransferCoins(chainBDenom), chainBAddress, chainCAddress, s.GetTimeoutHeight(ctx, chainC), 0, "") - s.AssertTxSuccess(transferTxResp) - }) - - t.Run("start relayer", func(t *testing.T) { - s.StartRelayer(relayer) - }) - - chainBIBCToken := testsuite.GetIBCToken(chainADenom, channelAToB.Counterparty.PortID, channelAToB.Counterparty.ChannelID) - t.Run("packets are relayed from A to B", func(t *testing.T) { - s.AssertPacketRelayed(ctx, chainA, channelAToB.PortID, channelAToB.ChannelID, 1) - - actualBalance, err := query.Balance(ctx, chainB, chainBAddress, chainBIBCToken.IBCDenom()) - s.Require().NoError(err) - - expected := testvalues.IBCTransferAmount - s.Require().Equal(expected, actualBalance.Int64()) - }) - - chainCIBCToken := testsuite.GetIBCToken(chainBDenom, channelBToC.Counterparty.PortID, channelBToC.Counterparty.ChannelID) - t.Run("packets are relayed from B to C", func(t *testing.T) { - s.AssertPacketRelayed(ctx, chainB, channelBToC.PortID, channelBToC.ChannelID, 1) - - actualBalance, err := query.Balance(ctx, chainC, chainCAddress, chainCIBCToken.IBCDenom()) - s.Require().NoError(err) - - expected := testvalues.IBCTransferAmount - s.Require().Equal(expected, actualBalance.Int64()) - }) -} - func (s *TransferForwardingTestSuite) TestForwarding_WithLastChainBeingICS20v1_Succeeds() { ctx := context.TODO() t := s.T() From 18d0567fb5cdcc8ee2a5ec49d737e0737af5df38 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 27 Jun 2024 15:05:49 +0300 Subject: [PATCH 126/141] nit: no generics silly --- .../apps/transfer/internal/events/events.go | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/apps/transfer/internal/events/events.go b/modules/apps/transfer/internal/events/events.go index 8bcbf49bb6d..bb17431bdd0 100644 --- a/modules/apps/transfer/internal/events/events.go +++ b/modules/apps/transfer/internal/events/events.go @@ -12,8 +12,8 @@ import ( // EmitTransferEvent emits a ibc transfer event on successful transfers. func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.Tokens, memo string, forwardingHops []types.Hop) { - tokensStr := mustMarshalType[types.Tokens](tokens) - forwardingHopsStr := mustMarshalType[[]types.Hop](forwardingHops) + tokensStr := mustMarshalJSON(tokens) + forwardingHopsStr := mustMarshalJSON(forwardingHops) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( @@ -33,8 +33,8 @@ func EmitTransferEvent(ctx sdk.Context, sender, receiver string, tokens types.To // EmitOnRecvPacketEvent emits a fungible token packet event in the OnRecvPacket callback func EmitOnRecvPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement, ackErr error) { - tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) - forwardingHopStr := mustMarshalType[[]types.Hop](packetData.Forwarding.Hops) + tokensStr := mustMarshalJSON(packetData.Tokens) + forwardingHopStr := mustMarshalJSON(packetData.Forwarding.Hops) eventAttributes := []sdk.Attribute{ sdk.NewAttribute(types.AttributeKeySender, packetData.Sender), @@ -63,8 +63,8 @@ func EmitOnRecvPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacket // EmitOnAcknowledgementPacketEvent emits a fungible token packet event in the OnAcknowledgementPacket callback func EmitOnAcknowledgementPacketEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2, ack channeltypes.Acknowledgement) { - tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) - forwardingHopsStr := mustMarshalType[[]types.Hop](packetData.Forwarding.Hops) + tokensStr := mustMarshalJSON(packetData.Tokens) + forwardingHopsStr := mustMarshalJSON(packetData.Forwarding.Hops) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( @@ -102,8 +102,8 @@ func EmitOnAcknowledgementPacketEvent(ctx sdk.Context, packetData types.Fungible // EmitOnTimeoutEvent emits a fungible token packet event in the OnTimeoutPacket callback func EmitOnTimeoutEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDataV2) { - tokensStr := mustMarshalType[types.Tokens](packetData.Tokens) - forwardingHopsStr := mustMarshalType[[]types.Hop](packetData.Forwarding.Hops) + tokensStr := mustMarshalJSON(packetData.Tokens) + forwardingHopsStr := mustMarshalJSON(packetData.Forwarding.Hops) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( @@ -122,7 +122,7 @@ func EmitOnTimeoutEvent(ctx sdk.Context, packetData types.FungibleTokenPacketDat // EmitDenomEvent emits a denomination event in the OnRecv callback. func EmitDenomEvent(ctx sdk.Context, token types.Token) { - denomStr := mustMarshalType[types.Denom](token.Denom) + denomStr := mustMarshalJSON(token.Denom) ctx.EventManager().EmitEvent( sdk.NewEvent( @@ -134,7 +134,7 @@ func EmitDenomEvent(ctx sdk.Context, token types.Token) { } // mustMarshalType json marshals the given type and panics on failure. -func mustMarshalType[T any](v T) string { +func mustMarshalJSON(v any) string { bz, err := json.Marshal(v) if err != nil { panic(err) From 1b7214de88342fb6ffab67986fe6343fbd84d38f Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 27 Jun 2024 15:10:44 +0300 Subject: [PATCH 127/141] nit: add clarifying comment to validate basic call on msg. --- modules/apps/transfer/keeper/msg_server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/apps/transfer/keeper/msg_server.go b/modules/apps/transfer/keeper/msg_server.go index 555217d5191..80eb5d196de 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -91,6 +91,7 @@ func (k Keeper) unwindHops(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgT msg.Forwarding.Hops = append(unwindHops, msg.Forwarding.Hops...) msg.Forwarding.Unwind = false + // Message is validate again, this would only fail if hops now exceeds maximum allowed. if err := msg.ValidateBasic(); err != nil { return nil, err } From 1f5e61f18d792e802b5884e1ba74075121d6b8bc Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 27 Jun 2024 15:19:31 +0300 Subject: [PATCH 128/141] nit: remove unused key. --- modules/apps/transfer/types/keys.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/apps/transfer/types/keys.go b/modules/apps/transfer/types/keys.go index 8975db4e893..1ec121d45f0 100644 --- a/modules/apps/transfer/types/keys.go +++ b/modules/apps/transfer/types/keys.go @@ -29,8 +29,7 @@ const ( // AllowAllPacketDataKeys holds the string key that allows all memo strings in authz transfer messages AllowAllPacketDataKeys = "*" - KeyTotalEscrowPrefix = "totalEscrowForDenom" - KeyTotalForwardPrefix = "totalForwardForDenom" + KeyTotalEscrowPrefix = "totalEscrowForDenom" ParamsKey = "params" From 0a78bdef65054265abd085961fd3c1372e1dcf76 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 27 Jun 2024 15:24:41 +0300 Subject: [PATCH 129/141] nit: clean up cli help text. --- modules/apps/transfer/client/cli/tx.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index 84f83a886a0..e3f65785b8d 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -43,8 +43,8 @@ packet if the coins list is a comma-separated string (e.g. 100uatom,100uosmo). T Timeout height can be set by passing in the height string in the form {revision}-{height} using the {packet-timeout-height} flag. Note, relative timeout height is not supported. Relative timeout timestamp is added to the value of the user's local system clock time using the {packet-timeout-timestamp} flag. If no timeout value is set then a default relative timeout value of 10 minutes is used. IBC tokens -can be automatically unwound to their native chain using the {unwind} flag. Please note that if the {unwind} flag used, then the transfer should contain only -tokens for a single denomination. Tokens can also be automatically forwarded through multiple chains using the {fowarding} flag and specifying +can be automatically unwound to their native chain using the {unwind} flag. Please note that if the {unwind} flag is used, then the transfer should contain only +a single token. Tokens can also be automatically forwarded through multiple chains using the {fowarding} flag and specifying a comma-separated list of source portID/channelID pairs for each intermediary chain. {unwind} and {forwarding} flags can be used together to unwind IBC tokens to their native chain and forward them to the final destination.`), Example: fmt.Sprintf("%s tx ibc-transfer transfer [src-port] [src-channel] [receiver] [coins]", version.AppName), @@ -133,7 +133,7 @@ to unwind IBC tokens to their native chain and forward them to the final destina cmd.Flags().Uint64(flagPacketTimeoutTimestamp, defaultRelativePacketTimeoutTimestamp, "Packet timeout timestamp in nanoseconds from now. Default is 10 minutes. The timeout is disabled when set to 0.") cmd.Flags().Bool(flagAbsoluteTimeouts, false, "Timeout flags are used as absolute timeouts.") cmd.Flags().String(flagMemo, "", "Memo to be sent along with the packet.") - cmd.Flags().String(flagForwarding, "", "Forwarding information in the form of a comma separated list of portID/channelID pairs, denoting the intermediary hops. If forwarding is specified any memo set will be included in the forwarding information created.") + cmd.Flags().String(flagForwarding, "", "Forwarding information in the form of a comma separated list of portID/channelID pairs.") cmd.Flags().Bool(flagUnwind, false, "Flag to indicate if the coin should be unwound to its native chain before forwarding.") flags.AddTxFlagsToCmd(cmd) From 07036a9ea1680f92700c74394bf5ee1334248420 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 27 Jun 2024 15:43:25 +0300 Subject: [PATCH 130/141] nit: don't export is blocked address helper. --- modules/apps/transfer/keeper/export_test.go | 5 +++++ modules/apps/transfer/keeper/keeper.go | 2 +- modules/apps/transfer/keeper/msg_server.go | 2 +- modules/apps/transfer/keeper/relay.go | 6 +++--- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/apps/transfer/keeper/export_test.go b/modules/apps/transfer/keeper/export_test.go index b6e09c02392..cda19c83814 100644 --- a/modules/apps/transfer/keeper/export_test.go +++ b/modules/apps/transfer/keeper/export_test.go @@ -44,6 +44,11 @@ func (k Keeper) GetForwardedPacket(ctx sdk.Context, portID, channelID string, se return k.getForwardedPacket(ctx, portID, channelID, sequence) } +// 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 799e4493d46..a5adf27b975 100644 --- a/modules/apps/transfer/keeper/keeper.go +++ b/modules/apps/transfer/keeper/keeper.go @@ -339,7 +339,7 @@ func (k Keeper) deleteForwardedPacket(ctx sdk.Context, portID, channelID string, // 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 80eb5d196de..9c40125cc50 100644 --- a/modules/apps/transfer/keeper/msg_server.go +++ b/modules/apps/transfer/keeper/msg_server.go @@ -32,7 +32,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. return nil, errorsmod.Wrapf(types.ErrSendDisabled, err.Error()) } - if k.IsBlockedAddr(sender) { + if k.isBlockedAddr(sender) { return nil, errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to send funds", sender) } diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index fbaba594e9f..1933d832bc4 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -213,7 +213,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t coin := sdk.NewCoin(token.Denom.IBCDenom(), transferAmount) - if k.IsBlockedAddr(receiver) { + if k.isBlockedAddr(receiver) { return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) } @@ -256,7 +256,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t } // send to receiver - if k.IsBlockedAddr(receiver) { + if k.isBlockedAddr(receiver) { return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to receive funds", receiver) } moduleAddr := k.authKeeper.GetModuleAddress(types.ModuleName) @@ -374,7 +374,7 @@ func (k Keeper) refundPacketTokens(ctx sdk.Context, packet channeltypes.Packet, return err } - if k.IsBlockedAddr(sender) { + if k.isBlockedAddr(sender) { return errorsmod.Wrapf(ibcerrors.ErrUnauthorized, "%s is not allowed to send funds", sender) } if err := k.bankKeeper.SendCoins(ctx, moduleAccountAddr, sender, sdk.NewCoins(coin)); err != nil { From 144287473ef8aba9e872b295716cc302634bc9d8 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 27 Jun 2024 15:51:02 +0300 Subject: [PATCH 131/141] nit: docustring for e2e test and helper. --- e2e/tests/transfer/forwarding_test.go | 2 ++ e2e/testsuite/testsuite.go | 1 + 2 files changed, 3 insertions(+) diff --git a/e2e/tests/transfer/forwarding_test.go b/e2e/tests/transfer/forwarding_test.go index 5037421f275..386e6a61c96 100644 --- a/e2e/tests/transfer/forwarding_test.go +++ b/e2e/tests/transfer/forwarding_test.go @@ -30,6 +30,8 @@ func (s *TransferForwardingTestSuite) SetupSuite() { s.SetupChains(context.TODO(), nil, testsuite.ThreeChainSetup()) } +// TestForwarding_WithLastChainBeingICS20v1_Succeeds tests the case where a token is forwarded and successfully +// received on a destination chain that is on ics20-v1 version. func (s *TransferForwardingTestSuite) TestForwarding_WithLastChainBeingICS20v1_Succeeds() { ctx := context.TODO() t := s.T() diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index c18fa3ac304..831f0ad5d2e 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -207,6 +207,7 @@ func (s *E2ETestSuite) SetupPaths(clientOpts ibc.CreateClientOptions, channelOpt } } +// CreatePath creates a path between chainA and chainB using the provided client and channel options. func (s *E2ETestSuite) CreatePath( ctx context.Context, chainA ibc.Chain, From 25c73c48220824bf798efdf91a976ddc1c176132 Mon Sep 17 00:00:00 2001 From: DimitrisJim Date: Thu, 27 Jun 2024 15:52:31 +0300 Subject: [PATCH 132/141] nit: improve documentation for transfer's OnRecv callback. Co-authored-by: Damian Nolan --- modules/apps/transfer/ibc_module.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/ibc_module.go b/modules/apps/transfer/ibc_module.go index 7d832f78aef..3748383f4ae 100644 --- a/modules/apps/transfer/ibc_module.go +++ b/modules/apps/transfer/ibc_module.go @@ -178,7 +178,7 @@ func (IBCModule) OnChanCloseConfirm( // 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. -// Return nil to signal that the acknowledgement will be written asynchronously. +// 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 (im IBCModule) OnRecvPacket( ctx sdk.Context, packet channeltypes.Packet, From baf3fd3242a802f660a9b5221f08d8d8e7c207bf Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 16:03:05 +0200 Subject: [PATCH 133/141] Apply suggestions from code review Co-authored-by: Aditya <14364734+AdityaSripal@users.noreply.github.com> --- modules/apps/transfer/client/cli/tx.go | 2 +- modules/apps/transfer/keeper/forwarding.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/transfer/client/cli/tx.go b/modules/apps/transfer/client/cli/tx.go index e3f65785b8d..14d0ccb61d8 100644 --- a/modules/apps/transfer/client/cli/tx.go +++ b/modules/apps/transfer/client/cli/tx.go @@ -46,7 +46,7 @@ using the {packet-timeout-timestamp} flag. If no timeout value is set then a def can be automatically unwound to their native chain using the {unwind} flag. Please note that if the {unwind} flag is used, then the transfer should contain only a single token. Tokens can also be automatically forwarded through multiple chains using the {fowarding} flag and specifying a comma-separated list of source portID/channelID pairs for each intermediary chain. {unwind} and {forwarding} flags can be used together -to unwind IBC tokens to their native chain and forward them to the final destination.`), +to first unwind IBC tokens to their native chain and then forward them to the final destination.`), Example: fmt.Sprintf("%s tx ibc-transfer transfer [src-port] [src-channel] [receiver] [coins]", version.AppName), Args: cobra.ExactArgs(4), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index 2ebf0ecdeef..db5a25a9c7e 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -16,7 +16,7 @@ import ( func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDataV2, packet channeltypes.Packet, receivedCoins sdk.Coins) error { var nextForwardingPath types.Forwarding if len(data.Forwarding.Hops) > 1 { - // remove the first hop since it has been completed (this chain has received the packet) + // remove the first hop since we are going to send to the first hop now and we want to propogate the rest of the hops to the receiver nextForwardingPath = types.NewForwarding(false, data.Forwarding.Hops[1:]...) } From 7d2a881f0a92b194220ccbce0cbf9bf45fd82b84 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 16:15:17 +0200 Subject: [PATCH 134/141] chore: remove unused function --- .../apps/transfer/internal/convert/convert.go | 29 ------------------- modules/apps/transfer/internal/packet.go | 7 +++-- 2 files changed, 4 insertions(+), 32 deletions(-) delete mode 100644 modules/apps/transfer/internal/convert/convert.go diff --git a/modules/apps/transfer/internal/convert/convert.go b/modules/apps/transfer/internal/convert/convert.go deleted file mode 100644 index fbb90ec7e56..00000000000 --- a/modules/apps/transfer/internal/convert/convert.go +++ /dev/null @@ -1,29 +0,0 @@ -package convert - -import ( - errorsmod "cosmossdk.io/errors" - - "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" -) - -// PacketDataV1ToV2 converts a v1 packet data to a v2 packet data. The packet data is validated -// before conversion. -func PacketDataV1ToV2(packetData types.FungibleTokenPacketData) (types.FungibleTokenPacketDataV2, error) { - if err := packetData.ValidateBasic(); err != nil { - return types.FungibleTokenPacketDataV2{}, errorsmod.Wrapf(err, "invalid packet data") - } - - denom := types.ExtractDenomFromPath(packetData.Denom) - return types.FungibleTokenPacketDataV2{ - Tokens: []types.Token{ - { - Denom: denom, - Amount: packetData.Amount, - }, - }, - Sender: packetData.Sender, - Receiver: packetData.Receiver, - Memo: packetData.Memo, - Forwarding: types.ForwardingPacketData{}, - }, nil -} diff --git a/modules/apps/transfer/internal/packet.go b/modules/apps/transfer/internal/packet.go index 0d5c7a9456e..cd6a2638954 100644 --- a/modules/apps/transfer/internal/packet.go +++ b/modules/apps/transfer/internal/packet.go @@ -51,8 +51,9 @@ func packetDataV1ToV2(packetData types.FungibleTokenPacketData) (types.FungibleT Amount: packetData.Amount, }, }, - Sender: packetData.Sender, - Receiver: packetData.Receiver, - Memo: packetData.Memo, + Sender: packetData.Sender, + Receiver: packetData.Receiver, + Memo: packetData.Memo, + Forwarding: types.ForwardingPacketData{}, }, nil } From 4ea36c22a574a29743d4084e0927973edea30009 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 16:16:38 +0200 Subject: [PATCH 135/141] perf: allocate slice to length of packet data tokens --- modules/apps/transfer/keeper/relay.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 1933d832bc4..70ec52c36b5 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -185,7 +185,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return err } - var receivedCoins sdk.Coins + receivedCoins := make(sdk.Coins, len(data.Tokens)) for _, token := range data.Tokens { labels := []metrics.Label{ telemetry.NewLabel(coretypes.LabelSourcePort, packet.GetSourcePort()), From 7411f2d16e9cce64c4ecf09c201e4ed5b8aaab5d Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 27 Jun 2024 16:59:51 +0200 Subject: [PATCH 136/141] chore(transfer/authz): wrapf unauthorized forwarding hops --- modules/apps/transfer/types/transfer_authorization.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index 2a08097345b..88b6fd4f307 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -176,7 +176,7 @@ func validateForwarding(forwarding Forwarding, allowedForwarding []AllowedForwar } if !isAllowedForwarding(forwarding.Hops, allowedForwarding) { - return errorsmod.Wrap(ErrInvalidForwarding, "not allowed hops") + return errorsmod.Wrapf(ErrInvalidForwarding, "not allowed hops %s", forwarding.Hops) } return nil From 199c14a148b3a2309a6320d50727512374c60398 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 17:00:54 +0200 Subject: [PATCH 137/141] lint --- modules/apps/transfer/keeper/forwarding.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/keeper/forwarding.go b/modules/apps/transfer/keeper/forwarding.go index db5a25a9c7e..f7108295cef 100644 --- a/modules/apps/transfer/keeper/forwarding.go +++ b/modules/apps/transfer/keeper/forwarding.go @@ -16,7 +16,7 @@ import ( func (k Keeper) forwardPacket(ctx sdk.Context, data types.FungibleTokenPacketDataV2, packet channeltypes.Packet, receivedCoins sdk.Coins) error { var nextForwardingPath types.Forwarding if len(data.Forwarding.Hops) > 1 { - // remove the first hop since we are going to send to the first hop now and we want to propogate the rest of the hops to the receiver + // remove the first hop since we are going to send to the first hop now and we want to propagate the rest of the hops to the receiver nextForwardingPath = types.NewForwarding(false, data.Forwarding.Hops[1:]...) } From c7af85a260ee80a4c0254c35f917f2d7d9323f38 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 17:03:40 +0200 Subject: [PATCH 138/141] Update modules/apps/transfer/types/forwarding.go Co-authored-by: DimitrisJim --- modules/apps/transfer/types/forwarding.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/types/forwarding.go b/modules/apps/transfer/types/forwarding.go index 6c5cd330d65..7af7d339522 100644 --- a/modules/apps/transfer/types/forwarding.go +++ b/modules/apps/transfer/types/forwarding.go @@ -6,7 +6,7 @@ import ( host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) -const MaximumNumberOfForwardingHops = 16 // denotes the maximum number of forwarding hops allowed +const MaximumNumberOfForwardingHops = 8 // denotes the maximum number of forwarding hops allowed // NewForwarding creates a new Forwarding instance given an unwind value and a variable number of hops. func NewForwarding(unwind bool, hops ...Hop) Forwarding { From 90d57dbf47daf6056d34431b5a9bcb01f6c7a6a0 Mon Sep 17 00:00:00 2001 From: Nikolas De Giorgis Date: Thu, 27 Jun 2024 19:15:22 +0100 Subject: [PATCH 139/141] Preallocate slice but keep len==0 (#6725) --- modules/apps/transfer/keeper/relay.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/apps/transfer/keeper/relay.go b/modules/apps/transfer/keeper/relay.go index 70ec52c36b5..4584307c0d2 100644 --- a/modules/apps/transfer/keeper/relay.go +++ b/modules/apps/transfer/keeper/relay.go @@ -185,7 +185,7 @@ func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data t return err } - receivedCoins := make(sdk.Coins, len(data.Tokens)) + receivedCoins := make(sdk.Coins, 0, len(data.Tokens)) for _, token := range data.Tokens { labels := []metrics.Label{ telemetry.NewLabel(coretypes.LabelSourcePort, packet.GetSourcePort()), From e310e27419dac240a184f4d26c6ec52d701f55d5 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 20:57:08 +0200 Subject: [PATCH 140/141] imp: validate allowed forwarding hops --- .../transfer/types/transfer_authorization.go | 8 +++++ .../types/transfer_authorization_test.go | 36 +++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/modules/apps/transfer/types/transfer_authorization.go b/modules/apps/transfer/types/transfer_authorization.go index 88b6fd4f307..7b73d064a1b 100644 --- a/modules/apps/transfer/types/transfer_authorization.go +++ b/modules/apps/transfer/types/transfer_authorization.go @@ -146,6 +146,14 @@ func (a TransferAuthorization) ValidateBasic() error { } found[allocation.AllowList[i]] = true } + + for i := 0; i < len(allocation.AllowedForwarding); i++ { + for _, hop := range allocation.AllowedForwarding[i].Hops { + if err := hop.Validate(); err != nil { + return errorsmod.Wrap(err, "invalid forwarding hop") + } + } + } } return nil diff --git a/modules/apps/transfer/types/transfer_authorization_test.go b/modules/apps/transfer/types/transfer_authorization_test.go index 74d84086e1c..20554327cf1 100644 --- a/modules/apps/transfer/types/transfer_authorization_test.go +++ b/modules/apps/transfer/types/transfer_authorization_test.go @@ -572,6 +572,16 @@ func (suite *TypesTestSuite) TestTransferAuthorizationValidateBasic() { }, true, }, + { + "success: with allowed forwarding hops", + func() { + transferAuthz.Allocations[0].AllowedForwarding = []types.AllowedForwarding{ + {Hops: []types.Hop{validHop}}, + {Hops: []types.Hop{{types.PortID, "channel-1"}}}, + } + }, + true, + }, { "empty allocations", func() { @@ -622,8 +632,8 @@ func (suite *TypesTestSuite) TestTransferAuthorizationValidateBasic() { false, }, { - name: "duplicate channel ID", - malleate: func() { + "duplicate channel ID", + func() { allocation := types.Allocation{ SourcePort: mock.PortID, SourceChannel: transferAuthz.Allocations[0].SourceChannel, @@ -633,7 +643,27 @@ func (suite *TypesTestSuite) TestTransferAuthorizationValidateBasic() { transferAuthz.Allocations = append(transferAuthz.Allocations, allocation) }, - expPass: false, + false, + }, + { + "fowarding hop with invalid port ID", + func() { + transferAuthz.Allocations[0].AllowedForwarding = []types.AllowedForwarding{ + {Hops: []types.Hop{validHop}}, + {Hops: []types.Hop{{"invalid/port", ibctesting.FirstChannelID}}}, + } + }, + false, + }, + { + "fowarding hop with invalid channel ID", + func() { + transferAuthz.Allocations[0].AllowedForwarding = []types.AllowedForwarding{ + {Hops: []types.Hop{validHop}}, + {Hops: []types.Hop{{types.PortID, "invalid/channel"}}}, + } + }, + false, }, } From f28e9374b029b6678b354f9fef21d0b43d39134c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 27 Jun 2024 21:09:05 +0200 Subject: [PATCH 141/141] test: unwind fails in Transfer rpc --- modules/apps/transfer/keeper/msg_server_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/apps/transfer/keeper/msg_server_test.go b/modules/apps/transfer/keeper/msg_server_test.go index 0f7c41971fb..13b2dc72d2c 100644 --- a/modules/apps/transfer/keeper/msg_server_test.go +++ b/modules/apps/transfer/keeper/msg_server_test.go @@ -112,6 +112,14 @@ func (suite *KeeperTestSuite) TestMsgTransfer() { }, ibcerrors.ErrInvalidRequest, }, + { + "failure: cannot unwind native tokens", + func() { + msg.Forwarding = types.NewForwarding(true) + msg.Tokens = []sdk.Coin{ibctesting.TestCoin} + }, + types.ErrInvalidForwarding, + }, } for _, tc := range testCases {