From 1293330fccd9ded7d73613b8d80e937213fc1adc Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 31 May 2023 13:05:10 +0200 Subject: [PATCH 01/12] adding boilerplate skeleton for chanUpgradeAck handler --- modules/core/04-channel/keeper/upgrade.go | 78 +++++++++++++++++++++++ modules/core/keeper/msg_server.go | 31 +++++++++ 2 files changed, 109 insertions(+) diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index a5693e1e3f2..0fb4d390fdc 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v7/internal/collections" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ) @@ -92,6 +93,69 @@ func (k Keeper) WriteUpgradeTryChannel( // grab channel inside this function to get most current channel status } +// ChanUpgradeAck is called by a module to accept the ACKUPGRADE handshake step of the channel upgrade protocol. +func (k Keeper) ChanUpgradeAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyFlushStatus types.Order, + counterpartyUpgrade types.Upgrade, + proofChannel, + proofUpgrade []byte, + proofHeight clienttypes.Height, +) error { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + + if !collections.Contains(channel.State, []types.State{types.INITUPGRADE, types.TRYUPGRADE}) { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s], got %s", types.INITUPGRADE, types.TRYUPGRADE, channel.State) + } + + // TODO: rebase with FlushStatus and update args and error return + // abortTransactionUnless(counterpartyFlushStatus == FLUSHING || counterpartyFlushStatus == FLUSHCOMPLETE) + if !collections.Contains(counterpartyFlushStatus, []types.Order{types.UNORDERED, types.ORDERED}) { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s], got %s", types.INITUPGRADE, types.TRYUPGRADE, channel.State) + } + + connectionEnd, err := k.GetConnection(ctx, channel.ConnectionHops[0]) + if err != nil { + return errorsmod.Wrapf(err, "failed to retrieve connection: %s", channel.ConnectionHops[0]) + } + + counterpartyHops := connectionEnd.GetCounterparty().GetConnectionID() + counterpartyChannel := types.Channel{ + State: types.TRYUPGRADE, + Ordering: channel.Ordering, + ConnectionHops: []string{counterpartyHops}, + Counterparty: types.NewCounterparty(portID, channelID), + Version: channel.Version, + UpgradeSequence: channel.UpgradeSequence, + // FlushStatus: counterpartyFlushStatus, + } + + upgrade, found := k.GetUpgrade(ctx, portID, channelID) + if !found { + return errorsmod.Wrapf(types.ErrUpgradeNotFound, "failed to retrieve channel upgrade: port ID (%s) channel ID (%s)", portID, channelID) + } + + // in the crossing hellos case, the versions returned by both on TRY must be the same + if channel.State == types.TRYUPGRADE { + if upgrade.Fields.Version != counterpartyUpgrade.Fields.Version { + // restoreChannel(portID, channelID) + return errorsmod.Wrap(types.ErrInvalidUpgrade, "todo: return types.UpgradeError(channel.UpgradeSequence, err)") + } + } + + if err := k.startFlushUpgradeHandshake(ctx, portID, channelID, upgrade.Fields, counterpartyChannel, counterpartyUpgrade, + proofChannel, proofUpgrade, proofHeight); err != nil { + return err + } + + return nil +} + // constructProposedUpgrade returns the proposed upgrade from the provided arguments. func (k Keeper) constructProposedUpgrade(ctx sdk.Context, portID, channelID string, fields types.UpgradeFields, upgradeTimeout types.Timeout) (types.Upgrade, error) { seq, found := k.GetNextSequenceSend(ctx, portID, channelID) @@ -104,3 +168,17 @@ func (k Keeper) constructProposedUpgrade(ctx sdk.Context, portID, channelID stri LatestSequenceSend: seq - 1, }, nil } + +func (k Keeper) startFlushUpgradeHandshake( + ctx sdk.Context, + portID, + channelID string, + proposedUpgradeFields types.UpgradeFields, + counterpartyChannel types.Channel, + counterpartyUpgrade types.Upgrade, + proofCounterpartyChannel, + proofUpgrade []byte, + proofHeight clienttypes.Height, +) error { + return nil +} diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 73d2e39dcbe..e8f8efbf3f3 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -10,6 +10,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" coretypes "github.com/cosmos/ibc-go/v7/modules/core/types" @@ -821,6 +822,36 @@ func (k Keeper) ChannelUpgradeTry(goCtx context.Context, msg *channeltypes.MsgCh // ChannelUpgradeAck defines a rpc handler method for MsgChannelUpgradeAck. func (k Keeper) ChannelUpgradeAck(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeAck) (*channeltypes.MsgChannelUpgradeAckResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) + if err != nil { + ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) + return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") + } + + cbs, ok := k.Router.GetRoute(module) + if !ok { + ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) + return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + } + + // TODO: update msg args + err = k.ChannelKeeper.ChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, channeltypes.NONE, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgradeSequence, msg.ProofHeight) + if err != nil { + ctx.Logger().Error("channel upgrade ack failed", "error", errorsmod.Wrap(err, "channel handshake upgrade ack failed")) + return nil, errorsmod.Wrap(err, "channel handshake upgrade ack failed") + } + + // TODO: update callback args?? remove counterparty channel ID?? + err = cbs.OnChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannel.Version, msg.CounterpartyChannel.Version) + if err != nil { + ctx.Logger().Error("channel upgrade ack callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", err.Error()) + + // restoreChannel(portID, channelID) + return &types.MsgChannelUpgradeAckResponse{}, nil + } + return nil, nil } From a8c6882d860dc92d273d1940ea83303a1d67c994 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 5 Jun 2023 14:26:58 +0200 Subject: [PATCH 02/12] updating msg servers args --- modules/core/keeper/msg_server.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index cf808679ff9..6da4ae0052d 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -772,14 +772,14 @@ func (k Keeper) ChannelUpgradeAck(goCtx context.Context, msg *channeltypes.MsgCh } // TODO: update msg args - err = k.ChannelKeeper.ChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, channeltypes.NONE, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgradeSequence, msg.ProofHeight) + err = k.ChannelKeeper.ChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, channeltypes.NONE, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) if err != nil { ctx.Logger().Error("channel upgrade ack failed", "error", errorsmod.Wrap(err, "channel handshake upgrade ack failed")) return nil, errorsmod.Wrap(err, "channel handshake upgrade ack failed") } - // TODO: update callback args?? remove counterparty channel ID?? - err = cbs.OnChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyChannel.Version, msg.CounterpartyChannel.Version) + // TODO: update callback args?? remove counterparty channel ID and version?? + err = cbs.OnChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, "", "") if err != nil { ctx.Logger().Error("channel upgrade ack callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", err.Error()) From c17c8ed23936622499c513f153d802d7e7373e54 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 5 Jun 2023 15:23:33 +0200 Subject: [PATCH 03/12] adding test scaffolding and syncing latest changes of feat branch --- modules/core/04-channel/keeper/upgrade.go | 10 +- .../core/04-channel/keeper/upgrade_test.go | 100 ++++++++++++++++++ modules/core/keeper/msg_server.go | 5 +- testing/endpoint.go | 7 +- 4 files changed, 110 insertions(+), 12 deletions(-) diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index 5c34b6f5ac3..8fdd26304d2 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -154,7 +154,7 @@ func (k Keeper) ChanUpgradeAck( ctx sdk.Context, portID, channelID string, - counterpartyFlushStatus types.Order, + counterpartyFlushStatus types.FlushStatus, counterpartyUpgrade types.Upgrade, proofChannel, proofUpgrade []byte, @@ -169,10 +169,8 @@ func (k Keeper) ChanUpgradeAck( return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s], got %s", types.INITUPGRADE, types.TRYUPGRADE, channel.State) } - // TODO: rebase with FlushStatus and update args and error return - // abortTransactionUnless(counterpartyFlushStatus == FLUSHING || counterpartyFlushStatus == FLUSHCOMPLETE) - if !collections.Contains(counterpartyFlushStatus, []types.Order{types.UNORDERED, types.ORDERED}) { - return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s], got %s", types.INITUPGRADE, types.TRYUPGRADE, channel.State) + if !collections.Contains(counterpartyFlushStatus, []types.FlushStatus{types.FLUSHING, types.FLUSHCOMPLETE}) { + return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s], got %s", types.FLUSHING, types.FLUSHCOMPLETE, counterpartyFlushStatus) } connectionEnd, err := k.GetConnection(ctx, channel.ConnectionHops[0]) @@ -188,7 +186,7 @@ func (k Keeper) ChanUpgradeAck( Counterparty: types.NewCounterparty(portID, channelID), Version: channel.Version, UpgradeSequence: channel.UpgradeSequence, - // FlushStatus: counterpartyFlushStatus, + FlushStatus: counterpartyFlushStatus, } upgrade, found := k.GetUpgrade(ctx, portID, channelID) diff --git a/modules/core/04-channel/keeper/upgrade_test.go b/modules/core/04-channel/keeper/upgrade_test.go index f879431a299..bda7de9d183 100644 --- a/modules/core/04-channel/keeper/upgrade_test.go +++ b/modules/core/04-channel/keeper/upgrade_test.go @@ -126,6 +126,106 @@ func (suite *KeeperTestSuite) TestChanUpgradeInit() { } } +func (suite *KeeperTestSuite) TestChanUpgradeAck() { + var ( + path *ibctesting.Path + upgrade types.Upgrade + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success", + func() {}, + true, + }, + { + "success with later upgrade sequence", + func() { + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 4 + path.EndpointA.SetChannel(channel) + }, + true, + }, + { + "channel not found", + func() { + path.EndpointA.ChannelID = "invalid-channel" + path.EndpointA.ChannelConfig.PortID = "invalid-port" + }, + false, + }, + { + "channel state is not in INITUPGRADE or TRYUPGRADE state", + func() { + suite.Require().NoError(path.EndpointA.SetChannelState(types.CLOSED)) + }, + false, + }, + { + "proposed channel connection not found", + func() { + upgrade.Fields.ConnectionHops = []string{"connection-100"} + }, + false, + }, + { + "invalid proposed channel connection state", + func() { + connectionEnd := path.EndpointA.GetConnection() + connectionEnd.State = connectiontypes.UNINITIALIZED + + suite.chainA.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainA.GetContext(), "connection-100", connectionEnd) + upgrade.Fields.ConnectionHops = []string{"connection-100"} + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + suite.coordinator.Setup(path) + + // path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = fmt.Sprintf("%s-v2", mock.Version) + err := path.EndpointA.ChanUpgradeInit() + suite.Require().NoError(err) + + err = path.EndpointB.ChanUpgradeTry() + suite.Require().NoError(err) + + tc.malleate() + + counterpartyUpgrade, found := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + suite.Require().True(found) + + proofChannel, proofUpgrade, proofHeight := path.EndpointA.QueryChannelUpgradeProof() + + err = suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeAck( + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, types.FLUSHCOMPLETE, counterpartyUpgrade, + proofChannel, proofUpgrade, proofHeight, + ) + + if tc.expPass { + // suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeAckChannel() + // channel := path.EndpointA.GetChannel() + + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + func (suite *KeeperTestSuite) TestValidateProposedUpgradeFields() { var ( proposedUpgrade *types.UpgradeFields diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 6da4ae0052d..d724e3fa0dd 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -752,7 +752,7 @@ func (k Keeper) ChannelUpgradeInit(goCtx context.Context, msg *channeltypes.MsgC // ChannelUpgradeTry defines a rpc handler method for MsgChannelUpgradeTry. func (k Keeper) ChannelUpgradeTry(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeTry) (*channeltypes.MsgChannelUpgradeTryResponse, error) { - return nil, nil + return &channeltypes.MsgChannelUpgradeTryResponse{}, nil } // ChannelUpgradeAck defines a rpc handler method for MsgChannelUpgradeAck. @@ -771,8 +771,7 @@ func (k Keeper) ChannelUpgradeAck(goCtx context.Context, msg *channeltypes.MsgCh return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) } - // TODO: update msg args - err = k.ChannelKeeper.ChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, channeltypes.NONE, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) + err = k.ChannelKeeper.ChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyFlushStatus, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) if err != nil { ctx.Logger().Error("channel upgrade ack failed", "error", errorsmod.Wrap(err, "channel handshake upgrade ack failed")) return nil, errorsmod.Wrap(err, "channel handshake upgrade ack failed") diff --git a/testing/endpoint.go b/testing/endpoint.go index e766a1527ed..7044e5ed349 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -600,10 +600,11 @@ func (endpoint *Endpoint) ChanUpgradeInit() error { } // ChanUpgradeTry sends a MsgChannelUpgradeTry on the associated endpoint. -func (endpoint *Endpoint) ChanUpgradeTry(timeout channeltypes.Timeout) error { +func (endpoint *Endpoint) ChanUpgradeTry() error { err := endpoint.UpdateClient() require.NoError(endpoint.Chain.TB, err) + upgrade := endpoint.GetProposedUpgrade() proofChannel, proofUpgrade, height := endpoint.QueryChannelUpgradeProof() counterpartyUpgrade, found := endpoint.Counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(endpoint.Counterparty.Chain.GetContext(), endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) @@ -612,8 +613,8 @@ func (endpoint *Endpoint) ChanUpgradeTry(timeout channeltypes.Timeout) error { msg := channeltypes.NewMsgChannelUpgradeTry( endpoint.ChannelConfig.PortID, endpoint.ChannelID, - []string{endpoint.ConnectionID}, - timeout, + upgrade.Fields.ConnectionHops, + upgrade.Timeout, counterpartyUpgrade, endpoint.Counterparty.GetChannel().UpgradeSequence, proofChannel, From fbacd836c28ca4d121d9ba944b91afb4f7bb5608 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 6 Jun 2023 12:06:58 +0200 Subject: [PATCH 04/12] configure both proposed upgrades to use mock.UpgradeVersion --- modules/core/04-channel/keeper/upgrade_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/core/04-channel/keeper/upgrade_test.go b/modules/core/04-channel/keeper/upgrade_test.go index bda7de9d183..b2e9b1de865 100644 --- a/modules/core/04-channel/keeper/upgrade_test.go +++ b/modules/core/04-channel/keeper/upgrade_test.go @@ -194,8 +194,9 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { path = ibctesting.NewPath(suite.chainA, suite.chainB) suite.coordinator.Setup(path) - // path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion - path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = fmt.Sprintf("%s-v2", mock.Version) + path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + err := path.EndpointA.ChanUpgradeInit() suite.Require().NoError(err) From f92edcb308cb1a3b7cef69d17a28c3aa2b3cb9d0 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 12 Jun 2023 17:56:27 +0200 Subject: [PATCH 05/12] updating chanUpgradeAck test cases --- modules/core/04-channel/keeper/upgrade.go | 9 +- .../core/04-channel/keeper/upgrade_test.go | 85 ++++++++++++++----- 2 files changed, 69 insertions(+), 25 deletions(-) diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index f893d2dcf61..ea0f019d1f6 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -191,7 +191,7 @@ func (k Keeper) WriteUpgradeTryChannel(ctx sdk.Context, portID, channelID string previousState := channel.State channel.State = types.TRYUPGRADE // TODO: determine flush status - // channel.FlushStatus = flushStatus + channel.FlushStatus = types.FLUSHING upgrade.Fields.Version = upgradeVersion @@ -237,11 +237,11 @@ func (k Keeper) ChanUpgradeAck( return errorsmod.Wrapf(err, "failed to retrieve connection: %s", channel.ConnectionHops[0]) } - counterpartyHops := connectionEnd.GetCounterparty().GetConnectionID() + counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()} counterpartyChannel := types.Channel{ State: types.TRYUPGRADE, Ordering: channel.Ordering, - ConnectionHops: []string{counterpartyHops}, + ConnectionHops: counterpartyHops, Counterparty: types.NewCounterparty(portID, channelID), Version: channel.Version, UpgradeSequence: channel.UpgradeSequence, @@ -256,8 +256,7 @@ func (k Keeper) ChanUpgradeAck( // in the crossing hellos case, the versions returned by both on TRY must be the same if channel.State == types.TRYUPGRADE { if upgrade.Fields.Version != counterpartyUpgrade.Fields.Version { - // restoreChannel(portID, channelID) - return errorsmod.Wrap(types.ErrInvalidUpgrade, "todo: return types.UpgradeError(channel.UpgradeSequence, err)") + return types.NewUpgradeError(channel.UpgradeSequence, errorsmod.Wrap(types.ErrIncompatibleCounterpartyUpgrade, "both channel ends must agree on the same version")) } } diff --git a/modules/core/04-channel/keeper/upgrade_test.go b/modules/core/04-channel/keeper/upgrade_test.go index 08c1bbe8137..4eb167237a2 100644 --- a/modules/core/04-channel/keeper/upgrade_test.go +++ b/modules/core/04-channel/keeper/upgrade_test.go @@ -327,8 +327,8 @@ func (suite *KeeperTestSuite) TestChanUpgradeTry() { func (suite *KeeperTestSuite) TestChanUpgradeAck() { var ( - path *ibctesting.Path - upgrade types.Upgrade + path *ibctesting.Path + counterpartyFlushStatus types.FlushStatus ) testCases := []struct { @@ -341,15 +341,18 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { func() {}, true, }, - { - "success with later upgrade sequence", - func() { - channel := path.EndpointA.GetChannel() - channel.UpgradeSequence = 4 - path.EndpointA.SetChannel(channel) - }, - true, - }, + // { + // "success with later upgrade sequence", + // func() { + // channel := path.EndpointA.GetChannel() + // channel.UpgradeSequence = 4 + // path.EndpointA.SetChannel(channel) + + // err := path.EndpointA.UpdateClient() + // suite.Require().NoError(err) + // }, + // true, + // }, { "channel not found", func() { @@ -366,20 +369,60 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { false, }, { - "proposed channel connection not found", + "counterparty flush status is not in FLUSHING or FLUSHCOMPLETE", func() { - upgrade.Fields.ConnectionHops = []string{"connection-100"} + counterpartyFlushStatus = types.NOTINFLUSH }, false, }, { - "invalid proposed channel connection state", + "connection not found", + func() { + channel := path.EndpointA.GetChannel() + channel.ConnectionHops = []string{"connection-100"} + path.EndpointA.SetChannel(channel) + }, + false, + }, + { + "invalid connection state", func() { connectionEnd := path.EndpointA.GetConnection() connectionEnd.State = connectiontypes.UNINITIALIZED + suite.chainA.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainA.GetContext(), path.EndpointA.ConnectionID, connectionEnd) + }, + false, + }, + { + "connection not found", + func() { + channel := path.EndpointA.GetChannel() + channel.ConnectionHops = []string{"connection-100"} + path.EndpointA.SetChannel(channel) + }, + false, + }, + { + "upgrade not found", + func() { + store := suite.chainA.GetContext().KVStore(suite.chainA.GetSimApp().GetKey(exported.ModuleName)) + store.Delete(host.ChannelUpgradeKey(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)) + }, + false, + }, + { + "channel end version mismatch on crossing hellos", + func() { + channel := path.EndpointA.GetChannel() + channel.State = types.TRYUPGRADE - suite.chainA.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainA.GetContext(), "connection-100", connectionEnd) - upgrade.Fields.ConnectionHops = []string{"connection-100"} + path.EndpointA.SetChannel(channel) + + upgrade, found := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) + suite.Require().True(found) + + upgrade.Fields.Version = "invalid-version" + suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.SetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgrade) }, false, }, @@ -396,12 +439,17 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { path.EndpointA.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion + counterpartyFlushStatus = types.FLUSHING + err := path.EndpointA.ChanUpgradeInit() suite.Require().NoError(err) err = path.EndpointB.ChanUpgradeTry() suite.Require().NoError(err) + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + tc.malleate() counterpartyUpgrade, found := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) @@ -410,14 +458,11 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { proofChannel, proofUpgrade, proofHeight := path.EndpointA.QueryChannelUpgradeProof() err = suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeAck( - suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, types.FLUSHCOMPLETE, counterpartyUpgrade, + suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, counterpartyFlushStatus, counterpartyUpgrade, proofChannel, proofUpgrade, proofHeight, ) if tc.expPass { - // suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.WriteUpgradeAckChannel() - // channel := path.EndpointA.GetChannel() - suite.Require().NoError(err) } else { suite.Require().Error(err) From 0ae120f4184342f8b5b53cd12228b981c5524aed Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 13 Jun 2023 01:25:00 +0200 Subject: [PATCH 06/12] updating var naming for consistency, adding additional testcases --- modules/core/04-channel/keeper/upgrade.go | 4 +- .../core/04-channel/keeper/upgrade_test.go | 53 ++++++++++++++----- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index ea0f019d1f6..159e4a409d8 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -232,12 +232,12 @@ func (k Keeper) ChanUpgradeAck( return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s], got %s", types.FLUSHING, types.FLUSHCOMPLETE, counterpartyFlushStatus) } - connectionEnd, err := k.GetConnection(ctx, channel.ConnectionHops[0]) + connection, err := k.GetConnection(ctx, channel.ConnectionHops[0]) if err != nil { return errorsmod.Wrapf(err, "failed to retrieve connection: %s", channel.ConnectionHops[0]) } - counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()} + counterpartyHops := []string{connection.GetCounterparty().GetConnectionID()} counterpartyChannel := types.Channel{ State: types.TRYUPGRADE, Ordering: channel.Ordering, diff --git a/modules/core/04-channel/keeper/upgrade_test.go b/modules/core/04-channel/keeper/upgrade_test.go index 4eb167237a2..a8f544a1c43 100644 --- a/modules/core/04-channel/keeper/upgrade_test.go +++ b/modules/core/04-channel/keeper/upgrade_test.go @@ -329,6 +329,7 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { var ( path *ibctesting.Path counterpartyFlushStatus types.FlushStatus + counterpartyUpgrade types.Upgrade ) testCases := []struct { @@ -341,18 +342,24 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { func() {}, true, }, - // { - // "success with later upgrade sequence", - // func() { - // channel := path.EndpointA.GetChannel() - // channel.UpgradeSequence = 4 - // path.EndpointA.SetChannel(channel) + { + "success with later upgrade sequence", + func() { + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 10 + path.EndpointA.SetChannel(channel) - // err := path.EndpointA.UpdateClient() - // suite.Require().NoError(err) - // }, - // true, - // }, + channel = path.EndpointB.GetChannel() + channel.UpgradeSequence = 10 + path.EndpointB.SetChannel(channel) + + suite.coordinator.CommitBlock(suite.chainA, suite.chainB) + + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + }, + true, + }, { "channel not found", func() { @@ -426,6 +433,22 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { }, false, }, + { + "startFlushUpgradeHandshake fails due to proof verification failure, counterparty upgrade connection hops are tampered with", + func() { + counterpartyUpgrade.Fields.ConnectionHops = []string{ibctesting.InvalidID} + }, + false, + }, + { + "startFlushUpgradeHandshake fails due to mismatch in upgrade sequences", + func() { + channel := path.EndpointA.GetChannel() + channel.UpgradeSequence = 5 + path.EndpointA.SetChannel(channel) + }, + false, + }, } for _, tc := range testCases { @@ -447,14 +470,16 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { err = path.EndpointB.ChanUpgradeTry() suite.Require().NoError(err) + // ensure client is up to date to receive valid proofs err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - tc.malleate() - - counterpartyUpgrade, found := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) + var found bool + counterpartyUpgrade, found = suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) suite.Require().True(found) + tc.malleate() + proofChannel, proofUpgrade, proofHeight := path.EndpointA.QueryChannelUpgradeProof() err = suite.chainA.GetSimApp().IBCKeeper.ChannelKeeper.ChanUpgradeAck( From 73e9352b827bfb3fcc14122b4e8659be52c05683 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 13 Jun 2023 01:27:11 +0200 Subject: [PATCH 07/12] rm msg server implementation --- modules/core/keeper/msg_server.go | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index b163ca822a5..33df77fb5b9 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -10,7 +10,6 @@ import ( clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" - "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" coretypes "github.com/cosmos/ibc-go/v7/modules/core/types" @@ -806,35 +805,6 @@ func (k Keeper) ChannelUpgradeTry(goCtx context.Context, msg *channeltypes.MsgCh // ChannelUpgradeAck defines a rpc handler method for MsgChannelUpgradeAck. func (k Keeper) ChannelUpgradeAck(goCtx context.Context, msg *channeltypes.MsgChannelUpgradeAck) (*channeltypes.MsgChannelUpgradeAckResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - module, _, err := k.ChannelKeeper.LookupModuleByChannel(ctx, msg.PortId, msg.ChannelId) - if err != nil { - ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", errorsmod.Wrap(err, "could not retrieve module from port-id")) - return nil, errorsmod.Wrap(err, "could not retrieve module from port-id") - } - - cbs, ok := k.Router.GetRoute(module) - if !ok { - ctx.Logger().Error("channel upgrade ack failed", "port-id", msg.PortId, "error", errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module)) - return nil, errorsmod.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) - } - - err = k.ChannelKeeper.ChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyFlushStatus, msg.CounterpartyUpgrade, msg.ProofChannel, msg.ProofUpgrade, msg.ProofHeight) - if err != nil { - ctx.Logger().Error("channel upgrade ack failed", "error", errorsmod.Wrap(err, "channel handshake upgrade ack failed")) - return nil, errorsmod.Wrap(err, "channel handshake upgrade ack failed") - } - - // TODO: update callback args?? remove counterparty channel ID and version?? - err = cbs.OnChanUpgradeAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyUpgrade.Fields.Version) - if err != nil { - ctx.Logger().Error("channel upgrade ack callback failed", "port-id", msg.PortId, "channel-id", msg.ChannelId, "error", err.Error()) - - // restoreChannel(portID, channelID) - return &types.MsgChannelUpgradeAckResponse{}, nil - } - return nil, nil } From 2b8b3fe81f5b482393e713f14b634701aac1b945 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 13 Jun 2023 10:05:50 +0200 Subject: [PATCH 08/12] adding invalid flush status err and rm lint ignore comment --- modules/core/04-channel/keeper/upgrade.go | 4 +--- modules/core/04-channel/types/errors.go | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index 159e4a409d8..d5316bce348 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -229,7 +229,7 @@ func (k Keeper) ChanUpgradeAck( } if !collections.Contains(counterpartyFlushStatus, []types.FlushStatus{types.FLUSHING, types.FLUSHCOMPLETE}) { - return errorsmod.Wrapf(types.ErrInvalidChannelState, "expected one of [%s, %s], got %s", types.FLUSHING, types.FLUSHCOMPLETE, counterpartyFlushStatus) + return errorsmod.Wrapf(types.ErrInvalidFlushStatus, "expected one of [%s, %s], got %s", types.FLUSHING, types.FLUSHCOMPLETE, counterpartyFlushStatus) } connection, err := k.GetConnection(ctx, channel.ConnectionHops[0]) @@ -272,8 +272,6 @@ func (k Keeper) ChanUpgradeAck( // Once the counterparty information has been verified, it will be validated against the self proposed upgrade. // If any of the proposed upgrade fields are incompatible, an upgrade error will be returned resulting in an // aborted upgrade. -// -//lint:ignore U1000 Ignore unused function temporarily for debugging func (k Keeper) startFlushUpgradeHandshake( ctx sdk.Context, portID, diff --git a/modules/core/04-channel/types/errors.go b/modules/core/04-channel/types/errors.go index 1f3ff7890f8..96a33c245be 100644 --- a/modules/core/04-channel/types/errors.go +++ b/modules/core/04-channel/types/errors.go @@ -45,4 +45,5 @@ var ( ErrInvalidUpgradeSequence = errorsmod.Register(SubModuleName, 29, "invalid upgrade sequence") ErrUpgradeNotFound = errorsmod.Register(SubModuleName, 30, "upgrade not found") ErrIncompatibleCounterpartyUpgrade = errorsmod.Register(SubModuleName, 31, "incompatible counterparty upgrade") + ErrInvalidFlushStatus = errorsmod.Register(SubModuleName, 32, "invalid flush status") ) From e53d1aaf92b938aef57f5f45b3ff179cb0747e7b Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 13 Jun 2023 10:32:13 +0200 Subject: [PATCH 09/12] adding test helpers to endpoint for get/set channel upgrade --- modules/core/04-channel/keeper/upgrade_test.go | 11 ++++------- testing/endpoint.go | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/modules/core/04-channel/keeper/upgrade_test.go b/modules/core/04-channel/keeper/upgrade_test.go index a8f544a1c43..298dbc2b204 100644 --- a/modules/core/04-channel/keeper/upgrade_test.go +++ b/modules/core/04-channel/keeper/upgrade_test.go @@ -425,11 +425,10 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { path.EndpointA.SetChannel(channel) - upgrade, found := suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) - suite.Require().True(found) - + upgrade := path.EndpointA.GetChannelUpgrade() upgrade.Fields.Version = "invalid-version" - suite.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.SetUpgrade(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, upgrade) + + path.EndpointA.SetChannelUpgrade(upgrade) }, false, }, @@ -474,9 +473,7 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - var found bool - counterpartyUpgrade, found = suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.GetUpgrade(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID) - suite.Require().True(found) + counterpartyUpgrade = path.EndpointB.GetChannelUpgrade() tc.malleate() diff --git a/testing/endpoint.go b/testing/endpoint.go index ee4567a7c9d..bee6c9421fe 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -790,6 +790,20 @@ func (endpoint *Endpoint) SetChannel(channel channeltypes.Channel) { endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel) } +// GetChannelUpgrade retrieves an IBC Channel Upgrade for the endpoint. The upgrade +// is expected to exist otherwise testing will fail. +func (endpoint *Endpoint) GetChannelUpgrade() channeltypes.Upgrade { + upgrade, found := endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.GetUpgrade(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + require.True(endpoint.Chain.TB, found) + + return upgrade +} + +// SetChannelUpgrade sets the channel upgrade for this endpoint. +func (endpoint *Endpoint) SetChannelUpgrade(upgrade channeltypes.Upgrade) { + endpoint.Chain.App.GetIBCKeeper().ChannelKeeper.SetUpgrade(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, upgrade) +} + // QueryClientStateProof performs and abci query for a client stat associated // with this endpoint and returns the ClientState along with the proof. func (endpoint *Endpoint) QueryClientStateProof() (exported.ClientState, []byte) { From f9c21676a0fa3ca72be335224a3c41696ad50933 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 13 Jun 2023 11:06:13 +0200 Subject: [PATCH 10/12] lint it --- .golangci.yml | 4 ++++ modules/core/04-channel/keeper/upgrade_test.go | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 123234d42f2..56f4fbcf3c9 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -60,3 +60,7 @@ linters-settings: allow-leading-space: true require-explanation: false require-specific: false + revive: + rules: + - name: if-return + disabled: true \ No newline at end of file diff --git a/modules/core/04-channel/keeper/upgrade_test.go b/modules/core/04-channel/keeper/upgrade_test.go index 298dbc2b204..6aa543614b9 100644 --- a/modules/core/04-channel/keeper/upgrade_test.go +++ b/modules/core/04-channel/keeper/upgrade_test.go @@ -363,8 +363,8 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { { "channel not found", func() { - path.EndpointA.ChannelID = "invalid-channel" - path.EndpointA.ChannelConfig.PortID = "invalid-port" + path.EndpointA.ChannelID = ibctesting.InvalidID + path.EndpointA.ChannelConfig.PortID = ibctesting.InvalidID }, false, }, From 18638ac65e9894e1c9833061772ca99a2f3b8454 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 13 Jun 2023 13:07:17 +0200 Subject: [PATCH 11/12] addressing PR review --- modules/core/04-channel/keeper/upgrade.go | 15 ++++++++------- modules/core/04-channel/keeper/upgrade_test.go | 11 +---------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index d5316bce348..8e8713167e5 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -209,6 +209,7 @@ func (k Keeper) AbortUpgrade(ctx sdk.Context, portID, channelID string, err erro } // ChanUpgradeAck is called by a module to accept the ACKUPGRADE handshake step of the channel upgrade protocol. +// This method should only be called by the IBC core msg server. func (k Keeper) ChanUpgradeAck( ctx sdk.Context, portID, @@ -234,7 +235,7 @@ func (k Keeper) ChanUpgradeAck( connection, err := k.GetConnection(ctx, channel.ConnectionHops[0]) if err != nil { - return errorsmod.Wrapf(err, "failed to retrieve connection: %s", channel.ConnectionHops[0]) + return errorsmod.Wrap(err, "failed to retrieve connection using the channel connection hops") } counterpartyHops := []string{connection.GetCounterparty().GetConnectionID()} @@ -245,7 +246,7 @@ func (k Keeper) ChanUpgradeAck( Counterparty: types.NewCounterparty(portID, channelID), Version: channel.Version, UpgradeSequence: channel.UpgradeSequence, - FlushStatus: counterpartyFlushStatus, + FlushStatus: counterpartyFlushStatus, // provided by the relayer } upgrade, found := k.GetUpgrade(ctx, portID, channelID) @@ -253,6 +254,11 @@ func (k Keeper) ChanUpgradeAck( return errorsmod.Wrapf(types.ErrUpgradeNotFound, "failed to retrieve channel upgrade: port ID (%s) channel ID (%s)", portID, channelID) } + if err := k.startFlushUpgradeHandshake(ctx, portID, channelID, upgrade.Fields, counterpartyChannel, counterpartyUpgrade, + proofChannel, proofUpgrade, proofHeight); err != nil { + return err + } + // in the crossing hellos case, the versions returned by both on TRY must be the same if channel.State == types.TRYUPGRADE { if upgrade.Fields.Version != counterpartyUpgrade.Fields.Version { @@ -260,11 +266,6 @@ func (k Keeper) ChanUpgradeAck( } } - if err := k.startFlushUpgradeHandshake(ctx, portID, channelID, upgrade.Fields, counterpartyChannel, counterpartyUpgrade, - proofChannel, proofUpgrade, proofHeight); err != nil { - return err - } - return nil } diff --git a/modules/core/04-channel/keeper/upgrade_test.go b/modules/core/04-channel/keeper/upgrade_test.go index 6aa543614b9..9f7c3cda45a 100644 --- a/modules/core/04-channel/keeper/upgrade_test.go +++ b/modules/core/04-channel/keeper/upgrade_test.go @@ -396,16 +396,7 @@ func (suite *KeeperTestSuite) TestChanUpgradeAck() { func() { connectionEnd := path.EndpointA.GetConnection() connectionEnd.State = connectiontypes.UNINITIALIZED - suite.chainA.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainA.GetContext(), path.EndpointA.ConnectionID, connectionEnd) - }, - false, - }, - { - "connection not found", - func() { - channel := path.EndpointA.GetChannel() - channel.ConnectionHops = []string{"connection-100"} - path.EndpointA.SetChannel(channel) + path.EndpointA.SetConnection(connectionEnd) }, false, }, From 1622f1db50dff32dbed720d8676fb91e039fe197 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 13 Jun 2023 18:41:53 +0200 Subject: [PATCH 12/12] Update modules/core/04-channel/keeper/upgrade.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- modules/core/04-channel/keeper/upgrade.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index d1836521a27..b0e38453443 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -232,6 +232,8 @@ func (k Keeper) WriteUpgradeAckChannel( // ChanUpgradeAck is called by a module to accept the ACKUPGRADE handshake step of the channel upgrade protocol. // This method should only be called by the IBC core msg server. +// This method will verify that the counterparty has entered TRYUPGRADE +// and that its own upgrade is compatible with the selected counterparty version. func (k Keeper) ChanUpgradeAck( ctx sdk.Context, portID,