diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index 78b7c464b3a..f8b23d35f0a 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -4,7 +4,6 @@ import ( "bytes" "slices" "strconv" - "time" errorsmod "cosmossdk.io/errors" @@ -74,25 +73,16 @@ func (k Keeper) SendPacket( return 0, errorsmod.Wrapf(clienttypes.ErrClientNotActive, "cannot send packet using client (%s) with status %s", connectionEnd.GetClientID(), status) } - // check if packet is timed out on the receiving chain latestHeight := clientState.GetLatestHeight() - if !timeoutHeight.IsZero() && latestHeight.GTE(timeoutHeight) { - return 0, errorsmod.Wrapf( - types.ErrPacketTimeout, - "receiving chain block height >= packet timeout height (%s >= %s)", latestHeight, timeoutHeight, - ) - } - latestTimestamp, err := k.connectionKeeper.GetTimestampAtHeight(ctx, connectionEnd, latestHeight) if err != nil { return 0, err } - if packet.GetTimeoutTimestamp() != 0 && latestTimestamp >= packet.GetTimeoutTimestamp() { - return 0, errorsmod.Wrapf( - types.ErrPacketTimeout, - "receiving chain block timestamp >= packet timeout timestamp (%s >= %s)", time.Unix(0, int64(latestTimestamp)).UTC(), time.Unix(0, int64(packet.GetTimeoutTimestamp())).UTC(), - ) + // check if packet is timed out on the receiving chain + timeout := types.NewTimeout(packet.GetTimeoutHeight().(clienttypes.Height), packet.GetTimeoutTimestamp()) + if timeout.Elapsed(latestHeight.(clienttypes.Height), latestTimestamp) { + return 0, errorsmod.Wrap(timeout.ErrTimeoutElapsed(latestHeight.(clienttypes.Height), latestTimestamp), "invalid packet timeout") } commitment := types.CommitPacket(k.cdc, packet) @@ -189,22 +179,11 @@ func (k Keeper) RecvPacket( ) } - // check if packet timeouted by comparing it with the latest height of the chain - selfHeight := clienttypes.GetSelfHeight(ctx) - timeoutHeight := packet.GetTimeoutHeight() - if !timeoutHeight.IsZero() && selfHeight.GTE(timeoutHeight) { - return errorsmod.Wrapf( - types.ErrPacketTimeout, - "block height >= packet timeout height (%s >= %s)", selfHeight, timeoutHeight, - ) - } - - // check if packet timeouted by comparing it with the latest timestamp of the chain - if packet.GetTimeoutTimestamp() != 0 && uint64(ctx.BlockTime().UnixNano()) >= packet.GetTimeoutTimestamp() { - return errorsmod.Wrapf( - types.ErrPacketTimeout, - "block timestamp >= packet timeout timestamp (%s >= %s)", ctx.BlockTime(), time.Unix(0, int64(packet.GetTimeoutTimestamp())).UTC(), - ) + // check if packet timed out by comparing it with the latest height of the chain + selfHeight, selfTimestamp := clienttypes.GetSelfHeight(ctx), uint64(ctx.BlockTime().UnixNano()) + timeout := types.NewTimeout(packet.GetTimeoutHeight().(clienttypes.Height), packet.GetTimeoutTimestamp()) + if timeout.Elapsed(selfHeight, selfTimestamp) { + return errorsmod.Wrap(timeout.ErrTimeoutElapsed(selfHeight, selfTimestamp), "packet timeout elapsed") } commitment := types.CommitPacket(k.cdc, packet) diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index 8a33cb563e7..59ea2efaefe 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -562,7 +562,7 @@ func (suite *KeeperTestSuite) TestRecvPacket() { packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.GetSelfHeight(suite.chainB.GetContext()), disabledTimeoutTimestamp) channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, - types.ErrPacketTimeout, + types.ErrTimeoutElapsed, }, { "timeout timestamp passed", @@ -572,7 +572,7 @@ func (suite *KeeperTestSuite) TestRecvPacket() { packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, disabledTimeoutHeight, uint64(suite.chainB.GetContext().BlockTime().UnixNano())) channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) }, - types.ErrPacketTimeout, + types.ErrTimeoutElapsed, }, { "next receive sequence is not found", diff --git a/modules/core/04-channel/keeper/timeout.go b/modules/core/04-channel/keeper/timeout.go index a0f7f189fa6..5e7e0a07450 100644 --- a/modules/core/04-channel/keeper/timeout.go +++ b/modules/core/04-channel/keeper/timeout.go @@ -68,10 +68,9 @@ func (k Keeper) TimeoutPacket( return err } - timeoutHeight := packet.GetTimeoutHeight() - if (timeoutHeight.IsZero() || proofHeight.LT(timeoutHeight)) && - (packet.GetTimeoutTimestamp() == 0 || proofTimestamp < packet.GetTimeoutTimestamp()) { - return errorsmod.Wrap(types.ErrPacketTimeout, "packet timeout has not been reached for height or timestamp") + timeout := types.NewTimeout(packet.GetTimeoutHeight().(clienttypes.Height), packet.GetTimeoutTimestamp()) + if !timeout.Elapsed(proofHeight.(clienttypes.Height), proofTimestamp) { + return errorsmod.Wrap(timeout.ErrTimeoutNotReached(proofHeight.(clienttypes.Height), proofTimestamp), "packet timeout not reached") } commitment := k.GetPacketCommitment(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) @@ -178,7 +177,7 @@ func (k Keeper) TimeoutExecuted( // the upgrade is aborted and the channel is set to CLOSED. if channel.State == types.FLUSHING { // an error receipt is written to state and the channel is restored to OPEN - k.MustAbortUpgrade(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), types.ErrPacketTimeout) + k.MustAbortUpgrade(ctx, packet.GetSourcePort(), packet.GetSourceChannel(), errorsmod.Wrap(types.ErrTimeoutElapsed, "packet timeout elapsed on ORDERED channel")) } channel.State = types.CLOSED diff --git a/modules/core/04-channel/keeper/timeout_test.go b/modules/core/04-channel/keeper/timeout_test.go index 27f6def9f85..22db7d65e2f 100644 --- a/modules/core/04-channel/keeper/timeout_test.go +++ b/modules/core/04-channel/keeper/timeout_test.go @@ -124,7 +124,7 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp) }, false}, {"timeout", func() { - expError = types.ErrPacketTimeout + expError = types.ErrTimeoutNotReached suite.coordinator.Setup(path) sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData) suite.Require().NoError(err) @@ -192,9 +192,9 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { }, false}, } - for i, tc := range testCases { + for _, tc := range testCases { tc := tc - suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() { + suite.Run(tc.msg, func() { var ( proof []byte proofHeight exported.Height diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index 767df52d5b1..b64f75fa540 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -722,11 +722,8 @@ func (k Keeper) ChanUpgradeTimeout( // proof must be from a height after timeout has elapsed. Either timeoutHeight or timeoutTimestamp must be defined. // if timeoutHeight is defined and proof is from before timeout height, abort transaction - timeoutHeight := upgrade.Timeout.Height - timeoutTimeStamp := upgrade.Timeout.Timestamp - if (timeoutHeight.IsZero() || proofHeight.LT(timeoutHeight)) && - (timeoutTimeStamp == 0 || proofTimestamp < timeoutTimeStamp) { - return errorsmod.Wrap(types.ErrInvalidUpgradeTimeout, "upgrade timeout has not been reached for height or timestamp") + if !upgrade.Timeout.Elapsed(proofHeight.(clienttypes.Height), proofTimestamp) { + return errorsmod.Wrap(upgrade.Timeout.ErrTimeoutNotReached(proofHeight.(clienttypes.Height), proofTimestamp), "upgrade timeout not reached") } // counterparty channel must be proved to still be in OPEN state or FLUSHING state. diff --git a/modules/core/04-channel/keeper/upgrade_test.go b/modules/core/04-channel/keeper/upgrade_test.go index d270d93e493..690fe77b22f 100644 --- a/modules/core/04-channel/keeper/upgrade_test.go +++ b/modules/core/04-channel/keeper/upgrade_test.go @@ -2032,7 +2032,7 @@ func (suite *KeeperTestSuite) TestChanUpgradeTimeout() { channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) proofChannel, proofHeight = path.EndpointB.QueryProof(channelKey) }, - types.ErrInvalidUpgradeTimeout, + types.ErrTimeoutNotReached, }, { "counterparty channel state is not OPEN or FLUSHING (crossing hellos)",