From e1c8740527e84b4335d42fdbe02587a92bab18f4 Mon Sep 17 00:00:00 2001 From: Justin Tieri <37750742+jtieri@users.noreply.github.com> Date: Wed, 27 Jul 2022 14:56:38 -0500 Subject: [PATCH] Handle closing of channels (#863) * WIP: handle closing ordered channels * treat ordered timeouts as different packet flows ending with channel close confirm * cleanup * remove dead code and cleanup `orderFromString` * purge relevant packet flow messages in the case of a channel closing for ordered channels * remove incorrect code * properly purge the relevant send packet and timeout messages * update comments + delete the relevant messages for the src and counterparty * fix deleting messages on wrong channel end * improve readability Co-authored-by: Andrew Gouin --- relayer/chains/cosmos/message_handlers.go | 2 +- relayer/processor/path_end_runtime.go | 35 ++++- relayer/processor/path_processor_internal.go | 136 +++++++++++++++---- relayer/processor/types_internal.go | 45 +++--- 4 files changed, 170 insertions(+), 48 deletions(-) diff --git a/relayer/chains/cosmos/message_handlers.go b/relayer/chains/cosmos/message_handlers.go index a1db03039..10fbd3b0b 100644 --- a/relayer/chains/cosmos/message_handlers.go +++ b/relayer/chains/cosmos/message_handlers.go @@ -61,7 +61,7 @@ func (ccp *CosmosChainProcessor) handleChannelMessage(eventType string, ci provi ccp.channelStateCache[channelKey] = false case chantypes.EventTypeChannelOpenAck, chantypes.EventTypeChannelOpenConfirm: ccp.channelStateCache[channelKey] = true - case chantypes.EventTypeChannelCloseInit, chantypes.EventTypeChannelCloseConfirm: + case chantypes.EventTypeChannelCloseConfirm: for k := range ccp.channelStateCache { if k.PortID == ci.PortID && k.ChannelID == ci.ChannelID { ccp.channelStateCache[k] = false diff --git a/relayer/processor/path_end_runtime.go b/relayer/processor/path_end_runtime.go index e17037c0d..78d22568a 100644 --- a/relayer/processor/path_end_runtime.go +++ b/relayer/processor/path_end_runtime.go @@ -482,6 +482,9 @@ func (pathEnd *pathEndRuntime) shouldSendChannelMessage(message channelIBCMessag // remove all retention of this connection handshake in pathEnd.messagesCache.ConnectionHandshake and counterparty toDelete := make(map[string][]ChannelKey) toDeleteCounterparty := make(map[string][]ChannelKey) + toDeletePacket := make(map[string][]uint64) + toDeleteCounterpartyPacket := make(map[string][]uint64) + counterpartyKey := channelKey.Counterparty() switch eventType { case chantypes.EventTypeChannelOpenTry: @@ -493,9 +496,39 @@ func (pathEnd *pathEndRuntime) shouldSendChannelMessage(message channelIBCMessag toDeleteCounterparty[chantypes.EventTypeChannelOpenAck] = []ChannelKey{counterpartyKey} toDelete[chantypes.EventTypeChannelOpenTry] = []ChannelKey{channelKey} toDeleteCounterparty[chantypes.EventTypeChannelOpenInit] = []ChannelKey{counterpartyKey.msgInitKey()} + case chantypes.EventTypeChannelCloseConfirm: + toDeleteCounterparty[chantypes.EventTypeChannelCloseInit] = []ChannelKey{counterpartyKey} + toDelete[chantypes.EventTypeChannelCloseConfirm] = []ChannelKey{channelKey} + + // Gather relevant send packet messages, for this channel key, that should be deleted if we + // are operating on an ordered channel. + if messageCache, ok := pathEnd.messageCache.PacketFlow[channelKey]; ok { + if seqCache, ok := messageCache[chantypes.EventTypeSendPacket]; ok { + for seq, packetInfo := range seqCache { + if packetInfo.ChannelOrder == chantypes.ORDERED.String() { + toDeletePacket[chantypes.EventTypeSendPacket] = append(toDeletePacket[chantypes.EventTypeSendPacket], seq) + } + } + } + } + + // Gather relevant timeout messages, for this counterparty channel key, that should be deleted if we + // are operating on an ordered channel. + if messageCache, ok := counterparty.messageCache.PacketFlow[counterpartyKey]; ok { + if seqCache, ok := messageCache[chantypes.EventTypeTimeoutPacket]; ok { + for seq, packetInfo := range seqCache { + if packetInfo.ChannelOrder == chantypes.ORDERED.String() { + toDeleteCounterpartyPacket[chantypes.EventTypeTimeoutPacket] = append(toDeleteCounterpartyPacket[chantypes.EventTypeTimeoutPacket], seq) + } + } + } + } } + // delete in progress send for this specific message - pathEnd.channelProcessing.deleteMessages(map[string][]ChannelKey{eventType: []ChannelKey{channelKey}}) + pathEnd.channelProcessing.deleteMessages(map[string][]ChannelKey{eventType: {channelKey}}) + pathEnd.messageCache.PacketFlow[channelKey].DeleteMessages(toDeletePacket) + counterparty.messageCache.PacketFlow[counterpartyKey].DeleteMessages(toDeleteCounterpartyPacket) // delete all connection handshake retention history for this channel pathEnd.messageCache.ChannelHandshake.DeleteMessages(toDelete) diff --git a/relayer/processor/path_processor_internal.go b/relayer/processor/path_processor_internal.go index 4fb8cd22f..7f56d3784 100644 --- a/relayer/processor/path_processor_internal.go +++ b/relayer/processor/path_processor_internal.go @@ -35,8 +35,9 @@ func (pp *PathProcessor) assemblePacketIBCMessage( func (pp *PathProcessor) getUnrelayedPacketsAndAcksAndToDelete(ctx context.Context, pathEndPacketFlowMessages pathEndPacketFlowMessages) pathEndPacketFlowResponse { res := pathEndPacketFlowResponse{ - ToDeleteSrc: make(map[string][]uint64), - ToDeleteDst: make(map[string][]uint64), + ToDeleteSrc: make(map[string][]uint64), + ToDeleteDst: make(map[string][]uint64), + ToDeleteDstChannel: make(map[string][]ChannelKey), } MsgTransferLoop: @@ -51,12 +52,42 @@ MsgTransferLoop: continue MsgTransferLoop } } - for timeoutSeq := range pathEndPacketFlowMessages.SrcMsgTimeout { + + for timeoutSeq, msgTimeout := range pathEndPacketFlowMessages.SrcMsgTimeout { if transferSeq == timeoutSeq { - // we have a timeout for this packet, so packet flow is complete - // remove all retention of this sequence number - res.ToDeleteSrc[chantypes.EventTypeSendPacket] = append(res.ToDeleteSrc[chantypes.EventTypeSendPacket], transferSeq) - res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket] = append(res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket], transferSeq) + if msgTimeout.ChannelOrder == chantypes.ORDERED.String() { + // For ordered channel packets, flow is not done until channel-close-confirm is observed. + if pathEndPacketFlowMessages.DstMsgChannelCloseConfirm == nil { + // have not observed a channel-close-confirm yet for this channel, send it if ready. + // will come back through here next block if not yet ready. + closeChan := channelIBCMessage{ + eventType: chantypes.EventTypeChannelCloseConfirm, + info: provider.ChannelInfo{ + Height: msgTimeout.Height, + PortID: msgTimeout.SourcePort, + ChannelID: msgTimeout.SourceChannel, + CounterpartyPortID: msgTimeout.DestPort, + CounterpartyChannelID: msgTimeout.DestChannel, + Order: orderFromString(msgTimeout.ChannelOrder), + }, + } + + if pathEndPacketFlowMessages.Src.shouldSendChannelMessage(closeChan, pathEndPacketFlowMessages.Dst) { + res.DstChannelMessage = append(res.DstChannelMessage, closeChan) + } + } else { + // ordered channel, and we have a channel close confirm, so packet-flow and channel-close-flow is complete. + // remove all retention of this sequence number and this channel-close-confirm. + res.ToDeleteDstChannel[chantypes.EventTypeChannelCloseConfirm] = append(res.ToDeleteDstChannel[chantypes.EventTypeChannelCloseConfirm], pathEndPacketFlowMessages.ChannelKey.Counterparty()) + res.ToDeleteSrc[chantypes.EventTypeSendPacket] = append(res.ToDeleteSrc[chantypes.EventTypeSendPacket], transferSeq) + res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket] = append(res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket], transferSeq) + } + } else { + // unordered channel, and we have a timeout for this packet, so packet flow is complete + // remove all retention of this sequence number + res.ToDeleteSrc[chantypes.EventTypeSendPacket] = append(res.ToDeleteSrc[chantypes.EventTypeSendPacket], transferSeq) + res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket] = append(res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket], transferSeq) + } continue MsgTransferLoop } } @@ -128,9 +159,18 @@ MsgTransferLoop: res.ToDeleteDst[chantypes.EventTypeRecvPacket] = append(res.ToDeleteDst[chantypes.EventTypeRecvPacket], ackSeq) res.ToDeleteSrc[chantypes.EventTypeAcknowledgePacket] = append(res.ToDeleteSrc[chantypes.EventTypeAcknowledgePacket], ackSeq) } - for timeoutSeq := range pathEndPacketFlowMessages.SrcMsgTimeout { - res.ToDeleteSrc[chantypes.EventTypeSendPacket] = append(res.ToDeleteSrc[chantypes.EventTypeSendPacket], timeoutSeq) - res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket] = append(res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket], timeoutSeq) + for timeoutSeq, msgTimeout := range pathEndPacketFlowMessages.SrcMsgTimeout { + if msgTimeout.ChannelOrder == chantypes.ORDERED.String() { + if pathEndPacketFlowMessages.DstMsgChannelCloseConfirm != nil { + // For ordered channel packets, flow is not done until channel-close-confirm is observed. + res.ToDeleteDstChannel[chantypes.EventTypeChannelCloseConfirm] = append(res.ToDeleteDstChannel[chantypes.EventTypeChannelCloseConfirm], pathEndPacketFlowMessages.ChannelKey.Counterparty()) + res.ToDeleteSrc[chantypes.EventTypeSendPacket] = append(res.ToDeleteSrc[chantypes.EventTypeSendPacket], timeoutSeq) + res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket] = append(res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket], timeoutSeq) + } + } else { + res.ToDeleteSrc[chantypes.EventTypeSendPacket] = append(res.ToDeleteSrc[chantypes.EventTypeSendPacket], timeoutSeq) + res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket] = append(res.ToDeleteSrc[chantypes.EventTypeTimeoutPacket], timeoutSeq) + } } for timeoutOnCloseSeq := range pathEndPacketFlowMessages.SrcMsgTimeoutOnClose { res.ToDeleteSrc[chantypes.EventTypeSendPacket] = append(res.ToDeleteSrc[chantypes.EventTypeSendPacket], timeoutOnCloseSeq) @@ -512,25 +552,41 @@ func (pp *PathProcessor) processLatestMessages(ctx context.Context, messageLifec pathEnd2ProcessRes := make([]pathEndPacketFlowResponse, len(channelPairs)) for i, pair := range channelPairs { + var pathEnd1ChannelCloseConfirm, pathEnd2ChannelCloseConfirm *provider.ChannelInfo + + if pathEnd1ChanCloseConfirmMsgs, ok := pp.pathEnd1.messageCache.ChannelHandshake[chantypes.EventTypeChannelCloseConfirm]; ok { + if pathEnd1ChannelCloseConfirmMsg, ok := pathEnd1ChanCloseConfirmMsgs[pair.pathEnd1ChannelKey]; ok { + pathEnd1ChannelCloseConfirm = &pathEnd1ChannelCloseConfirmMsg + } + } + + if pathEnd2ChanCloseConfirmMsgs, ok := pp.pathEnd2.messageCache.ChannelHandshake[chantypes.EventTypeChannelCloseConfirm]; ok { + if pathEnd2ChannelCloseConfirmMsg, ok := pathEnd2ChanCloseConfirmMsgs[pair.pathEnd2ChannelKey]; ok { + pathEnd2ChannelCloseConfirm = &pathEnd2ChannelCloseConfirmMsg + } + } + pathEnd1PacketFlowMessages := pathEndPacketFlowMessages{ - Src: pp.pathEnd1, - Dst: pp.pathEnd2, - ChannelKey: pair.pathEnd1ChannelKey, - SrcMsgTransfer: pp.pathEnd1.messageCache.PacketFlow[pair.pathEnd1ChannelKey][chantypes.EventTypeSendPacket], - DstMsgRecvPacket: pp.pathEnd2.messageCache.PacketFlow[pair.pathEnd2ChannelKey][chantypes.EventTypeRecvPacket], - SrcMsgAcknowledgement: pp.pathEnd1.messageCache.PacketFlow[pair.pathEnd1ChannelKey][chantypes.EventTypeAcknowledgePacket], - SrcMsgTimeout: pp.pathEnd1.messageCache.PacketFlow[pair.pathEnd1ChannelKey][chantypes.EventTypeTimeoutPacket], - SrcMsgTimeoutOnClose: pp.pathEnd1.messageCache.PacketFlow[pair.pathEnd1ChannelKey][chantypes.EventTypeTimeoutPacketOnClose], + Src: pp.pathEnd1, + Dst: pp.pathEnd2, + ChannelKey: pair.pathEnd1ChannelKey, + SrcMsgTransfer: pp.pathEnd1.messageCache.PacketFlow[pair.pathEnd1ChannelKey][chantypes.EventTypeSendPacket], + DstMsgRecvPacket: pp.pathEnd2.messageCache.PacketFlow[pair.pathEnd2ChannelKey][chantypes.EventTypeRecvPacket], + SrcMsgAcknowledgement: pp.pathEnd1.messageCache.PacketFlow[pair.pathEnd1ChannelKey][chantypes.EventTypeAcknowledgePacket], + SrcMsgTimeout: pp.pathEnd1.messageCache.PacketFlow[pair.pathEnd1ChannelKey][chantypes.EventTypeTimeoutPacket], + SrcMsgTimeoutOnClose: pp.pathEnd1.messageCache.PacketFlow[pair.pathEnd1ChannelKey][chantypes.EventTypeTimeoutPacketOnClose], + DstMsgChannelCloseConfirm: pathEnd2ChannelCloseConfirm, } pathEnd2PacketFlowMessages := pathEndPacketFlowMessages{ - Src: pp.pathEnd2, - Dst: pp.pathEnd1, - ChannelKey: pair.pathEnd2ChannelKey, - SrcMsgTransfer: pp.pathEnd2.messageCache.PacketFlow[pair.pathEnd2ChannelKey][chantypes.EventTypeSendPacket], - DstMsgRecvPacket: pp.pathEnd1.messageCache.PacketFlow[pair.pathEnd1ChannelKey][chantypes.EventTypeRecvPacket], - SrcMsgAcknowledgement: pp.pathEnd2.messageCache.PacketFlow[pair.pathEnd2ChannelKey][chantypes.EventTypeAcknowledgePacket], - SrcMsgTimeout: pp.pathEnd2.messageCache.PacketFlow[pair.pathEnd2ChannelKey][chantypes.EventTypeTimeoutPacket], - SrcMsgTimeoutOnClose: pp.pathEnd2.messageCache.PacketFlow[pair.pathEnd2ChannelKey][chantypes.EventTypeTimeoutPacketOnClose], + Src: pp.pathEnd2, + Dst: pp.pathEnd1, + ChannelKey: pair.pathEnd2ChannelKey, + SrcMsgTransfer: pp.pathEnd2.messageCache.PacketFlow[pair.pathEnd2ChannelKey][chantypes.EventTypeSendPacket], + DstMsgRecvPacket: pp.pathEnd1.messageCache.PacketFlow[pair.pathEnd1ChannelKey][chantypes.EventTypeRecvPacket], + SrcMsgAcknowledgement: pp.pathEnd2.messageCache.PacketFlow[pair.pathEnd2ChannelKey][chantypes.EventTypeAcknowledgePacket], + SrcMsgTimeout: pp.pathEnd2.messageCache.PacketFlow[pair.pathEnd2ChannelKey][chantypes.EventTypeTimeoutPacket], + SrcMsgTimeoutOnClose: pp.pathEnd2.messageCache.PacketFlow[pair.pathEnd2ChannelKey][chantypes.EventTypeTimeoutPacketOnClose], + DstMsgChannelCloseConfirm: pathEnd1ChannelCloseConfirm, } pathEnd1ProcessRes[i] = pp.getUnrelayedPacketsAndAcksAndToDelete(ctx, pathEnd1PacketFlowMessages) @@ -540,7 +596,10 @@ func (pp *PathProcessor) processLatestMessages(ctx context.Context, messageLifec // concatenate applicable messages for pathend pathEnd1ConnectionMessages, pathEnd2ConnectionMessages := pp.connectionMessagesToSend(pathEnd1ConnectionHandshakeRes, pathEnd2ConnectionHandshakeRes) pathEnd1ChannelMessages, pathEnd2ChannelMessages := pp.channelMessagesToSend(pathEnd1ChannelHandshakeRes, pathEnd2ChannelHandshakeRes) - pathEnd1PacketMessages, pathEnd2PacketMessages := pp.packetMessagesToSend(channelPairs, pathEnd1ProcessRes, pathEnd2ProcessRes) + + pathEnd1PacketMessages, pathEnd2PacketMessages, pathEnd1ChanCloseMessages, pathEnd2ChanCloseMessages := pp.packetMessagesToSend(channelPairs, pathEnd1ProcessRes, pathEnd2ProcessRes) + pathEnd1ChannelMessages = append(pathEnd1ChannelMessages, pathEnd1ChanCloseMessages...) + pathEnd2ChannelMessages = append(pathEnd2ChannelMessages, pathEnd2ChanCloseMessages...) pathEnd1Messages := pathEndMessages{ connectionMessages: pathEnd1ConnectionMessages, @@ -626,6 +685,7 @@ func (pp *PathProcessor) assembleMessage( return } om.Append(message) + } func (pp *PathProcessor) assembleAndSendMessages( @@ -869,17 +929,29 @@ func (pp *PathProcessor) connectionMessagesToSend(pathEnd1ConnectionHandshakeRes return pathEnd1ConnectionMessages, pathEnd2ConnectionMessages } -func (pp *PathProcessor) packetMessagesToSend(channelPairs []channelPair, pathEnd1ProcessRes []pathEndPacketFlowResponse, pathEnd2ProcessRes []pathEndPacketFlowResponse) ([]packetIBCMessage, []packetIBCMessage) { +func (pp *PathProcessor) packetMessagesToSend( + channelPairs []channelPair, + pathEnd1ProcessRes []pathEndPacketFlowResponse, + pathEnd2ProcessRes []pathEndPacketFlowResponse, +) ([]packetIBCMessage, []packetIBCMessage, []channelIBCMessage, []channelIBCMessage) { pathEnd1PacketLen := 0 pathEnd2PacketLen := 0 + pathEnd1ChannelLen := 0 + pathEnd2ChannelLen := 0 + for i := 0; i < len(channelPairs); i++ { pathEnd1PacketLen += len(pathEnd2ProcessRes[i].DstMessages) + len(pathEnd1ProcessRes[i].SrcMessages) pathEnd2PacketLen += len(pathEnd1ProcessRes[i].DstMessages) + len(pathEnd2ProcessRes[i].SrcMessages) + pathEnd1ChannelLen += len(pathEnd2ProcessRes[i].DstChannelMessage) + pathEnd2ChannelLen += len(pathEnd1ProcessRes[i].DstChannelMessage) } pathEnd1PacketMessages := make([]packetIBCMessage, 0, pathEnd1PacketLen) pathEnd2PacketMessages := make([]packetIBCMessage, 0, pathEnd2PacketLen) + pathEnd1ChannelMessage := make([]channelIBCMessage, 0, pathEnd1ChannelLen) + pathEnd2ChannelMessage := make([]channelIBCMessage, 0, pathEnd2ChannelLen) + for i, channelPair := range channelPairs { pathEnd1PacketMessages = append(pathEnd1PacketMessages, pathEnd2ProcessRes[i].DstMessages...) pathEnd1PacketMessages = append(pathEnd1PacketMessages, pathEnd1ProcessRes[i].SrcMessages...) @@ -887,11 +959,17 @@ func (pp *PathProcessor) packetMessagesToSend(channelPairs []channelPair, pathEn pathEnd2PacketMessages = append(pathEnd2PacketMessages, pathEnd1ProcessRes[i].DstMessages...) pathEnd2PacketMessages = append(pathEnd2PacketMessages, pathEnd2ProcessRes[i].SrcMessages...) + pathEnd1ChannelMessage = append(pathEnd1ChannelMessage, pathEnd2ProcessRes[i].DstChannelMessage...) + pathEnd2ChannelMessage = append(pathEnd2ChannelMessage, pathEnd1ProcessRes[i].DstChannelMessage...) + + pp.pathEnd1.messageCache.ChannelHandshake.DeleteMessages(pathEnd2ProcessRes[i].ToDeleteDstChannel) + pp.pathEnd2.messageCache.ChannelHandshake.DeleteMessages(pathEnd1ProcessRes[i].ToDeleteDstChannel) + pp.pathEnd1.messageCache.PacketFlow[channelPair.pathEnd1ChannelKey].DeleteMessages(pathEnd1ProcessRes[i].ToDeleteSrc, pathEnd2ProcessRes[i].ToDeleteDst) pp.pathEnd2.messageCache.PacketFlow[channelPair.pathEnd2ChannelKey].DeleteMessages(pathEnd2ProcessRes[i].ToDeleteSrc, pathEnd1ProcessRes[i].ToDeleteDst) pp.pathEnd1.packetProcessing[channelPair.pathEnd1ChannelKey].deleteMessages(pathEnd1ProcessRes[i].ToDeleteSrc, pathEnd2ProcessRes[i].ToDeleteDst) pp.pathEnd2.packetProcessing[channelPair.pathEnd2ChannelKey].deleteMessages(pathEnd2ProcessRes[i].ToDeleteSrc, pathEnd1ProcessRes[i].ToDeleteDst) } - return pathEnd1PacketMessages, pathEnd2PacketMessages + return pathEnd1PacketMessages, pathEnd2PacketMessages, pathEnd1ChannelMessage, pathEnd2ChannelMessage } diff --git a/relayer/processor/types_internal.go b/relayer/processor/types_internal.go index d861933ea..db5237c8d 100644 --- a/relayer/processor/types_internal.go +++ b/relayer/processor/types_internal.go @@ -1,8 +1,10 @@ package processor import ( + "strings" "sync" + chantypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" "github.com/cosmos/relayer/v2/relayer/provider" ) @@ -101,14 +103,15 @@ func (c connectionProcessingCache) deleteMessages(toDelete ...map[string][]Conne // contains MsgRecvPacket from counterparty // entire packet flow type pathEndPacketFlowMessages struct { - Src *pathEndRuntime - Dst *pathEndRuntime - ChannelKey ChannelKey - SrcMsgTransfer PacketSequenceCache - DstMsgRecvPacket PacketSequenceCache - SrcMsgAcknowledgement PacketSequenceCache - SrcMsgTimeout PacketSequenceCache - SrcMsgTimeoutOnClose PacketSequenceCache + Src *pathEndRuntime + Dst *pathEndRuntime + ChannelKey ChannelKey + SrcMsgTransfer PacketSequenceCache + DstMsgRecvPacket PacketSequenceCache + SrcMsgAcknowledgement PacketSequenceCache + SrcMsgTimeout PacketSequenceCache + SrcMsgTimeoutOnClose PacketSequenceCache + DstMsgChannelCloseConfirm *provider.ChannelInfo } type pathEndConnectionHandshakeMessages struct { @@ -129,19 +132,15 @@ type pathEndChannelHandshakeMessages struct { DstMsgChannelOpenConfirm ChannelMessageCache } -type pathEndChannelCloseMessages struct { - Src *pathEndRuntime - Dst *pathEndRuntime - SrcMsgChannelCloseInit ChannelMessageCache - DstMsgChannelCloseConfirm ChannelMessageCache -} - type pathEndPacketFlowResponse struct { SrcMessages []packetIBCMessage DstMessages []packetIBCMessage - ToDeleteSrc map[string][]uint64 - ToDeleteDst map[string][]uint64 + DstChannelMessage []channelIBCMessage + + ToDeleteSrc map[string][]uint64 + ToDeleteDst map[string][]uint64 + ToDeleteDstChannel map[string][]ChannelKey } type pathEndChannelHandshakeResponse struct { @@ -220,3 +219,15 @@ type channelMessageToTrack struct { msg channelIBCMessage assembled bool } + +// orderFromString parses a string into a channel order byte. +func orderFromString(order string) chantypes.Order { + switch strings.ToUpper(order) { + case chantypes.UNORDERED.String(): + return chantypes.UNORDERED + case chantypes.ORDERED.String(): + return chantypes.ORDERED + default: + return chantypes.NONE + } +}