Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

testing: implement packet parsing from events in MsgSendPacketWithSender #8012

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 0 additions & 105 deletions testing/endpoint_v2.go

This file was deleted.

44 changes: 44 additions & 0 deletions testing/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import (
"slices"
"strconv"

"github.com/cosmos/gogoproto/proto"
testifysuite "github.com/stretchr/testify/suite"

abci "github.com/cometbft/cometbft/abci/types"

clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types"
connectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types"
channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types"
channeltypesv2 "github.com/cosmos/ibc-go/v10/modules/core/04-channel/v2/types"
)

// ParseClientIDFromEvents parses events emitted from a MsgCreateClient and returns the
Expand Down Expand Up @@ -251,3 +253,45 @@ func attributeByKey(attributes []abci.EventAttribute, key string) (abci.EventAtt
}
return attributes[idx], true
}

// ParsePacketFromEventsV2 parses events emitted from a send packet and returns
// the first EventTypeSendPacket packet found.
// Returns an error if no packet is found.
func ParsePacketFromEventsV2(events []abci.Event) (channeltypesv2.Packet, error) {
packets, err := ParsePacketsFromEventsV2(channeltypesv2.EventTypeSendPacket, events)
if err != nil {
return channeltypesv2.Packet{}, err
}
return packets[0], nil
}

// ParsePacketsFromEventsV2 parses events emitted from a MsgSendPacket and returns
// all the packets found.
// Returns an error if no packet is found.
func ParsePacketsFromEventsV2(eventType string, events []abci.Event) ([]channeltypesv2.Packet, error) {
ferr := func(err error) ([]channeltypesv2.Packet, error) {
return nil, fmt.Errorf("ibctesting.ParsePacketsFromEventsV2: %w", err)
}
var packets []channeltypesv2.Packet
for _, event := range events {
if event.Type == eventType {
for _, attr := range event.Attributes {
if string(attr.Key) == "packet_hex" {
packetBytes, err := hex.DecodeString(string(attr.Value))
if err != nil {
return ferr(fmt.Errorf("failed to decode packet bytes: %w", err))
}
var packet channeltypesv2.Packet
if err := proto.Unmarshal(packetBytes, &packet); err != nil {
return ferr(fmt.Errorf("failed to unmarshal packet: %w", err))
}
packets = append(packets, packet)
}
}
}
}
if len(packets) == 0 {
return ferr(errors.New("packet not found in events"))
}
return packets, nil
}
184 changes: 182 additions & 2 deletions testing/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import (
"encoding/hex"
"testing"

"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/require"

abci "github.com/cometbft/cometbft/abci/types"

"github.com/cosmos/ibc-go/v10/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types"
channeltypesv2 "github.com/cosmos/ibc-go/v10/modules/core/04-channel/v2/types"
ibctesting "github.com/cosmos/ibc-go/v10/testing"
)

Expand Down Expand Up @@ -137,7 +139,7 @@ func TestParsePacketsFromEvents(t *testing.T) {
{
name: "fail: no events",
events: []abci.Event{},
expectedError: "acknowledgement event attribute not found",
expectedError: "packet not found in events",
},
{
name: "fail: events without packet",
Expand All @@ -149,7 +151,7 @@ func TestParsePacketsFromEvents(t *testing.T) {
Type: "yyy",
},
},
expectedError: "acknowledgement event attribute not found",
expectedError: "packet not found in events",
},
{
name: "fail: event packet with invalid AttributeKeySequence",
Expand Down Expand Up @@ -219,3 +221,181 @@ func TestParsePacketsFromEvents(t *testing.T) {
})
}
}

func TestParsePacketsFromEventsV2(t *testing.T) {
testCases := []struct {
name string
events []abci.Event
expectedPackets []channeltypesv2.Packet
expectedError string
}{
{
name: "success with multiple packets",
events: []abci.Event{
{
Type: "xxx",
},
{
Type: channeltypesv2.EventTypeSendPacket,
Attributes: []abci.EventAttribute{
{
Key: "packet_hex",
Value: hex.EncodeToString(func() []byte {
packet := channeltypesv2.Packet{
SourceClient: "client-0",
DestinationClient: "client-1",
Sequence: 1,
TimeoutTimestamp: 100,
Payloads: []channeltypesv2.Payload{
{
SourcePort: "transfer",
DestinationPort: "transfer",
Version: "1.0",
Encoding: "proto3",
Value: []byte("data1"),
},
},
}
bz, err := proto.Marshal(&packet)
require.NoError(t, err)
return bz
}()),
},
},
},
{
Type: "yyy",
},
{
Type: channeltypesv2.EventTypeSendPacket,
Attributes: []abci.EventAttribute{
{
Key: "packet_hex",
Value: hex.EncodeToString(func() []byte {
packet := channeltypesv2.Packet{
SourceClient: "client-0",
DestinationClient: "client-1",
Sequence: 2,
TimeoutTimestamp: 200,
Payloads: []channeltypesv2.Payload{
{
SourcePort: "transfer",
DestinationPort: "transfer",
Version: "1.0",
Encoding: "proto3",
Value: []byte("data2"),
},
},
}
bz, err := proto.Marshal(&packet)
require.NoError(t, err)
return bz
}()),
},
},
},
},
expectedPackets: []channeltypesv2.Packet{
{
SourceClient: "client-0",
DestinationClient: "client-1",
Sequence: 1,
TimeoutTimestamp: 100,
Payloads: []channeltypesv2.Payload{
{
SourcePort: "transfer",
DestinationPort: "transfer",
Version: "1.0",
Encoding: "proto3",
Value: []byte("data1"),
},
},
},
{
SourceClient: "client-0",
DestinationClient: "client-1",
Sequence: 2,
TimeoutTimestamp: 200,
Payloads: []channeltypesv2.Payload{
{
SourcePort: "transfer",
DestinationPort: "transfer",
Version: "1.0",
Encoding: "proto3",
Value: []byte("data2"),
},
},
},
},
},
{
name: "fail: no events",
events: []abci.Event{},
expectedError: "packet not found in events",
},
{
name: "fail: events without packet",
events: []abci.Event{
{
Type: "xxx",
},
{
Type: "yyy",
},
},
expectedError: "packet not found in events",
},
{
name: "fail: invalid hex encoding",
events: []abci.Event{
{
Type: channeltypesv2.EventTypeSendPacket,
Attributes: []abci.EventAttribute{
{
Key: "packet_hex",
Value: "invalid hex",
},
},
},
},
expectedError: "failed to decode packet bytes",
},
{
name: "fail: invalid proto encoding",
events: []abci.Event{
{
Type: channeltypesv2.EventTypeSendPacket,
Attributes: []abci.EventAttribute{
{
Key: "packet_hex",
Value: hex.EncodeToString([]byte("invalid proto")),
},
},
},
},
expectedError: "failed to unmarshal packet",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
allPackets, err := ibctesting.ParsePacketsFromEventsV2(channeltypesv2.EventTypeSendPacket, tc.events)

if tc.expectedError == "" {
require.NoError(t, err)
require.Equal(t, tc.expectedPackets, allPackets)

// Test ParsePacketFromEventsV2 as well
firstPacket, err := ibctesting.ParsePacketFromEventsV2(tc.events)
require.NoError(t, err)
require.Equal(t, tc.expectedPackets[0], firstPacket)
} else {
require.ErrorContains(t, err, tc.expectedError)

// Test ParsePacketFromEventsV2 as well
_, err = ibctesting.ParsePacketFromEventsV2(tc.events)
require.ErrorContains(t, err, tc.expectedError)
}
})
}
}