Skip to content

Commit

Permalink
Flexible Connection Handshake Selection (#7427)
Browse files Browse the repository at this point in the history
* update connopeninit

Update ConnOpenInit to reflect changes in cosmos/ibc#482. An additional version field is added to the connection handshake and connection open init message to take in an optional field. If this field is empty, then the default versions are used for connection handshake version negotiation.

* add version compatibility check in open init

* implement partial changes to conn open try

* partial implementation of conn open ack changes

* fix tests

* add handshake tests

* make proto

* fix conflicts

* fix lint

* fix lint

* increase code cov

Co-authored-by: Federico Kunze <federico.kunze94@gmail.com>
  • Loading branch information
colin-axner and fedekunze committed Oct 1, 2020
1 parent 53f8aec commit 432ba30
Show file tree
Hide file tree
Showing 13 changed files with 657 additions and 312 deletions.
41 changes: 22 additions & 19 deletions proto/ibc/core/connection/v1/connection.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -28,21 +29,22 @@ message MsgConnectionOpenTry {

string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
string connection_id = 2 [(gogoproto.moretags) = "yaml:\"connection_id\""];
google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""];
Counterparty counterparty = 4 [(gogoproto.nullable) = false];
repeated string counterparty_versions = 5 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""];
ibc.core.client.v1.Height proof_height = 6
string proved_id = 3 [(gogoproto.moretags) = "yaml:\"proved_id\""];
google.protobuf.Any client_state = 4 [(gogoproto.moretags) = "yaml:\"client_state\""];
Counterparty counterparty = 5 [(gogoproto.nullable) = false];
repeated string counterparty_versions = 6 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""];
ibc.core.client.v1.Height proof_height = 7
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
// proof of the initialization the connection on Chain A: `UNITIALIZED ->
// INIT`
bytes proof_init = 7 [(gogoproto.moretags) = "yaml:\"proof_init\""];
bytes proof_init = 8 [(gogoproto.moretags) = "yaml:\"proof_init\""];
// proof of client state included in message
bytes proof_client = 8 [(gogoproto.moretags) = "yaml:\"proof_client\""];
bytes proof_client = 9 [(gogoproto.moretags) = "yaml:\"proof_client\""];
// proof of client consensus state
bytes proof_consensus = 9 [(gogoproto.moretags) = "yaml:\"proof_consensus\""];
ibc.core.client.v1.Height consensus_height = 10
bytes proof_consensus = 10 [(gogoproto.moretags) = "yaml:\"proof_consensus\""];
ibc.core.client.v1.Height consensus_height = 11
[(gogoproto.moretags) = "yaml:\"consensus_height\"", (gogoproto.nullable) = false];
string signer = 11;
string signer = 12;
}

// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to
Expand All @@ -51,21 +53,22 @@ message MsgConnectionOpenAck {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""];
string version = 2;
google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""];
ibc.core.client.v1.Height proof_height = 4
string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""];
string counterparty_connection_id = 2 [(gogoproto.moretags) = "yaml:\"counterparty_connection_id\""];
string version = 3;
google.protobuf.Any client_state = 4 [(gogoproto.moretags) = "yaml:\"client_state\""];
ibc.core.client.v1.Height proof_height = 5
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
// proof of the initialization the connection on Chain B: `UNITIALIZED ->
// TRYOPEN`
bytes proof_try = 5 [(gogoproto.moretags) = "yaml:\"proof_try\""];
bytes proof_try = 6 [(gogoproto.moretags) = "yaml:\"proof_try\""];
// proof of client state included in message
bytes proof_client = 6 [(gogoproto.moretags) = "yaml:\"proof_client\""];
bytes proof_client = 7 [(gogoproto.moretags) = "yaml:\"proof_client\""];
// proof of client consensus state
bytes proof_consensus = 7 [(gogoproto.moretags) = "yaml:\"proof_consensus\""];
ibc.core.client.v1.Height consensus_height = 8
bytes proof_consensus = 8 [(gogoproto.moretags) = "yaml:\"proof_consensus\""];
ibc.core.client.v1.Height consensus_height = 9
[(gogoproto.moretags) = "yaml:\"consensus_height\"", (gogoproto.nullable) = false];
string signer = 9;
string signer = 10;
}

// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to
Expand Down
63 changes: 48 additions & 15 deletions x/ibc/03-connection/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,23 @@ import (
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)

const (
flagVersionIdentifier = "version-identifier"
flagVersionFeatures = "version-features"
flagProvedID = "proved-id"
)

