diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index a176a0623ab..901c2b75d9f 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -890,9 +890,17 @@ func (k Keeper) ChannelUpgradeAck(goCtx context.Context, msg *channeltypes.MsgCh cacheCtx, writeFn := ctx.CacheContext() err = cbs.OnChanUpgradeAck(cacheCtx, msg.PortId, msg.ChannelId, msg.CounterpartyUpgrade.Fields.Version) if err != nil { + channel, found := k.ChannelKeeper.GetChannel(ctx, msg.PortId, msg.ChannelId) + if !found { + return nil, errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "channel not found for port ID (%s) channel ID (%s)", msg.PortId, msg.ChannelId) + } + ctx.Logger().Error("channel upgrade ack callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", err.Error()) cbs.OnChanUpgradeRestore(ctx, msg.PortId, msg.ChannelId) - k.ChannelKeeper.MustAbortUpgrade(ctx, msg.PortId, msg.ChannelId, err) + + // explicitly wrap the application callback in an upgrade error with the correct upgrade sequence. + // this prevents any errors caused from the application returning an UpgradeError with an incorrect sequence. + k.ChannelKeeper.MustAbortUpgrade(ctx, msg.PortId, msg.ChannelId, channeltypes.NewUpgradeError(channel.UpgradeSequence, err)) return &channeltypes.MsgChannelUpgradeAckResponse{Result: channeltypes.FAILURE}, nil } diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index dd2113d00b7..0b40fb637bb 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -1393,6 +1393,18 @@ func (suite *KeeperTestSuite) TestChannelUpgradeAck() { suite.Require().Empty(events) }, }, + { + "application callback returns an upgrade error", + func() { + suite.chainA.GetSimApp().IBCMockModule.IBCApp.OnChanUpgradeAck = func(ctx sdk.Context, portID, channelID, counterpartyVersion string) error { + return channeltypes.NewUpgradeError(10000000, ibcmock.MockApplicationCallbackError) + } + }, + func(res *channeltypes.MsgChannelUpgradeAckResponse, events []abci.Event, err error) { + suite.Require().Equal(channeltypes.FAILURE, res.Result) + suite.Require().Equal(uint64(1), path.EndpointA.GetChannel().UpgradeSequence, "application callback upgrade sequence should not be used") + }, + }, } for _, tc := range cases {