Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: remove crossing hellos from 03-connection (backport #1672) #1691

Merged
merged 5 commits into from
Jul 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### API Breaking

* (modules/core/03-connection) [\#1672](https://github.com/cosmos/ibc-go/pull/1672) Remove crossing hellos from connection handshakes. The `PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated.
* (modules/core/04-channel) [\#1317](https://github.com/cosmos/ibc-go/pull/1317) Remove crossing hellos from channel handshakes. The `PreviousChannelId` in `MsgChannelOpenTry` has been deprecated.
* (transfer) [\#1250](https://github.com/cosmos/ibc-go/pull/1250) Deprecate `GetTransferAccount` since the `transfer` module account is never used.
* (channel) [\#1283](https://github.com/cosmos/ibc-go/pull/1283) The `OnChanOpenInit` application callback now returns a version string in line with the latest [spec changes](https://github.com/cosmos/ibc/pull/629).
Expand Down
2 changes: 1 addition & 1 deletion docs/ibc/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -4244,7 +4244,7 @@ connection on Chain B.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `client_id` | [string](#string) | | |
| `previous_connection_id` | [string](#string) | | in the case of crossing hello's, when both chains call OpenInit, we need the connection identifier of the previous connection in state INIT |
| `previous_connection_id` | [string](#string) | | **Deprecated.** Deprecated: this field is unused. Crossing hellos are no longer supported in core IBC. |
| `client_state` | [google.protobuf.Any](#google.protobuf.Any) | | |
| `counterparty` | [Counterparty](#ibc.core.connection.v1.Counterparty) | | |
| `delay_period` | [uint64](#uint64) | | |
Expand Down
7 changes: 6 additions & 1 deletion docs/migrations/v3-to-v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ No genesis or in-place migrations required when upgrading from v1 or v2 of ibc-g

## IBC Apps

### ICS03 - Connection

Crossing hellos have been removed from 03-connection handshake negotiation.
`PreviousConnectionId` in `MsgConnectionOpenTry` has been deprecated and is no longer used by core IBC.

### ICS04 - Channel

The `WriteAcknowledgement` API now takes the `exported.Acknowledgement` type instead of passing in the acknowledgement byte array directly.
Expand Down Expand Up @@ -100,4 +105,4 @@ if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId,

When using the `DenomTrace` gRPC, the full IBC denomination with the `ibc/` prefix may now be passed in.

Crossing hellos are no longer supported by core IBC. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM).
Crossing hellos are no longer supported by core IBC for 03-connection and 04-channel. The handshake should be completed in the logical 4 step process (INIT, TRY, ACK, CONFIRM).
79 changes: 13 additions & 66 deletions modules/core/03-connection/keeper/handshake.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package keeper

import (
"bytes"

"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/gogo/protobuf/proto"

clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types"
"github.com/cosmos/ibc-go/v4/modules/core/03-connection/types"
Expand All @@ -28,7 +25,7 @@ func (k Keeper) ConnOpenInit(
) (string, error) {
versions := types.GetCompatibleVersions()
if version != nil {
if !types.IsSupportedVersion(version) {
if !types.IsSupportedVersion(types.GetCompatibleVersions(), version) {
return "", sdkerrors.Wrap(types.ErrInvalidVersion, "version is not supported")
}

Expand Down Expand Up @@ -63,7 +60,6 @@ func (k Keeper) ConnOpenInit(
// - Identifiers are checked on msg validation
func (k Keeper) ConnOpenTry(
ctx sdk.Context,
previousConnectionID string, // previousIdentifier
counterparty types.Counterparty, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier
delayPeriod uint64,
clientID string, // clientID of chainA
Expand All @@ -75,44 +71,9 @@ func (k Keeper) ConnOpenTry(
proofHeight exported.Height, // height at which relayer constructs proof of A storing connectionEnd in state
consensusHeight exported.Height, // latest height of chain B which chain A has stored in its chain B client
) (string, error) {
var (
connectionID string
previousConnection types.ConnectionEnd
found bool
)

// empty connection identifier indicates continuing a previous connection handshake
if previousConnectionID != "" {
// ensure that the previous connection exists
previousConnection, found = k.GetConnection(ctx, previousConnectionID)
if !found {
return "", sdkerrors.Wrapf(types.ErrConnectionNotFound, "previous connection does not exist for supplied previous connectionID %s", previousConnectionID)
}

// ensure that the existing connection's
// counterparty is chainA and connection is on INIT stage.
// Check that existing connection versions for initialized connection is equal to compatible
// versions for this chain.
// ensure that existing connection's delay period is the same as desired delay period.
if !(previousConnection.Counterparty.ConnectionId == "" &&
bytes.Equal(previousConnection.Counterparty.Prefix.Bytes(), counterparty.Prefix.Bytes()) &&
previousConnection.ClientId == clientID &&
previousConnection.Counterparty.ClientId == counterparty.ClientId &&
previousConnection.DelayPeriod == delayPeriod) {
return "", sdkerrors.Wrap(types.ErrInvalidConnection, "connection fields mismatch previous connection fields")
}

if !(previousConnection.State == types.INIT) {
return "", sdkerrors.Wrapf(types.ErrInvalidConnectionState, "previous connection state is in state %s, expected INIT", previousConnection.State)
}

// continue with previous connection
connectionID = previousConnectionID

} else {
// generate a new connection
connectionID = k.GenerateConnectionIdentifier(ctx)
}
// generate a new connection
connectionID := k.GenerateConnectionIdentifier(ctx)

selfHeight := clienttypes.GetSelfHeight(ctx)
if consensusHeight.GTE(selfHeight) {
Expand All @@ -139,15 +100,10 @@ func (k Keeper) ConnOpenTry(
expectedCounterparty := types.NewCounterparty(clientID, "", commitmenttypes.NewMerklePrefix(prefix.Bytes()))
expectedConnection := types.NewConnectionEnd(types.INIT, counterparty.ClientId, expectedCounterparty, types.ExportedVersionsToProto(counterpartyVersions), delayPeriod)

supportedVersions := types.GetCompatibleVersions()
if len(previousConnection.Versions) != 0 {
supportedVersions = previousConnection.GetVersions()
}

// chain B picks a version from Chain A's available versions that is compatible
// with Chain B's supported IBC versions. PickVersion will select the intersection
// of the supported versions and the counterparty versions.
version, err := types.PickVersion(supportedVersions, counterpartyVersions)
version, err := types.PickVersion(types.GetCompatibleVersions(), counterpartyVersions)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -181,7 +137,7 @@ func (k Keeper) ConnOpenTry(
}

k.SetConnection(ctx, connectionID, connection)
k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", previousConnection.State.String(), "new-state", "TRYOPEN")
k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", "NONE", "new-state", "TRYOPEN")

defer func() {
telemetry.IncrCounter(1, "ibc", "connection", "open-try")
Expand Down Expand Up @@ -223,28 +179,19 @@ func (k Keeper) ConnOpenAck(
return sdkerrors.Wrap(types.ErrConnectionNotFound, connectionID)
}

// Verify the provided version against the previously set connection state
switch {
// connection on ChainA must be in INIT or TRYOPEN
case connection.State != types.INIT && connection.State != types.TRYOPEN:
return sdkerrors.Wrapf(
types.ErrInvalidConnectionState,
"connection state is not INIT or TRYOPEN (got %s)", connection.State.String(),
)

// if the connection is INIT then the provided version must be supproted
case connection.State == types.INIT && !types.IsSupportedVersion(version):
// verify the previously set connection state
if connection.State != types.INIT {
return sdkerrors.Wrapf(
types.ErrInvalidConnectionState,
"connection state is in INIT but the provided version is not supported %s", version,
"connection state is not INIT (got %s)", connection.State.String(),
)
}

// if the connection is in TRYOPEN then the version must be the only set version in the
// retreived connection state.
case connection.State == types.TRYOPEN && (len(connection.Versions) != 1 || !proto.Equal(connection.Versions[0], version)):
// ensure selected version is supported
if !types.IsSupportedVersion(types.ProtoVersionsToExported(connection.Versions), version) {
return sdkerrors.Wrapf(
types.ErrInvalidConnectionState,
"connection state is in TRYOPEN but the provided version (%s) is not set in the previous connection versions %s", version, connection.Versions,
"the counterparty selected version %s is not supported by versions selected on INIT", version,
)
}

Expand Down Expand Up @@ -283,7 +230,7 @@ func (k Keeper) ConnOpenAck(
return err
}

k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", connection.State.String(), "new-state", "OPEN")
k.Logger(ctx).Info("connection state updated", "connection-id", connectionID, "previous-state", "INIT", "new-state", "OPEN")

defer func() {
telemetry.IncrCounter(1, "ibc", "connection", "open-ack")
Expand Down
70 changes: 6 additions & 64 deletions modules/core/03-connection/keeper/handshake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,11 @@ func (suite *KeeperTestSuite) TestConnOpenInit() {
// connection on chainA is INIT
func (suite *KeeperTestSuite) TestConnOpenTry() {
var (
path *ibctesting.Path
delayPeriod uint64
previousConnectionID string
versions []exported.Version
consensusHeight exported.Height
counterpartyClient exported.ClientState
path *ibctesting.Path
delayPeriod uint64
versions []exported.Version
consensusHeight exported.Height
counterpartyClient exported.ClientState
)

testCases := []struct {
Expand All @@ -100,15 +99,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() {
// retrieve client state of chainA to pass as counterpartyClient
counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID)
}, true},
{"success with crossing hellos", func() {
err := suite.coordinator.ConnOpenInitOnBothChains(path)
suite.Require().NoError(err)

// retrieve client state of chainA to pass as counterpartyClient
counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID)

previousConnectionID = path.EndpointB.ConnectionID
}, true},
{"success with delay period", func() {
err := path.EndpointA.ConnOpenInit()
suite.Require().NoError(err)
Expand Down Expand Up @@ -227,8 +217,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() {

// retrieve client state of chainA to pass as counterpartyClient
counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID)

previousConnectionID = path.EndpointB.ConnectionID
}, false},
{"invalid previous connection has invalid versions", func() {
// open init chainA
Expand All @@ -253,8 +241,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() {

// retrieve client state of chainA to pass as counterpartyClient
counterpartyClient = suite.chainA.GetClientState(path.EndpointA.ClientID)

previousConnectionID = path.EndpointB.ConnectionID
}, false},
}

Expand All @@ -265,7 +251,6 @@ func (suite *KeeperTestSuite) TestConnOpenTry() {
suite.SetupTest() // reset
consensusHeight = clienttypes.ZeroHeight() // must be explicitly changed in malleate
versions = types.GetCompatibleVersions() // must be explicitly changed in malleate
previousConnectionID = ""
path = ibctesting.NewPath(suite.chainA, suite.chainB)
suite.coordinator.SetupClients(path)

Expand All @@ -292,7 +277,7 @@ func (suite *KeeperTestSuite) TestConnOpenTry() {
proofClient, _ := suite.chainA.QueryProof(clientKey)

connectionID, err := suite.chainB.App.GetIBCKeeper().ConnectionKeeper.ConnOpenTry(
suite.chainB.GetContext(), previousConnectionID, counterparty, delayPeriod, path.EndpointB.ClientID, counterpartyClient,
suite.chainB.GetContext(), counterparty, delayPeriod, path.EndpointB.ClientID, counterpartyClient,
versions, proofInit, proofClient, proofConsensus,
proofHeight, consensusHeight,
)
Expand Down Expand Up @@ -333,27 +318,6 @@ func (suite *KeeperTestSuite) TestConnOpenAck() {
// retrieve client state of chainB to pass as counterpartyClient
counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID)
}, true},
{"success from tryopen", func() {
// chainA is in TRYOPEN, chainB is in TRYOPEN
err := path.EndpointB.ConnOpenInit()
suite.Require().NoError(err)

err = path.EndpointA.ConnOpenTry()
suite.Require().NoError(err)

// set chainB to TRYOPEN
connection := path.EndpointB.GetConnection()
connection.State = types.TRYOPEN
connection.Counterparty.ConnectionId = path.EndpointA.ConnectionID
suite.chainB.App.GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID, connection)
// update path.EndpointB.ClientID so state change is committed
path.EndpointB.UpdateClient()

path.EndpointA.UpdateClient()

// retrieve client state of chainB to pass as counterpartyClient
counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID)
}, true},
{"invalid counterparty client", func() {
err := path.EndpointA.ConnOpenInit()
suite.Require().NoError(err)
Expand Down Expand Up @@ -440,28 +404,6 @@ func (suite *KeeperTestSuite) TestConnOpenAck() {

version = types.NewVersion("2.0", nil)
}, false},
{"connection is in TRYOPEN but the set version in the connection is invalid", func() {
// chainA is in TRYOPEN, chainB is in TRYOPEN
err := path.EndpointB.ConnOpenInit()
suite.Require().NoError(err)

err = path.EndpointA.ConnOpenTry()
suite.Require().NoError(err)

// set chainB to TRYOPEN
connection := path.EndpointB.GetConnection()
connection.State = types.TRYOPEN
suite.chainB.App.GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chainB.GetContext(), path.EndpointB.ConnectionID, connection)

// update path.EndpointB.ClientID so state change is committed
path.EndpointB.UpdateClient()
path.EndpointA.UpdateClient()

// retrieve client state of chainB to pass as counterpartyClient
counterpartyClient = suite.chainB.GetClientState(path.EndpointB.ClientID)

version = types.NewVersion("2.0", nil)
}, false},
{"incompatible IBC versions", func() {
err := path.EndpointA.ConnOpenInit()
suite.Require().NoError(err)
Expand Down
Loading