// 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),
Expand All @@ -45,9 +53,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 {
Expand All @@ -58,6 +84,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
Expand Down Expand Up @@ -87,6 +117,7 @@ func NewConnectionOpenTryCmd() *cobra.Command {
}

connectionID := args[0]
provedID, _ := cmd.Flags().GetString(flagProvedID)
clientID := args[1]
counterpartyConnectionID := args[2]
counterpartyClientID := args[3]
Expand Down Expand Up @@ -129,7 +160,7 @@ func NewConnectionOpenTryCmd() *cobra.Command {
}

msg := types.NewMsgConnectionOpenTry(
connectionID, clientID, counterpartyConnectionID, counterpartyClientID,
connectionID, provedID, clientID, counterpartyConnectionID, counterpartyClientID,
counterpartyClient, counterpartyPrefix, []string{counterpartyVersions},
proofInit, proofClient, proofConsensus, proofHeight,
consensusHeight, clientCtx.GetFromAddress(),
Expand All @@ -143,6 +174,7 @@ func NewConnectionOpenTryCmd() *cobra.Command {
},
}

cmd.Flags().String(flagProvedID, "", "identifier set by the counterparty chain")
flags.AddTxFlagsToCmd(cmd)

return cmd
Expand All @@ -152,16 +184,16 @@ func NewConnectionOpenTryCmd() *cobra.Command {
// connection open attempt from chain B to chain A
func NewConnectionOpenAckCmd() *cobra.Command {
cmd := &cobra.Command{
Use: `open-ack [connection-id] [path/to/client_state.json] [consensus-height] [proof-height]
Use: `open-ack [connection-id] [counterparty-connection-id] [path/to/client_state.json] [consensus-height] [proof-height]
[path/to/proof_try.json] [path/to/proof_client.json] [path/to/proof_consensus.json] [version]`,
Short: "relay the acceptance of a connection open attempt",
Long: "Relay the acceptance of a connection open attempt from chain B to chain A",
Example: fmt.Sprintf(
`%s tx %s %s open-ack [connection-id] [path/to/client_state.json] [consensus-height] [proof-height]
`%s tx %s %s open-ack [connection-id] [counterparty-connection-id] [path/to/client_state.json] [consensus-height] [proof-height]
[path/to/proof_try.json] [path/to/proof_client.json] [path/to/proof_consensus.json] [version]`,
version.AppName, host.ModuleName, types.SubModuleName,
),
Args: cobra.ExactArgs(8),
Args: cobra.ExactArgs(9),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.ReadTxCommandFlags(clientCtx, cmd.Flags())
Expand All @@ -170,40 +202,41 @@ func NewConnectionOpenAckCmd() *cobra.Command {
}

connectionID := args[0]
counterpartyConnectionID := args[1]

counterpartyClient, err := utils.ParseClientState(clientCtx.LegacyAmino, args[1])
counterpartyClient, err := utils.ParseClientState(clientCtx.LegacyAmino, args[2])
if err != nil {
return err
}

consensusHeight, err := clienttypes.ParseHeight(args[2])
consensusHeight, err := clienttypes.ParseHeight(args[3])
if err != nil {
return err
}
proofHeight, err := clienttypes.ParseHeight(args[3])
proofHeight, err := clienttypes.ParseHeight(args[4])
if err != nil {
return err
}

proofTry, err := utils.ParseProof(clientCtx.LegacyAmino, args[4])
proofTry, err := utils.ParseProof(clientCtx.LegacyAmino, args[5])
if err != nil {
return err
}

proofClient, err := utils.ParseProof(clientCtx.LegacyAmino, args[5])
proofClient, err := utils.ParseProof(clientCtx.LegacyAmino, args[6])
if err != nil {
return err
}

proofConsensus, err := utils.ParseProof(clientCtx.LegacyAmino, args[6])
proofConsensus, err := utils.ParseProof(clientCtx.LegacyAmino, args[7])
if err != nil {
return err
}

version := args[7]
version := args[8]

msg := types.NewMsgConnectionOpenAck(
connectionID, counterpartyClient, proofTry, proofClient, proofConsensus, proofHeight,
connectionID, counterpartyConnectionID, counterpartyClient, proofTry, proofClient, proofConsensus, proofHeight,
consensusHeight, version, clientCtx.GetFromAddress(),
)

Expand Down
6 changes: 3 additions & 3 deletions x/ibc/03-connection/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down Expand Up @@ -43,7 +43,7 @@ func HandleMsgConnectionOpenTry(ctx sdk.Context, k keeper.Keeper, msg *types.Msg
}

if err := k.ConnOpenTry(
ctx, msg.ConnectionId, msg.Counterparty, msg.ClientId, targetClient,
ctx, msg.ConnectionId, msg.ProvedId, msg.Counterparty, msg.ClientId, targetClient,
msg.CounterpartyVersions, msg.ProofInit, msg.ProofClient, msg.ProofConsensus,
msg.ProofHeight, msg.ConsensusHeight,
); err != nil {
Expand Down Expand Up @@ -77,7 +77,7 @@ func HandleMsgConnectionOpenAck(ctx sdk.Context, k keeper.Keeper, msg *types.Msg
}

if err := k.ConnOpenAck(
ctx, msg.ConnectionId, targetClient, msg.Version,
ctx, msg.ConnectionId, targetClient, msg.Version, msg.CounterpartyConnectionId,
msg.ProofTry, msg.ProofClient, msg.ProofConsensus,
msg.ProofHeight, msg.ConsensusHeight,
); err != nil {
Expand Down
Loading

0 comments on commit 432ba30

Please sign in to comment.