From 8c2c0a5fe415a1309b6f73c30819b57c626600c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 21 Dec 2021 15:29:13 +0100 Subject: [PATCH] reorganize channel handshake handler (#647) * reorganize channel handshake handler split out channel state changes into its own function. * readjust 27-interchain-accounts to not rely on state being set before the application callback * add changelog and migration doc entry * Update modules/core/04-channel/keeper/handshake.go --- CHANGELOG.md | 1 + docs/migrations/v2-to-v3.md | 8 ++ .../controller/keeper/handshake.go | 7 +- .../controller/keeper/handshake_test.go | 7 - .../host/keeper/handshake.go | 7 +- .../host/keeper/handshake_test.go | 7 - .../types/expected_keepers.go | 2 +- modules/core/04-channel/keeper/handshake.go | 124 +++++++++++++++--- modules/core/04-channel/keeper/keeper.go | 10 ++ modules/core/keeper/msg_server.go | 85 ++++++------ 10 files changed, 175 insertions(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e22659c6fc..435e0e7330f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#383](https://github.com/cosmos/ibc-go/pull/383) Adds helper functions for merging and splitting middleware versions from the underlying app version. * (modules/core/05-port) [\#288](https://github.com/cosmos/ibc-go/issues/288) Making the 05-port keeper function IsBound public. The IsBound function checks if the provided portID is already binded to a module. * (channel) [\#644](https://github.com/cosmos/ibc-go/pull/644) Adds `GetChannelConnection` to the ChannelKeeper. This function returns the connectionID and connection state associated with a channel. +* (channel) [\647](https://github.com/cosmos/ibc-go/pull/647) Reorganizes channel handshake handling to set channel state after IBC application callbacks. ### Features diff --git a/docs/migrations/v2-to-v3.md b/docs/migrations/v2-to-v3.md index 9f0f130300d..06a1cb938da 100644 --- a/docs/migrations/v2-to-v3.md +++ b/docs/migrations/v2-to-v3.md @@ -22,6 +22,14 @@ ICS27 Interchain Accounts has been added as a supported IBC application of ibc-g ## IBC Apps +### Channel state will not be set before application callback + +The channel handshake logic has been reorganized within core IBC. +Channel state will not be set in state after the application callback is performed. +Applications must rely only on the passed in channel parameters instead of querying the channel keeper for channel state. + +### IBC application callbacks moved from `AppModule` to `IBCModule` + Previously, IBC module callbacks were apart of the `AppModule` type. The recommended approach is to create an `IBCModule` type and move the IBC module callbacks from `AppModule` to `IBCModule` in a separate file `ibc_module.go`. diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go index 66f0720f66c..ea0b907569a 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake.go @@ -42,7 +42,7 @@ func (k Keeper) OnChanOpenInit( return sdkerrors.Wrapf(err, "expected format %s, got %s", icatypes.ControllerPortFormat, portID) } - if err := k.validateControllerPortParams(ctx, channelID, portID, connSequence, counterpartyConnSequence); err != nil { + if err := k.validateControllerPortParams(ctx, connectionHops, connSequence, counterpartyConnSequence); err != nil { return sdkerrors.Wrapf(err, "failed to validate controller port %s", portID) } @@ -104,8 +104,9 @@ func (k Keeper) OnChanCloseConfirm( // validateControllerPortParams asserts the provided connection sequence and counterparty connection sequence // match that of the associated connection stored in state -func (k Keeper) validateControllerPortParams(ctx sdk.Context, channelID, portID string, connectionSeq, counterpartyConnectionSeq uint64) error { - connectionID, connection, err := k.channelKeeper.GetChannelConnection(ctx, portID, channelID) +func (k Keeper) validateControllerPortParams(ctx sdk.Context, connectionHops []string, connectionSeq, counterpartyConnectionSeq uint64) error { + connectionID := connectionHops[0] + connection, err := k.channelKeeper.GetConnection(ctx, connectionID) if err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go index c121447cf3c..3df200e51a3 100644 --- a/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/controller/keeper/handshake_test.go @@ -59,13 +59,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenInit() { }, false, }, - { - "channel not found", - func() { - path.EndpointA.ChannelID = "invalid-channel-id" - }, - false, - }, { "connection not found", func() { diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake.go b/modules/apps/27-interchain-accounts/host/keeper/handshake.go index 3c19c931122..0b06ad0042e 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake.go @@ -43,7 +43,7 @@ func (k Keeper) OnChanOpenTry( return sdkerrors.Wrapf(err, "expected format %s, got %s", icatypes.ControllerPortFormat, counterparty.PortId) } - if err := k.validateControllerPortParams(ctx, channelID, portID, connSequence, counterpartyConnSequence); err != nil { + if err := k.validateControllerPortParams(ctx, connectionHops, connSequence, counterpartyConnSequence); err != nil { return sdkerrors.Wrapf(err, "failed to validate controller port %s", counterparty.PortId) } @@ -104,8 +104,9 @@ func (k Keeper) OnChanCloseConfirm( // validateControllerPortParams asserts the provided connection sequence and counterparty connection sequence // match that of the associated connection stored in state -func (k Keeper) validateControllerPortParams(ctx sdk.Context, channelID, portID string, connectionSeq, counterpartyConnectionSeq uint64) error { - connectionID, connection, err := k.channelKeeper.GetChannelConnection(ctx, portID, channelID) +func (k Keeper) validateControllerPortParams(ctx sdk.Context, connectionHops []string, connectionSeq, counterpartyConnectionSeq uint64) error { + connectionID := connectionHops[0] + connection, err := k.channelKeeper.GetConnection(ctx, connectionID) if err != nil { return err } diff --git a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go index 23b7b88b58f..03346efa1a1 100644 --- a/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go +++ b/modules/apps/27-interchain-accounts/host/keeper/handshake_test.go @@ -51,13 +51,6 @@ func (suite *KeeperTestSuite) TestOnChanOpenTry() { }, false, }, - { - "channel not found", - func() { - path.EndpointB.ChannelID = "invalid-channel-id" - }, - false, - }, { "connection not found", func() { diff --git a/modules/apps/27-interchain-accounts/types/expected_keepers.go b/modules/apps/27-interchain-accounts/types/expected_keepers.go index ba782e1d2f1..4c6a1708e43 100644 --- a/modules/apps/27-interchain-accounts/types/expected_keepers.go +++ b/modules/apps/27-interchain-accounts/types/expected_keepers.go @@ -27,7 +27,7 @@ type ICS4Wrapper interface { type ChannelKeeper interface { GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) - GetChannelConnection(ctx sdk.Context, portID, channelID string) (string, ibcexported.ConnectionI, error) + GetConnection(ctx sdk.Context, connectionID string) (ibcexported.ConnectionI, error) } // PortKeeper defines the expected IBC port keeper diff --git a/modules/core/04-channel/keeper/handshake.go b/modules/core/04-channel/keeper/handshake.go index f1fa5eafcb6..e35ae4bd851 100644 --- a/modules/core/04-channel/keeper/handshake.go +++ b/modules/core/04-channel/keeper/handshake.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -53,14 +55,30 @@ func (k Keeper) ChanOpenInit( } channelID := k.GenerateChannelIdentifier(ctx) - channel := types.NewChannel(types.INIT, order, counterparty, connectionHops, version) - k.SetChannel(ctx, portID, channelID, channel) capKey, err := k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) if err != nil { return "", nil, sdkerrors.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, channelID) } + return channelID, capKey, nil +} + +// WriteOpenInitChannel writes a channel which has successfully passed the OpenInit handshake step. +// The channel is set in state and all the associated Send and Recv sequences are set to 1. +// An event is emitted for the handshake step. +func (k Keeper) WriteOpenInitChannel( + ctx sdk.Context, + portID, + channelID string, + order types.Order, + connectionHops []string, + counterparty types.Counterparty, + version string, +) { + channel := types.NewChannel(types.INIT, order, counterparty, connectionHops, version) + k.SetChannel(ctx, portID, channelID, channel) + k.SetNextSequenceSend(ctx, portID, channelID, 1) k.SetNextSequenceRecv(ctx, portID, channelID, 1) k.SetNextSequenceAck(ctx, portID, channelID, 1) @@ -82,7 +100,12 @@ func (k Keeper) ChanOpenInit( ), }) - return channelID, capKey, nil + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) } // ChanOpenTry is called by a module to accept the first step of a channel opening @@ -171,16 +194,13 @@ func (k Keeper) ChanOpenTry( ) } - // NOTE: this step has been switched with the one below to reverse the connection - // hops - channel := types.NewChannel(types.TRYOPEN, order, counterparty, connectionHops, version) counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()} // expectedCounterpaty is the counterparty of the counterparty's channel end // (i.e self) expectedCounterparty := types.NewCounterparty(portID, "") expectedChannel := types.NewChannel( - types.INIT, channel.Ordering, expectedCounterparty, + types.INIT, order, expectedCounterparty, counterpartyHops, counterpartyVersion, ) @@ -202,9 +222,6 @@ func (k Keeper) ChanOpenTry( return "", nil, sdkerrors.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, channelID) } - k.SetNextSequenceSend(ctx, portID, channelID, 1) - k.SetNextSequenceRecv(ctx, portID, channelID, 1) - k.SetNextSequenceAck(ctx, portID, channelID, 1) } else { // capability initialized in ChanOpenInit capKey, found = k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(portID, channelID)) @@ -215,6 +232,30 @@ func (k Keeper) ChanOpenTry( } } + return channelID, capKey, nil +} + +// WriteOpenTryChannel writes a channel which has successfully passed the OpenTry handshake step. +// The channel is set in state. If a previous channel state did not exist, all the Send and Recv +// sequences are set to 1. An event is emitted for the handshake step. +func (k Keeper) WriteOpenTryChannel( + ctx sdk.Context, + portID, + channelID string, + order types.Order, + connectionHops []string, + counterparty types.Counterparty, + version string, +) { + previousChannel, previousChannelFound := k.GetChannel(ctx, portID, channelID) + if !previousChannelFound { + k.SetNextSequenceSend(ctx, portID, channelID, 1) + k.SetNextSequenceRecv(ctx, portID, channelID, 1) + k.SetNextSequenceAck(ctx, portID, channelID, 1) + } + + channel := types.NewChannel(types.TRYOPEN, order, counterparty, connectionHops, version) + k.SetChannel(ctx, portID, channelID, channel) k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", previousChannel.State.String(), "new-state", "TRYOPEN") @@ -233,8 +274,12 @@ func (k Keeper) ChanOpenTry( sdk.NewAttribute(types.AttributeKeyConnectionID, channel.ConnectionHops[0]), ), }) - - return channelID, capKey, nil + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) } // ChanOpenAck is called by the handshake-originating module to acknowledge the @@ -294,17 +339,34 @@ func (k Keeper) ChanOpenAck( return err } - k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", channel.State.String(), "new-state", "OPEN") + return nil +} - defer func() { - telemetry.IncrCounter(1, "ibc", "channel", "open-ack") - }() +// WriteOpenAckChannel writes an updated channel state for the successful OpenAck handshake step. +// An event is emitted for the handshake step. +func (k Keeper) WriteOpenAckChannel( + ctx sdk.Context, + portID, + channelID, + counterpartyVersion, + counterpartyChannelID string, +) { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(fmt.Sprintf("could not find existing channel when updating channel state in successful ChanOpenAck step, channelID: %s, portID: %s", channelID, portID)) + } channel.State = types.OPEN channel.Version = counterpartyVersion channel.Counterparty.ChannelId = counterpartyChannelID k.SetChannel(ctx, portID, channelID, channel) + k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", channel.State.String(), "new-state", "OPEN") + + defer func() { + telemetry.IncrCounter(1, "ibc", "channel", "open-ack") + }() + ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeChannelOpenAck, @@ -315,8 +377,13 @@ func (k Keeper) ChanOpenAck( sdk.NewAttribute(types.AttributeKeyConnectionID, channel.ConnectionHops[0]), ), }) + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) - return nil } // ChanOpenConfirm is called by the counterparty module to close their end of the @@ -373,6 +440,21 @@ func (k Keeper) ChanOpenConfirm( return err } + return nil +} + +// WriteOpenConfirmChannel writes an updated channel state for the successful OpenConfirm handshake step. +// An event is emitted for the handshake step. +func (k Keeper) WriteOpenConfirmChannel( + ctx sdk.Context, + portID, + channelID string, +) { + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(fmt.Sprintf("could not find existing channel when updating channel state in successful ChanOpenConfirm step, channelID: %s, portID: %s", channelID, portID)) + } + channel.State = types.OPEN k.SetChannel(ctx, portID, channelID, channel) k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", "TRYOPEN", "new-state", "OPEN") @@ -391,8 +473,12 @@ func (k Keeper) ChanOpenConfirm( sdk.NewAttribute(types.AttributeKeyConnectionID, channel.ConnectionHops[0]), ), }) - - return nil + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) } // Closing Handshake diff --git a/modules/core/04-channel/keeper/keeper.go b/modules/core/04-channel/keeper/keeper.go index e680b23f182..67396423d48 100644 --- a/modules/core/04-channel/keeper/keeper.go +++ b/modules/core/04-channel/keeper/keeper.go @@ -403,6 +403,16 @@ func (k Keeper) GetChannelClientState(ctx sdk.Context, portID, channelID string) return connection.ClientId, clientState, nil } +// GetConnection wraps the conenction keeper's GetConnection function. +func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (exported.ConnectionI, error) { + connection, found := k.connectionKeeper.GetConnection(ctx, connectionID) + if !found { + return nil, sdkerrors.Wrapf(connectiontypes.ErrConnectionNotFound, "connection-id: %s", connectionID) + } + + return connection, nil +} + // GetChannelConnection returns the connection ID and state associated with the given port and channel identifier. func (k Keeper) GetChannelConnection(ctx sdk.Context, portID, channelID string) (string, exported.ConnectionI, error) { channel, found := k.GetChannel(ctx, portID, channelID) diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index e2c92fdeb1d..039167da7a0 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -255,6 +255,8 @@ func (k Keeper) ConnectionOpenConfirm(goCtx context.Context, msg *connectiontype } // ChannelOpenInit defines a rpc handler method for MsgChannelOpenInit. +// ChannelOpenInit will perform 04-channel checks, route to the application +// callback, and write an OpenInit channel into state upon successful exection. func (k Keeper) ChannelOpenInit(goCtx context.Context, msg *channeltypes.MsgChannelOpenInit) (*channeltypes.MsgChannelOpenInitResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -264,6 +266,13 @@ func (k Keeper) ChannelOpenInit(goCtx context.Context, msg *channeltypes.MsgChan return nil, sdkerrors.Wrap(err, "could not retrieve module from port-id") } + // Retrieve application callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + } + + // Perform 04-channel verification channelID, cap, err := k.ChannelKeeper.ChanOpenInit( ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, portCap, msg.Channel.Counterparty, msg.Channel.Version, @@ -272,35 +281,36 @@ func (k Keeper) ChannelOpenInit(goCtx context.Context, msg *channeltypes.MsgChan return nil, sdkerrors.Wrap(err, "channel handshake open init failed") } - // Retrieve callbacks from router - cbs, ok := k.Router.GetRoute(module) - if !ok { - return nil, sdkerrors.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) - } - + // Perform application logic callback if err = cbs.OnChanOpenInit(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, channelID, cap, msg.Channel.Counterparty, msg.Channel.Version); err != nil { return nil, sdkerrors.Wrap(err, "channel open init callback failed") } - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, channeltypes.AttributeValueCategory), - ), - }) + // Write channel into state + k.ChannelKeeper.WriteOpenInitChannel(ctx, msg.PortId, channelID, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.Channel.Counterparty, msg.Channel.Version) return &channeltypes.MsgChannelOpenInitResponse{}, nil } // ChannelOpenTry defines a rpc handler method for MsgChannelOpenTry. +// ChannelOpenTry will perform 04-channel checks, route to the application +// callback, and write an OpenTry channel into state upon successful exection. func (k Keeper) ChannelOpenTry(goCtx context.Context, msg *channeltypes.MsgChannelOpenTry) (*channeltypes.MsgChannelOpenTryResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + // Lookup module by port capability module, portCap, err := k.PortKeeper.LookupModuleByPort(ctx, msg.PortId) if err != nil { return nil, sdkerrors.Wrap(err, "could not retrieve module from port-id") } + // Retrieve application callbacks from router + cbs, ok := k.Router.GetRoute(module) + if !ok { + return nil, sdkerrors.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) + } + + // Perform 04-channel verification channelID, cap, err := k.ChannelKeeper.ChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, msg.PreviousChannelId, portCap, msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion, msg.ProofInit, msg.ProofHeight, ) @@ -308,27 +318,20 @@ func (k Keeper) ChannelOpenTry(goCtx context.Context, msg *channeltypes.MsgChann return nil, sdkerrors.Wrap(err, "channel handshake open try failed") } - // Retrieve callbacks from router - cbs, ok := k.Router.GetRoute(module) - if !ok { - return nil, sdkerrors.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) - } - + // Perform application logic callback if err = cbs.OnChanOpenTry(ctx, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.PortId, channelID, cap, msg.Channel.Counterparty, msg.Channel.Version, msg.CounterpartyVersion); err != nil { return nil, sdkerrors.Wrap(err, "channel open try callback failed") } - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, channeltypes.AttributeValueCategory), - ), - }) + // Write channel into state + k.ChannelKeeper.WriteOpenTryChannel(ctx, msg.PortId, channelID, msg.Channel.Ordering, msg.Channel.ConnectionHops, msg.Channel.Counterparty, msg.Channel.Version) return &channeltypes.MsgChannelOpenTryResponse{}, nil } // ChannelOpenAck defines a rpc handler method for MsgChannelOpenAck. +// ChannelOpenAck will perform 04-channel checks, route to the application +// callback, and write an OpenAck channel into state upon successful exection. func (k Keeper) ChannelOpenAck(goCtx context.Context, msg *channeltypes.MsgChannelOpenAck) (*channeltypes.MsgChannelOpenAckResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -338,34 +341,33 @@ func (k Keeper) ChannelOpenAck(goCtx context.Context, msg *channeltypes.MsgChann return nil, sdkerrors.Wrap(err, "could not retrieve module from port-id") } - // Retrieve callbacks from router + // Retrieve application callbacks from router cbs, ok := k.Router.GetRoute(module) if !ok { return nil, sdkerrors.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) } - err = k.ChannelKeeper.ChanOpenAck( + // Perform 04-channel verification + if err = k.ChannelKeeper.ChanOpenAck( ctx, msg.PortId, msg.ChannelId, cap, msg.CounterpartyVersion, msg.CounterpartyChannelId, msg.ProofTry, msg.ProofHeight, - ) - if err != nil { + ); err != nil { return nil, sdkerrors.Wrap(err, "channel handshake open ack failed") } + // Perform application logic callback if err = cbs.OnChanOpenAck(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyVersion); err != nil { return nil, sdkerrors.Wrap(err, "channel open ack callback failed") } - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, channeltypes.AttributeValueCategory), - ), - }) + // Write channel into state + k.ChannelKeeper.WriteOpenAckChannel(ctx, msg.PortId, msg.ChannelId, msg.CounterpartyVersion, msg.CounterpartyChannelId) return &channeltypes.MsgChannelOpenAckResponse{}, nil } // ChannelOpenConfirm defines a rpc handler method for MsgChannelOpenConfirm. +// ChannelOpenConfirm will perform 04-channel checks, route to the application +// callback, and write an OpenConfirm channel into state upon successful exection. func (k Keeper) ChannelOpenConfirm(goCtx context.Context, msg *channeltypes.MsgChannelOpenConfirm) (*channeltypes.MsgChannelOpenConfirmResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -375,27 +377,24 @@ func (k Keeper) ChannelOpenConfirm(goCtx context.Context, msg *channeltypes.MsgC return nil, sdkerrors.Wrap(err, "could not retrieve module from port-id") } - // Retrieve callbacks from router + // Retrieve application callbacks from router cbs, ok := k.Router.GetRoute(module) if !ok { return nil, sdkerrors.Wrapf(porttypes.ErrInvalidRoute, "route not found to module: %s", module) } - err = k.ChannelKeeper.ChanOpenConfirm(ctx, msg.PortId, msg.ChannelId, cap, msg.ProofAck, msg.ProofHeight) - if err != nil { + // Perform 04-channel verification + if err = k.ChannelKeeper.ChanOpenConfirm(ctx, msg.PortId, msg.ChannelId, cap, msg.ProofAck, msg.ProofHeight); err != nil { return nil, sdkerrors.Wrap(err, "channel handshake open confirm failed") } + // Perform application logic callback if err = cbs.OnChanOpenConfirm(ctx, msg.PortId, msg.ChannelId); err != nil { return nil, sdkerrors.Wrap(err, "channel open confirm callback failed") } - ctx.EventManager().EmitEvents(sdk.Events{ - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, channeltypes.AttributeValueCategory), - ), - }) + // Write channel into state + k.ChannelKeeper.WriteOpenConfirmChannel(ctx, msg.PortId, msg.ChannelId) return &channeltypes.MsgChannelOpenConfirmResponse{}, nil }