Some checks failed
CodeQL / Analyze (push) Waiting to run
golangci-lint / lint (push) Waiting to run
Tests / Code Coverage / build (amd64) (push) Waiting to run
Tests / Code Coverage / build (arm64) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[additional-args:-tags="test_e2e" name:e2e path:./e2e]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:08-wasm path:./modules/light-clients/08-wasm]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:ibc-go path:.]) (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (push) Has been cancelled
258 lines
9.7 KiB
Go
258 lines
9.7 KiB
Go
package keeper
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
errorsmod "cosmossdk.io/errors"
|
|
|
|
sdk "git.cw.tr/mukan-network/mukan-sdk/types"
|
|
|
|
icatypes "git.cw.tr/mukan-network/mukan-ibc/modules/apps/27-interchain-accounts/types"
|
|
connectiontypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/03-connection/types"
|
|
channeltypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/04-channel/types"
|
|
)
|
|
|
|
// OnChanOpenInit performs basic validation of channel initialization.
|
|
// The counterparty port identifier must be the host chain representation as defined in the types package,
|
|
// the channel version must be equal to the version in the types package,
|
|
// there must not be an active channel for the specified port identifier.
|
|
func (k Keeper) OnChanOpenInit(
|
|
ctx sdk.Context,
|
|
order channeltypes.Order,
|
|
connectionHops []string,
|
|
portID string,
|
|
channelID string,
|
|
counterparty channeltypes.Counterparty,
|
|
version string,
|
|
) (string, error) {
|
|
if !strings.HasPrefix(portID, icatypes.ControllerPortPrefix) {
|
|
return "", errorsmod.Wrapf(icatypes.ErrInvalidControllerPort, "expected %s{owner-account-address}, got %s", icatypes.ControllerPortPrefix, portID)
|
|
}
|
|
|
|
if counterparty.PortId != icatypes.HostPortID {
|
|
return "", errorsmod.Wrapf(icatypes.ErrInvalidHostPort, "expected %s, got %s", icatypes.HostPortID, counterparty.PortId)
|
|
}
|
|
|
|
var (
|
|
err error
|
|
metadata icatypes.Metadata
|
|
)
|
|
if strings.TrimSpace(version) == "" {
|
|
connection, err := k.channelKeeper.GetConnection(ctx, connectionHops[0])
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
metadata = icatypes.NewDefaultMetadata(connectionHops[0], connection.Counterparty.ConnectionId)
|
|
} else {
|
|
metadata, err = icatypes.MetadataFromVersion(version)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
|
|
if err := icatypes.ValidateControllerMetadata(ctx, k.channelKeeper, connectionHops, metadata); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
activeChannelID, found := k.GetActiveChannelID(ctx, connectionHops[0], portID)
|
|
if found {
|
|
channel, found := k.channelKeeper.GetChannel(ctx, portID, activeChannelID)
|
|
if !found {
|
|
panic(fmt.Errorf("active channel mapping set for %s but channel does not exist in channel store", activeChannelID))
|
|
}
|
|
|
|
if channel.State != channeltypes.CLOSED {
|
|
return "", errorsmod.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s must be %s", activeChannelID, portID, channeltypes.CLOSED)
|
|
}
|
|
|
|
if channel.Ordering != order {
|
|
return "", errorsmod.Wrapf(channeltypes.ErrInvalidChannelOrdering, "order cannot change when reopening a channel expected %s, got %s", channel.Ordering, order)
|
|
}
|
|
|
|
appVersion, found := k.GetAppVersion(ctx, portID, activeChannelID)
|
|
if !found {
|
|
panic(fmt.Errorf("active channel mapping set for %s, but channel does not exist in channel store", activeChannelID))
|
|
}
|
|
|
|
if !icatypes.IsPreviousMetadataEqual(appVersion, metadata) {
|
|
return "", errorsmod.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version")
|
|
}
|
|
}
|
|
|
|
return string(icatypes.ModuleCdc.MustMarshalJSON(&metadata)), nil
|
|
}
|
|
|
|
// OnChanOpenAck sets the active channel for the interchain account/owner pair
|
|
// and stores the associated interchain account address in state keyed by it's corresponding port identifier
|
|
func (k Keeper) OnChanOpenAck(
|
|
ctx sdk.Context,
|
|
portID,
|
|
channelID string,
|
|
counterpartyVersion string,
|
|
) error {
|
|
if portID == icatypes.HostPortID {
|
|
return errorsmod.Wrapf(icatypes.ErrInvalidControllerPort, "portID cannot be host chain port ID: %s", icatypes.HostPortID)
|
|
}
|
|
|
|
if !strings.HasPrefix(portID, icatypes.ControllerPortPrefix) {
|
|
return errorsmod.Wrapf(icatypes.ErrInvalidControllerPort, "expected %s{owner-account-address}, got %s", icatypes.ControllerPortPrefix, portID)
|
|
}
|
|
|
|
metadata, err := icatypes.MetadataFromVersion(counterpartyVersion)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if activeChannelID, found := k.GetOpenActiveChannel(ctx, metadata.ControllerConnectionId, portID); found {
|
|
return errorsmod.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s", activeChannelID, portID)
|
|
}
|
|
|
|
channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID)
|
|
if !found {
|
|
return errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "failed to retrieve channel %s on port %s", channelID, portID)
|
|
}
|
|
|
|
if err := icatypes.ValidateControllerMetadata(ctx, k.channelKeeper, channel.ConnectionHops, metadata); err != nil {
|
|
return err
|
|
}
|
|
|
|
if strings.TrimSpace(metadata.Address) == "" {
|
|
return errorsmod.Wrap(icatypes.ErrInvalidAccountAddress, "interchain account address cannot be empty")
|
|
}
|
|
|
|
k.SetActiveChannelID(ctx, metadata.ControllerConnectionId, portID, channelID)
|
|
k.SetInterchainAccountAddress(ctx, metadata.ControllerConnectionId, portID, metadata.Address)
|
|
|
|
return nil
|
|
}
|
|
|
|
// OnChanCloseConfirm removes the active channel stored in state
|
|
func (Keeper) OnChanCloseConfirm(
|
|
ctx sdk.Context,
|
|
portID,
|
|
channelID string,
|
|
) error {
|
|
return nil
|
|
}
|
|
|
|
// OnChanUpgradeInit performs the upgrade init step of the channel upgrade handshake.
|
|
// The upgrade init callback must verify the proposed changes to the order, connectionHops, and version.
|
|
// Within the version we have the tx type, encoding, interchain account address, host/controller connectionID's
|
|
// and the ICS27 protocol version.
|
|
//
|
|
// The following may be changed:
|
|
// - tx type (must be supported)
|
|
// - encoding (must be supported)
|
|
// - order
|
|
//
|
|
// The following may not be changed:
|
|
// - connectionHops (and subsequently host/controller connectionIDs)
|
|
// - interchain account address
|
|
// - ICS27 protocol version
|
|
func (k Keeper) OnChanUpgradeInit(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedversion string) (string, error) {
|
|
// verify connection hops has not changed
|
|
connectionID, err := k.GetConnectionID(ctx, portID, channelID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if len(proposedConnectionHops) != 1 || proposedConnectionHops[0] != connectionID {
|
|
return "", errorsmod.Wrapf(channeltypes.ErrInvalidUpgrade, "expected connection hops %s, got %s", []string{connectionID}, proposedConnectionHops)
|
|
}
|
|
|
|
// verify proposed version only modifies tx type or encoding
|
|
if strings.TrimSpace(proposedversion) == "" {
|
|
return "", errorsmod.Wrap(icatypes.ErrInvalidVersion, "version cannot be empty")
|
|
}
|
|
|
|
proposedMetadata, err := icatypes.MetadataFromVersion(proposedversion)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
currentMetadata, err := k.getAppMetadata(ctx, portID, channelID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// ValidateControllerMetadata will ensure the ICS27 protocol version has not changed and that the
|
|
// tx type and encoding are supported
|
|
if err := icatypes.ValidateControllerMetadata(ctx, k.channelKeeper, proposedConnectionHops, proposedMetadata); err != nil {
|
|
return "", errorsmod.Wrap(err, "invalid upgrade metadata")
|
|
}
|
|
|
|
// the interchain account address on the host chain
|
|
// must remain the same after the upgrade.
|
|
if currentMetadata.Address != proposedMetadata.Address {
|
|
return "", errorsmod.Wrap(icatypes.ErrInvalidAccountAddress, "interchain account address cannot be changed")
|
|
}
|
|
|
|
if currentMetadata.ControllerConnectionId != proposedMetadata.ControllerConnectionId {
|
|
return "", errorsmod.Wrap(connectiontypes.ErrInvalidConnection, "proposed controller connection ID must not change")
|
|
}
|
|
|
|
if currentMetadata.HostConnectionId != proposedMetadata.HostConnectionId {
|
|
return "", errorsmod.Wrap(connectiontypes.ErrInvalidConnection, "proposed host connection ID must not change")
|
|
}
|
|
|
|
return proposedversion, nil
|
|
}
|
|
|
|
// OnChanUpgradeAck implements the ack setup of the channel upgrade handshake.
|
|
// The upgrade ack callback must verify the proposed changes to the channel version.
|
|
// Within the channel version we have the tx type, encoding, interchain account address, host/controller connectionID's
|
|
// and the ICS27 protocol version.
|
|
//
|
|
// The following may be changed:
|
|
// - tx type (must be supported)
|
|
// - encoding (must be supported)
|
|
//
|
|
// The following may not be changed:
|
|
// - controller connectionID
|
|
// - host connectionID
|
|
// - interchain account address
|
|
// - ICS27 protocol version
|
|
func (k Keeper) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error {
|
|
if strings.TrimSpace(counterpartyVersion) == "" {
|
|
return errorsmod.Wrap(channeltypes.ErrInvalidChannelVersion, "counterparty version cannot be empty")
|
|
}
|
|
|
|
proposedMetadata, err := icatypes.MetadataFromVersion(counterpartyVersion)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
currentMetadata, err := k.getAppMetadata(ctx, portID, channelID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID)
|
|
if !found {
|
|
return errorsmod.Wrapf(channeltypes.ErrChannelNotFound, "failed to retrieve channel %s on port %s", channelID, portID)
|
|
}
|
|
|
|
// ValidateControllerMetadata will ensure the ICS27 protocol version has not changed and that the
|
|
// tx type and encoding are supported. Note, we pass in the current channel connection hops. The upgrade init
|
|
// step will verify that the proposed connection hops will not change.
|
|
if err := icatypes.ValidateControllerMetadata(ctx, k.channelKeeper, channel.ConnectionHops, proposedMetadata); err != nil {
|
|
return errorsmod.Wrap(err, "invalid upgrade metadata")
|
|
}
|
|
|
|
// the interchain account address on the host chain
|
|
// must remain the same after the upgrade.
|
|
if currentMetadata.Address != proposedMetadata.Address {
|
|
return errorsmod.Wrap(icatypes.ErrInvalidAccountAddress, "address cannot be changed")
|
|
}
|
|
|
|
if currentMetadata.ControllerConnectionId != proposedMetadata.ControllerConnectionId {
|
|
return errorsmod.Wrap(connectiontypes.ErrInvalidConnection, "proposed controller connection ID must not change")
|
|
}
|
|
|
|
if currentMetadata.HostConnectionId != proposedMetadata.HostConnectionId {
|
|
return errorsmod.Wrap(connectiontypes.ErrInvalidConnection, "proposed host connection ID must not change")
|
|
}
|
|
|
|
return nil
|
|
}
|