github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/modules/apps/27-interchain-accounts/host/keeper/handshake.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     8  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
     9  	capabilitytypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/capability/types"
    10  	icatypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/apps/27-interchain-accounts/types"
    11  	channeltypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/04-channel/types"
    12  	host "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/24-host"
    13  )
    14  
    15  // OnChanOpenTry performs basic validation of the ICA channel
    16  // and registers a new interchain account (if it doesn't exist).
    17  // The version returned will include the registered interchain
    18  // account address.
    19  func (k Keeper) OnChanOpenTry(
    20  	ctx sdk.Context,
    21  	order channeltypes.Order,
    22  	connectionHops []string,
    23  	portID,
    24  	channelID string,
    25  	chanCap *capabilitytypes.Capability,
    26  	counterparty channeltypes.Counterparty,
    27  	counterpartyVersion string,
    28  ) (string, error) {
    29  	if order != channeltypes.ORDERED {
    30  		return "", sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s", channeltypes.ORDERED, order)
    31  	}
    32  
    33  	if portID != icatypes.PortID {
    34  		return "", sdkerrors.Wrapf(icatypes.ErrInvalidHostPort, "expected %s, got %s", icatypes.PortID, portID)
    35  	}
    36  
    37  	if !strings.HasPrefix(counterparty.PortId, icatypes.PortPrefix) {
    38  		return "", sdkerrors.Wrapf(icatypes.ErrInvalidControllerPort, "expected %s{owner-account-address}, got %s", icatypes.PortPrefix, counterparty.PortId)
    39  	}
    40  
    41  	var metadata icatypes.Metadata
    42  	if err := icatypes.ModuleCdc.UnmarshalJSON([]byte(counterpartyVersion), &metadata); err != nil {
    43  		return "", sdkerrors.Wrapf(icatypes.ErrUnknownDataType, "cannot unmarshal ICS-27 interchain accounts metadata")
    44  	}
    45  
    46  	if err := icatypes.ValidateHostMetadata(ctx, k.channelKeeper, connectionHops, metadata); err != nil {
    47  		return "", err
    48  	}
    49  
    50  	activeChannelID, found := k.GetActiveChannelID(ctx, connectionHops[0], counterparty.PortId)
    51  	if found {
    52  		channel, found := k.channelKeeper.GetChannel(ctx, portID, activeChannelID)
    53  		if !found {
    54  			panic(fmt.Sprintf("active channel mapping set for %s but channel does not exist in channel store", activeChannelID))
    55  		}
    56  
    57  		if channel.State == channeltypes.OPEN {
    58  			return "", sdkerrors.Wrapf(icatypes.ErrActiveChannelAlreadySet, "existing active channel %s for portID %s is already OPEN", activeChannelID, portID)
    59  		}
    60  
    61  		if !icatypes.IsPreviousMetadataEqual(channel.Version, metadata) {
    62  			return "", sdkerrors.Wrap(icatypes.ErrInvalidVersion, "previous active channel metadata does not match provided version")
    63  		}
    64  	}
    65  
    66  	// On the host chain the capability may only be claimed during the OnChanOpenTry
    67  	// The capability being claimed in OpenInit is for a controller chain (the port is different)
    68  	if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
    69  		return "", sdkerrors.Wrapf(err, "failed to claim capability for channel %s on port %s", channelID, portID)
    70  	}
    71  
    72  	accAddress := icatypes.GenerateAddress(k.accountKeeper.GetModuleAddress(icatypes.ModuleName), metadata.HostConnectionId, counterparty.PortId)
    73  
    74  	// Register interchain account if it does not already exist
    75  	k.RegisterInterchainAccount(ctx, metadata.HostConnectionId, counterparty.PortId, accAddress)
    76  
    77  	metadata.Address = accAddress.String()
    78  	versionBytes, err := icatypes.ModuleCdc.MarshalJSON(&metadata)
    79  	if err != nil {
    80  		return "", err
    81  	}
    82  
    83  	return string(versionBytes), nil
    84  }
    85  
    86  // OnChanOpenConfirm completes the handshake process by setting the active channel in state on the host chain
    87  func (k Keeper) OnChanOpenConfirm(
    88  	ctx sdk.Context,
    89  	portID,
    90  	channelID string,
    91  ) error {
    92  	channel, found := k.channelKeeper.GetChannel(ctx, portID, channelID)
    93  	if !found {
    94  		return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "failed to retrieve channel %s on port %s", channelID, portID)
    95  	}
    96  
    97  	// It is assumed the controller chain will not allow multiple active channels to be created for the same connectionID/portID
    98  	// If the controller chain does allow multiple active channels to be created for the same connectionID/portID,
    99  	// disallowing overwriting the current active channel guarantees the channel can no longer be used as the controller
   100  	// and host will disagree on what the currently active channel is
   101  	k.SetActiveChannelID(ctx, channel.ConnectionHops[0], channel.Counterparty.PortId, channelID)
   102  
   103  	return nil
   104  }
   105  
   106  // OnChanCloseConfirm removes the active channel stored in state
   107  func (k Keeper) OnChanCloseConfirm(
   108  	ctx sdk.Context,
   109  	portID,
   110  	channelID string,
   111  ) error {
   112  	return nil
   113  }