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 }