diff --git a/modules/core/04-channel/v2/keeper/msg_server.go b/modules/core/04-channel/v2/keeper/msg_server.go index 23de9ec0c74..1d8add950d4 100644 --- a/modules/core/04-channel/v2/keeper/msg_server.go +++ b/modules/core/04-channel/v2/keeper/msg_server.go @@ -165,10 +165,6 @@ func (k *Keeper) RecvPacket(ctx context.Context, msg *channeltypesv2.MsgRecvPack // Timeout implements the PacketMsgServer Timeout method. func (k *Keeper) Timeout(ctx context.Context, timeout *channeltypesv2.MsgTimeout) (*channeltypesv2.MsgTimeoutResponse, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) - if err := k.timeoutPacket(ctx, timeout.Packet, timeout.ProofUnreceived, timeout.ProofHeight); err != nil { - sdkCtx.Logger().Error("Timeout packet failed", "source-channel", timeout.Packet.SourceChannel, "destination-channel", timeout.Packet.DestinationChannel, "error", errorsmod.Wrap(err, "timeout packet failed")) - return nil, errorsmod.Wrapf(err, "timeout packet failed for source id: %s and destination id: %s", timeout.Packet.SourceChannel, timeout.Packet.DestinationChannel) - } signer, err := sdk.AccAddressFromBech32(timeout.Signer) if err != nil { @@ -176,6 +172,24 @@ func (k *Keeper) Timeout(ctx context.Context, timeout *channeltypesv2.MsgTimeout return nil, errorsmod.Wrap(err, "invalid address for msg Signer") } + cacheCtx, writeFn := sdkCtx.CacheContext() + if err := k.timeoutPacket(cacheCtx, timeout.Packet, timeout.ProofUnreceived, timeout.ProofHeight); err != nil { + sdkCtx.Logger().Error("Timeout packet failed", "source-channel", timeout.Packet.SourceChannel, "destination-channel", timeout.Packet.DestinationChannel, "error", errorsmod.Wrap(err, "timeout packet failed")) + return nil, errorsmod.Wrapf(err, "timeout packet failed for source id: %s and destination id: %s", timeout.Packet.SourceChannel, timeout.Packet.DestinationChannel) + } + + switch err { + case nil: + writeFn() + case channeltypesv1.ErrNoOpMsg: + // no-ops do not need event emission as they will be ignored + sdkCtx.Logger().Debug("no-op on redundant relay", "source-channel", timeout.Packet.SourceChannel) + return &channeltypesv2.MsgTimeoutResponse{Result: channeltypesv1.NOOP}, nil + default: + sdkCtx.Logger().Error("timeout failed", "source-channel", timeout.Packet.SourceChannel, "error", errorsmod.Wrap(err, "timeout packet verification failed")) + return nil, errorsmod.Wrap(err, "timeout packet verification failed") + } + for _, pd := range timeout.Packet.Data { cbs := k.Router.Route(pd.SourcePort) err := cbs.OnTimeoutPacket(ctx, timeout.Packet.SourceChannel, timeout.Packet.DestinationChannel, pd, signer) diff --git a/modules/core/04-channel/v2/keeper/msg_server_test.go b/modules/core/04-channel/v2/keeper/msg_server_test.go index 6eec08b6133..392ca982155 100644 --- a/modules/core/04-channel/v2/keeper/msg_server_test.go +++ b/modules/core/04-channel/v2/keeper/msg_server_test.go @@ -514,7 +514,9 @@ func (suite *KeeperTestSuite) TestMsgTimeout() { // Send packet from A to B timeoutTimestamp := suite.chainA.GetTimeoutTimestamp() mockData := mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB) - packet, err := path.EndpointA.MsgSendPacket(timeoutTimestamp, mockData) + + var err error + packet, err = path.EndpointA.MsgSendPacket(timeoutTimestamp, mockData) // msgSendPacket := channeltypesv2.NewMsgSendPacket(path.EndpointA.ChannelID, timeoutTimestamp, suite.chainA.SenderAccount.GetAddress().String(), mockData) // res, err := path.EndpointA.Chain.SendMsgs(msgSendPacket) suite.Require().NoError(err)