github.com/okex/exchain@v1.8.0/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/okex/exchain/libs/cosmos-sdk/types"
     7  	sdkerrors "github.com/okex/exchain/libs/cosmos-sdk/types/errors"
     8  	capabilitytypes "github.com/okex/exchain/libs/cosmos-sdk/x/capability/types"
     9  	connectiontypes "github.com/okex/exchain/libs/ibc-go/modules/core/03-connection/types"
    10  	"github.com/okex/exchain/libs/ibc-go/modules/core/04-channel/types"
    11  	porttypes "github.com/okex/exchain/libs/ibc-go/modules/core/05-port/types"
    12  	host "github.com/okex/exchain/libs/ibc-go/modules/core/24-host"
    13  	"github.com/okex/exchain/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  //  channel, since the other end has been closed.
   280  func (k Keeper) ChanOpenConfirmV4(
   281  	ctx sdk.Context,
   282  	portID,
   283  	channelID string,
   284  	chanCap *capabilitytypes.Capability,
   285  	proofAck []byte,
   286  	proofHeight exported.Height,
   287  ) error {
   288  	channel, found := k.GetChannel(ctx, portID, channelID)
   289  	if !found {
   290  		return sdkerrors.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
   291  	}
   292  
   293  	if channel.State != types.TRYOPEN {
   294  		return sdkerrors.Wrapf(
   295  			types.ErrInvalidChannelState,
   296  			"channel state is not TRYOPEN (got %s)", channel.State.String(),
   297  		)
   298  	}
   299  
   300  	if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
   301  		return sdkerrors.Wrapf(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)", portID, channelID)
   302  	}
   303  
   304  	connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
   305  	if !found {
   306  		return sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0])
   307  	}
   308  
   309  	if connectionEnd.GetState() != int32(connectiontypes.OPEN) {
   310  		return sdkerrors.Wrapf(
   311  			connectiontypes.ErrInvalidConnectionState,
   312  			"connection state is not OPEN (got %s)", connectiontypes.State(connectionEnd.GetState()).String(),
   313  		)
   314  	}
   315  
   316  	counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()}
   317  
   318  	counterparty := types.NewCounterparty(portID, channelID)
   319  	expectedChannel := types.NewChannel(
   320  		types.OPEN, channel.Ordering, counterparty,
   321  		counterpartyHops, channel.Version,
   322  	)
   323  
   324  	if err := k.connectionKeeper.VerifyChannelState(
   325  		ctx, connectionEnd, proofHeight, proofAck,
   326  		channel.Counterparty.PortId, channel.Counterparty.ChannelId,
   327  		expectedChannel,
   328  	); err != nil {
   329  		return err
   330  	}
   331  
   332  	return nil
   333  }
   334  
   335  // WriteOpenConfirmChannel writes an updated channel state for the successful OpenConfirm handshake step.
   336  // An event is emitted for the handshake step.
   337  func (k Keeper) WriteOpenConfirmChannel(
   338  	ctx sdk.Context,
   339  	portID,
   340  	channelID string,
   341  ) {
   342  	channel, found := k.GetChannel(ctx, portID, channelID)
   343  	if !found {
   344  		panic(fmt.Sprintf("could not find existing channel when updating channel state in successful ChanOpenConfirm step, channelID: %s, portID: %s", channelID, portID))
   345  	}
   346  
   347  	channel.State = types.OPEN
   348  	k.SetChannel(ctx, portID, channelID, channel)
   349  	k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", "TRYOPEN", "new-state", "OPEN")
   350  
   351  	EmitChannelOpenConfirmEvent(ctx, portID, channelID, channel)
   352  }
   353  
   354  // Closing Handshake
   355  //
   356  // This section defines the set of functions required to close a channel handshake
   357  // as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#closing-handshake
   358  //
   359  // ChanCloseInit is called by either module to close their end of the channel. Once
   360  // closed, channels cannot be reopened.
   361  func (k Keeper) ChanCloseInitV4(
   362  	ctx sdk.Context,
   363  	portID,
   364  	channelID string,
   365  	chanCap *capabilitytypes.Capability,
   366  ) error {
   367  	if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
   368  		return sdkerrors.Wrapf(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)", portID, channelID)
   369  	}
   370  
   371  	channel, found := k.GetChannel(ctx, portID, channelID)
   372  	if !found {
   373  		return sdkerrors.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
   374  	}
   375  
   376  	if channel.State == types.CLOSED {
   377  		return sdkerrors.Wrap(types.ErrInvalidChannelState, "channel is already CLOSED")
   378  	}
   379  
   380  	connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
   381  	if !found {
   382  		return sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0])
   383  	}
   384  
   385  	if connectionEnd.GetState() != int32(connectiontypes.OPEN) {
   386  		return sdkerrors.Wrapf(
   387  			connectiontypes.ErrInvalidConnectionState,
   388  			"connection state is not OPEN (got %s)", connectiontypes.State(connectionEnd.GetState()).String(),
   389  		)
   390  	}
   391  
   392  	k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", channel.State.String(), "new-state", "CLOSED")
   393  
   394  	channel.State = types.CLOSED
   395  	k.SetChannel(ctx, portID, channelID, channel)
   396  
   397  	EmitChannelCloseInitEvent(ctx, portID, channelID, channel)
   398  
   399  	return nil
   400  }
   401  
   402  // ChanCloseConfirm is called by the counterparty module to close their end of the
   403  // channel, since the other end has been closed.
   404  func (k Keeper) ChanCloseConfirmV4(
   405  	ctx sdk.Context,
   406  	portID,
   407  	channelID string,
   408  	chanCap *capabilitytypes.Capability,
   409  	proofInit []byte,
   410  	proofHeight exported.Height,
   411  ) error {
   412  	if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
   413  		return sdkerrors.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)")
   414  	}
   415  
   416  	channel, found := k.GetChannel(ctx, portID, channelID)
   417  	if !found {
   418  		return sdkerrors.Wrapf(types.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID)
   419  	}
   420  
   421  	if channel.State == types.CLOSED {
   422  		return sdkerrors.Wrap(types.ErrInvalidChannelState, "channel is already CLOSED")
   423  	}
   424  
   425  	connectionEnd, found := k.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0])
   426  	if !found {
   427  		return sdkerrors.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0])
   428  	}
   429  
   430  	if connectionEnd.GetState() != int32(connectiontypes.OPEN) {
   431  		return sdkerrors.Wrapf(
   432  			connectiontypes.ErrInvalidConnectionState,
   433  			"connection state is not OPEN (got %s)", connectiontypes.State(connectionEnd.GetState()).String(),
   434  		)
   435  	}
   436  
   437  	counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()}
   438  
   439  	counterparty := types.NewCounterparty(portID, channelID)
   440  	expectedChannel := types.NewChannel(
   441  		types.CLOSED, channel.Ordering, counterparty,
   442  		counterpartyHops, channel.Version,
   443  	)
   444  
   445  	if err := k.connectionKeeper.VerifyChannelState(
   446  		ctx, connectionEnd, proofHeight, proofInit,
   447  		channel.Counterparty.PortId, channel.Counterparty.ChannelId,
   448  		expectedChannel,
   449  	); err != nil {
   450  		return err
   451  	}
   452  
   453  	k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", channelID, "previous-state", channel.State.String(), "new-state", "CLOSED")
   454  
   455  	channel.State = types.CLOSED
   456  	k.SetChannel(ctx, portID, channelID, channel)
   457  
   458  	EmitChannelCloseConfirmEvent(ctx, portID, channelID, channel)
   459  
   460  	return nil
   461  }