package ibctesting_test import ( "encoding/hex" "testing" "github.com/cosmos/gogoproto/proto" "github.com/stretchr/testify/require" abci "git.cw.tr/mukan-network/mukan-consensus/abci/types" transfertypes "git.cw.tr/mukan-network/mukan-ibc/modules/apps/transfer/types" "git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/types" channeltypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/04-channel/types" channeltypesv2 "git.cw.tr/mukan-network/mukan-ibc/modules/core/04-channel/v2/types" ibctesting "git.cw.tr/mukan-network/mukan-ibc/testing" mockv1 "git.cw.tr/mukan-network/mukan-ibc/testing/mock" mockv2 "git.cw.tr/mukan-network/mukan-ibc/testing/mock/v2" ) func TestParseV1PacketsFromEvents(t *testing.T) { testCases := []struct { name string events []abci.Event expectedPackets []channeltypes.Packet expectedError string }{ { name: "success", events: []abci.Event{ { Type: "xxx", }, { Type: channeltypes.EventTypeSendPacket, Attributes: []abci.EventAttribute{ { Key: channeltypes.AttributeKeyDataHex, Value: hex.EncodeToString([]byte("data1")), }, { Key: channeltypes.AttributeKeySequence, Value: "42", }, { Key: channeltypes.AttributeKeySrcPort, Value: "srcPort", }, { Key: channeltypes.AttributeKeySrcChannel, Value: "srcChannel", }, { Key: channeltypes.AttributeKeyDstPort, Value: "dstPort", }, { Key: channeltypes.AttributeKeyDstChannel, Value: "dstChannel", }, { Key: channeltypes.AttributeKeyTimeoutHeight, Value: "1-2", }, { Key: channeltypes.AttributeKeyTimeoutTimestamp, Value: "1000", }, }, }, { Type: "yyy", }, { Type: channeltypes.EventTypeSendPacket, Attributes: []abci.EventAttribute{ { Key: channeltypes.AttributeKeyDataHex, Value: hex.EncodeToString([]byte("data2")), }, { Key: channeltypes.AttributeKeySequence, Value: "43", }, { Key: channeltypes.AttributeKeySrcPort, Value: "srcPort", }, { Key: channeltypes.AttributeKeySrcChannel, Value: "srcChannel", }, { Key: channeltypes.AttributeKeyDstPort, Value: "dstPort", }, { Key: channeltypes.AttributeKeyDstChannel, Value: "dstChannel", }, { Key: channeltypes.AttributeKeyTimeoutHeight, Value: "1-3", }, { Key: channeltypes.AttributeKeyTimeoutTimestamp, Value: "1001", }, }, }, }, expectedPackets: []channeltypes.Packet{ { Sequence: 42, SourcePort: "srcPort", SourceChannel: "srcChannel", DestinationPort: "dstPort", DestinationChannel: "dstChannel", Data: []byte("data1"), TimeoutHeight: types.Height{ RevisionNumber: 1, RevisionHeight: 2, }, TimeoutTimestamp: 1000, }, { Sequence: 43, SourcePort: "srcPort", SourceChannel: "srcChannel", DestinationPort: "dstPort", DestinationChannel: "dstChannel", Data: []byte("data2"), TimeoutHeight: types.Height{ RevisionNumber: 1, RevisionHeight: 3, }, TimeoutTimestamp: 1001, }, }, }, { name: "fail: no events", events: []abci.Event{}, expectedError: "acknowledgement event attribute not found", }, { name: "fail: events without packet", events: []abci.Event{ { Type: "xxx", }, { Type: "yyy", }, }, expectedError: "acknowledgement event attribute not found", }, { name: "fail: event packet with invalid AttributeKeySequence", events: []abci.Event{ { Type: channeltypes.EventTypeSendPacket, Attributes: []abci.EventAttribute{ { Key: channeltypes.AttributeKeySequence, Value: "x", }, }, }, }, expectedError: "strconv.ParseUint: parsing \"x\": invalid syntax", }, { name: "fail: event packet with invalid AttributeKeyTimeoutHeight", events: []abci.Event{ { Type: channeltypes.EventTypeSendPacket, Attributes: []abci.EventAttribute{ { Key: channeltypes.AttributeKeyTimeoutHeight, Value: "x", }, }, }, }, expectedError: "expected height string format: {revision}-{height}. Got: x: invalid height", }, { name: "fail: event packet with invalid AttributeKeyTimeoutTimestamp", events: []abci.Event{ { Type: channeltypes.EventTypeSendPacket, Attributes: []abci.EventAttribute{ { Key: channeltypes.AttributeKeyTimeoutTimestamp, Value: "x", }, }, }, }, expectedError: "strconv.ParseUint: parsing \"x\": invalid syntax", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { allPackets, err := ibctesting.ParseIBCV1Packets(channeltypes.EventTypeSendPacket, tc.events) if tc.expectedError == "" { require.NoError(t, err) require.Equal(t, tc.expectedPackets, allPackets) } else { require.ErrorContains(t, err, tc.expectedError) } firstPacket, err := ibctesting.ParseV1PacketFromEvents(tc.events) if tc.expectedError == "" { require.NoError(t, err) require.Equal(t, tc.expectedPackets[0], firstPacket) } else { require.ErrorContains(t, err, tc.expectedError) } }) } } func TestParseV2PacketsFromEvents(t *testing.T) { testCases := []struct { name string eventType string events []abci.Event expectedPackets []channeltypesv2.Packet expectedError string }{ { name: "success: One v2 packet without payload + One v2 packet with payload", eventType: channeltypesv2.EventTypeRecvPacket, events: []abci.Event{ { Type: "xxx", }, { Type: channeltypesv2.EventTypeRecvPacket, Attributes: []abci.EventAttribute{ { Key: channeltypesv2.AttributeKeySequence, Value: "42", }, { Key: channeltypesv2.AttributeKeySrcClient, Value: "srcClient", }, { Key: channeltypesv2.AttributeKeyDstClient, Value: "destClient", }, { Key: channeltypesv2.AttributeKeyTimeoutTimestamp, Value: "1283798137", }, }, }, { Type: "yyy", }, { Type: channeltypesv2.EventTypeRecvPacket, // If AttributeKeyEncodedPacketHex is present, other attributes are ignored. Attributes: []abci.EventAttribute{ { Key: channeltypesv2.AttributeKeySequence, Value: "43", // Value Ignored }, { Key: channeltypesv2.AttributeKeySrcClient, Value: "srcClient-2", // Value Ignored }, { Key: channeltypesv2.AttributeKeyDstClient, Value: "destClient-2", // Value Ignored }, { Key: channeltypesv2.AttributeKeyTimeoutTimestamp, Value: "12837997475", // Value Ignored }, { Key: channeltypesv2.AttributeKeyEncodedPacketHex, Value: func() string { payload := mockv2.NewMockPayload(mockv2.ModuleNameA, mockv2.ModuleNameB) packet := channeltypesv2.NewPacket(44, "srcClient", "destClient", 19474197444, payload) encodedPacket, err := proto.Marshal(&packet) if err != nil { panic(err) } return hex.EncodeToString(encodedPacket) }(), }, }, }, }, expectedPackets: []channeltypesv2.Packet{ { Sequence: 42, SourceClient: "srcClient", DestinationClient: "destClient", TimeoutTimestamp: 1283798137, }, { Sequence: 44, SourceClient: "srcClient", DestinationClient: "destClient", TimeoutTimestamp: 19474197444, Payloads: []channeltypesv2.Payload{ { SourcePort: mockv2.ModuleNameA, DestinationPort: mockv2.ModuleNameB, Version: mockv1.Version, Encoding: transfertypes.EncodingProtobuf, Value: mockv1.MockPacketData, }, }, }, }, }, { name: "fail: no events", eventType: channeltypesv2.EventTypeSendPacket, events: []abci.Event{}, expectedError: "no IBC v2 packets found in events", }, { name: "fail: events without packet", eventType: channeltypesv2.EventTypeSendPacket, events: []abci.Event{ { Type: "xxx", }, { Type: "yyy", }, }, expectedError: "no IBC v2 packets found in events", }, { name: "fail: event packet with invalid AttributeKeySequence", eventType: channeltypesv2.EventTypeSendPacket, events: []abci.Event{ { Type: channeltypesv2.EventTypeSendPacket, Attributes: []abci.EventAttribute{ { Key: channeltypesv2.AttributeKeySequence, Value: "x", }, }, }, }, expectedError: "strconv.ParseUint: parsing \"x\": invalid syntax", }, { name: "fail: event packet with invalid AttributeKeyTimeoutHeight", eventType: channeltypesv2.EventTypeSendPacket, events: []abci.Event{ { Type: channeltypesv2.EventTypeSendPacket, Attributes: []abci.EventAttribute{ { Key: channeltypesv2.AttributeKeyTimeoutTimestamp, Value: "x", }, }, }, }, expectedError: "strconv.ParseUint: parsing \"x\": invalid syntax", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { packets, err := ibctesting.ParseIBCV2Packets(tc.eventType, tc.events) if tc.expectedError != "" { require.ErrorContains(t, err, tc.expectedError) return } require.NoError(t, err) require.Equal(t, tc.expectedPackets, packets) }) } }