diff --git a/modules/core/04-channel/keeper/events.go b/modules/core/04-channel/keeper/events.go index 4ec0d324ee0..711b3684772 100644 --- a/modules/core/04-channel/keeper/events.go +++ b/modules/core/04-channel/keeper/events.go @@ -361,6 +361,28 @@ func emitChannelUpgradeOpenEvent(ctx sdk.Context, portID string, channelID strin }) } +// emitChannelUpgradeTimeoutEvent emits an upgrade timeout event. +func emitChannelUpgradeTimeoutEvent(ctx sdk.Context, portID string, channelID string, currentChannel types.Channel, upgrade types.Upgrade) { + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeChannelUpgradeTimeout, + sdk.NewAttribute(types.AttributeKeyPortID, portID), + sdk.NewAttribute(types.AttributeKeyChannelID, channelID), + sdk.NewAttribute(types.AttributeCounterpartyPortID, currentChannel.Counterparty.PortId), + sdk.NewAttribute(types.AttributeCounterpartyChannelID, currentChannel.Counterparty.ChannelId), + sdk.NewAttribute(types.AttributeKeyUpgradeConnectionHops, upgrade.Fields.ConnectionHops[0]), + sdk.NewAttribute(types.AttributeKeyUpgradeVersion, upgrade.Fields.Version), + sdk.NewAttribute(types.AttributeKeyUpgradeOrdering, upgrade.Fields.Ordering.String()), + sdk.NewAttribute(types.AttributeKeyUpgradeTimeout, upgrade.Timeout.String()), + sdk.NewAttribute(types.AttributeKeyUpgradeSequence, fmt.Sprintf("%d", currentChannel.UpgradeSequence)), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), + ), + }) +} + // emitErrorReceiptEvent emits an error receipt event func emitErrorReceiptEvent(ctx sdk.Context, portID string, channelID string, currentChannel types.Channel, upgrade types.Upgrade, err error) { ctx.EventManager().EmitEvents(sdk.Events{ diff --git a/modules/core/04-channel/keeper/export_test.go b/modules/core/04-channel/keeper/export_test.go index d97fd5e5a67..4ee7f0f11fc 100644 --- a/modules/core/04-channel/keeper/export_test.go +++ b/modules/core/04-channel/keeper/export_test.go @@ -35,3 +35,8 @@ func (k Keeper) ValidateUpgradeFields(ctx sdk.Context, proposedUpgrade types.Upg func (k Keeper) WriteUpgradeOpenChannel(ctx sdk.Context, portID, channelID string) { k.writeUpgradeOpenChannel(ctx, portID, channelID) } + +// WriteUpgradeTimeoutChannel is a wrapper around writeUpgradeTimeoutChannel to allow the function to be directly called in tests. +func (k Keeper) WriteUpgradeTimeoutChannel(ctx sdk.Context, portID, channelID string) error { + return k.writeUpgradeTimeoutChannel(ctx, portID, channelID) +} diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index a92ef651627..572e3f406e7 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -359,6 +359,35 @@ func (k Keeper) ChanUpgradeAck( return nil } +// writeUpgradeTimeoutChannel restores the channel state of an initialising chain in the event that the counterparty chain has passed the timeout set in ChanUpgradeInit to the state before the upgrade was proposed. +// Auxiliary upgrade state is also deleted. +// An event is emitted for the handshake step. +func (k Keeper) writeUpgradeTimeoutChannel( + ctx sdk.Context, + portID, channelID string, +) error { + defer telemetry.IncrCounter(1, "ibc", "channel", "upgrade-timeout") + + channel, found := k.GetChannel(ctx, portID, channelID) + if !found { + panic(fmt.Sprintf("could not find existing channel when updating channel state in successful ChanUpgradeTimeout step, channelID: %s, portID: %s", channelID, portID)) + } + + upgrade, found := k.GetUpgrade(ctx, portID, channelID) + if !found { + panic(fmt.Sprintf("could not find existing upgrade when cancelling channel upgrade, channelID: %s, portID: %s", channelID, portID)) + } + + if err := k.AbortUpgrade(ctx, portID, channelID, types.NewUpgradeError(channel.UpgradeSequence, types.ErrUpgradeTimeout)); err != nil { + return errorsmod.Wrapf(types.ErrUpgradeRestoreFailed, "err: %v", err) + } + + k.Logger(ctx).Info("channel state restored", "port-id", portID, "channel-id", channelID) + emitChannelUpgradeTimeoutEvent(ctx, portID, channelID, channel, upgrade) + + return nil +} + // startFlushUpgradeHandshake will verify the counterparty proposed upgrade and the current channel state. // 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 diff --git a/modules/core/04-channel/types/errors.go b/modules/core/04-channel/types/errors.go index 3b11df9b162..cb668b3c824 100644 --- a/modules/core/04-channel/types/errors.go +++ b/modules/core/04-channel/types/errors.go @@ -47,4 +47,6 @@ var ( ErrIncompatibleCounterpartyUpgrade = errorsmod.Register(SubModuleName, 31, "incompatible counterparty upgrade") ErrInvalidUpgradeError = errorsmod.Register(SubModuleName, 32, "invalid upgrade error") ErrInvalidFlushStatus = errorsmod.Register(SubModuleName, 33, "invalid flush status") + ErrUpgradeRestoreFailed = errorsmod.Register(SubModuleName, 34, "restore failed") + ErrUpgradeTimeout = errorsmod.Register(SubModuleName, 35, "upgrade timed-out") ) diff --git a/modules/core/04-channel/types/events.go b/modules/core/04-channel/types/events.go index d82703c40f3..ddef5cdfc14 100644 --- a/modules/core/04-channel/types/events.go +++ b/modules/core/04-channel/types/events.go @@ -47,22 +47,24 @@ const ( AttributeKeyUpgradeOrdering = "upgrade_ordering" AttributeKeyUpgradeErrorReceipt = "upgrade_error_receipt" AttributeKeyUpgradeChannelFlushStatus = "channel_flush_status" + AttributeKeyUpgradeTimeout = "upgrade_timeout" ) // IBC channel events vars var ( - EventTypeChannelOpenInit = "channel_open_init" - EventTypeChannelOpenTry = "channel_open_try" - EventTypeChannelOpenAck = "channel_open_ack" - EventTypeChannelOpenConfirm = "channel_open_confirm" - EventTypeChannelCloseInit = "channel_close_init" - EventTypeChannelCloseConfirm = "channel_close_confirm" - EventTypeChannelClosed = "channel_close" - EventTypeChannelUpgradeInit = "channel_upgrade_init" - EventTypeChannelUpgradeTry = "channel_upgrade_try" - EventTypeChannelUpgradeAck = "channel_upgrade_ack" - EventTypeChannelUpgradeOpen = "channel_upgrade_open" - EventTypeChannelUpgradeCancel = "channel_upgrade_cancelled" + EventTypeChannelOpenInit = "channel_open_init" + EventTypeChannelOpenTry = "channel_open_try" + EventTypeChannelOpenAck = "channel_open_ack" + EventTypeChannelOpenConfirm = "channel_open_confirm" + EventTypeChannelCloseInit = "channel_close_init" + EventTypeChannelCloseConfirm = "channel_close_confirm" + EventTypeChannelClosed = "channel_close" + EventTypeChannelUpgradeInit = "channel_upgrade_init" + EventTypeChannelUpgradeTry = "channel_upgrade_try" + EventTypeChannelUpgradeAck = "channel_upgrade_ack" + EventTypeChannelUpgradeOpen = "channel_upgrade_open" + EventTypeChannelUpgradeTimeout = "channel_upgrade_timeout" + EventTypeChannelUpgradeCancel = "channel_upgrade_cancelled" AttributeValueCategory = fmt.Sprintf("%s_%s", ibcexported.ModuleName, SubModuleName) )