From 8c3c04f99a4cfddd1a63691316a9d3031a916fec Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 19:35:45 +0100 Subject: [PATCH] fix: allow `RecvPacket` and `WriteAcknowledgement` when channel is `FLUSHING` or `FLUSHCOMPLETE` (#5668) (#5684) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * in write acknowledgement the channel state is allowed to be flushing as well * add test case * allow recv packet and write acknowledgement when state is also FLUSHCOMPLETE * fix tests --------- Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> (cherry picked from commit 91a1e8fbc37a767dfee10b102f59f501ff1d62e4) Co-authored-by: Carlos Rodriguez --- modules/core/04-channel/keeper/packet.go | 11 +-- modules/core/04-channel/keeper/packet_test.go | 73 +++++++++++++++---- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index f8b23d35f0a..e2703b449f5 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -118,8 +118,8 @@ func (k Keeper) RecvPacket( return errorsmod.Wrap(types.ErrChannelNotFound, packet.GetDestChannel()) } - if !slices.Contains([]types.State{types.OPEN, types.FLUSHING}, channel.State) { - return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected channel state to be one of [%s, %s], but got %s", types.OPEN, types.FLUSHING, channel.State) + if !slices.Contains([]types.State{types.OPEN, types.FLUSHING, types.FLUSHCOMPLETE}, channel.State) { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected channel state to be one of [%s, %s, %s], but got %s", types.OPEN, types.FLUSHING, types.FLUSHCOMPLETE, channel.State) } // If counterpartyUpgrade is stored we need to ensure that the @@ -287,11 +287,8 @@ func (k Keeper) WriteAcknowledgement( return errorsmod.Wrap(types.ErrChannelNotFound, packet.GetDestChannel()) } - if !channel.IsOpen() { - return errorsmod.Wrapf( - types.ErrInvalidChannelState, - "channel state is not OPEN (got %s)", channel.State.String(), - ) + if !slices.Contains([]types.State{types.OPEN, types.FLUSHING, types.FLUSHCOMPLETE}, channel.State) { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s, %s], got %s", types.OPEN, types.FLUSHING, types.FLUSHCOMPLETE, channel.State) } // Authenticate capability to ensure caller has authority to receive packet on this channel diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index 97ca8d4326c..adc96cebae0 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -321,6 +321,38 @@ func (suite *KeeperTestSuite) TestRecvPacket() { }, nil, }, + { + "success UNORDERED channel in FLUSHING", + func() { + // setup uses an UNORDERED channel + suite.coordinator.Setup(path) + channel := path.EndpointB.GetChannel() + channel.State = types.FLUSHING + path.EndpointB.SetChannel(channel) + + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + }, + nil, + }, + { + "success UNORDERED channel in FLUSHCOMPLETE", + func() { + // setup uses an UNORDERED channel + suite.coordinator.Setup(path) + channel := path.EndpointB.GetChannel() + channel.State = types.FLUSHCOMPLETE + path.EndpointB.SetChannel(channel) + + sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) + suite.Require().NoError(err) + packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + }, + nil, + }, { "success with out of order packet: UNORDERED channel", func() { @@ -393,21 +425,6 @@ func (suite *KeeperTestSuite) TestRecvPacket() { }, types.ErrInvalidPacket, }, - { - "failure while upgrading channel, channel in flush complete state", - func() { - suite.coordinator.Setup(path) - sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) - suite.Require().NoError(err) - packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) - channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - - channel := path.EndpointB.GetChannel() - channel.State = types.FLUSHCOMPLETE - path.EndpointB.SetChannel(channel) - }, - types.ErrInvalidChannelState, - }, { "packet already relayed ORDERED channel (no-op)", func() { @@ -685,6 +702,32 @@ func (suite *KeeperTestSuite) TestWriteAcknowledgement() { }, true, }, + { + "success: channel flushing", + func() { + suite.coordinator.Setup(path) + packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + ack = ibcmock.MockAcknowledgement + + err := path.EndpointB.SetChannelState(types.FLUSHING) + suite.Require().NoError(err) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + }, + true, + }, + { + "success: channel flush complete", + func() { + suite.coordinator.Setup(path) + packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) + ack = ibcmock.MockAcknowledgement + + err := path.EndpointB.SetChannelState(types.FLUSHCOMPLETE) + suite.Require().NoError(err) + channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + }, + true, + }, {"channel not found", func() { // use wrong channel naming suite.coordinator.Setup(path)