github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/modules/core/04-channel/keeper/handshake_v4.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  
     6  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     7  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
     8  	capabilitytypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/capability/types"
     9  	connectiontypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/03-connection/types"
    10  	"github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/04-channel/types"
    11  	porttypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/05-port/types"
    12  	host "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/24-host"
    13  	"github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/exported"
    14  )
    15  
    16  // ChanOpenInit is called by a module to initiate a channel opening handshake with
    17  // a module on another chain. The counterparty channel identifier is validated to be
    18  // empty in msg validation.
    19  func (k Keeper) ChanOpenInitV4(
    20  	ctx sdk.Context,
    21  	order types.Order,
    22  	connectionHops []string,
    23  	portID string,
    24  	portCap *capabilitytypes.Capability,
    25  	counterparty types.Counterparty,
    26  	version string,
    27  ) (string, *capabilitytypes.Capability, error) {
    28  	// connection hop length checked on msg.ValidateBasic()
    29  	connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0])
    30  	if !found {
    31  		return "", nil, sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, connectionHops[0])
    32  	}
    33  
    34  	getVersions := connectionEnd.GetVersions()
    35  	if len(getVersions) != 1 {
    36  		return "", nil, sdkerrors.Wrapf(
    37  			connectiontypes.ErrInvalidVersion,
    38  			"single version must be negotiated on connection before opening channel, got: %v",
    39  			getVersions,
    40  		)
    41  	}
    42  
    43  	if !connectiontypes.VerifySupportedFeature(getVersions[0], order.String()) {
    44  		return "", nil, sdkerrors.Wrapf(
    45  			connectiontypes.ErrInvalidVersion,
    46  			"connection version %s does not support channel ordering: %s",
    47  			getVersions[0], order.String(),
    48  		)
    49  	}
    50  
    51  	if !k.portKeeper.Authenticate(ctx, portCap, portID) {
    52  		return "", nil, sdkerrors.Wrapf(porttypes.ErrInvalidPort, "caller does not own port capability for port ID %s", portID)
    53  	}
    54  
    55  	channelID := k.GenerateChannelIdentifier(ctx)
    56  
    57  	capKey, err := k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, channelID))
    58  	if err != nil {
    59  		return "", nil, sdkerrors.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, channelID)
    60  	}
    61  
    62  	return channelID, capKey, nil
    63  }
    64  
    65  // WriteOpenInitChannel writes a channel which has successfully passed the OpenInit handshake step.
    66  // The channel is set in state and all the associated Send and Recv sequences are set to 1.
    67  // An event is emitted for the handshake step.
    68  func (k Keeper) WriteOpenInitChannel(
    69  	ctx sdk.Context,
    70  	portID,
    71  	channelID string,
    72  	order types.Order,
    73  	connectionHops []string,
    74  	counterparty types.Counterparty,
    75  	version string,
    76  ) {
    77  	channel := types.NewChannel(types.INIT, order, counterparty, connectionHops, version)
    78  	k.SetChannel(ctx, portID, channelID, channel)
    79  
    80  	k.SetNextSequenceSend(ctx, portID, channelID, 1)
    81  	k.SetNextSequenceRecv(ctx, portID, channelID, 1)
    82  	k.SetNextSequenceAck(ctx, portID, channelID, 1)
    83  
    84  	k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", "NONE", "new-state", "INIT")
    85  
    86  	EmitChannelOpenInitEvent(ctx, portID, channelID, channel)
    87  }
    88  
    89  // v4
    90  func (k Keeper) ChanOpenTryV4(
    91  	ctx sdk.Context,
    92  	order types.Order,
    93  	connectionHops []string,
    94  	portID string,
    95  	portCap *capabilitytypes.Capability,
    96  	counterparty types.Counterparty,
    97  	counterpartyVersion string,
    98  	proofInit []byte,
    99  	proofHeight exported.Height,
   100  ) (string, *capabilitytypes.Capability, error) {
   101  	// connection hops only supports a single connection
   102  	if len(connectionHops) != 1 {
   103  		return "", nil, sdkerrors.Wrapf(types.ErrTooManyConnectionHops, "expected 1, got %d", len(connectionHops))
   104  	}
   105  
   106  	// generate a new channel
   107  	channelID := k.GenerateChannelIdentifier(ctx)
   108  
   109  	if !k.portKeeper.Authenticate(ctx, portCap, portID) {
   110  		return "", nil, sdkerrors.Wrapf(porttypes.ErrInvalidPort, "caller does not own port capability for port ID %s", portID)
   111  	}
   112  
   113  	connectionEnd, found := k.connectionKeeper.GetConnection(ctx, connectionHops[0])
   114  	if !found {
   115  		return "", nil, sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, connectionHops[0])
   116  	}
   117  
   118  	if connectionEnd.GetState() != int32(connectiontypes.OPEN) {
   119  		return "", nil, sdkerrors.Wrapf(
   120  			connectiontypes.ErrInvalidConnectionState,
   121  			"connection state is not OPEN (got %s)", connectiontypes.State(connectionEnd.GetState()).String(),
   122  		)
   123  	}
   124  
   125  	getVersions := connectionEnd.GetVersions()
   126  	if len(getVersions) != 1 {
   127  		return "", nil, sdkerrors.Wrapf(
   128  			connectiontypes.ErrInvalidVersion,
   129  			"single version must be negotiated on connection before opening channel, got: %v",
   130  			getVersions,
   131  		)
   132  	}
   133  
   134  	if !connectiontypes.VerifySupportedFeature(getVersions[0], order.String()) {
   135  		return "", nil, sdkerrors.Wrapf(
   136  			connectiontypes.ErrInvalidVersion,
   137  			"connection version %s does not support channel ordering: %s",
   138  			getVersions[0], order.String(),
   139  		)
   140  	}
   141  
   142  	counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()}
   143  
   144  	// expectedCounterpaty is the counterparty of the counterparty's channel end
   145  	// (i.e self)
   146  	expectedCounterparty := types.NewCounterparty(portID, "")
   147  	expectedChannel := types.NewChannel(
   148  		types.INIT, order, expectedCounterparty,
   149  		counterpartyHops, counterpartyVersion,
   150  	)
   151  
   152  	if err := k.connectionKeeper.VerifyChannelState(
   153  		ctx, connectionEnd, proofHeight, proofInit,
   154  		counterparty.PortId, counterparty.ChannelId, expectedChannel,
   155  	); err != nil {
   156  		return "", nil, err
   157  	}
   158  
   159  	var (
   160  		capKey *capabilitytypes.Capability
   161  		err    error
   162  	)
   163  
   164  	capKey, err = k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, channelID))
   165  	if err != nil {
   166  		return "", nil, sdkerrors.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, channelID)
   167  	}
   168  
   169  	return channelID, capKey, nil
   170  }
   171  
   172  // WriteOpenTryChannel writes a channel which has successfully passed the OpenTry handshake step.
   173  // The channel is set in state. If a previous channel state did not exist, all the Send and Recv
   174  // sequences are set to 1. An event is emitted for the handshake step.
   175  func (k Keeper) WriteOpenTryChannel(
   176  	ctx sdk.Context,
   177  	portID,
   178  	channelID string,
   179  	order types.Order,
   180  	connectionHops []string,
   181  	counterparty types.Counterparty,
   182  	version string,
   183  ) {
   184  	k.SetNextSequenceSend(ctx, portID, channelID, 1)
   185  	k.SetNextSequenceRecv(ctx, portID, channelID, 1)
   186  	k.SetNextSequenceAck(ctx, portID, channelID, 1)
   187  
   188  	channel := types.NewChannel(types.TRYOPEN, order, counterparty, connectionHops, version)
   189  
   190  	k.SetChannel(ctx, portID, channelID, channel)
   191  
   192  	k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", "NONE", "new-state", "TRYOPEN")
   193  
   194  	EmitChannelOpenTryEvent(ctx, portID, channelID, channel)
   195  }
   196  
   197  // ChanOpenAck is called by the handshake-originating module to acknowledge the
   198  // acceptance of the initial request by the counterparty module on the other chain.
   199  func (k Keeper) ChanOpenAckV4(
   200  	ctx sdk.Context,
   201  	portID,
   202  	channelID string,
   203  	chanCap *capabilitytypes.Capability,
   204  	counterpartyVersion,
   205  	counterpartyChannelID string,
   206  	proofTry []byte,
   207  	proofHeight exported.Height,
   208  ) error {
   209  	channel, found := k.GetChannel(ctx, portID, channelID)
   210  	if !found {
   211  		return sdkerrors.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
   212  	}
   213  
   214  	if channel.State != types.INIT {
   215  		return sdkerrors.Wrapf(types.ErrInvalidChannelState, "channel state should be INIT (got %s)", channel.State.String())
   216  	}
   217  
   218  	if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
   219  		return sdkerrors.Wrapf(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)", portID, channelID)
   220  	}
   221  
   222  	connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
   223  	if !found {
   224  		return sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0])
   225  	}
   226  
   227  	if connectionEnd.GetState() != int32(connectiontypes.OPEN) {
   228  		return sdkerrors.Wrapf(
   229  			connectiontypes.ErrInvalidConnectionState,
   230  			"connection state is not OPEN (got %s)", connectiontypes.State(connectionEnd.GetState()).String(),
   231  		)
   232  	}
   233  
   234  	counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()}
   235  
   236  	// counterparty of the counterparty channel end (i.e self)
   237  	expectedCounterparty := types.NewCounterparty(portID, channelID)
   238  	expectedChannel := types.NewChannel(
   239  		types.TRYOPEN, channel.Ordering, expectedCounterparty,
   240  		counterpartyHops, counterpartyVersion,
   241  	)
   242  
   243  	if err := k.connectionKeeper.VerifyChannelState(
   244  		ctx, connectionEnd, proofHeight, proofTry,
   245  		channel.Counterparty.PortId, counterpartyChannelID,
   246  		expectedChannel,
   247  	); err != nil {
   248  		return err
   249  	}
   250  
   251  	return nil
   252  }
   253  
   254  // WriteOpenAckChannel writes an updated channel state for the successful OpenAck handshake step.
   255  // An event is emitted for the handshake step.
   256  func (k Keeper) WriteOpenAckChannel(
   257  	ctx sdk.Context,
   258  	portID,
   259  	channelID,
   260  	counterpartyVersion,
   261  	counterpartyChannelID string,
   262  ) {
   263  	channel, found := k.GetChannel(ctx, portID, channelID)
   264  	if !found {
   265  		panic(fmt.Sprintf("could not find existing channel when updating channel state in successful ChanOpenAck step, channelID: %s, portID: %s", channelID, portID))
   266  	}
   267  
   268  	channel.State = types.OPEN
   269  	channel.Version = counterpartyVersion
   270  	channel.Counterparty.ChannelId = counterpartyChannelID
   271  	k.SetChannel(ctx, portID, channelID, channel)
   272  
   273  	k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", channel.State.String(), "new-state", "OPEN")
   274  
   275  	EmitChannelOpenAckEvent(ctx, portID, channelID, channel)
   276  }
   277  
   278  // ChanOpenConfirm is called by the counterparty module to close their end of the
   279  //
   280  //	channel, since the other end has been closed.
   281  func (k Keeper) ChanOpenConfirmV4(
   282  	ctx sdk.Context,
   283  	portID,
   284  	channelID string,
   285  	chanCap *capabilitytypes.Capability,
   286  	proofAck []byte,
   287  	proofHeight exported.Height,
   288  ) error {
   289  	channel, found := k.GetChannel(ctx, portID, channelID)
   290  	if !found {
   291  		return sdkerrors.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
   292  	}
   293  
   294  	if channel.State != types.TRYOPEN {
   295  		return sdkerrors.Wrapf(
   296  			types.ErrInvalidChannelState,
   297  			"channel state is not TRYOPEN (got %s)", channel.State.String(),
   298  		)
   299  	}
   300  
   301  	if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
   302  		return sdkerrors.Wrapf(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)", portID, channelID)
   303  	}
   304  
   305  	connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
   306  	if !found {
   307  		return sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0])
   308  	}
   309  
   310  	if connectionEnd.GetState() != int32(connectiontypes.OPEN) {
   311  		return sdkerrors.Wrapf(
   312  			connectiontypes.ErrInvalidConnectionState,
   313  			"connection state is not OPEN (got %s)", connectiontypes.State(connectionEnd.GetState()).String(),
   314  		)
   315  	}
   316  
   317  	counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()}
   318  
   319  	counterparty := types.NewCounterparty(portID, channelID)
   320  	expectedChannel := types.NewChannel(
   321  		types.OPEN, channel.Ordering, counterparty,
   322  		counterpartyHops, channel.Version,
   323  	)
   324  
   325  	if err := k.connectionKeeper.VerifyChannelState(
   326  		ctx, connectionEnd, proofHeight, proofAck,
   327  		channel.Counterparty.PortId, channel.Counterparty.ChannelId,
   328  		expectedChannel,
   329  	); err != nil {
   330  		return err
   331  	}
   332  
   333  	return nil
   334  }
   335  
   336  // WriteOpenConfirmChannel writes an updated channel state for the successful OpenConfirm handshake step.
   337  // An event is emitted for the handshake step.
   338  func (k Keeper) WriteOpenConfirmChannel(
   339  	ctx sdk.Context,
   340  	portID,
   341  	channelID string,
   342  ) {
   343  	channel, found := k.GetChannel(ctx, portID, channelID)
   344  	if !found {
   345  		panic(fmt.Sprintf("could not find existing channel when updating channel state in successful ChanOpenConfirm step, channelID: %s, portID: %s", channelID, portID))
   346  	}
   347  
   348  	channel.State = types.OPEN
   349  	k.SetChannel(ctx, portID, channelID, channel)
   350  	k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", "TRYOPEN", "new-state", "OPEN")
   351  
   352  	EmitChannelOpenConfirmEvent(ctx, portID, channelID, channel)
   353  }
   354  
   355  // Closing Handshake
   356  //
   357  // This section defines the set of functions required to close a channel handshake
   358  // as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#closing-handshake
   359  //
   360  // ChanCloseInit is called by either module to close their end of the channel. Once
   361  // closed, channels cannot be reopened.
   362  func (k Keeper) ChanCloseInitV4(
   363  	ctx sdk.Context,
   364  	portID,
   365  	channelID string,
   366  	chanCap *capabilitytypes.Capability,
   367  ) error {
   368  	if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
   369  		return sdkerrors.Wrapf(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)", portID, channelID)
   370  	}
   371  
   372  	channel, found := k.GetChannel(ctx, portID, channelID)
   373  	if !found {
   374  		return sdkerrors.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
   375  	}
   376  
   377  	if channel.State == types.CLOSED {
   378  		return sdkerrors.Wrap(types.ErrInvalidChannelState, "channel is already CLOSED")
   379  	}
   380  
   381  	connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
   382  	if !found {
   383  		return sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0])
   384  	}
   385  
   386  	if connectionEnd.GetState() != int32(connectiontypes.OPEN) {
   387  		return sdkerrors.Wrapf(
   388  			connectiontypes.ErrInvalidConnectionState,
   389  			"connection state is not OPEN (got %s)", connectiontypes.State(connectionEnd.GetState()).String(),
   390  		)
   391  	}
   392  
   393  	k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", channel.State.String(), "new-state", "CLOSED")
   394  
   395  	channel.State = types.CLOSED
   396  	k.SetChannel(ctx, portID, channelID, channel)
   397  
   398  	EmitChannelCloseInitEvent(ctx, portID, channelID, channel)
   399  
   400  	return nil
   401  }
   402  
   403  // ChanCloseConfirm is called by the counterparty module to close their end of the
   404  // channel, since the other end has been closed.
   405  func (k Keeper) ChanCloseConfirmV4(
   406  	ctx sdk.Context,
   407  	portID,
   408  	channelID string,
   409  	chanCap *capabilitytypes.Capability,
   410  	proofInit []byte,
   411  	proofHeight exported.Height,
   412  ) error {
   413  	if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
   414  		return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)")
   415  	}
   416  
   417  	channel, found := k.GetChannel(ctx, portID, channelID)
   418  	if !found {
   419  		return sdkerrors.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
   420  	}
   421  
   422  	if channel.State == types.CLOSED {
   423  		return sdkerrors.Wrap(types.ErrInvalidChannelState, "channel is already CLOSED")
   424  	}
   425  
   426  	connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
   427  	if !found {
   428  		return sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0])
   429  	}
   430  
   431  	if connectionEnd.GetState() != int32(connectiontypes.OPEN) {
   432  		return sdkerrors.Wrapf(
   433  			connectiontypes.ErrInvalidConnectionState,
   434  			"connection state is not OPEN (got %s)", connectiontypes.State(connectionEnd.GetState()).String(),
   435  		)
   436  	}
   437  
   438  	counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()}
   439  
   440  	counterparty := types.NewCounterparty(portID, channelID)
   441  	expectedChannel := types.NewChannel(
   442  		types.CLOSED, channel.Ordering, counterparty,
   443  		counterpartyHops, channel.Version,
   444  	)
   445  
   446  	if err := k.connectionKeeper.VerifyChannelState(
   447  		ctx, connectionEnd, proofHeight, proofInit,
   448  		channel.Counterparty.PortId, channel.Counterparty.ChannelId,
   449  		expectedChannel,
   450  	); err != nil {
   451  		return err
   452  	}
   453  
   454  	k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", channel.State.String(), "new-state", "CLOSED")
   455  
   456  	channel.State = types.CLOSED
   457  	k.SetChannel(ctx, portID, channelID, channel)
   458  
   459  	EmitChannelCloseConfirmEvent(ctx, portID, channelID, channel)
   460  
   461  	return nil
   462  }