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

Handle ordered packets in UnreceivedPackets query. #3346

51 changes: 43 additions & 8 deletions modules/core/04-channel/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,18 +398,53 @@ func (q Keeper) UnreceivedPackets(c context.Context, req *types.QueryUnreceivedP

ctx := sdk.UnwrapSDKContext(c)

unreceivedSequences := []uint64{}
channel, found := q.GetChannel(sdk.UnwrapSDKContext(c), req.PortId, req.ChannelId)
if !found {
return nil, status.Error(
codes.NotFound,
errorsmod.Wrapf(types.ErrChannelNotFound, "port-id: %s, channel-id %s", req.PortId, req.ChannelId).Error(),
)
}

for i, seq := range req.PacketCommitmentSequences {
if seq == 0 {
return nil, status.Errorf(codes.InvalidArgument, "packet sequence %d cannot be 0", i)
unreceivedSequences := []uint64{}
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
switch channel.Ordering {
case types.UNORDERED:
for i, seq := range req.PacketCommitmentSequences {
if seq == 0 {
return nil, status.Errorf(codes.InvalidArgument, "packet sequence %d cannot be 0", i)
}
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved

// if packet receipt exists on the receiving chain, then packet has already been received
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
if _, found := q.GetPacketReceipt(ctx, req.PortId, req.ChannelId, seq); !found {
unreceivedSequences = append(unreceivedSequences, seq)
}
}

// if packet receipt exists on the receiving chain, then packet has already been received
if _, found := q.GetPacketReceipt(ctx, req.PortId, req.ChannelId, seq); !found {
unreceivedSequences = append(unreceivedSequences, seq)
case types.ORDERED:
nextSequenceRecv, found := q.GetNextSequenceRecv(ctx, req.PortId, req.ChannelId)
if !found {
return nil, status.Error(
codes.NotFound,
errorsmod.Wrapf(
types.ErrSequenceReceiveNotFound,
"destination port: %s, destination channel: %s", req.PortId, req.ChannelId,
).Error(),
)
}

for i, seq := range req.PacketCommitmentSequences {
if seq == 0 {
return nil, status.Errorf(codes.InvalidArgument, "packet sequence %d cannot be 0", i)
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
}

// If the packet sequence is greater than the sequence most recently received, then the packet has not been received.
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
if seq >= nextSequenceRecv {
unreceivedSequences = append(unreceivedSequences, seq)
}
}
default:
return nil, status.Error(
codes.InvalidArgument,
errorsmod.Wrap(types.ErrInvalidChannelOrdering, channel.Ordering.String()).Error())
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
}

selfHeight := clienttypes.GetSelfHeight(ctx)
Expand Down
63 changes: 63 additions & 0 deletions modules/core/04-channel/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,31 @@ func (suite *KeeperTestSuite) TestQueryUnreceivedPackets() {
},
false,
},
{
"invalid seq, ordered channel",
func() {
path := ibctesting.NewPath(suite.chainA, suite.chainB)
path.SetChannelOrdered()
suite.coordinator.Setup(path)

req = &types.QueryUnreceivedPacketsRequest{
PortId: path.EndpointA.ChannelConfig.PortID,
ChannelId: path.EndpointA.ChannelID,
PacketCommitmentSequences: []uint64{0},
}
},
false,
},
{
"channel not found",
func() {
req = &types.QueryUnreceivedPacketsRequest{
PortId: "invalid-port-id",
ChannelId: "invalid-channel-id",
}
},
false,
},
{
"basic success unreceived packet commitments",
func() {
Expand Down Expand Up @@ -1219,6 +1244,44 @@ func (suite *KeeperTestSuite) TestQueryUnreceivedPackets() {
},
true,
},
{
"basic success unreceived packet commitments, ordered channel",
func() {
path := ibctesting.NewPath(suite.chainA, suite.chainB)
path.SetChannelOrdered()
suite.coordinator.Setup(path)

// Note: NextSequenceRecv is set to 1 on channel creation.
expSeq = []uint64{1}
req = &types.QueryUnreceivedPacketsRequest{
PortId: path.EndpointA.ChannelConfig.PortID,
ChannelId: path.EndpointA.ChannelID,
PacketCommitmentSequences: []uint64{1},
}
},
true,
},
{
"basic success multiple unreceived packet commitments, ordered channel",
func() {
path := ibctesting.NewPath(suite.chainA, suite.chainB)
path.SetChannelOrdered()
suite.coordinator.Setup(path)

charleenfei marked this conversation as resolved.
Show resolved Hide resolved
// Excersise scenario from issue 1532. NextSequenceRecv is 5, commitments for 2, 7, 9, 10
// are present. 2 is received so 7, 9, 10 should be unreceived.
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
expSeq = []uint64{7, 9, 10}
packetCommitments := []uint64{2, 7, 9, 10}
suite.chainA.App.GetIBCKeeper().ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, 5)
Copy link
Contributor

@charleenfei charleenfei Mar 27, 2023

Choose a reason for hiding this comment

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

maybe the NextSequenceRecv parameter and the expSeq/packetCommitments variables can be set up as well generally as variables for the test which are then malleated per test?

Copy link
Contributor Author

@DimitrisJim DimitrisJim Mar 27, 2023

Choose a reason for hiding this comment

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

expSeq is already set up as so (If i'm understanding the comment correctly) and the rationale I got was that it's done since we need to assert its value against the expected in the main test body. Let me know if I got something wrong here.

Copy link
Contributor

Choose a reason for hiding this comment

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

ah okay, i was just seeing the packet commitment sequences getting declared/set on the tests as well as the sequence number, so i was thinking to just set them as variables instead for readability -- but i am not very strongly opinionated, i agree that expSeq is the most important as we are testing for that value as the expected one. thanks!


req = &types.QueryUnreceivedPacketsRequest{
PortId: path.EndpointA.ChannelConfig.PortID,
ChannelId: path.EndpointA.ChannelID,
PacketCommitmentSequences: packetCommitments,
}
},
true,
},
}

for _, tc := range testCases {
Expand Down