diff --git a/proto/ibc/connection/connection.proto b/proto/ibc/connection/connection.proto index 261fd85b03af..23a47e79a668 100644 --- a/proto/ibc/connection/connection.proto +++ b/proto/ibc/connection/connection.proto @@ -17,7 +17,8 @@ message MsgConnectionOpenInit { string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; string connection_id = 2 [(gogoproto.moretags) = "yaml:\"connection_id\""]; Counterparty counterparty = 3 [(gogoproto.nullable) = false]; - string signer = 4; + string version = 4; + string signer = 5; } // MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a diff --git a/x/ibc/03-connection/client/cli/tx.go b/x/ibc/03-connection/client/cli/tx.go index dba20ac1a4d4..88d26e782a3e 100644 --- a/x/ibc/03-connection/client/cli/tx.go +++ b/x/ibc/03-connection/client/cli/tx.go @@ -16,15 +16,22 @@ import ( host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ) +const ( + flagVersionIdentifier = "version-identifier" + flagVersionFeatures = "version-features" +) + // NewConnectionOpenInitCmd defines the command to initialize a connection on // chain A with a given counterparty chain B func NewConnectionOpenInitCmd() *cobra.Command { cmd := &cobra.Command{ Use: "open-init [connection-id] [client-id] [counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json]", Short: "Initialize connection on chain A", - Long: "Initialize a connection on chain A with a given counterparty chain B", + Long: `Initialize a connection on chain A with a given counterparty chain B. + - 'version-identifier' flag can be a single pre-selected version identifier to be used in the handshake. + - 'version-features' flag can be a list of features separated by commas to accompany the version identifier.`, Example: fmt.Sprintf( - "%s tx %s %s open-init [connection-id] [client-id] [counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json]", + "%s tx %s %s open-init [connection-id] [client-id] [counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json] --version-identifier=\"1.0\" --version-features=\"ORDER_UNORDERED\"", version.AppName, host.ModuleName, types.SubModuleName, ), Args: cobra.ExactArgs(5), @@ -45,9 +52,27 @@ func NewConnectionOpenInitCmd() *cobra.Command { return err } + var encodedVersion string + versionIdentifier, _ := cmd.Flags().GetString(flagVersionIdentifier) + + if versionIdentifier != "" { + var features []string + + versionFeatures, _ := cmd.Flags().GetString(flagVersionFeatures) + if versionFeatures != "" { + features = strings.Split(versionFeatures, ",") + } + + version := types.NewVersion(versionIdentifier, features) + encodedVersion, err = version.Encode() + if err != nil { + return err + } + } + msg := types.NewMsgConnectionOpenInit( connectionID, clientID, counterpartyConnectionID, counterpartyClientID, - counterpartyPrefix, clientCtx.GetFromAddress(), + counterpartyPrefix, encodedVersion, clientCtx.GetFromAddress(), ) if err := msg.ValidateBasic(); err != nil { @@ -58,6 +83,10 @@ func NewConnectionOpenInitCmd() *cobra.Command { }, } + // NOTE: we should use empty default values since the user may not want to select a version + // at this step in the handshake. + cmd.Flags().String(flagVersionIdentifier, "", "version identifier to be used in the connection handshake version negotiation") + cmd.Flags().String(flagVersionFeatures, "", "version features list separated by commas without spaces. The features must function with the version identifier.") flags.AddTxFlagsToCmd(cmd) return cmd diff --git a/x/ibc/03-connection/handler.go b/x/ibc/03-connection/handler.go index 4ce2932f1b92..8a7b86f8d5ba 100644 --- a/x/ibc/03-connection/handler.go +++ b/x/ibc/03-connection/handler.go @@ -11,7 +11,7 @@ import ( // HandleMsgConnectionOpenInit defines the sdk.Handler for MsgConnectionOpenInit func HandleMsgConnectionOpenInit(ctx sdk.Context, k keeper.Keeper, msg *types.MsgConnectionOpenInit) (*sdk.Result, error) { if err := k.ConnOpenInit( - ctx, msg.ConnectionId, msg.ClientId, msg.Counterparty, + ctx, msg.ConnectionId, msg.ClientId, msg.Counterparty, msg.Version, ); err != nil { return nil, sdkerrors.Wrap(err, "connection handshake open init failed") } diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index 12b874d36a15..9cd3aca4e8f1 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -21,14 +21,24 @@ func (k Keeper) ConnOpenInit( connectionID, // identifier clientID string, counterparty types.Counterparty, // desiredCounterpartyConnectionIdentifier, counterpartyPrefix, counterpartyClientIdentifier + version string, ) error { _, found := k.GetConnection(ctx, connectionID) if found { return types.ErrConnectionExists } + versions := types.GetCompatibleEncodedVersions() + if version != "" { + if !types.IsSupportedVersion(version) { + return sdkerrors.Wrap(types.ErrInvalidVersion, "version is not supported") + } + + versions = []string{version} + } + // connection defines chain A's ConnectionEnd - connection := types.NewConnectionEnd(types.INIT, clientID, counterparty, types.GetCompatibleEncodedVersions()) + connection := types.NewConnectionEnd(types.INIT, clientID, counterparty, versions) k.SetConnection(ctx, connectionID, connection) if err := k.addConnectionToClient(ctx, clientID, connectionID); err != nil { diff --git a/x/ibc/03-connection/keeper/handshake_test.go b/x/ibc/03-connection/keeper/handshake_test.go index d55f7e299883..607539f3a775 100644 --- a/x/ibc/03-connection/keeper/handshake_test.go +++ b/x/ibc/03-connection/keeper/handshake_test.go @@ -17,6 +17,7 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { var ( clientA string clientB string + version string ) testCases := []struct { @@ -27,9 +28,17 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { {"success", func() { clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, ibctesting.Tendermint) }, true}, + {"success with non empty version", func() { + clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, ibctesting.Tendermint) + version = types.GetCompatibleEncodedVersions()[0] + }, true}, {"connection already exists", func() { clientA, clientB, _, _ = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, ibctesting.Tendermint) }, false}, + {"invalid version", func() { + clientA, clientB = suite.coordinator.SetupClients(suite.chainA, suite.chainB, ibctesting.Tendermint) + version = "bad version" + }, false}, {"couldn't add connection to client", func() { // swap client identifiers to result in client that does not exist clientB, clientA = suite.coordinator.SetupClients(suite.chainA, suite.chainB, ibctesting.Tendermint) @@ -40,6 +49,7 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { tc := tc suite.Run(tc.msg, func() { suite.SetupTest() // reset + version = "" // must be explicitly changed tc.malleate() @@ -47,7 +57,7 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { connB := suite.chainB.GetFirstTestConnection(clientB, clientA) counterparty := types.NewCounterparty(clientB, connB.ID, suite.chainB.GetPrefix()) - err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenInit(suite.chainA.GetContext(), connA.ID, clientA, counterparty) + err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenInit(suite.chainA.GetContext(), connA.ID, clientA, counterparty, version) if tc.expPass { suite.Require().NoError(err) diff --git a/x/ibc/03-connection/types/connection.pb.go b/x/ibc/03-connection/types/connection.pb.go index 700cbfcf52f1..b56051da1bc1 100644 --- a/x/ibc/03-connection/types/connection.pb.go +++ b/x/ibc/03-connection/types/connection.pb.go @@ -70,7 +70,8 @@ type MsgConnectionOpenInit 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"` - Signer string `protobuf:"bytes,4,opt,name=signer,proto3" json:"signer,omitempty"` + Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` + Signer string `protobuf:"bytes,5,opt,name=signer,proto3" json:"signer,omitempty"` } func (m *MsgConnectionOpenInit) Reset() { *m = MsgConnectionOpenInit{} } @@ -555,70 +556,70 @@ func init() { func init() { proto.RegisterFile("ibc/connection/connection.proto", fileDescriptor_3bf62bacf5a27ee9) } var fileDescriptor_3bf62bacf5a27ee9 = []byte{ - // 995 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0x4b, 0x6f, 0x1a, 0x57, - 0x14, 0x66, 0x60, 0x78, 0x1d, 0xc0, 0x26, 0x53, 0x1c, 0x4f, 0x69, 0x3a, 0x83, 0xa6, 0x1b, 0xab, - 0x55, 0xa0, 0x49, 0xaa, 0x2c, 0x90, 0xba, 0x30, 0x84, 0xa8, 0xa3, 0x36, 0x0e, 0x1a, 0xe3, 0x4a, - 0xf5, 0xa2, 0x08, 0x86, 0x0b, 0xbe, 0xc2, 0xcc, 0xa0, 0x99, 0xa1, 0x0a, 0xdb, 0x2e, 0xaa, 0xc8, - 0xab, 0x6e, 0xbb, 0xb0, 0x14, 0xa9, 0xff, 0xa4, 0xab, 0x48, 0xdd, 0x64, 0xd9, 0x6e, 0x50, 0x65, - 0x6f, 0xba, 0xa6, 0x3f, 0xa0, 0xd5, 0x7d, 0xcc, 0x03, 0x6c, 0xab, 0x8a, 0xed, 0x28, 0x2b, 0xce, - 0xb9, 0xe7, 0x7c, 0x73, 0xef, 0x77, 0xce, 0x77, 0x1f, 0x80, 0x8a, 0xfb, 0x66, 0xcd, 0xb4, 0x2d, - 0x0b, 0x99, 0x1e, 0xb6, 0xad, 0x88, 0x59, 0x9d, 0x3a, 0xb6, 0x67, 0x4b, 0x1b, 0xb8, 0x6f, 0x56, - 0xc3, 0xd1, 0x72, 0x69, 0x64, 0x8f, 0x6c, 0x1a, 0xaa, 0x11, 0x8b, 0x65, 0x95, 0x3f, 0x1c, 0xd9, - 0xf6, 0xe8, 0x18, 0xd5, 0xa8, 0xd7, 0x9f, 0x0d, 0x6b, 0x3d, 0x6b, 0xce, 0x43, 0x7c, 0x86, 0xc9, - 0x04, 0x7b, 0x13, 0x64, 0x79, 0x11, 0x93, 0x27, 0x6c, 0xd3, 0x84, 0x63, 0x4c, 0x83, 0xf4, 0x87, - 0x05, 0xb4, 0x7f, 0x04, 0xd8, 0x7a, 0xe6, 0x8e, 0x9a, 0xc1, 0xe4, 0xcf, 0xa7, 0xc8, 0xd2, 0x2d, - 0xec, 0x49, 0x0f, 0x20, 0xcb, 0x32, 0xbb, 0x78, 0x20, 0x0b, 0x15, 0x61, 0x27, 0xdb, 0x28, 0x2d, - 0x17, 0x6a, 0x71, 0xde, 0x9b, 0x1c, 0xd7, 0xb5, 0x20, 0xa4, 0x19, 0x19, 0x66, 0xeb, 0x03, 0xe9, - 0x4b, 0x28, 0x84, 0x2c, 0x08, 0x2c, 0x4e, 0x61, 0xf2, 0x72, 0xa1, 0x96, 0x38, 0x2c, 0x1a, 0xd6, - 0x8c, 0x7c, 0xe8, 0xeb, 0x03, 0xe9, 0x29, 0xe4, 0x4d, 0x7b, 0x66, 0x79, 0xc8, 0x99, 0xf6, 0x1c, - 0x6f, 0x2e, 0x27, 0x2a, 0xc2, 0x4e, 0xee, 0xe1, 0xbd, 0xea, 0x6a, 0x75, 0xaa, 0xcd, 0x48, 0x4e, - 0x43, 0x7c, 0xbd, 0x50, 0x63, 0xc6, 0x0a, 0x4e, 0xba, 0x0b, 0x29, 0x17, 0x8f, 0x2c, 0xe4, 0xc8, - 0x22, 0x99, 0xdf, 0xe0, 0x5e, 0x3d, 0xf3, 0xf2, 0x95, 0x1a, 0xfb, 0xfb, 0x95, 0x1a, 0xd3, 0x7e, - 0x4a, 0x41, 0xe9, 0x02, 0xeb, 0x8e, 0x33, 0x7f, 0x0f, 0xa4, 0xdb, 0x90, 0xe7, 0x9f, 0x75, 0xbd, - 0x9e, 0x87, 0x38, 0xe9, 0x52, 0x95, 0x35, 0xbb, 0xea, 0x37, 0xbb, 0xba, 0x6b, 0xcd, 0x1b, 0xdb, - 0xcb, 0x85, 0xfa, 0xc1, 0xca, 0x52, 0x28, 0x46, 0x33, 0x72, 0xcc, 0xdd, 0x27, 0xde, 0x85, 0x32, - 0x8a, 0xd7, 0x2c, 0xe3, 0x01, 0x6c, 0x45, 0xfd, 0xee, 0x0f, 0xc8, 0x71, 0xb1, 0x6d, 0xb9, 0x72, - 0xb2, 0x92, 0xd8, 0xc9, 0x36, 0x2a, 0xcb, 0x85, 0x7a, 0xcf, 0x27, 0x78, 0x49, 0x9a, 0x66, 0x94, - 0xa2, 0xe3, 0xdf, 0xf2, 0x61, 0xc9, 0x80, 0xfc, 0xd4, 0xb1, 0xed, 0x61, 0xf7, 0x08, 0xe1, 0xd1, - 0x91, 0x27, 0xa7, 0xe8, 0xf2, 0x24, 0xb6, 0x3c, 0x26, 0xcd, 0xaf, 0x68, 0xa4, 0xf1, 0x11, 0x59, - 0x54, 0x48, 0x39, 0x8a, 0xd2, 0x8c, 0x1c, 0x75, 0x59, 0xa6, 0xf4, 0x05, 0x00, 0x8b, 0x62, 0x0b, - 0x7b, 0x72, 0xba, 0x22, 0xec, 0xe4, 0x1b, 0x5b, 0xcb, 0x85, 0x7a, 0x27, 0x8a, 0x24, 0x31, 0xcd, - 0xc8, 0x52, 0x87, 0x2a, 0xbc, 0xee, 0xaf, 0x84, 0x4d, 0x2b, 0x67, 0x28, 0x6e, 0x7b, 0x7d, 0x46, - 0x16, 0xf5, 0x67, 0x6c, 0x52, 0x4f, 0x6a, 0xc2, 0x26, 0x8f, 0xda, 0x96, 0x8b, 0x2c, 0x77, 0xe6, - 0xca, 0x59, 0x0a, 0x2f, 0x2f, 0x17, 0xea, 0xdd, 0x15, 0xb8, 0x9f, 0xa0, 0x19, 0x1b, 0xec, 0x0b, - 0xfe, 0x80, 0xf4, 0x3d, 0x14, 0x83, 0xa8, 0x5f, 0x0e, 0xb8, 0xb2, 0x1c, 0x2a, 0x2f, 0xc7, 0x76, - 0xa0, 0xaa, 0x15, 0xa4, 0x66, 0x6c, 0x06, 0x43, 0xbc, 0x2c, 0xe1, 0x46, 0xc8, 0x5d, 0xb1, 0x11, - 0x7e, 0x17, 0x2f, 0xd9, 0x08, 0xbb, 0xe6, 0xf8, 0xa2, 0xaa, 0x85, 0xb7, 0x52, 0xb5, 0x0c, 0x69, - 0xae, 0x03, 0xb6, 0x1d, 0x0c, 0xdf, 0x7d, 0x07, 0x7a, 0x5f, 0x17, 0x94, 0x78, 0x0b, 0x82, 0x7a, - 0x00, 0x4c, 0x27, 0x5d, 0xcf, 0x99, 0xcb, 0x49, 0xda, 0xd8, 0xc8, 0x39, 0x10, 0x84, 0x34, 0x23, - 0x43, 0x6d, 0x72, 0x74, 0xac, 0xab, 0x29, 0x75, 0x33, 0x35, 0xa5, 0x6f, 0x45, 0x4d, 0x99, 0x77, - 0xa2, 0xa6, 0xec, 0x15, 0x6a, 0xfa, 0x31, 0x0e, 0xf2, 0x05, 0x35, 0x35, 0x6d, 0x6b, 0x88, 0x9d, - 0xc9, 0x4d, 0x15, 0x15, 0x74, 0xa4, 0x67, 0x8e, 0xa9, 0xa6, 0x2e, 0xe9, 0x48, 0xcf, 0x1c, 0xfb, - 0x1d, 0x21, 0x1a, 0x5e, 0x17, 0x46, 0xe2, 0x16, 0x84, 0xf1, 0xff, 0x77, 0xcb, 0x9f, 0x02, 0x14, - 0xc2, 0x0a, 0xb4, 0xac, 0xc1, 0x75, 0x2e, 0x95, 0x32, 0x64, 0x82, 0xe3, 0x36, 0x4e, 0x8e, 0x5b, - 0x23, 0xf0, 0xa5, 0xcf, 0x20, 0x19, 0x6e, 0x9d, 0x8d, 0x87, 0x5b, 0xeb, 0x07, 0x3b, 0xdd, 0x15, - 0x06, 0xcb, 0xb9, 0xad, 0xcb, 0xa0, 0x2e, 0x12, 0x7e, 0xda, 0xbf, 0x02, 0x94, 0xf4, 0x01, 0xb2, - 0x3c, 0x3c, 0xc4, 0x68, 0x10, 0xb2, 0x94, 0x3e, 0x86, 0x78, 0xc0, 0xad, 0xb0, 0x5c, 0xa8, 0x59, - 0xc6, 0x8d, 0x90, 0x8a, 0xe3, 0xb5, 0x0a, 0xc4, 0xdf, 0xba, 0x02, 0x89, 0xab, 0x2a, 0x20, 0x5e, - 0xa3, 0x02, 0xc9, 0x1b, 0x55, 0xe0, 0x37, 0x01, 0xf2, 0xd1, 0xd4, 0xf7, 0xf0, 0x62, 0xa8, 0x43, - 0x6a, 0xea, 0xa0, 0x21, 0x7e, 0xb1, 0xf6, 0x40, 0x0a, 0x9e, 0x7c, 0xcf, 0x90, 0x33, 0x3e, 0x46, - 0x6d, 0x9a, 0xc3, 0xa9, 0x70, 0x04, 0x27, 0xf1, 0x09, 0xe4, 0xd8, 0xc1, 0xd3, 0xee, 0x79, 0x47, - 0xae, 0x54, 0x82, 0xe4, 0x94, 0x18, 0xb2, 0x40, 0xeb, 0xcc, 0x1c, 0xed, 0x10, 0x36, 0xc3, 0x06, - 0xb3, 0xc4, 0x6b, 0x70, 0x0d, 0xbe, 0x1d, 0x8f, 0x7e, 0xfb, 0x6b, 0x48, 0xf3, 0xf7, 0x80, 0xa4, - 0x00, 0x60, 0x5f, 0x51, 0x0e, 0xfb, 0xa8, 0x11, 0x19, 0x21, 0x3a, 0x18, 0xa2, 0x9e, 0x37, 0x73, - 0x50, 0xb0, 0x13, 0x7c, 0x9f, 0xb1, 0xf9, 0xf4, 0x17, 0x01, 0x92, 0xec, 0x26, 0x78, 0x0c, 0xea, - 0x7e, 0x67, 0xb7, 0xd3, 0xea, 0x1e, 0xec, 0xe9, 0x7b, 0x7a, 0x47, 0xdf, 0xfd, 0x46, 0x3f, 0x6c, - 0x3d, 0xe9, 0x1e, 0xec, 0xed, 0xb7, 0x5b, 0x4d, 0xfd, 0xa9, 0xde, 0x7a, 0x52, 0x8c, 0x95, 0xef, - 0x9c, 0x9c, 0x56, 0x0a, 0x2b, 0x09, 0x92, 0x0c, 0xc0, 0x70, 0x64, 0xb0, 0x28, 0x94, 0x33, 0x27, - 0xa7, 0x15, 0x91, 0xd8, 0x92, 0x02, 0x05, 0x16, 0xe9, 0x18, 0xdf, 0x3d, 0x6f, 0xb7, 0xf6, 0x8a, - 0xf1, 0x72, 0xee, 0xe4, 0xb4, 0x92, 0xe6, 0x6e, 0x88, 0xa4, 0xc1, 0x04, 0x43, 0x12, 0xbb, 0x2c, - 0xbe, 0xfc, 0x55, 0x89, 0x35, 0xda, 0xaf, 0xcf, 0x14, 0xe1, 0xcd, 0x99, 0x22, 0xfc, 0x75, 0xa6, - 0x08, 0x3f, 0x9f, 0x2b, 0xb1, 0x37, 0xe7, 0x4a, 0xec, 0x8f, 0x73, 0x25, 0x76, 0xf8, 0x78, 0x84, - 0xbd, 0xa3, 0x59, 0x9f, 0xf4, 0xad, 0x66, 0xda, 0xee, 0xc4, 0x76, 0xf9, 0xcf, 0x7d, 0x77, 0x30, - 0xae, 0xbd, 0xa8, 0x91, 0x07, 0xfb, 0xe7, 0x8f, 0xee, 0x47, 0xfe, 0x36, 0x78, 0xf3, 0x29, 0x72, - 0xfb, 0x29, 0x7a, 0x43, 0x3e, 0xfa, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x86, 0xc8, 0x16, 0xfc, 0x55, - 0x0c, 0x00, 0x00, + // 1004 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xcd, 0x6f, 0x1a, 0x47, + 0x14, 0x67, 0x97, 0xe5, 0xeb, 0x01, 0x36, 0xd9, 0xe2, 0x78, 0x4b, 0x53, 0x16, 0x6d, 0x2f, 0x56, + 0xab, 0x40, 0x93, 0x54, 0x39, 0x20, 0xf5, 0x60, 0x08, 0x51, 0x57, 0x6d, 0x1c, 0xb4, 0xc6, 0x95, + 0xea, 0x43, 0x11, 0x1f, 0x03, 0x1e, 0x61, 0x76, 0xd1, 0xee, 0x52, 0x85, 0x6b, 0x0f, 0x55, 0x64, + 0xa9, 0x52, 0xaf, 0x3d, 0x58, 0x8a, 0xd4, 0xff, 0xa4, 0xa7, 0x48, 0xbd, 0xe4, 0xd8, 0x5e, 0x50, + 0x65, 0x5f, 0x7a, 0xe6, 0x1f, 0x68, 0x35, 0x1f, 0xfb, 0x01, 0x36, 0x87, 0xd8, 0x54, 0x3e, 0xf1, + 0xde, 0xfc, 0xde, 0x9b, 0x99, 0xf7, 0x9b, 0xdf, 0x9b, 0x1d, 0x40, 0xc5, 0xdd, 0x5e, 0xa5, 0x67, + 0x99, 0x26, 0xea, 0xb9, 0xd8, 0x32, 0x43, 0x66, 0x79, 0x62, 0x5b, 0xae, 0x25, 0x6f, 0xe1, 0x6e, + 0xaf, 0x1c, 0x8c, 0x16, 0xf2, 0x43, 0x6b, 0x68, 0x51, 0xa8, 0x42, 0x2c, 0x16, 0x55, 0xf8, 0x70, + 0x68, 0x59, 0xc3, 0x53, 0x54, 0xa1, 0x5e, 0x77, 0x3a, 0xa8, 0x74, 0xcc, 0x19, 0x87, 0xf8, 0x0a, + 0xe3, 0x31, 0x76, 0xc7, 0xc8, 0x74, 0x43, 0x26, 0x0f, 0xd8, 0xa5, 0x01, 0xa7, 0x98, 0x82, 0xf4, + 0x87, 0x01, 0xda, 0xcf, 0x22, 0xec, 0xbc, 0x70, 0x86, 0x75, 0x7f, 0xf1, 0x97, 0x13, 0x64, 0xea, + 0x26, 0x76, 0xe5, 0x47, 0x90, 0x62, 0x91, 0x6d, 0xdc, 0x57, 0x84, 0x92, 0xb0, 0x97, 0xaa, 0xe5, + 0x17, 0x73, 0x35, 0x37, 0xeb, 0x8c, 0x4f, 0xab, 0x9a, 0x0f, 0x69, 0x46, 0x92, 0xd9, 0x7a, 0x5f, + 0xfe, 0x12, 0xb2, 0x41, 0x15, 0x24, 0x4d, 0xa4, 0x69, 0xca, 0x62, 0xae, 0xe6, 0x79, 0x5a, 0x18, + 0xd6, 0x8c, 0x4c, 0xe0, 0xeb, 0x7d, 0xf9, 0x39, 0x64, 0x7a, 0xd6, 0xd4, 0x74, 0x91, 0x3d, 0xe9, + 0xd8, 0xee, 0x4c, 0x89, 0x96, 0x84, 0xbd, 0xf4, 0xe3, 0x07, 0xe5, 0x65, 0x76, 0xca, 0xf5, 0x50, + 0x4c, 0x4d, 0x7a, 0x3b, 0x57, 0x23, 0xc6, 0x52, 0x9e, 0xac, 0x40, 0xe2, 0x07, 0x64, 0x3b, 0xd8, + 0x32, 0x15, 0x89, 0x6c, 0xc0, 0xf0, 0x5c, 0xf9, 0x3e, 0xc4, 0x1d, 0x3c, 0x34, 0x91, 0xad, 0xc4, + 0x28, 0xc0, 0xbd, 0x6a, 0xf2, 0xf5, 0x1b, 0x35, 0xf2, 0xcf, 0x1b, 0x35, 0xa2, 0xfd, 0x14, 0x87, + 0xfc, 0x15, 0x3e, 0x5a, 0xf6, 0xec, 0x0e, 0xe8, 0x68, 0x42, 0x86, 0x4f, 0xeb, 0xb8, 0x1d, 0x17, + 0x71, 0x3a, 0xf2, 0x65, 0x26, 0x83, 0xb2, 0x27, 0x83, 0xf2, 0xbe, 0x39, 0xab, 0xed, 0x2e, 0xe6, + 0xea, 0x07, 0x4b, 0x5b, 0xa1, 0x39, 0x9a, 0x91, 0x66, 0xee, 0x21, 0xf1, 0xae, 0x10, 0x2c, 0xdd, + 0x90, 0xe0, 0x23, 0xd8, 0x09, 0xfb, 0x6d, 0x4e, 0xaf, 0xa3, 0xc4, 0x4a, 0xd1, 0xbd, 0x54, 0xad, + 0xb4, 0x98, 0xab, 0x0f, 0xbc, 0x02, 0xaf, 0x09, 0xd3, 0x8c, 0x7c, 0x78, 0xfc, 0x5b, 0x3e, 0x2c, + 0x1b, 0x90, 0x99, 0xd8, 0x96, 0x35, 0x68, 0x9f, 0x20, 0x3c, 0x3c, 0x71, 0x95, 0x38, 0xdd, 0x9e, + 0xcc, 0xb6, 0xc7, 0x44, 0xfb, 0x15, 0x45, 0x6a, 0x1f, 0x91, 0x4d, 0x05, 0x25, 0x87, 0xb3, 0x34, + 0x23, 0x4d, 0x5d, 0x16, 0x29, 0x7f, 0x01, 0xc0, 0x50, 0x6c, 0x62, 0x57, 0x49, 0x94, 0x84, 0xbd, + 0x4c, 0x6d, 0x67, 0x31, 0x57, 0xef, 0x85, 0x33, 0x09, 0xa6, 0x19, 0x29, 0xea, 0x50, 0xed, 0x57, + 0xbd, 0x9d, 0xb0, 0x65, 0x95, 0x24, 0xcd, 0xdb, 0x5d, 0x5d, 0x91, 0xa1, 0xde, 0x8a, 0x75, 0xea, + 0xc9, 0x75, 0xd8, 0xe6, 0xa8, 0x65, 0x3a, 0xc8, 0x74, 0xa6, 0x8e, 0x92, 0xa2, 0xe9, 0x85, 0xc5, + 0x5c, 0xbd, 0xbf, 0x94, 0xee, 0x05, 0x68, 0xc6, 0x16, 0x9b, 0xc1, 0x1b, 0x90, 0xbf, 0x87, 0x9c, + 0x8f, 0x7a, 0x74, 0xc0, 0x5a, 0x3a, 0x54, 0x4e, 0xc7, 0xae, 0xaf, 0xaa, 0xa5, 0x4c, 0xcd, 0xd8, + 0xf6, 0x87, 0x38, 0x2d, 0x41, 0x23, 0xa4, 0xd7, 0x34, 0xc2, 0x1f, 0xd2, 0x35, 0x8d, 0xb0, 0xdf, + 0x1b, 0x5d, 0x55, 0xb5, 0xf0, 0x5e, 0xaa, 0x0e, 0x35, 0xa7, 0xb8, 0xdc, 0x9c, 0x9b, 0xd7, 0xfb, + 0xaa, 0xa0, 0xa4, 0x0d, 0x08, 0xea, 0x11, 0x30, 0x9d, 0xb4, 0x5d, 0x7b, 0x46, 0x6f, 0x91, 0x4c, + 0xf8, 0x1e, 0xf0, 0x21, 0xcd, 0x48, 0x52, 0x9b, 0x5c, 0x1d, 0xab, 0x6a, 0x8a, 0xdf, 0x4e, 0x4d, + 0x89, 0x8d, 0xa8, 0x29, 0xf9, 0xbf, 0xa8, 0x29, 0xb5, 0x46, 0x4d, 0x3f, 0x8a, 0xa0, 0x5c, 0x51, + 0x53, 0xdd, 0x32, 0x07, 0xd8, 0x1e, 0xdf, 0x56, 0x51, 0xfe, 0x89, 0x74, 0x7a, 0x23, 0xaa, 0xa9, + 0x6b, 0x4e, 0xa4, 0xd3, 0x1b, 0x79, 0x27, 0x42, 0x34, 0xbc, 0x2a, 0x8c, 0xe8, 0x06, 0x84, 0x11, + 0x90, 0x20, 0xad, 0x21, 0xe1, 0x2f, 0x01, 0xb2, 0x01, 0x03, 0x0d, 0xb3, 0x7f, 0x93, 0x8f, 0x4a, + 0x01, 0x92, 0xfe, 0x75, 0x2b, 0x92, 0xeb, 0xd6, 0xf0, 0x7d, 0xf9, 0x33, 0x88, 0x05, 0xad, 0xb3, + 0xf5, 0x78, 0x67, 0xf5, 0x62, 0xa7, 0x5d, 0x61, 0xb0, 0x98, 0x4d, 0x7d, 0x0c, 0xaa, 0x12, 0xa9, + 0x4f, 0xfb, 0x57, 0x80, 0xbc, 0xde, 0x47, 0xa6, 0x8b, 0x07, 0x18, 0xf5, 0x83, 0x2a, 0xe5, 0x8f, + 0x41, 0xf4, 0x6b, 0xcb, 0x2e, 0xe6, 0x6a, 0x8a, 0xd5, 0x46, 0x8a, 0x12, 0xf1, 0x0a, 0x03, 0xe2, + 0x7b, 0x33, 0x10, 0x5d, 0xc7, 0x80, 0x74, 0x03, 0x06, 0x62, 0xb7, 0x62, 0xe0, 0x77, 0x01, 0x32, + 0xe1, 0xd0, 0x3b, 0x78, 0x31, 0x54, 0x21, 0x3e, 0xb1, 0xd1, 0x00, 0xbf, 0x5a, 0x79, 0x3a, 0xf9, + 0x8f, 0xc1, 0x17, 0xc8, 0x1e, 0x9d, 0xa2, 0x26, 0x8d, 0xe1, 0xa5, 0xf0, 0x0c, 0x5e, 0xc4, 0x27, + 0x90, 0x66, 0x17, 0x4f, 0xb3, 0xe3, 0x9e, 0x38, 0x72, 0x1e, 0x62, 0x13, 0x62, 0x28, 0x02, 0xe5, + 0x99, 0x39, 0xda, 0x31, 0x6c, 0x07, 0x07, 0xcc, 0x02, 0x6f, 0x50, 0xab, 0x3f, 0xb7, 0x18, 0x9e, + 0xfb, 0x6b, 0x48, 0xf0, 0xf7, 0x80, 0x5c, 0x04, 0xc0, 0x9e, 0xa2, 0x6c, 0x36, 0xa9, 0x11, 0x1a, + 0x21, 0x3a, 0x18, 0xa0, 0x8e, 0x3b, 0xb5, 0x91, 0xdf, 0x09, 0x9e, 0xcf, 0xaa, 0xf9, 0xf4, 0x57, + 0x01, 0x62, 0xec, 0x4b, 0xf0, 0x14, 0xd4, 0xc3, 0xd6, 0x7e, 0xab, 0xd1, 0x3e, 0x3a, 0xd0, 0x0f, + 0xf4, 0x96, 0xbe, 0xff, 0x8d, 0x7e, 0xdc, 0x78, 0xd6, 0x3e, 0x3a, 0x38, 0x6c, 0x36, 0xea, 0xfa, + 0x73, 0xbd, 0xf1, 0x2c, 0x17, 0x29, 0xdc, 0x3b, 0x3b, 0x2f, 0x65, 0x97, 0x02, 0x64, 0x05, 0x80, + 0xe5, 0x91, 0xc1, 0x9c, 0x50, 0x48, 0x9e, 0x9d, 0x97, 0x24, 0x62, 0xcb, 0x45, 0xc8, 0x32, 0xa4, + 0x65, 0x7c, 0xf7, 0xb2, 0xd9, 0x38, 0xc8, 0x89, 0x85, 0xf4, 0xd9, 0x79, 0x29, 0xc1, 0xdd, 0x20, + 0x93, 0x82, 0x51, 0x96, 0x49, 0xec, 0x82, 0xf4, 0xfa, 0xb7, 0x62, 0xa4, 0xd6, 0x7c, 0x7b, 0x51, + 0x14, 0xde, 0x5d, 0x14, 0x85, 0xbf, 0x2f, 0x8a, 0xc2, 0x2f, 0x97, 0xc5, 0xc8, 0xbb, 0xcb, 0x62, + 0xe4, 0xcf, 0xcb, 0x62, 0xe4, 0xf8, 0xe9, 0x10, 0xbb, 0x27, 0xd3, 0x2e, 0x39, 0xb7, 0x4a, 0xcf, + 0x72, 0xc6, 0x96, 0xc3, 0x7f, 0x1e, 0x3a, 0xfd, 0x51, 0xe5, 0x55, 0x85, 0x3c, 0xe5, 0x3f, 0x7f, + 0xf2, 0x30, 0xf4, 0x87, 0xc2, 0x9d, 0x4d, 0x90, 0xd3, 0x8d, 0xd3, 0x2f, 0xe4, 0x93, 0xff, 0x02, + 0x00, 0x00, 0xff, 0xff, 0x10, 0x68, 0x4f, 0x5f, 0x6f, 0x0c, 0x00, 0x00, } func (m *MsgConnectionOpenInit) Marshal() (dAtA []byte, err error) { @@ -646,6 +647,13 @@ func (m *MsgConnectionOpenInit) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.Signer) i = encodeVarintConnection(dAtA, i, uint64(len(m.Signer))) i-- + dAtA[i] = 0x2a + } + if len(m.Version) > 0 { + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintConnection(dAtA, i, uint64(len(m.Version))) + i-- dAtA[i] = 0x22 } { @@ -1241,6 +1249,10 @@ func (m *MsgConnectionOpenInit) Size() (n int) { } l = m.Counterparty.Size() n += 1 + l + sovConnection(uint64(l)) + l = len(m.Version) + if l > 0 { + n += 1 + l + sovConnection(uint64(l)) + } l = len(m.Signer) if l > 0 { n += 1 + l + sovConnection(uint64(l)) @@ -1618,6 +1630,38 @@ func (m *MsgConnectionOpenInit) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", 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.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } diff --git a/x/ibc/03-connection/types/msgs.go b/x/ibc/03-connection/types/msgs.go index 8f70559dbc35..52a151e3af52 100644 --- a/x/ibc/03-connection/types/msgs.go +++ b/x/ibc/03-connection/types/msgs.go @@ -17,13 +17,14 @@ var _ sdk.Msg = &MsgConnectionOpenInit{} func NewMsgConnectionOpenInit( connectionID, clientID, counterpartyConnectionID, counterpartyClientID string, counterpartyPrefix commitmenttypes.MerklePrefix, - signer sdk.AccAddress, + version string, signer sdk.AccAddress, ) *MsgConnectionOpenInit { counterparty := NewCounterparty(counterpartyClientID, counterpartyConnectionID, counterpartyPrefix) return &MsgConnectionOpenInit{ ConnectionId: connectionID, ClientId: clientID, Counterparty: counterparty, + Version: version, Signer: signer.String(), } } @@ -38,7 +39,7 @@ func (msg MsgConnectionOpenInit) Type() string { return "connection_open_init" } -// ValidateBasic implements sdk.Msg +// ValidateBasic implements sdk.Msg. func (msg MsgConnectionOpenInit) ValidateBasic() error { if err := host.ConnectionIdentifierValidator(msg.ConnectionId); err != nil { return sdkerrors.Wrap(err, "invalid connection ID") @@ -46,6 +47,11 @@ func (msg MsgConnectionOpenInit) ValidateBasic() error { if err := host.ClientIdentifierValidator(msg.ClientId); err != nil { return sdkerrors.Wrap(err, "invalid client ID") } + if msg.Version != "" { + if err := ValidateVersion(msg.Version); err != nil { + return sdkerrors.Wrap(err, "basic validation of the provided version failed") + } + } if msg.Signer == "" { return sdkerrors.ErrInvalidAddress } diff --git a/x/ibc/03-connection/types/msgs_test.go b/x/ibc/03-connection/types/msgs_test.go index 00cd17e23fbf..6be56856310e 100644 --- a/x/ibc/03-connection/types/msgs_test.go +++ b/x/ibc/03-connection/types/msgs_test.go @@ -67,37 +67,31 @@ func TestMsgTestSuite(t *testing.T) { func (suite *MsgTestSuite) TestNewMsgConnectionOpenInit() { prefix := commitmenttypes.NewMerklePrefix([]byte("storePrefixKey")) signer, _ := sdk.AccAddressFromBech32("cosmos1ckgw5d7jfj7wwxjzs9fdrdev9vc8dzcw3n2lht") - - testMsgs := []*types.MsgConnectionOpenInit{ - types.NewMsgConnectionOpenInit("test/conn1", "clienttotesta", "connectiontotest", "clienttotest", prefix, signer), - types.NewMsgConnectionOpenInit("ibcconntest", "test/iris", "connectiontotest", "clienttotest", prefix, signer), - types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "test/conn1", "clienttotest", prefix, signer), - types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "test/conn1", prefix, signer), - types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", emptyPrefix, signer), - types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", prefix, nil), - types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", prefix, signer), - } + // empty versions are considered valid, the default compatible versions + // will be used in protocol. + version := "" var testCases = []struct { + name string msg *types.MsgConnectionOpenInit expPass bool - errMsg string }{ - {testMsgs[0], false, "invalid connection ID"}, - {testMsgs[1], false, "invalid client ID"}, - {testMsgs[2], false, "invalid counterparty client ID"}, - {testMsgs[3], false, "invalid counterparty connection ID"}, - {testMsgs[4], false, "empty counterparty prefix"}, - {testMsgs[5], false, "empty singer"}, - {testMsgs[6], true, "success"}, + {"invalid connection ID", types.NewMsgConnectionOpenInit("test/conn1", "clienttotesta", "connectiontotest", "clienttotest", prefix, version, signer), false}, + {"invalid client ID", types.NewMsgConnectionOpenInit("ibcconntest", "test/iris", "connectiontotest", "clienttotest", prefix, version, signer), false}, + {"invalid counterparty client ID", types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "test/conn1", "clienttotest", prefix, version, signer), false}, + {"invalid counterparty connection ID", types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "test/conn1", prefix, version, signer), false}, + {"empty counterparty prefix", types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", emptyPrefix, version, signer), false}, + {"supplied version fails basic validation", types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", prefix, "bad version", signer), false}, + {"empty singer", types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", prefix, version, nil), false}, + {"success", types.NewMsgConnectionOpenInit("ibcconntest", "clienttotest", "connectiontotest", "clienttotest", prefix, version, signer), true}, } - for i, tc := range testCases { + for _, tc := range testCases { err := tc.msg.ValidateBasic() if tc.expPass { - suite.Require().NoError(err, "Msg %d failed: %v", i, err) + suite.Require().NoError(err, tc.name) } else { - suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) + suite.Require().Error(err, tc.name) } } } diff --git a/x/ibc/spec/01_concepts.md b/x/ibc/spec/01_concepts.md index 8ced5fb0de3f..7b565d410998 100644 --- a/x/ibc/spec/01_concepts.md +++ b/x/ibc/spec/01_concepts.md @@ -94,7 +94,9 @@ to support within their connection state. It is expected that this set of versions is from most preferred to least preferred. This is not a strict requirement for the SDK implementation of IBC because the party calling `ConnOpenTry` will greedily select the latest version it supports that the -counterparty supports as well. +counterparty supports as well. A specific version can optionally be passed +as `Version` to ensure that the handshake will either complete with that +version or fail. During `ConnOpenTry`, party B will select a version from the counterparty's supported versions. Priority will be placed on the latest supported version. diff --git a/x/ibc/spec/04_messages.md b/x/ibc/spec/04_messages.md index 6e68a11fac0c..30b0f5b96696 100644 --- a/x/ibc/spec/04_messages.md +++ b/x/ibc/spec/04_messages.md @@ -88,10 +88,11 @@ A connection is initialized on a light client using the `MsgConnectionOpenInit`. ```go type MsgConnectionOpenInit struct { - ClientId string - ConnectionId string - Counterparty Counterparty - Signer sdk.AccAddress + ClientId string + ConnectionId string + Counterparty Counterparty + Version string + Signer string } ``` @@ -99,11 +100,12 @@ This message is expected to fail if: - `ClientId` is invalid (see naming requirements) - `ConnectionId` is invalid (see naming requirements) - `Counterparty` is empty +- 'Version' is not empty and invalid - `Signer` is empty - A Client hasn't been created for the given ID - A Connection for the given ID already exists -The message creates a connection for the given ID with an INIT state. +The message creates a connection for the given ID with an INIT state. ### MsgConnectionOpenTry diff --git a/x/ibc/testing/chain.go b/x/ibc/testing/chain.go index 31181c7ee15b..f74bc4867c9f 100644 --- a/x/ibc/testing/chain.go +++ b/x/ibc/testing/chain.go @@ -50,8 +50,9 @@ const ( UnbondingPeriod time.Duration = time.Hour * 24 * 7 * 3 MaxClockDrift time.Duration = time.Second * 10 - DefaultChannelVersion = ibctransfertypes.Version - InvalidID = "IDisInvalid" + DefaultChannelVersion = ibctransfertypes.Version + DefaultOpenInitVersion = "" + InvalidID = "IDisInvalid" ConnectionIDPrefix = "conn" ChannelIDPrefix = "chan" @@ -572,7 +573,7 @@ func (chain *TestChain) ConnectionOpenInit( msg := connectiontypes.NewMsgConnectionOpenInit( connection.ID, connection.ClientID, counterpartyConnection.ID, connection.CounterpartyClientID, - counterparty.GetPrefix(), + counterparty.GetPrefix(), DefaultOpenInitVersion, chain.SenderAccount.GetAddress(), ) return chain.sendMsgs(msg)