Standardize connection versioning + channel versioning docs (#6640)

* update connection versions with feature set flag

* make connection version modular to support channel versioning and registering

* revert IBCVersion renaming, add channel versioning logic

* fix channel version flag

* remove unnecessary godoc

* remove unused func

* fix lint and version test

* add test and fix error

* revert changes

* update docs

* remove unnecessary godoc

* Apply suggestions from code review

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>

* update doc

* add test cases for unchecked lines

* go fmt

* begin migration to standardized version

* revert proto changes

* restructure versioning to go from string to proto

* update versionStr to encodedVersion naming

* fix version test build

* fix keeper tests

* fix various tests

* fixes from self review

* update docs

* fix lint

* add more code cov

* rename ToString funcs to Encode/DecodeVersion + GetCompatibleEncodedVersions renaming

* update spec docs

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
colin axner 2020-07-14 10:43:26 +02:00 committed by GitHub
parent 839ee4f5e7
commit 5dfc4a2ec9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 811 additions and 401 deletions

View File

@ -142,6 +142,28 @@ OnChanCloseConfirm(
}
```
#### Channel Handshake Version Negotiation
Application modules are expected to verify versioning used during the channel handshake procedure.
* `ChanOpenInit` callback should verify that the `MsgChanOpenInit.Version` is valid
* `ChanOpenTry` callback should verify that the `MsgChanOpenTry.Version` is valid and that `MsgChanOpenTry.CounterpartyVersion` is valid.
* `ChanOpenAck` callback should verify that the `MsgChanOpenAck.CounterpartyVersion` is valid and supported.
Versions must be strings but can implement any versioning structure. If your application plans to
have linear releases then semantic versioning is recommended. If your application plans to release
various features in between major releases then it is advised to use the same versioning scheme
as IBC. This versioning scheme specifies a version identifier and compatible feature set with
that identifier. Valid version selection includes selecting a compatible version identifier with
a subset of features supported by your application for that version. The struct is used for this
scheme can be found in `03-connection/types`.
Since the version type is a string, applications have the ability to do simple version verification
via string matching or they can use the already impelemented versioning system and pass the proto
encoded version into each handhshake call as necessary.
ICS20 currently implements basic string matching with a single supported version.
### Bind Ports
Currently, ports must be bound on app initialization. A module may bind to ports in `InitGenesis`

View File

@ -9,70 +9,97 @@ import "ibc/commitment/commitment.proto";
// MsgConnectionOpenInit defines the msg sent by an account on Chain A to
// initialize a connection with Chain B.
message MsgConnectionOpenInit {
string client_id = 1 [(gogoproto.customname) = "ClientID", (gogoproto.moretags) = "yaml:\"client_id\""];
string connection_id = 2 [(gogoproto.customname) = "ConnectionID", (gogoproto.moretags) = "yaml:\"connection_id\""];
Counterparty counterparty = 3 [(gogoproto.nullable) = false];
bytes signer = 4 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
string client_id = 1 [
(gogoproto.customname) = "ClientID",
(gogoproto.moretags) = "yaml:\"client_id\""
];
string connection_id = 2 [
(gogoproto.customname) = "ConnectionID",
(gogoproto.moretags) = "yaml:\"connection_id\""
];
Counterparty counterparty = 3 [(gogoproto.nullable) = false];
bytes signer = 4
[(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
}
// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a connection
// on Chain B.
// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a
// connection on Chain B.
message MsgConnectionOpenTry {
string client_id = 1 [(gogoproto.customname) = "ClientID", (gogoproto.moretags) = "yaml:\"client_id\""];
string connection_id = 2 [(gogoproto.customname) = "ConnectionID", (gogoproto.moretags) = "yaml:\"connection_id\""];
Counterparty counterparty = 3 [(gogoproto.nullable) = false];
repeated string counterparty_versions = 4 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""];
// proof of the initialization the connection on Chain A: `UNITIALIZED -> INIT`
bytes proof_init = 5 [(gogoproto.moretags) = "yaml:\"proof_init\""];
string client_id = 1 [
(gogoproto.customname) = "ClientID",
(gogoproto.moretags) = "yaml:\"client_id\""
];
string connection_id = 2 [
(gogoproto.customname) = "ConnectionID",
(gogoproto.moretags) = "yaml:\"connection_id\""
];
Counterparty counterparty = 3 [(gogoproto.nullable) = false];
repeated string counterparty_versions = 4 [
(gogoproto.moretags) = "yaml:\"counterparty_versions\""
];
// proof of the initialization the connection on Chain A: `UNITIALIZED ->
// INIT`
bytes proof_init = 5 [(gogoproto.moretags) = "yaml:\"proof_init\""];
uint64 proof_height = 6;
// proof of client consensus state
bytes proof_consensus = 7
[(gogoproto.moretags) = "yaml:\"proof_consensus\""];
uint64 consensus_height = 8 [(gogoproto.moretags) = "yaml:\"consensus_height\""];
bytes signer = 9 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
bytes proof_consensus = 7 [(gogoproto.moretags) = "yaml:\"proof_consensus\""];
uint64 consensus_height = 8
[(gogoproto.moretags) = "yaml:\"consensus_height\""];
bytes signer = 9
[(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
}
// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to acknowledge
// the change of connection state to TRYOPEN on Chain B.
// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to
// acknowledge the change of connection state to TRYOPEN on Chain B.
message MsgConnectionOpenAck {
string connection_id = 1 [(gogoproto.customname) = "ConnectionID", (gogoproto.moretags) = "yaml:\"connection_id\""];
string version = 2;
// proof of the initialization the connection on Chain B: `UNITIALIZED -> TRYOPEN`
bytes proof_try = 3
[(gogoproto.moretags) = "yaml:\"proof_try\""];
string connection_id = 1 [
(gogoproto.customname) = "ConnectionID",
(gogoproto.moretags) = "yaml:\"connection_id\""
];
string version = 2;
// proof of the initialization the connection on Chain B: `UNITIALIZED ->
// TRYOPEN`
bytes proof_try = 3 [(gogoproto.moretags) = "yaml:\"proof_try\""];
uint64 proof_height = 4 [(gogoproto.moretags) = "yaml:\"proof_height\""];
// proof of client consensus state
bytes proof_consensus = 5
[(gogoproto.moretags) = "yaml:\"proof_consensus\""];
uint64 consensus_height = 6 [(gogoproto.moretags) = "yaml:\"consensus_height\""];
bytes signer = 7 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
bytes proof_consensus = 5 [(gogoproto.moretags) = "yaml:\"proof_consensus\""];
uint64 consensus_height = 6
[(gogoproto.moretags) = "yaml:\"consensus_height\""];
bytes signer = 7
[(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
}
// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to acknowledge
// the change of connection state to OPEN on Chain A.
// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to
// acknowledge the change of connection state to OPEN on Chain A.
message MsgConnectionOpenConfirm {
string connection_id = 1 [(gogoproto.customname) = "ConnectionID", (gogoproto.moretags) = "yaml:\"connection_id\""];
string connection_id = 1 [
(gogoproto.customname) = "ConnectionID",
(gogoproto.moretags) = "yaml:\"connection_id\""
];
// proof for the change of the connection state on Chain A: `INIT -> OPEN`
bytes proof_ack = 2
[(gogoproto.moretags) = "yaml:\"proof_ack\""];
bytes proof_ack = 2 [(gogoproto.moretags) = "yaml:\"proof_ack\""];
uint64 proof_height = 3 [(gogoproto.moretags) = "yaml:\"proof_height\""];
bytes signer = 4 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
bytes signer = 4
[(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"];
}
// ICS03 - Connection Data Structures as defined in
// https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures
// ConnectionEnd defines a stateful object on a chain connected to another separate
// one.
// NOTE: there must only be 2 defined ConnectionEnds to establish a connection
// between two chains.
// ConnectionEnd defines a stateful object on a chain connected to another
// separate one. NOTE: there must only be 2 defined ConnectionEnds to establish
// a connection between two chains.
message ConnectionEnd {
option (gogoproto.goproto_getters) = false;
// connection identifier.
string id = 1 [(gogoproto.customname) = "ID", (gogoproto.moretags) = "yaml:\"id\""];
string id = 1
[(gogoproto.customname) = "ID", (gogoproto.moretags) = "yaml:\"id\""];
// client associated with this connection.
string client_id = 2 [(gogoproto.customname) = "ClientID", (gogoproto.moretags) = "yaml:\"client_id\""];
// opaque string which can be utilised to determine encodings or protocols for
string client_id = 2 [
(gogoproto.customname) = "ClientID",
(gogoproto.moretags) = "yaml:\"client_id\""
];
// IBC version which can be utilised to determine encodings or protocols for
// channels or packets utilising this connection
repeated string versions = 3;
// current state of the connection end.
@ -87,10 +114,12 @@ enum State {
option (gogoproto.goproto_enum_prefix) = false;
// Default State
STATE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNINITIALIZED"];
STATE_UNINITIALIZED_UNSPECIFIED = 0
[(gogoproto.enumvalue_customname) = "UNINITIALIZED"];
// A connection end has just started the opening handshake.
STATE_INIT = 1 [(gogoproto.enumvalue_customname) = "INIT"];
// A connection end has acknowledged the handshake step on the counterparty chain.
// A connection end has acknowledged the handshake step on the counterparty
// chain.
STATE_TRYOPEN = 2 [(gogoproto.enumvalue_customname) = "TRYOPEN"];
// A connection end has completed the handshake.
STATE_OPEN = 3 [(gogoproto.enumvalue_customname) = "OPEN"];
@ -100,10 +129,18 @@ enum State {
message Counterparty {
option (gogoproto.goproto_getters) = false;
// identifies the client on the counterparty chain associated with a given connection.
string client_id = 1 [(gogoproto.customname) = "ClientID", (gogoproto.moretags) = "yaml:\"client_id\""];
// identifies the connection end on the counterparty chain associated with a given connection.
string connection_id = 2 [(gogoproto.customname) = "ConnectionID", (gogoproto.moretags) = "yaml:\"connection_id\""];
// identifies the client on the counterparty chain associated with a given
// connection.
string client_id = 1 [
(gogoproto.customname) = "ClientID",
(gogoproto.moretags) = "yaml:\"client_id\""
];
// identifies the connection end on the counterparty chain associated with a
// given connection.
string connection_id = 2 [
(gogoproto.customname) = "ConnectionID",
(gogoproto.moretags) = "yaml:\"connection_id\""
];
// commitment merkle prefix of the counterparty chain
ibc.commitment.MerklePrefix prefix = 3 [(gogoproto.nullable) = false];
}
@ -117,7 +154,21 @@ message ClientPaths {
// ConnectionPaths define all the connection paths for a given client state.
message ConnectionPaths {
// client state unique identifier
string client_id = 1 [(gogoproto.customname) = "ClientID", (gogoproto.moretags) = "yaml:\"client_id\""];
string client_id = 1 [
(gogoproto.customname) = "ClientID",
(gogoproto.moretags) = "yaml:\"client_id\""
];
// list of connection paths
repeated string paths = 2;
}
// Version defines the versioning scheme used to negotiate the IBC verison in
// the connection handshake.
message Version {
option (gogoproto.goproto_getters) = false;
// unique version identifier
string identifier = 1;
// list of features compatible with the specified identifier
repeated string features = 2;
}

View File

@ -284,7 +284,7 @@ func (chain *TestChain) createConnection(
State: state,
ClientID: clientID,
Counterparty: counterparty,
Versions: connectiontypes.GetCompatibleVersions(),
Versions: connectiontypes.GetCompatibleEncodedVersions(),
}
ctx := chain.GetContext()
chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection)

View File

@ -259,7 +259,7 @@ func (chain *TestChain) createConnection(
State: state,
ClientID: clientID,
Counterparty: counterparty,
Versions: connectiontypes.GetCompatibleVersions(),
Versions: connectiontypes.GetCompatibleEncodedVersions(),
}
ctx := chain.GetContext()
chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection)

View File

@ -195,7 +195,7 @@ func (am AppModule) OnChanOpenInit(
}
if version != types.Version {
return sdkerrors.Wrapf(types.ErrInvalidVersion, "got: %s, expected %s", version, types.Version)
return sdkerrors.Wrapf(types.ErrInvalidVersion, "got %s, expected %s", version, types.Version)
}
// Claim channel capability passed back by IBC module

View File

@ -9,5 +9,5 @@ var (
ErrInvalidPacketTimeout = sdkerrors.Register(ModuleName, 2, "invalid packet timeout")
ErrOnlyOneDenomAllowed = sdkerrors.Register(ModuleName, 3, "only one denom allowed")
ErrInvalidDenomForTransfer = sdkerrors.Register(ModuleName, 4, "invalid denomination for cross-chain transfer")
ErrInvalidVersion = sdkerrors.Register(ModuleName, 5, "invalid version")
ErrInvalidVersion = sdkerrors.Register(ModuleName, 5, "invalid ICS20 version")
)

View File

@ -50,7 +50,7 @@ func (suite *KeeperTestSuite) TestQueryConnection() {
connB := suite.chainB.GetFirstTestConnection(clientB, clientA)
counterparty := types.NewCounterparty(clientB, connB.ID, suite.chainB.GetPrefix())
expConnection = types.NewConnectionEnd(types.INIT, connA.ID, clientA, counterparty, types.GetCompatibleVersions())
expConnection = types.NewConnectionEnd(types.INIT, connA.ID, clientA, counterparty, types.GetCompatibleEncodedVersions())
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), connA.ID, expConnection)
req = &types.QueryConnectionRequest{
@ -119,9 +119,9 @@ func (suite *KeeperTestSuite) TestQueryConnections() {
counterparty2 := types.NewCounterparty(clientB, connB1.ID, suite.chainB.GetPrefix())
counterparty3 := types.NewCounterparty(clientB1, connB2.ID, suite.chainB.GetPrefix())
conn1 := types.NewConnectionEnd(types.OPEN, connA0.ID, clientA, counterparty1, types.GetCompatibleVersions())
conn2 := types.NewConnectionEnd(types.INIT, connA1.ID, clientA, counterparty2, types.GetCompatibleVersions())
conn3 := types.NewConnectionEnd(types.OPEN, connA2.ID, clientA1, counterparty3, types.GetCompatibleVersions())
conn1 := types.NewConnectionEnd(types.OPEN, connA0.ID, clientA, counterparty1, types.GetCompatibleEncodedVersions())
conn2 := types.NewConnectionEnd(types.INIT, connA1.ID, clientA, counterparty2, types.GetCompatibleEncodedVersions())
conn3 := types.NewConnectionEnd(types.OPEN, connA2.ID, clientA1, counterparty3, types.GetCompatibleEncodedVersions())
expConnections = []*types.ConnectionEnd{&conn1, &conn2, &conn3}

View File

@ -26,7 +26,7 @@ func (k Keeper) ConnOpenInit(
}
// connection defines chain A's ConnectionEnd
connection := types.NewConnectionEnd(types.INIT, connectionID, clientID, counterparty, types.GetCompatibleVersions())
connection := types.NewConnectionEnd(types.INIT, connectionID, clientID, counterparty, types.GetCompatibleEncodedVersions())
k.SetConnection(ctx, connectionID, connection)
if err := k.addConnectionToClient(ctx, clientID, connectionID); err != nil {
@ -128,7 +128,7 @@ func (k Keeper) ConnOpenTry(
func (k Keeper) ConnOpenAck(
ctx sdk.Context,
connectionID string,
version string, // version that ChainB chose in ConnOpenTry
encodedVersion string, // version that ChainB chose in ConnOpenTry
proofTry []byte, // proof that connectionEnd was added to ChainB state in ConnOpenTry
proofConsensus []byte, // proof that chainB has stored ConsensusState of chainA on its client
proofHeight uint64, // height that relayer constructed proofTry
@ -156,7 +156,12 @@ func (k Keeper) ConnOpenAck(
)
}
// Check that ChainB's proposed version number is supported by chainA
version, err := types.DecodeVersion(encodedVersion)
if err != nil {
return sdkerrors.Wrap(err, "version negotiation failed")
}
// Check that ChainB's proposed version identifier is supported by chainA
supportedVersion, found := types.FindSupportedVersion(version, types.GetCompatibleVersions())
if !found {
return sdkerrors.Wrapf(
@ -166,11 +171,8 @@ func (k Keeper) ConnOpenAck(
}
// Check that ChainB's proposed feature set is supported by chainA
if !types.VerifyProposedFeatureSet(version, supportedVersion) {
return sdkerrors.Wrapf(
types.ErrVersionNegotiationFailed,
"connection version feature set provided (%s) is not supported (%s)", version, types.GetCompatibleVersions(),
)
if err := supportedVersion.VerifyProposedVersion(version); err != nil {
return err
}
// Retrieve chainA's consensus state at consensusheight
@ -181,7 +183,7 @@ func (k Keeper) ConnOpenAck(
prefix := k.GetCommitmentPrefix()
expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, commitmenttypes.NewMerklePrefix(prefix.Bytes()))
expectedConnection := types.NewConnectionEnd(types.TRYOPEN, connection.Counterparty.ConnectionID, connection.Counterparty.ClientID, expectedCounterparty, []string{version})
expectedConnection := types.NewConnectionEnd(types.TRYOPEN, connection.Counterparty.ConnectionID, connection.Counterparty.ClientID, expectedCounterparty, []string{encodedVersion})
// Ensure that ChainB stored expected connectionEnd in its state during ConnOpenTry
if err := k.VerifyConnectionState(
@ -202,7 +204,7 @@ func (k Keeper) ConnOpenAck(
// Update connection state to Open
connection.State = types.OPEN
connection.Versions = []string{version}
connection.Versions = []string{encodedVersion}
k.SetConnection(ctx, connectionID, connection)
return nil
}

View File

@ -102,7 +102,9 @@ func (suite *KeeperTestSuite) TestConnOpenTry() {
_, _, err := suite.coordinator.ConnOpenInit(suite.chainA, suite.chainB, clientA, clientB)
suite.Require().NoError(err)
versions = []string{"(version won't match,[])"}
version, err := types.NewVersion("0.0", nil).Encode()
suite.Require().NoError(err)
versions = []string{version}
}, false},
{"connection state verification failed", func() {
clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, clientexported.Tendermint)
@ -140,9 +142,9 @@ func (suite *KeeperTestSuite) TestConnOpenTry() {
tc := tc
suite.Run(tc.msg, func() {
suite.SetupTest() // reset
consensusHeight = 0 // must be explicitly changed in malleate
versions = types.GetCompatibleVersions() // must be explicitly changed in malleate
suite.SetupTest() // reset
consensusHeight = 0 // must be explicitly changed in malleate
versions = types.GetCompatibleEncodedVersions() // must be explicitly changed in malleate
tc.malleate()
@ -266,6 +268,17 @@ func (suite *KeeperTestSuite) TestConnOpenAck() {
version = ""
}, false},
{"feature set verification failed - unsupported feature", func() {
clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, clientexported.Tendermint)
connA, connB, err := suite.coordinator.ConnOpenInit(suite.chainA, suite.chainB, clientA, clientB)
suite.Require().NoError(err)
err = suite.coordinator.ConnOpenTry(suite.chainB, suite.chainA, connB, connA)
suite.Require().NoError(err)
version, err = types.NewVersion(types.DefaultIBCVersionIdentifier, []string{"ORDER_ORDERED", "ORDER_UNORDERED", "ORDER_DAG"}).Encode()
suite.Require().NoError(err)
}, false},
{"self consensus state not found", func() {
clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, clientexported.Tendermint)
connA, connB, err := suite.coordinator.ConnOpenInit(suite.chainA, suite.chainB, clientA, clientB)
@ -305,9 +318,9 @@ func (suite *KeeperTestSuite) TestConnOpenAck() {
for _, tc := range testCases {
tc := tc
suite.Run(tc.msg, func() {
suite.SetupTest() // reset
version = types.GetCompatibleVersions()[0] // must be explicitly changed in malleate
consensusHeight = 0 // must be explicitly changed in malleate
suite.SetupTest() // reset
version = types.GetCompatibleEncodedVersions()[0] // must be explicitly changed in malleate
consensusHeight = 0 // must be explicitly changed in malleate
tc.malleate()

View File

@ -47,10 +47,10 @@ func (suite *KeeperTestSuite) TestSetAndGetClientConnectionPaths() {
_, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetClientConnectionPaths(suite.chainA.GetContext(), clientA)
suite.False(existed)
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetClientConnectionPaths(suite.chainA.GetContext(), clientA, types.GetCompatibleVersions())
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetClientConnectionPaths(suite.chainA.GetContext(), clientA, types.GetCompatibleEncodedVersions())
paths, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetClientConnectionPaths(suite.chainA.GetContext(), clientA)
suite.True(existed)
suite.EqualValues(types.GetCompatibleVersions(), paths)
suite.EqualValues(types.GetCompatibleEncodedVersions(), paths)
}
// create 2 connections: A0 - B0, A1 - B1
@ -61,8 +61,8 @@ func (suite KeeperTestSuite) TestGetAllConnections() {
counterpartyB0 := types.NewCounterparty(clientB, connB0.ID, suite.chainB.GetPrefix()) // connection B0
counterpartyB1 := types.NewCounterparty(clientB, connB1.ID, suite.chainB.GetPrefix()) // connection B1
conn1 := types.NewConnectionEnd(types.OPEN, connA0.ID, clientA, counterpartyB0, types.GetCompatibleVersions()) // A0 - B0
conn2 := types.NewConnectionEnd(types.OPEN, connA1.ID, clientA, counterpartyB1, types.GetCompatibleVersions()) // A1 - B1
conn1 := types.NewConnectionEnd(types.OPEN, connA0.ID, clientA, counterpartyB0, types.GetCompatibleEncodedVersions()) // A0 - B0
conn2 := types.NewConnectionEnd(types.OPEN, connA1.ID, clientA, counterpartyB1, types.GetCompatibleEncodedVersions()) // A1 - B1
expConnections := []types.ConnectionEnd{conn1, conn2}
connections := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetAllConnections(suite.chainA.GetContext())

View File

@ -60,7 +60,7 @@ func (c ConnectionEnd) ValidateBasic() error {
return sdkerrors.Wrap(sdkerrors.ErrInvalidVersion, "empty connection versions")
}
for _, version := range c.Versions {
if err := host.ConnectionVersionValidator(version); err != nil {
if err := ValidateVersion(version); err != nil {
return err
}
}

View File

@ -34,7 +34,8 @@ const (
UNINITIALIZED State = 0
// A connection end has just started the opening handshake.
INIT State = 1
// A connection end has acknowledged the handshake step on the counterparty chain.
// A connection end has acknowledged the handshake step on the counterparty
// chain.
TRYOPEN State = 2
// A connection end has completed the handshake.
OPEN State = 3
@ -132,14 +133,15 @@ func (m *MsgConnectionOpenInit) GetSigner() github_com_cosmos_cosmos_sdk_types.A
return nil
}
// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a connection
// on Chain B.
// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a
// connection on Chain B.
type MsgConnectionOpenTry struct {
ClientID string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"`
ConnectionID string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"`
Counterparty Counterparty `protobuf:"bytes,3,opt,name=counterparty,proto3" json:"counterparty"`
CounterpartyVersions []string `protobuf:"bytes,4,rep,name=counterparty_versions,json=counterpartyVersions,proto3" json:"counterparty_versions,omitempty" yaml:"counterparty_versions"`
// proof of the initialization the connection on Chain A: `UNITIALIZED -> INIT`
// proof of the initialization the connection on Chain A: `UNITIALIZED ->
// INIT`
ProofInit []byte `protobuf:"bytes,5,opt,name=proof_init,json=proofInit,proto3" json:"proof_init,omitempty" yaml:"proof_init"`
ProofHeight uint64 `protobuf:"varint,6,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height,omitempty"`
// proof of client consensus state
@ -244,12 +246,13 @@ func (m *MsgConnectionOpenTry) GetSigner() github_com_cosmos_cosmos_sdk_types.Ac
return nil
}
// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to acknowledge
// the change of connection state to TRYOPEN on Chain B.
// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to
// acknowledge the change of connection state to TRYOPEN on Chain B.
type MsgConnectionOpenAck struct {
ConnectionID string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"`
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
// proof of the initialization the connection on Chain B: `UNITIALIZED -> TRYOPEN`
// proof of the initialization the connection on Chain B: `UNITIALIZED ->
// TRYOPEN`
ProofTry []byte `protobuf:"bytes,3,opt,name=proof_try,json=proofTry,proto3" json:"proof_try,omitempty" yaml:"proof_try"`
ProofHeight uint64 `protobuf:"varint,4,opt,name=proof_height,json=proofHeight,proto3" json:"proof_height,omitempty" yaml:"proof_height"`
// proof of client consensus state
@ -340,8 +343,8 @@ func (m *MsgConnectionOpenAck) GetSigner() github_com_cosmos_cosmos_sdk_types.Ac
return nil
}
// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to acknowledge
// the change of connection state to OPEN on Chain A.
// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to
// acknowledge the change of connection state to OPEN on Chain A.
type MsgConnectionOpenConfirm struct {
ConnectionID string `protobuf:"bytes,1,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"`
// proof for the change of the connection state on Chain A: `INIT -> OPEN`
@ -411,16 +414,15 @@ func (m *MsgConnectionOpenConfirm) GetSigner() github_com_cosmos_cosmos_sdk_type
return nil
}
// ConnectionEnd defines a stateful object on a chain connected to another separate
// one.
// NOTE: there must only be 2 defined ConnectionEnds to establish a connection
// between two chains.
// ConnectionEnd defines a stateful object on a chain connected to another
// separate one. NOTE: there must only be 2 defined ConnectionEnds to establish
// a connection between two chains.
type ConnectionEnd struct {
// connection identifier.
ID string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"`
// client associated with this connection.
ClientID string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"`
// opaque string which can be utilised to determine encodings or protocols for
// IBC version which can be utilised to determine encodings or protocols for
// channels or packets utilising this connection
Versions []string `protobuf:"bytes,3,rep,name=versions,proto3" json:"versions,omitempty"`
// current state of the connection end.
@ -464,9 +466,11 @@ var xxx_messageInfo_ConnectionEnd proto.InternalMessageInfo
// Counterparty defines the counterparty chain associated with a connection end.
type Counterparty struct {
// identifies the client on the counterparty chain associated with a given connection.
// identifies the client on the counterparty chain associated with a given
// connection.
ClientID string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty" yaml:"client_id"`
// identifies the connection end on the counterparty chain associated with a given connection.
// identifies the connection end on the counterparty chain associated with a
// given connection.
ConnectionID string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"`
// commitment merkle prefix of the counterparty chain
Prefix types.MerklePrefix `protobuf:"bytes,3,opt,name=prefix,proto3" json:"prefix"`
@ -606,6 +610,48 @@ func (m *ConnectionPaths) GetPaths() []string {
return nil
}
// Version defines the versioning scheme used to negotiate the IBC verison in
// the connection handshake.
type Version struct {
// unique version identifier
Identifier string `protobuf:"bytes,1,opt,name=identifier,proto3" json:"identifier,omitempty"`
// list of features compatible with the specified identifier
Features []string `protobuf:"bytes,2,rep,name=features,proto3" json:"features,omitempty"`
}
func (m *Version) Reset() { *m = Version{} }
func (m *Version) String() string { return proto.CompactTextString(m) }
func (*Version) ProtoMessage() {}
func (*Version) Descriptor() ([]byte, []int) {
return fileDescriptor_3bf62bacf5a27ee9, []int{8}
}
func (m *Version) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *Version) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_Version.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *Version) XXX_Merge(src proto.Message) {
xxx_messageInfo_Version.Merge(m, src)
}
func (m *Version) XXX_Size() int {
return m.Size()
}
func (m *Version) XXX_DiscardUnknown() {
xxx_messageInfo_Version.DiscardUnknown(m)
}
var xxx_messageInfo_Version proto.InternalMessageInfo
func init() {
proto.RegisterEnum("ibc.connection.State", State_name, State_value)
proto.RegisterType((*MsgConnectionOpenInit)(nil), "ibc.connection.MsgConnectionOpenInit")
@ -616,67 +662,71 @@ func init() {
proto.RegisterType((*Counterparty)(nil), "ibc.connection.Counterparty")
proto.RegisterType((*ClientPaths)(nil), "ibc.connection.ClientPaths")
proto.RegisterType((*ConnectionPaths)(nil), "ibc.connection.ConnectionPaths")
proto.RegisterType((*Version)(nil), "ibc.connection.Version")
}
func init() { proto.RegisterFile("ibc/connection/connection.proto", fileDescriptor_3bf62bacf5a27ee9) }
var fileDescriptor_3bf62bacf5a27ee9 = []byte{
// 879 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x56, 0x4f, 0x6f, 0xe2, 0x46,
0x14, 0xc7, 0xc6, 0xfc, 0x1b, 0x20, 0x61, 0xbd, 0xd0, 0xb5, 0xdc, 0x95, 0xed, 0x7a, 0x2f, 0xa8,
0x55, 0xa0, 0xbb, 0x5b, 0xed, 0x01, 0xa9, 0x07, 0x20, 0x44, 0xb5, 0xd4, 0xb0, 0xc8, 0x21, 0x95,
0xba, 0x17, 0x04, 0xb6, 0x81, 0x11, 0xc1, 0x46, 0xf6, 0xa4, 0x5a, 0xbe, 0x41, 0xc4, 0xa9, 0xd7,
0x1e, 0x22, 0x55, 0xca, 0x97, 0xe8, 0x27, 0xa8, 0x72, 0xcc, 0xb1, 0x27, 0xab, 0x22, 0xdf, 0x00,
0xf5, 0xd4, 0x53, 0xe5, 0x19, 0x63, 0x1b, 0x88, 0x5a, 0xa5, 0xe4, 0x50, 0xf5, 0xc4, 0xfb, 0xf3,
0x9b, 0x37, 0xef, 0xbd, 0xdf, 0xf3, 0x63, 0x80, 0x08, 0x07, 0x5a, 0x55, 0xb3, 0x4c, 0xd3, 0xd0,
0x10, 0xb4, 0xcc, 0x88, 0x58, 0x99, 0xd9, 0x16, 0xb2, 0xd8, 0x03, 0x38, 0xd0, 0x2a, 0xa1, 0x95,
0x2f, 0x8e, 0xac, 0x91, 0x85, 0x5d, 0x55, 0x4f, 0x22, 0x28, 0xde, 0x0f, 0x33, 0x9d, 0x42, 0x34,
0x35, 0x4c, 0x14, 0x11, 0x09, 0x40, 0xfe, 0x85, 0x06, 0xa5, 0x53, 0x67, 0xd4, 0x0c, 0x02, 0xbd,
0x9f, 0x19, 0xa6, 0x62, 0x42, 0xc4, 0x7e, 0x0d, 0x32, 0xda, 0x05, 0x34, 0x4c, 0xd4, 0x83, 0x3a,
0x47, 0x49, 0x54, 0x39, 0xd3, 0x90, 0x96, 0xae, 0x98, 0x6e, 0x62, 0xa3, 0x72, 0xbc, 0x72, 0xc5,
0xc2, 0xbc, 0x3f, 0xbd, 0xa8, 0xc9, 0x01, 0x4c, 0x56, 0xd3, 0x44, 0x56, 0x74, 0xf6, 0x14, 0xe4,
0xc3, 0xec, 0xbc, 0x10, 0x34, 0x0e, 0x51, 0x5e, 0xba, 0x62, 0x2e, 0xbc, 0x0d, 0x87, 0x29, 0xfa,
0x61, 0xa2, 0x70, 0x59, 0xcd, 0x85, 0xba, 0xa2, 0xb3, 0x27, 0x20, 0xa7, 0x59, 0x97, 0x26, 0x32,
0xec, 0x59, 0xdf, 0x46, 0x73, 0x2e, 0x2e, 0x51, 0xe5, 0xec, 0x9b, 0x97, 0x95, 0xcd, 0x2e, 0x54,
0x9a, 0x11, 0x4c, 0x83, 0xb9, 0x75, 0xc5, 0x98, 0xba, 0x71, 0x8e, 0x55, 0x40, 0xd2, 0x81, 0x23,
0xd3, 0xb0, 0x39, 0x46, 0xa2, 0xca, 0xb9, 0xc6, 0xeb, 0x3f, 0x5d, 0xf1, 0x68, 0x04, 0xd1, 0xf8,
0x72, 0x50, 0xd1, 0xac, 0x69, 0x55, 0xb3, 0x9c, 0xa9, 0xe5, 0xf8, 0x3f, 0x47, 0x8e, 0x3e, 0xa9,
0xa2, 0xf9, 0xcc, 0x70, 0x2a, 0x75, 0x4d, 0xab, 0xeb, 0xba, 0x6d, 0x38, 0x8e, 0xea, 0x07, 0x90,
0xff, 0x60, 0x40, 0x71, 0xa7, 0x75, 0x5d, 0x7b, 0xfe, 0x3f, 0xed, 0xdc, 0x39, 0x28, 0x45, 0xf5,
0xde, 0x0f, 0x86, 0xed, 0x40, 0xcb, 0x74, 0x38, 0x46, 0x8a, 0x7b, 0x15, 0xae, 0x5c, 0xf1, 0xe5,
0x3a, 0x9d, 0x07, 0x60, 0xb2, 0x5a, 0x8c, 0xda, 0xbf, 0xf3, 0xcd, 0xec, 0x57, 0x00, 0xcc, 0x6c,
0xcb, 0x1a, 0xf6, 0xa0, 0x09, 0x11, 0x97, 0xc0, 0xa4, 0x94, 0x56, 0xae, 0xf8, 0x8c, 0xc4, 0x0a,
0x7d, 0xb2, 0x9a, 0xc1, 0x0a, 0x1e, 0xce, 0xcf, 0x40, 0x8e, 0x78, 0xc6, 0x06, 0x1c, 0x8d, 0x11,
0x97, 0x94, 0xa8, 0x32, 0xa3, 0x66, 0xb1, 0xed, 0x1b, 0x6c, 0x62, 0x9b, 0xe0, 0x90, 0x40, 0x34,
0xcb, 0x74, 0x0c, 0xd3, 0xb9, 0x74, 0xb8, 0x14, 0x8e, 0xce, 0xaf, 0x5c, 0xf1, 0x93, 0x68, 0xf4,
0x00, 0x20, 0xab, 0x07, 0xd8, 0xd2, 0x5c, 0x1b, 0xd8, 0x13, 0x50, 0x08, 0xbc, 0xeb, 0xbb, 0xd2,
0xde, 0x5d, 0x8d, 0x4f, 0x57, 0xae, 0xf8, 0x22, 0x68, 0xff, 0x06, 0x42, 0x56, 0x0f, 0x03, 0x93,
0x9f, 0x4c, 0x38, 0x76, 0x99, 0x7d, 0xc7, 0xee, 0xd7, 0xf8, 0x03, 0x63, 0x57, 0xd7, 0x26, 0xbb,
0x73, 0x43, 0xed, 0x35, 0x37, 0x1c, 0x48, 0xf9, 0xdc, 0x91, 0x01, 0x54, 0xd7, 0x2a, 0xfb, 0x1a,
0x10, 0x26, 0x7a, 0xc8, 0x26, 0xe3, 0x94, 0x6b, 0x14, 0xc3, 0x99, 0x0e, 0x5c, 0xb2, 0x9a, 0xc6,
0xb2, 0xf7, 0x49, 0xd4, 0xb6, 0xf8, 0x62, 0x70, 0x0f, 0x5f, 0xac, 0x5c, 0xf1, 0x79, 0xf4, 0xd4,
0xba, 0x7f, 0xff, 0x44, 0x64, 0xe2, 0x49, 0x88, 0x4c, 0xee, 0x45, 0x64, 0x6a, 0x5f, 0x22, 0x6f,
0x68, 0xc0, 0xed, 0x10, 0xd9, 0xb4, 0xcc, 0x21, 0xb4, 0xa7, 0x4f, 0x4d, 0x66, 0x40, 0x59, 0x5f,
0x9b, 0x60, 0x3a, 0x1f, 0xa0, 0xac, 0xaf, 0x4d, 0xd6, 0x94, 0x79, 0xe3, 0xb4, 0x4d, 0x59, 0xfc,
0x11, 0x94, 0x3d, 0xe1, 0x96, 0x5d, 0xd0, 0x20, 0x1f, 0x16, 0xdc, 0x32, 0x75, 0xf6, 0x15, 0xa0,
0x83, 0x7e, 0x3c, 0x5f, 0xba, 0x22, 0x8d, 0xbb, 0x90, 0x21, 0x49, 0x79, 0xa5, 0xd3, 0x50, 0xdf,
0xdc, 0xc1, 0xf4, 0xa3, 0x77, 0x30, 0x0f, 0xd2, 0xc1, 0x7e, 0x8b, 0x7b, 0xfb, 0x4d, 0x0d, 0x74,
0xf6, 0x0b, 0x90, 0x70, 0x50, 0x1f, 0x19, 0xb8, 0xb6, 0x83, 0x37, 0xa5, 0xed, 0x4d, 0x7a, 0xe6,
0x39, 0x55, 0x82, 0xd9, 0xd9, 0xbe, 0x89, 0x7f, 0xb7, 0x7d, 0x6b, 0xcc, 0xd5, 0xcf, 0x62, 0x4c,
0x76, 0x29, 0x90, 0x8b, 0x42, 0xff, 0x63, 0x7f, 0x35, 0x35, 0x90, 0x9c, 0xd9, 0xc6, 0x10, 0x7e,
0xdc, 0xfa, 0x93, 0x09, 0xde, 0x1c, 0xa7, 0x86, 0x3d, 0xb9, 0x30, 0x3a, 0x18, 0xe3, 0x97, 0xe9,
0x9f, 0xf0, 0x0b, 0x7c, 0x05, 0xb2, 0x24, 0xf5, 0x4e, 0x1f, 0x8d, 0x1d, 0xb6, 0x08, 0x12, 0x33,
0x4f, 0xe0, 0x28, 0xcc, 0x01, 0x51, 0xe4, 0x21, 0x38, 0x0c, 0x93, 0x23, 0xc0, 0x3d, 0xfb, 0x10,
0xdc, 0x43, 0x47, 0xee, 0xf9, 0xfc, 0x27, 0x0a, 0x24, 0x30, 0x99, 0xec, 0x3b, 0x20, 0x9e, 0x75,
0xeb, 0xdd, 0x56, 0xef, 0xbc, 0xad, 0xb4, 0x95, 0xae, 0x52, 0xff, 0x56, 0xf9, 0xd0, 0x3a, 0xee,
0x9d, 0xb7, 0xcf, 0x3a, 0xad, 0xa6, 0x72, 0xa2, 0xb4, 0x8e, 0x0b, 0x31, 0xfe, 0xd9, 0xe2, 0x5a,
0xca, 0x6f, 0x00, 0x58, 0x0e, 0x00, 0x72, 0xce, 0x33, 0x16, 0x28, 0x3e, 0xbd, 0xb8, 0x96, 0x18,
0x4f, 0x66, 0x05, 0x90, 0x27, 0x9e, 0xae, 0xfa, 0xfd, 0xfb, 0x4e, 0xab, 0x5d, 0xa0, 0xf9, 0xec,
0xe2, 0x5a, 0x4a, 0xf9, 0x6a, 0x78, 0x12, 0x3b, 0xe3, 0xe4, 0xa4, 0x27, 0xf3, 0xcc, 0xd5, 0x8d,
0x10, 0x6b, 0x74, 0x6e, 0x97, 0x02, 0x75, 0xb7, 0x14, 0xa8, 0xdf, 0x97, 0x02, 0xf5, 0xe3, 0xbd,
0x10, 0xbb, 0xbb, 0x17, 0x62, 0xbf, 0xdd, 0x0b, 0xb1, 0x0f, 0xef, 0xfe, 0xf6, 0x3b, 0xfb, 0x58,
0xf5, 0x5e, 0x84, 0x5f, 0xbe, 0x3d, 0x8a, 0xbc, 0x2d, 0xf1, 0xb7, 0x37, 0x48, 0xe2, 0x07, 0xe1,
0xdb, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x37, 0x42, 0xa5, 0xea, 0x7a, 0x0a, 0x00, 0x00,
// 914 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x56, 0xcd, 0x6e, 0xdb, 0x46,
0x10, 0x16, 0x29, 0xea, 0x6f, 0x2c, 0xdb, 0x0a, 0x23, 0x37, 0x04, 0x1b, 0x90, 0x2c, 0x73, 0x11,
0x5a, 0x58, 0x6a, 0x92, 0x22, 0x07, 0x03, 0x3d, 0x48, 0xb2, 0x8c, 0x12, 0xad, 0x1d, 0x81, 0x96,
0x0b, 0x34, 0x17, 0x41, 0x26, 0x57, 0xf2, 0x42, 0x16, 0x29, 0x90, 0xeb, 0x22, 0x7e, 0x83, 0xc0,
0xa7, 0x5e, 0x7b, 0x30, 0x50, 0x20, 0x2f, 0xd1, 0x27, 0x28, 0x72, 0xcc, 0xb1, 0x27, 0xa2, 0x90,
0xdf, 0x40, 0xe8, 0xa9, 0xa7, 0x82, 0xbb, 0x14, 0x49, 0x59, 0x46, 0x8b, 0x54, 0x3e, 0x14, 0x39,
0x71, 0x7e, 0xbe, 0x9d, 0xdd, 0x99, 0x6f, 0x38, 0xbb, 0xa0, 0xe2, 0x53, 0xab, 0x61, 0xb9, 0x8e,
0x83, 0x2c, 0x82, 0x5d, 0x27, 0x25, 0xd6, 0xa7, 0x9e, 0x4b, 0x5c, 0x71, 0x0b, 0x9f, 0x5a, 0xf5,
0xc4, 0x2a, 0x57, 0x47, 0xee, 0xc8, 0xa5, 0xae, 0x46, 0x28, 0x31, 0x94, 0x1c, 0x85, 0x99, 0x4c,
0x30, 0x99, 0x20, 0x87, 0xa4, 0x44, 0x06, 0xd0, 0x7f, 0xe5, 0x61, 0xe7, 0xd0, 0x1f, 0xb5, 0xe3,
0x40, 0x2f, 0xa7, 0xc8, 0x31, 0x1c, 0x4c, 0xc4, 0xaf, 0xa1, 0x64, 0x9d, 0x63, 0xe4, 0x90, 0x3e,
0xb6, 0x25, 0x4e, 0xe3, 0x6a, 0xa5, 0x96, 0x36, 0x0b, 0xd4, 0x62, 0x9b, 0x1a, 0x8d, 0xfd, 0x79,
0xa0, 0x56, 0x2e, 0x07, 0x93, 0xf3, 0x3d, 0x3d, 0x86, 0xe9, 0x66, 0x91, 0xc9, 0x86, 0x2d, 0x1e,
0xc2, 0x66, 0x72, 0xba, 0x30, 0x04, 0x4f, 0x43, 0xd4, 0x66, 0x81, 0x5a, 0x4e, 0x76, 0xa3, 0x61,
0xaa, 0x51, 0x98, 0x34, 0x5c, 0x37, 0xcb, 0x89, 0x6e, 0xd8, 0xe2, 0x01, 0x94, 0x2d, 0xf7, 0xc2,
0x21, 0xc8, 0x9b, 0x0e, 0x3c, 0x72, 0x29, 0x65, 0x35, 0xae, 0xb6, 0xf1, 0xec, 0x71, 0x7d, 0xb9,
0x0a, 0xf5, 0x76, 0x0a, 0xd3, 0x12, 0xde, 0x05, 0x6a, 0xc6, 0x5c, 0x5a, 0x27, 0x1a, 0x90, 0xf7,
0xf1, 0xc8, 0x41, 0x9e, 0x24, 0x68, 0x5c, 0xad, 0xdc, 0x7a, 0xfa, 0x57, 0xa0, 0xee, 0x8e, 0x30,
0x39, 0xbb, 0x38, 0xad, 0x5b, 0xee, 0xa4, 0x61, 0xb9, 0xfe, 0xc4, 0xf5, 0xa3, 0xcf, 0xae, 0x6f,
0x8f, 0x1b, 0xe4, 0x72, 0x8a, 0xfc, 0x7a, 0xd3, 0xb2, 0x9a, 0xb6, 0xed, 0x21, 0xdf, 0x37, 0xa3,
0x00, 0xfa, 0x9f, 0x02, 0x54, 0x57, 0x4a, 0xd7, 0xf3, 0x2e, 0x3f, 0xd2, 0xca, 0x9d, 0xc0, 0x4e,
0x5a, 0xef, 0xff, 0x88, 0x3c, 0x1f, 0xbb, 0x8e, 0x2f, 0x09, 0x5a, 0x36, 0xcc, 0x70, 0x1e, 0xa8,
0x8f, 0x17, 0xc7, 0xb9, 0x03, 0xa6, 0x9b, 0xd5, 0xb4, 0xfd, 0xfb, 0xc8, 0x2c, 0x7e, 0x05, 0x30,
0xf5, 0x5c, 0x77, 0xd8, 0xc7, 0x0e, 0x26, 0x52, 0x8e, 0x92, 0xb2, 0x33, 0x0f, 0xd4, 0x07, 0x2c,
0x56, 0xe2, 0xd3, 0xcd, 0x12, 0x55, 0x68, 0x73, 0x7e, 0x06, 0x65, 0xe6, 0x39, 0x43, 0x78, 0x74,
0x46, 0xa4, 0xbc, 0xc6, 0xd5, 0x04, 0x73, 0x83, 0xda, 0xbe, 0xa1, 0x26, 0xb1, 0x0d, 0xdb, 0x0c,
0x62, 0xb9, 0x8e, 0x8f, 0x1c, 0xff, 0xc2, 0x97, 0x0a, 0x34, 0xba, 0x3c, 0x0f, 0xd4, 0x4f, 0xd2,
0xd1, 0x63, 0x80, 0x6e, 0x6e, 0x51, 0x4b, 0x7b, 0x61, 0x10, 0x0f, 0xa0, 0x12, 0x7b, 0x17, 0x7b,
0x15, 0xc3, 0xbd, 0x5a, 0x9f, 0xce, 0x03, 0xf5, 0x51, 0x5c, 0xfe, 0x25, 0x84, 0x6e, 0x6e, 0xc7,
0xa6, 0xe8, 0x30, 0x49, 0xdb, 0x95, 0xd6, 0x6d, 0xbb, 0xdf, 0xb2, 0x77, 0xb4, 0x5d, 0xd3, 0x1a,
0xaf, 0xf6, 0x0d, 0xb7, 0x56, 0xdf, 0x48, 0x50, 0x88, 0xb8, 0x63, 0x0d, 0x68, 0x2e, 0x54, 0xf1,
0x29, 0x30, 0x26, 0xfa, 0xc4, 0x63, 0xed, 0x54, 0x6e, 0x55, 0x93, 0x9e, 0x8e, 0x5d, 0xba, 0x59,
0xa4, 0x72, 0xf8, 0x4b, 0xec, 0xdd, 0xe2, 0x4b, 0xa0, 0x35, 0x7c, 0x34, 0x0f, 0xd4, 0x87, 0xe9,
0x55, 0x8b, 0xfa, 0xfd, 0x1b, 0x91, 0xb9, 0x7b, 0x21, 0x32, 0xbf, 0x16, 0x91, 0x85, 0x75, 0x89,
0x7c, 0xcb, 0x83, 0xb4, 0x42, 0x64, 0xdb, 0x75, 0x86, 0xd8, 0x9b, 0xdc, 0x37, 0x99, 0x31, 0x65,
0x03, 0x6b, 0x4c, 0xe9, 0xbc, 0x83, 0xb2, 0x81, 0x35, 0x5e, 0x50, 0x16, 0xb6, 0xd3, 0x6d, 0xca,
0xb2, 0x1f, 0x40, 0xd9, 0x3d, 0x4e, 0xd9, 0x2b, 0x1e, 0x36, 0x93, 0x84, 0x3b, 0x8e, 0x2d, 0x3e,
0x01, 0x3e, 0xae, 0xc7, 0xc3, 0x59, 0xa0, 0xf2, 0xb4, 0x0a, 0x25, 0x76, 0xa8, 0x30, 0x75, 0x1e,
0xdb, 0xcb, 0x33, 0x98, 0xff, 0xe0, 0x19, 0x2c, 0x43, 0x31, 0x9e, 0x6f, 0xd9, 0x70, 0xbe, 0x99,
0xb1, 0x2e, 0x7e, 0x01, 0x39, 0x9f, 0x0c, 0x08, 0xa2, 0xb9, 0x6d, 0x3d, 0xdb, 0xb9, 0x3d, 0x49,
0x8f, 0x43, 0xa7, 0xc9, 0x30, 0x2b, 0xd3, 0x37, 0xf7, 0xdf, 0xa6, 0xef, 0x9e, 0xf0, 0xe6, 0x17,
0x35, 0xa3, 0x07, 0x1c, 0x94, 0xd3, 0xd0, 0xff, 0xd9, 0x55, 0xb3, 0x07, 0xf9, 0xa9, 0x87, 0x86,
0xf8, 0xf5, 0xad, 0x4b, 0x26, 0x7e, 0x73, 0x1c, 0x22, 0x6f, 0x7c, 0x8e, 0xba, 0x14, 0x13, 0xa5,
0x19, 0xad, 0x88, 0x12, 0x7c, 0x02, 0x1b, 0xec, 0xe8, 0xdd, 0x01, 0x39, 0xf3, 0xc5, 0x2a, 0xe4,
0xa6, 0xa1, 0x20, 0x71, 0x94, 0x03, 0xa6, 0xe8, 0x43, 0xd8, 0x4e, 0x0e, 0xc7, 0x80, 0x6b, 0xd6,
0x21, 0xde, 0x87, 0x4f, 0xef, 0xf3, 0x2d, 0x14, 0xa2, 0x6b, 0x4a, 0x54, 0x00, 0xb0, 0x8d, 0x1c,
0x82, 0x87, 0x18, 0x79, 0x6c, 0x03, 0x33, 0x65, 0x09, 0xfb, 0x65, 0x88, 0x06, 0xe4, 0xc2, 0x43,
0x8b, 0x18, 0xb1, 0xce, 0x32, 0xfb, 0xfc, 0x67, 0x0e, 0x72, 0xb4, 0x33, 0xc4, 0x17, 0xa0, 0x1e,
0xf7, 0x9a, 0xbd, 0x4e, 0xff, 0xe4, 0xc8, 0x38, 0x32, 0x7a, 0x46, 0xf3, 0x3b, 0xe3, 0x55, 0x67,
0xbf, 0x7f, 0x72, 0x74, 0xdc, 0xed, 0xb4, 0x8d, 0x03, 0xa3, 0xb3, 0x5f, 0xc9, 0xc8, 0x0f, 0xae,
0xae, 0xb5, 0xcd, 0x25, 0x80, 0x28, 0x01, 0xb0, 0x75, 0xa1, 0xb1, 0xc2, 0xc9, 0xc5, 0xab, 0x6b,
0x4d, 0x08, 0x65, 0x51, 0x81, 0x4d, 0xe6, 0xe9, 0x99, 0x3f, 0xbc, 0xec, 0x76, 0x8e, 0x2a, 0xbc,
0xbc, 0x71, 0x75, 0xad, 0x15, 0x22, 0x35, 0x59, 0x49, 0x9d, 0x59, 0xb6, 0x32, 0x94, 0x65, 0xe1,
0xcd, 0x5b, 0x25, 0xd3, 0xea, 0xbe, 0x9b, 0x29, 0xdc, 0xfb, 0x99, 0xc2, 0xfd, 0x31, 0x53, 0xb8,
0x9f, 0x6e, 0x94, 0xcc, 0xfb, 0x1b, 0x25, 0xf3, 0xfb, 0x8d, 0x92, 0x79, 0xf5, 0xe2, 0x1f, 0x7f,
0xda, 0xd7, 0x8d, 0xf0, 0x79, 0xf9, 0xe5, 0xf3, 0xdd, 0xd4, 0x43, 0x95, 0xfe, 0xc8, 0xa7, 0x79,
0xfa, 0xba, 0x7c, 0xfe, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaf, 0x4e, 0x8d, 0xdb, 0xc7, 0x0a,
0x00, 0x00,
}
func (m *MsgConnectionOpenInit) Marshal() (dAtA []byte, err error) {
@ -1116,6 +1166,45 @@ func (m *ConnectionPaths) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *Version) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Version) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *Version) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Features) > 0 {
for iNdEx := len(m.Features) - 1; iNdEx >= 0; iNdEx-- {
i -= len(m.Features[iNdEx])
copy(dAtA[i:], m.Features[iNdEx])
i = encodeVarintConnection(dAtA, i, uint64(len(m.Features[iNdEx])))
i--
dAtA[i] = 0x12
}
}
if len(m.Identifier) > 0 {
i -= len(m.Identifier)
copy(dAtA[i:], m.Identifier)
i = encodeVarintConnection(dAtA, i, uint64(len(m.Identifier)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintConnection(dAtA []byte, offset int, v uint64) int {
offset -= sovConnection(v)
base := offset
@ -1333,6 +1422,25 @@ func (m *ConnectionPaths) Size() (n int) {
return n
}
func (m *Version) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Identifier)
if l > 0 {
n += 1 + l + sovConnection(uint64(l))
}
if len(m.Features) > 0 {
for _, s := range m.Features {
l = len(s)
n += 1 + l + sovConnection(uint64(l))
}
}
return n
}
func sovConnection(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
@ -2827,6 +2935,123 @@ func (m *ConnectionPaths) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *Version) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConnection
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Version: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Version: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Identifier", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConnection
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthConnection
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthConnection
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Identifier = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Features", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConnection
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthConnection
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthConnection
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Features = append(m.Features, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipConnection(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthConnection
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthConnection
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipConnection(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0

View File

@ -7,6 +7,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
var (
@ -24,17 +25,17 @@ func TestConnectionValidateBasic(t *testing.T) {
}{
{
"valid connection",
types.ConnectionEnd{connectionID, clientID, []string{types.DefaultIBCVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}},
types.ConnectionEnd{connectionID, clientID, []string{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}},
true,
},
{
"invalid connection id",
types.ConnectionEnd{"(connectionIDONE)", clientID, []string{types.DefaultIBCVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}},
types.ConnectionEnd{"(connectionIDONE)", clientID, []string{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}},
false,
},
{
"invalid client id",
types.ConnectionEnd{connectionID, "(clientID1)", []string{types.DefaultIBCVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}},
types.ConnectionEnd{connectionID, "(clientID1)", []string{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}},
false,
},
{
@ -49,7 +50,7 @@ func TestConnectionValidateBasic(t *testing.T) {
},
{
"invalid counterparty",
types.ConnectionEnd{connectionID, clientID, []string{types.DefaultIBCVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, emptyPrefix}},
types.ConnectionEnd{connectionID, clientID, []string{ibctesting.ConnectionVersion}, types.INIT, types.Counterparty{clientID2, connectionID2, emptyPrefix}},
false,
},
}

View File

@ -8,6 +8,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
func TestValidateGenesis(t *testing.T) {
@ -26,7 +27,7 @@ func TestValidateGenesis(t *testing.T) {
name: "valid genesis",
genState: types.NewGenesisState(
[]types.ConnectionEnd{
types.NewConnectionEnd(types.INIT, connectionID, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{types.DefaultIBCVersion}),
types.NewConnectionEnd(types.INIT, connectionID, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{ibctesting.ConnectionVersion}),
},
[]types.ConnectionPaths{
{clientID, []string{host.ConnectionPath(connectionID)}},
@ -38,7 +39,7 @@ func TestValidateGenesis(t *testing.T) {
name: "invalid connection",
genState: types.NewGenesisState(
[]types.ConnectionEnd{
types.NewConnectionEnd(types.INIT, connectionID, "(CLIENTIDONE)", types.Counterparty{clientID, connectionID, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{types.DefaultIBCVersion}),
types.NewConnectionEnd(types.INIT, connectionID, "(CLIENTIDONE)", types.Counterparty{clientID, connectionID, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{ibctesting.ConnectionVersion}),
},
[]types.ConnectionPaths{
{clientID, []string{host.ConnectionPath(connectionID)}},
@ -50,7 +51,7 @@ func TestValidateGenesis(t *testing.T) {
name: "invalid client id",
genState: types.NewGenesisState(
[]types.ConnectionEnd{
types.NewConnectionEnd(types.INIT, connectionID, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{types.DefaultIBCVersion}),
types.NewConnectionEnd(types.INIT, connectionID, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{ibctesting.ConnectionVersion}),
},
[]types.ConnectionPaths{
{"(CLIENTIDONE)", []string{host.ConnectionPath(connectionID)}},
@ -62,7 +63,7 @@ func TestValidateGenesis(t *testing.T) {
name: "invalid path",
genState: types.NewGenesisState(
[]types.ConnectionEnd{
types.NewConnectionEnd(types.INIT, connectionID, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{types.DefaultIBCVersion}),
types.NewConnectionEnd(types.INIT, connectionID, clientID, types.Counterparty{clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))}, []string{ibctesting.ConnectionVersion}),
},
[]types.ConnectionPaths{
{clientID, []string{connectionID}},

View File

@ -102,9 +102,9 @@ func (msg MsgConnectionOpenTry) ValidateBasic() error {
if len(msg.CounterpartyVersions) == 0 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidVersion, "empty counterparty versions")
}
for _, version := range msg.CounterpartyVersions {
if err := host.ConnectionVersionValidator(version); err != nil {
return err
for i, version := range msg.CounterpartyVersions {
if err := ValidateVersion(version); err != nil {
return sdkerrors.Wrapf(err, "basic validation failed on version with index %d", i)
}
}
if len(msg.ProofInit) == 0 {
@ -169,7 +169,7 @@ func (msg MsgConnectionOpenAck) ValidateBasic() error {
if err := host.ConnectionIdentifierValidator(msg.ConnectionID); err != nil {
return sdkerrors.Wrap(err, "invalid connection ID")
}
if err := host.ConnectionVersionValidator(msg.Version); err != nil {
if err := ValidateVersion(msg.Version); err != nil {
return err
}
if len(msg.ProofTry) == 0 {

View File

@ -16,6 +16,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
var (
@ -103,18 +104,19 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() {
signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht")
testMsgs := []*types.MsgConnectionOpenTry{
types.NewMsgConnectionOpenTry("test/conn1", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{types.DefaultIBCVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "test/iris", "connectiontotest", "clienttotest", prefix, []string{types.DefaultIBCVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "ibc/test", "clienttotest", prefix, []string{types.DefaultIBCVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "test/conn1", prefix, []string{types.DefaultIBCVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", emptyPrefix, []string{types.DefaultIBCVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("test/conn1", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{ibctesting.ConnectionVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "test/iris", "connectiontotest", "clienttotest", prefix, []string{ibctesting.ConnectionVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "ibc/test", "clienttotest", prefix, []string{ibctesting.ConnectionVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "test/conn1", prefix, []string{ibctesting.ConnectionVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", emptyPrefix, []string{ibctesting.ConnectionVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{types.DefaultIBCVersion}, emptyProof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{types.DefaultIBCVersion}, suite.proof, emptyProof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{types.DefaultIBCVersion}, suite.proof, suite.proof, 0, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{types.DefaultIBCVersion}, suite.proof, suite.proof, 10, 0, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{types.DefaultIBCVersion}, suite.proof, suite.proof, 10, 10, nil),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{types.DefaultIBCVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{ibctesting.ConnectionVersion}, emptyProof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{ibctesting.ConnectionVersion}, suite.proof, emptyProof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{ibctesting.ConnectionVersion}, suite.proof, suite.proof, 0, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{ibctesting.ConnectionVersion}, suite.proof, suite.proof, 10, 0, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{ibctesting.ConnectionVersion}, suite.proof, suite.proof, 10, 10, nil),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{ibctesting.ConnectionVersion}, suite.proof, suite.proof, 10, 10, signer),
types.NewMsgConnectionOpenTry("ibcconntest", "clienttotesta", "connectiontotest", "clienttotest", prefix, []string{"(invalid version)"}, suite.proof, suite.proof, 10, 10, signer),
}
var testCases = []struct {
@ -134,6 +136,7 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenTry() {
{testMsgs[9], false, "invalid consensusHeight"},
{testMsgs[10], false, "empty singer"},
{testMsgs[11], true, "success"},
{testMsgs[12], false, "invalid version"},
}
for i, tc := range testCases {
@ -150,14 +153,14 @@ func (suite *MsgTestSuite) TestNewMsgConnectionOpenAck() {
signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht")
testMsgs := []*types.MsgConnectionOpenAck{
types.NewMsgConnectionOpenAck("test/conn1", suite.proof, suite.proof, 10, 10, types.DefaultIBCVersion, signer),
types.NewMsgConnectionOpenAck("ibcconntest", emptyProof, suite.proof, 10, 10, types.DefaultIBCVersion, signer),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, emptyProof, 10, 10, types.DefaultIBCVersion, signer),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 0, 10, types.DefaultIBCVersion, signer),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 0, types.DefaultIBCVersion, signer),
types.NewMsgConnectionOpenAck("test/conn1", suite.proof, suite.proof, 10, 10, ibctesting.ConnectionVersion, signer),
types.NewMsgConnectionOpenAck("ibcconntest", emptyProof, suite.proof, 10, 10, ibctesting.ConnectionVersion, signer),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, emptyProof, 10, 10, ibctesting.ConnectionVersion, signer),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 0, 10, ibctesting.ConnectionVersion, signer),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 0, ibctesting.ConnectionVersion, signer),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, "", signer),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, types.DefaultIBCVersion, nil),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, types.DefaultIBCVersion, signer),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, ibctesting.ConnectionVersion, nil),
types.NewMsgConnectionOpenAck("ibcconntest", suite.proof, suite.proof, 10, 10, ibctesting.ConnectionVersion, signer),
}
var testCases = []struct {
msg *types.MsgConnectionOpenAck

View File

@ -1,127 +1,184 @@
package types
import (
"fmt"
"strings"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)
var (
// DefaultIBCVersion represents the latest supported version of IBC.
// The current version supports only ORDERED and UNORDERED channels.
DefaultIBCVersion = CreateVersionString("1", []string{"ORDER_ORDERED", "ORDER_UNORDERED"})
// DefaultIBCVersion represents the latest supported version of IBC used
// in connection version negotiation. The current version supports only
// ORDERED and UNORDERED channels and requires at least one channel type
// to be agreed upon.
DefaultIBCVersion = NewVersion(DefaultIBCVersionIdentifier, []string{"ORDER_ORDERED", "ORDER_UNORDERED"})
// DefaultIBCVersionIdentifier is the IBC v1.0.0 protocol version identifier
DefaultIBCVersionIdentifier = "1"
// AllowNilFeatureSet is a helper map to indicate if a specified version
// identifier is allowed to have a nil feature set. Any versions supported,
// but not included in the map default to not supporting nil feature sets.
allowNilFeatureSet = map[string]bool{
DefaultIBCVersionIdentifier: false,
}
)
// NewVersion returns a new instance of Version.
func NewVersion(identifier string, features []string) Version {
return Version{
Identifier: identifier,
Features: features,
}
}
// GetIdentifier implements the VersionI interface
func (version Version) GetIdentifier() string {
return version.Identifier
}
// GetFeatures implements the VersionI interface
func (version Version) GetFeatures() []string {
return version.Features
}
// ValidateVersion does basic validation of the version identifier and
// features. It unmarshals the version string into a Version object.
func ValidateVersion(encodedVersion string) error {
var version Version
if err := SubModuleCdc.UnmarshalBinaryBare([]byte(encodedVersion), &version); err != nil {
return sdkerrors.Wrapf(err, "failed to unmarshal version string %s", encodedVersion)
}
if strings.TrimSpace(version.Identifier) == "" {
return sdkerrors.Wrap(ErrInvalidVersion, "version identifier cannot be blank")
}
for i, feature := range version.Features {
if strings.TrimSpace(feature) == "" {
return sdkerrors.Wrapf(ErrInvalidVersion, "feature cannot be blank, index %d", i)
}
}
return nil
}
// Encode proto encodes the version and returns the bytes as a string.
func (version Version) Encode() (string, error) {
encodedVersion, err := SubModuleCdc.MarshalBinaryBare(&version)
if err != nil {
return "", err
}
return string(encodedVersion), nil
}
// EncodeVersions iterates over the provided versions and marshals each
// into proto encoded strings. This represents the stored value of the version
// in the connection end as well as the value passed over the wire.
func EncodeVersions(versions []Version) ([]string, error) {
encodedVersions := make([]string, len(versions))
for i, version := range versions {
ver, err := version.Encode()
if err != nil {
return nil, err
}
encodedVersions[i] = ver
}
return encodedVersions, nil
}
// DecodeVersion unmarshals a proto encoded version into a Version struct.
func DecodeVersion(encodedVersion string) (Version, error) {
var version Version
if err := SubModuleCdc.UnmarshalBinaryBare([]byte(encodedVersion), &version); err != nil {
return Version{}, sdkerrors.Wrapf(err, "failed to unmarshal version string %s", encodedVersion)
}
return version, nil
}
// DecodeVersions returns the supplied list of proto encoded version strings
// as unmarshalled Version structs.
func DecodeVersions(encodedVersions []string) ([]Version, error) {
versions := make([]Version, len(encodedVersions))
for i, encodedVersion := range encodedVersions {
version, err := DecodeVersion(encodedVersion)
if err != nil {
return nil, err
}
versions[i] = version
}
return versions, nil
}
// GetCompatibleVersions returns a descending ordered set of compatible IBC
// versions for the caller chain's connection end. The latest supported
// version should be first element and the set should descend to the oldest
// supported version.
func GetCompatibleVersions() []string {
return []string{DefaultIBCVersion}
func GetCompatibleVersions() []Version {
return []Version{DefaultIBCVersion}
}
// CreateVersionString constructs a valid connection version given a
// version identifier and feature set. The format is written as:
//
// ([version_identifier],[feature_0,feature_1,feature_2...])
//
// A connection version is considered invalid if it is not in this format
// or violates one of these rules:
// - the version identifier is empty or contains commas
// - a specified feature contains commas
func CreateVersionString(identifier string, featureSet []string) string {
return fmt.Sprintf("(%s,[%s])", identifier, strings.Join(featureSet, ","))
}
// UnpackVersion parses a version string and returns the identifier and the
// feature set of a version. An error is returned if the version is not valid.
func UnpackVersion(version string) (string, []string, error) {
// validate version so valid splitting assumptions can be made
if err := host.ConnectionVersionValidator(version); err != nil {
return "", nil, err
// GetCompatibleEncodedVersions returns the return value from GetCompatibleVersions
// as a proto encoded string.
func GetCompatibleEncodedVersions() []string {
versions, err := EncodeVersions(GetCompatibleVersions())
if err != nil {
panic(err) // should not occur with properly set hardcoded versions
}
// peel off prefix and suffix of the tuple
version = strings.TrimPrefix(version, "(")
version = strings.TrimSuffix(version, ")")
// split into identifier and feature set
splitVersion := strings.SplitN(version, ",", 2)
if splitVersion[0] == version {
return "", nil, sdkerrors.Wrapf(ErrInvalidVersion, "failed to split version '%s' into identifier and features", version)
}
identifier := splitVersion[0]
// peel off prefix and suffix of features
featureSet := strings.TrimPrefix(splitVersion[1], "[")
featureSet = strings.TrimSuffix(featureSet, "]")
// check if features are empty
if len(featureSet) == 0 {
return identifier, []string{}, nil
}
features := strings.Split(featureSet, ",")
return identifier, features, nil
return versions
}
// FindSupportedVersion returns the version with a matching version identifier
// if it exists. The returned boolean is true if the version is found and
// false otherwise.
func FindSupportedVersion(version string, supportedVersions []string) (string, bool) {
identifier, _, err := UnpackVersion(version)
if err != nil {
return "", false
}
func FindSupportedVersion(version Version, supportedVersions []Version) (Version, bool) {
for _, supportedVersion := range supportedVersions {
supportedIdentifier, _, err := UnpackVersion(supportedVersion)
if err != nil {
continue
}
if identifier == supportedIdentifier {
if version.GetIdentifier() == supportedVersion.GetIdentifier() {
return supportedVersion, true
}
}
return "", false
return Version{}, false
}
// PickVersion iterates over the descending ordered set of compatible IBC
// versions and selects the first version with a version identifier that is
// supported by the counterparty. The returned version contains a feature
// set with the intersection of the features supported by the source and
// counterparty chains. This function is called in the ConnOpenTry handshake
// procedure.
func PickVersion(counterpartyVersions []string) (string, error) {
versions := GetCompatibleVersions()
// counterparty chains. If the feature set intersection is nil and this is
// not allowed for the chosen version identifier then the search for a
// compatible version continues. This function is called in the ConnOpenTry
// handshake procedure.
func PickVersion(encodedCounterpartyVersions []string) (string, error) {
counterpartyVersions, err := DecodeVersions(encodedCounterpartyVersions)
if err != nil {
return "", sdkerrors.Wrapf(err, "failed to unmarshal counterparty versions (%s) when attempting to pick compatible version", encodedCounterpartyVersions)
}
supportedVersions := GetCompatibleVersions()
for _, ver := range versions {
for _, supportedVersion := range supportedVersions {
// check if the source version is supported by the counterparty
if counterpartyVer, found := FindSupportedVersion(ver, counterpartyVersions); found {
sourceIdentifier, sourceFeatures, err := UnpackVersion(ver)
if err != nil {
return "", err
if counterpartyVersion, found := FindSupportedVersion(supportedVersion, counterpartyVersions); found {
featureSet := GetFeatureSetIntersection(supportedVersion.GetFeatures(), counterpartyVersion.GetFeatures())
if len(featureSet) == 0 && !allowNilFeatureSet[supportedVersion.GetIdentifier()] {
continue
}
_, counterpartyFeatures, err := UnpackVersion(counterpartyVer)
if err != nil {
return "", err
}
featureSet := GetFeatureSetIntersection(sourceFeatures, counterpartyFeatures)
version := CreateVersionString(sourceIdentifier, featureSet)
return version, nil
return NewVersion(supportedVersion.GetIdentifier(), featureSet).Encode()
}
}
return "", sdkerrors.Wrapf(
ErrVersionNegotiationFailed,
"failed to find a matching counterparty version (%s) from the supported version list (%s)", counterpartyVersions, versions,
"failed to find a matching counterparty version (%s) from the supported version list (%s)", counterpartyVersions, supportedVersions,
)
}
@ -139,37 +196,46 @@ func GetFeatureSetIntersection(sourceFeatureSet, counterpartyFeatureSet []string
return featureSet
}
// VerifyProposedFeatureSet verifies that the entire feature set in the
// proposed version is supported by this chain.
func VerifyProposedFeatureSet(proposedVersion, supportedVersion string) bool {
_, proposedFeatureSet, err := UnpackVersion(proposedVersion)
if err != nil {
return false
// VerifyProposedVersion verifies that the entire feature set in the
// proposed version is supported by this chain. If the feature set is
// empty it verifies that this is allowed for the specified version
// identifier.
func (version Version) VerifyProposedVersion(proposedVersion Version) error {
if proposedVersion.GetIdentifier() != version.GetIdentifier() {
return sdkerrors.Wrapf(
ErrVersionNegotiationFailed,
"proposed version identifier does not equal supported version identifier (%s != %s)", proposedVersion.GetIdentifier(), version.GetIdentifier(),
)
}
_, supportedFeatureSet, err := UnpackVersion(supportedVersion)
if err != nil {
return false
if len(proposedVersion.GetFeatures()) == 0 && !allowNilFeatureSet[proposedVersion.GetIdentifier()] {
return sdkerrors.Wrapf(
ErrVersionNegotiationFailed,
"nil feature sets are not supported for version identifier (%s)", proposedVersion.GetIdentifier(),
)
}
for _, proposedFeature := range proposedFeatureSet {
if !contains(proposedFeature, supportedFeatureSet) {
return false
for _, proposedFeature := range proposedVersion.GetFeatures() {
if !contains(proposedFeature, version.GetFeatures()) {
return sdkerrors.Wrapf(
ErrVersionNegotiationFailed,
"proposed feature (%s) is not a supported feature set (%s)", proposedFeature, version.GetFeatures(),
)
}
}
return true
return nil
}
// VerifySupportedFeature takes in a version string and feature string and returns
// VerifySupportedFeature takes in a version and feature string and returns
// true if the feature is supported by the version and false otherwise.
func VerifySupportedFeature(version, feature string) bool {
_, featureSet, err := UnpackVersion(version)
func VerifySupportedFeature(encodedVersion, feature string) bool {
version, err := DecodeVersion(encodedVersion)
if err != nil {
return false
}
for _, f := range featureSet {
for _, f := range version.GetFeatures() {
if f == feature {
return true
}
@ -181,7 +247,7 @@ func VerifySupportedFeature(version, feature string) bool {
// string set.
func contains(elem string, set []string) bool {
for _, element := range set {
if strings.TrimSpace(elem) == strings.TrimSpace(element) {
if elem == element {
return true
}
}

View File

@ -6,61 +6,79 @@ import (
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
// testing of invalid version formats exist within 24-host/validate_test.go
func TestUnpackVersion(t *testing.T) {
func TestValidateVersion(t *testing.T) {
testCases := []struct {
name string
version string
expIdentifier string
expFeatures []string
expPass bool
name string
version types.Version
expPass bool
}{
{"valid version", "(1,[ORDERED channel,UNORDERED channel])", "1", []string{"ORDERED channel", "UNORDERED channel"}, true},
{"valid empty features", "(1,[])", "1", []string{}, true},
{"empty identifier", "(,[features])", "", []string{}, false},
{"invalid version", "identifier,[features]", "", []string{}, false},
{"empty string", " ", "", []string{}, false},
{"valid version", types.DefaultIBCVersion, true},
{"valid empty feature set", types.NewVersion(types.DefaultIBCVersionIdentifier, []string{}), true},
{"empty version identifier", types.NewVersion(" ", []string{"ORDER_UNORDERED"}), false},
{"empty feature", types.NewVersion(types.DefaultIBCVersionIdentifier, []string{"ORDER_UNORDERED", " "}), false},
}
for _, tc := range testCases {
tc := tc
for i, tc := range testCases {
encodedVersion, err := tc.version.Encode()
require.NoError(t, err, "test case %d failed to marshal version string: %s", i, tc.name)
t.Run(tc.name, func(t *testing.T) {
identifier, features, err := types.UnpackVersion(tc.version)
err = types.ValidateVersion(encodedVersion)
if tc.expPass {
require.NoError(t, err)
require.Equal(t, tc.expIdentifier, identifier)
require.Equal(t, tc.expFeatures, features)
} else {
require.Error(t, err)
}
})
if tc.expPass {
require.NoError(t, err, "valid test case %d failed: %s", i, tc.name)
} else {
require.Error(t, err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func TestDecodeVersion(t *testing.T) {
testCases := []struct {
name string
version string
expVersion types.Version
expPass bool
}{
{"valid version", ibctesting.ConnectionVersion, types.DefaultIBCVersion, true},
{"invalid version", "not a proto encoded version", types.Version{}, false},
{"empty string", " ", types.Version{}, false},
}
for i, tc := range testCases {
version, err := types.DecodeVersion(tc.version)
if tc.expPass {
require.NoError(t, err, "valid test case %d failed: %s", i, tc.name)
require.Equal(t, tc.expVersion, version)
} else {
require.Error(t, err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func TestFindSupportedVersion(t *testing.T) {
testCases := []struct {
name string
version string
supportedVersions []string
expVersion string
version types.Version
supportedVersions []types.Version
expVersion types.Version
expFound bool
}{
{"valid supported version", types.DefaultIBCVersion, types.GetCompatibleVersions(), types.DefaultIBCVersion, true},
{"empty (invalid) version", "", types.GetCompatibleVersions(), "", false},
{"empty supported versions", types.DefaultIBCVersion, []string{}, "", false},
{"desired version is last", types.DefaultIBCVersion, []string{"(validversion,[])", "(2,[feature])", "(3,[])", types.DefaultIBCVersion}, types.DefaultIBCVersion, true},
{"desired version identifier with different feature set", "(1,[features])", types.GetCompatibleVersions(), types.DefaultIBCVersion, true},
{"version not supported", "(2,[DAG])", types.GetCompatibleVersions(), "", false},
{"empty (invalid) version", types.Version{}, types.GetCompatibleVersions(), types.Version{}, false},
{"empty supported versions", types.DefaultIBCVersion, []types.Version{}, types.Version{}, false},
{"desired version is last", types.DefaultIBCVersion, []types.Version{types.NewVersion("1.1", nil), types.NewVersion("2", []string{"ORDER_UNORDERED"}), types.NewVersion("3", nil), types.DefaultIBCVersion}, types.DefaultIBCVersion, true},
{"desired version identifier with different feature set", types.NewVersion(types.DefaultIBCVersionIdentifier, []string{"ORDER_DAG"}), types.GetCompatibleVersions(), types.DefaultIBCVersion, true},
{"version not supported", types.NewVersion("2", []string{"ORDER_DAG"}), types.GetCompatibleVersions(), types.Version{}, false},
}
for i, tc := range testCases {
version, found := types.FindSupportedVersion(tc.version, tc.supportedVersions)
require.Equal(t, tc.expVersion, version, "test case %d: %s", i, tc.name)
require.Equal(t, tc.expVersion.GetIdentifier(), version.GetIdentifier(), "test case %d: %s", i, tc.name)
require.Equal(t, tc.expFound, found, "test case %d: %s", i, tc.name)
}
}
@ -68,62 +86,77 @@ func TestFindSupportedVersion(t *testing.T) {
func TestPickVersion(t *testing.T) {
testCases := []struct {
name string
counterpartyVersions []string
expVer string
counterpartyVersions []types.Version
expVer types.Version
expPass bool
}{
{"valid default ibc version", types.GetCompatibleVersions(), types.DefaultIBCVersion, true},
{"valid version in counterparty versions", []string{"(version1,[])", "(2.0.0,[DAG,ZK])", types.DefaultIBCVersion}, types.DefaultIBCVersion, true},
{"valid identifier match but empty feature set", []string{"(1,[DAG,ORDERED-ZK,UNORDERED-zk])"}, "(1,[])", true},
{"empty counterparty versions", []string{}, "", false},
{"non-matching counterparty versions", []string{"(2.0.0,[])"}, "", false},
{"valid version in counterparty versions", []types.Version{types.NewVersion("version1", nil), types.NewVersion("2.0.0", []string{"ORDER_UNORDERED-ZK"}), types.DefaultIBCVersion}, types.DefaultIBCVersion, true},
{"valid identifier match but empty feature set not allowed", []types.Version{types.NewVersion(types.DefaultIBCVersionIdentifier, []string{"DAG", "ORDERED-ZK", "UNORDERED-zk]"})}, types.NewVersion(types.DefaultIBCVersionIdentifier, nil), false},
{"empty counterparty versions", []types.Version{}, types.Version{}, false},
{"non-matching counterparty versions", []types.Version{types.NewVersion("2.0.0", nil)}, types.Version{}, false},
}
for i, tc := range testCases {
version, err := types.PickVersion(tc.counterpartyVersions)
encodedCounterpartyVersions, err := types.EncodeVersions(tc.counterpartyVersions)
require.NoError(t, err)
encodedVersion, err := types.PickVersion(encodedCounterpartyVersions)
if tc.expPass {
require.NoError(t, err, "valid test case %d failed: %s", i, tc.name)
version, err := types.DecodeVersion(encodedVersion)
require.NoError(t, err)
require.Equal(t, tc.expVer, version, "valid test case %d falied: %s", i, tc.name)
} else {
require.Error(t, err, "invalid test case %d passed: %s", i, tc.name)
require.Equal(t, "", version, "invalid test case %d passed: %s", i, tc.name)
require.Equal(t, "", encodedVersion, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func TestVerifyProposedFeatureSet(t *testing.T) {
func TestVerifyProposedVersion(t *testing.T) {
testCases := []struct {
name string
proposedVersion string
supportedVersion string
proposedVersion types.Version
supportedVersion types.Version
expPass bool
}{
{"entire feature set supported", types.DefaultIBCVersion, types.CreateVersionString("1", []string{"ORDER_ORDERED", "ORDER_UNORDERED", "ORDER_DAG"}), true},
{"empty feature sets", types.CreateVersionString("1", []string{}), types.DefaultIBCVersion, true},
{"one feature missing", types.DefaultIBCVersion, types.CreateVersionString("1", []string{"ORDER_UNORDERED", "ORDER_DAG"}), false},
{"both features missing", types.DefaultIBCVersion, types.CreateVersionString("1", []string{"ORDER_DAG"}), false},
{"entire feature set supported", types.DefaultIBCVersion, types.NewVersion("1", []string{"ORDER_ORDERED", "ORDER_UNORDERED", "ORDER_DAG"}), true},
{"empty feature sets not supported", types.NewVersion("1", []string{}), types.DefaultIBCVersion, false},
{"one feature missing", types.DefaultIBCVersion, types.NewVersion("1", []string{"ORDER_UNORDERED", "ORDER_DAG"}), false},
{"both features missing", types.DefaultIBCVersion, types.NewVersion("1", []string{"ORDER_DAG"}), false},
{"identifiers do not match", types.NewVersion("2", []string{"ORDER_UNORDERED", "ORDER_ORDERED"}), types.DefaultIBCVersion, false},
}
for i, tc := range testCases {
supported := types.VerifyProposedFeatureSet(tc.proposedVersion, tc.supportedVersion)
err := tc.supportedVersion.VerifyProposedVersion(tc.proposedVersion)
require.Equal(t, tc.expPass, supported, "test case %d: %s", i, tc.name)
if tc.expPass {
require.NoError(t, err, "test case %d: %s", i, tc.name)
} else {
require.Error(t, err, "test case %d: %s", i, tc.name)
}
}
}
func TestVerifySupportedFeature(t *testing.T) {
nilFeatures, err := types.NewVersion(types.DefaultIBCVersionIdentifier, nil).Encode()
require.NoError(t, err)
testCases := []struct {
name string
version string
feature string
expPass bool
}{
{"check ORDERED supported", types.DefaultIBCVersion, "ORDER_ORDERED", true},
{"check UNORDERED supported", types.DefaultIBCVersion, "ORDER_UNORDERED", true},
{"check DAG unsupported", types.DefaultIBCVersion, "ORDER_DAG", false},
{"check empty feature set returns false", types.CreateVersionString("1", []string{}), "ORDER_ORDERED", false},
{"check ORDERED supported", ibctesting.ConnectionVersion, "ORDER_ORDERED", true},
{"check UNORDERED supported", ibctesting.ConnectionVersion, "ORDER_UNORDERED", true},
{"check DAG unsupported", ibctesting.ConnectionVersion, "ORDER_DAG", false},
{"check empty feature set returns false", nilFeatures, "ORDER_ORDERED", false},
{"failed to unmarshal version", "not an encoded version", "ORDER_ORDERED", false},
}
for i, tc := range testCases {

View File

@ -10,6 +10,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
ibctransfertypes "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"
connectionutils "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
)
@ -54,7 +55,7 @@ func NewChannelOpenInitCmd() *cobra.Command {
}
cmd.Flags().Bool(FlagOrdered, true, "Pass flag for opening ordered channels")
cmd.Flags().String(FlagIBCVersion, types.DefaultChannelVersion, "supported IBC version")
cmd.Flags().String(FlagIBCVersion, ibctransfertypes.Version, "IBC application version")
flags.AddTxFlagsToCmd(cmd)
return cmd
@ -107,7 +108,7 @@ func NewChannelOpenTryCmd() *cobra.Command {
}
cmd.Flags().Bool(FlagOrdered, true, "Pass flag for opening ordered channels")
cmd.Flags().String(FlagIBCVersion, types.DefaultChannelVersion, "supported IBC version")
cmd.Flags().String(FlagIBCVersion, ibctransfertypes.Version, "IBC application version")
flags.AddTxFlagsToCmd(cmd)
return cmd
@ -152,8 +153,7 @@ func NewChannelOpenAckCmd() *cobra.Command {
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
cmd.Flags().String(FlagIBCVersion, types.DefaultChannelVersion, "supported IBC version")
cmd.Flags().String(FlagIBCVersion, ibctransfertypes.Version, "IBC application version")
flags.AddTxFlagsToCmd(cmd)
return cmd

View File

@ -66,7 +66,11 @@ func (suite *KeeperTestSuite) TestChanOpenInit() {
// modify connA versions
conn := suite.chainA.GetConnection(connA)
conn.Versions = append(conn.Versions, connectiontypes.CreateVersionString("2", []string{"ORDER_ORDERED", "ORDER_UNORDERED"}))
version, err := connectiontypes.NewVersion("2", []string{"ORDER_ORDERED", "ORDER_UNORDERED"}).Encode()
suite.Require().NoError(err)
conn.Versions = append(conn.Versions, version)
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(
suite.chainA.GetContext(),
connA.ID, conn,
@ -80,7 +84,11 @@ func (suite *KeeperTestSuite) TestChanOpenInit() {
// modify connA versions to only support UNORDERED channels
conn := suite.chainA.GetConnection(connA)
conn.Versions = []string{connectiontypes.CreateVersionString("1", []string{"ORDER_UNORDERED"})}
version, err := connectiontypes.NewVersion("1", []string{"ORDER_UNORDERED"}).Encode()
suite.Require().NoError(err)
conn.Versions = []string{version}
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(
suite.chainA.GetContext(),
connA.ID, conn,
@ -207,7 +215,11 @@ func (suite *KeeperTestSuite) TestChanOpenTry() {
// modify connB versions
conn := suite.chainB.GetConnection(connB)
conn.Versions = append(conn.Versions, connectiontypes.CreateVersionString("2", []string{"ORDER_ORDERED", "ORDER_UNORDERED"}))
version, err := connectiontypes.NewVersion("2", []string{"ORDER_ORDERED", "ORDER_UNORDERED"}).Encode()
suite.Require().NoError(err)
conn.Versions = append(conn.Versions, version)
suite.chainB.App.IBCKeeper.ConnectionKeeper.SetConnection(
suite.chainB.GetContext(),
connB.ID, conn,
@ -221,7 +233,11 @@ func (suite *KeeperTestSuite) TestChanOpenTry() {
// modify connA versions to only support UNORDERED channels
conn := suite.chainA.GetConnection(connA)
conn.Versions = []string{connectiontypes.CreateVersionString("1", []string{"ORDER_UNORDERED"})}
version, err := connectiontypes.NewVersion("1", []string{"ORDER_UNORDERED"}).Encode()
suite.Require().NoError(err)
conn.Versions = []string{version}
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(
suite.chainA.GetContext(),
connA.ID, conn,
@ -364,6 +380,7 @@ func (suite *KeeperTestSuite) TestChanOpenAck() {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
heightDiff = 0 // must be explicitly changed
tc.malleate()
channelA := connA.FirstOrNextTestChannel()

View File

@ -13,9 +13,6 @@ var (
_ exported.CounterpartyI = (*Counterparty)(nil)
)
// DefaultChannelVersion defines the default channel version used during handshake.
const DefaultChannelVersion = "1.0.0"
// NewChannel creates a new Channel instance
func NewChannel(
state State, ordering Order, counterparty Counterparty,

View File

@ -14,15 +14,6 @@ import (
// - `[`, `]`, `<`, `>`
var IsValidID = regexp.MustCompile(`^[a-zA-Z0-9\.\_\+\-\#\[\]\<\>]+$`).MatchString
// IsValidConnectionVersion defines the regular expression to check if the
// string is in the form of a tuple consisting of a string identifier and
// a set of features. The entire version tuple must be enclosed in parentheses.
// The version identifier must not contain any commas. The set of features
// must be enclosed in brackets and separated by commas.
//
// valid connection version = ([version_identifier], [feature_0, feature_1, etc])
var IsValidConnectionVersion = regexp.MustCompile(`^\([^,]+\,\[([^,]+(\,[^,]+)*)?\]\)$`).MatchString
// ICS 024 Identifier and Path Validation Implementation
//
// This file defines ValidateFn to validate identifier and path strings
@ -83,24 +74,6 @@ func PortIdentifierValidator(id string) error {
return defaultIdentifierValidator(id, 2, 20)
}
// ConnectionVersionValidator is the default validator function for Connection
// versions. A valid version must be in semantic versioning form and contain
// only non-negative integers.
func ConnectionVersionValidator(version string) error {
if strings.TrimSpace(version) == "" {
return sdkerrors.Wrap(ErrInvalidVersion, "version cannot be blank")
}
if !IsValidConnectionVersion(version) {
return sdkerrors.Wrapf(
ErrInvalidVersion,
"version '%s' must be in '(version_identifier,[feature_0, feature_1])' with no extra spacing", version,
)
}
return nil
}
// NewPathValidator takes in a Identifier Validator function and returns
// a Path Validator function which requires path only has valid identifiers
// alphanumeric character strings, and "/" separators

View File

@ -111,31 +111,3 @@ func TestCustomPathValidator(t *testing.T) {
}
}
}
func TestConnectionVersionValidator(t *testing.T) {
testCases := []testCase{
{"valid connection version", "(my-test-version 1.0,[feature0, feature1])", true},
{"valid random character version, no commas", "(a!@!#$%^&34,[)(*&^),....,feature_2])", true},
{"valid: empty features", "(identifier,[])", true},
{"invalid: empty features with spacing", "(identifier, [ ])", false},
{"missing identifier", "( , [feature_0])", false},
{"no features bracket", "(identifier, feature_0, feature_1)", false},
{"no tuple parentheses", "identifier, [feature$%#]", false},
{"string with only spaces", " ", false},
{"empty string", "", false},
{"no comma", "(idenitifer [features])", false},
{"invalid comma usage in features", "(identifier, [feature_0,,feature_1])", false},
{"empty features with comma", "(identifier, [ , ])", false},
}
for _, tc := range testCases {
err := ConnectionVersionValidator(tc.id)
if tc.expPass {
require.NoError(t, err, tc.msg)
} else {
require.Error(t, err, tc.msg)
}
}
}

View File

@ -11,6 +11,7 @@ import (
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
"github.com/cosmos/cosmos-sdk/x/ibc/types"
)
@ -47,7 +48,7 @@ func (suite *IBCTestSuite) TestValidateGenesis() {
),
ConnectionGenesis: connectiontypes.NewGenesisState(
[]connectiontypes.ConnectionEnd{
connectiontypes.NewConnectionEnd(connectiontypes.INIT, connectionID, clientID, connectiontypes.NewCounterparty(clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))), []string{connectiontypes.DefaultIBCVersion}),
connectiontypes.NewConnectionEnd(connectiontypes.INIT, connectionID, clientID, connectiontypes.NewCounterparty(clientID2, connectionID2, commitmenttypes.NewMerklePrefix([]byte("prefix"))), []string{ibctesting.ConnectionVersion}),
},
[]connectiontypes.ConnectionPaths{
connectiontypes.NewConnectionPaths(clientID, []string{host.ConnectionPath(connectionID)}),

View File

@ -45,3 +45,35 @@ identifier, but differing feature sets. This will result in undefined behavior
with regards to version selection in `ConnOpenTry`. Each version in a set of
versions should have a unique version identifier.
:::
### Channel Version Negotation
During the channel handshake procedure a version must be agreed upon between
the two parties. The selection process is largely left to the callers and
the verification of valid versioning must be handled by application developers
in the channel handshake callbacks.
During `ChanOpenInit`, a version string is passed in and set in party A's
channel state.
During `ChanOpenTry`, a version string for party A and for party B are passed
in. The party A version string must match the version string used in
`ChanOpenInit` otherwise channel state verification will fail. The party B
version string could be anything (even different than the proposed one by
party A). However, the proposed version by party B is expected to be fully
supported by party A.
During the `ChanOpenAck` callback, the application module is expected to verify
the version proposed by party B using the `MsgChanOpenAck` `CounterpartyVersion`
field. The application module should throw an error if the version string is
not valid.
Application modules may implement their own versioning system, such as semantic
versioning, or they may lean upon the versioning system used for in connection
version negotiation. To use the connection version semantics the application
would simply pass the proto encoded version into each of the handshake calls
and decode the version string into a `Version` instance to do version verification
in the handshake callbacks.
Implementations which do not feel they would benefit from versioning can do
basic string matching using a single compatible version.

View File

@ -21,6 +21,7 @@ import (
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
ibctransfertypes "github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
@ -38,7 +39,7 @@ const (
UnbondingPeriod time.Duration = time.Hour * 24 * 7 * 3
MaxClockDrift time.Duration = time.Second * 10
ChannelVersion = "ics20-1"
ChannelVersion = ibctransfertypes.Version
InvalidID = "IDisInvalid"
ConnectionIDPrefix = "connectionid"
@ -50,7 +51,7 @@ var (
DefaultTrustLevel tmmath.Fraction = lite.DefaultTrustLevel
TestHash = []byte("TESTING HASH")
ConnectionVersion = connectiontypes.DefaultIBCVersion
ConnectionVersion = connectiontypes.GetCompatibleEncodedVersions()[0]
)
// TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI