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 }