diff --git a/e2e/e2e/connection.py b/e2e/e2e/connection.py index 2e97d742f2..4fdcab762f 100644 --- a/e2e/e2e/connection.py +++ b/e2e/e2e/connection.py @@ -19,9 +19,7 @@ class TxConnInit(Cmd[TxConnInitRes]): def args(self) -> List[str]: return [self.dst_chain_id, self.src_chain_id, - self.dst_client_id, self.src_client_id, - "default-conn", - "default-conn"] + self.dst_client_id, self.src_client_id] def process(self, result: Any) -> TxConnInitRes: return from_dict(TxConnInitRes, result[0]['OpenInitConnection']) @@ -46,7 +44,7 @@ class TxConnTry(Cmd[TxConnTryRes]): def args(self) -> List[str]: return [self.dst_chain_id, self.src_chain_id, self.dst_client_id, self.src_client_id, - "default-conn", self.src_conn_id] + "--src-connection-id", self.src_conn_id] def process(self, result: Any) -> TxConnTryRes: return from_dict(TxConnTryRes, result[0]['OpenTryConnection']) @@ -72,7 +70,8 @@ class TxConnAck(Cmd[TxConnAckRes]): def args(self) -> List[str]: return [self.dst_chain_id, self.src_chain_id, self.dst_client_id, self.src_client_id, - self.dst_conn_id, self.src_conn_id] + "--dst-connection-id", self.dst_conn_id, + "--src-connection-id", self.src_conn_id] def process(self, result: Any) -> TxConnAckRes: return from_dict(TxConnAckRes, result[0]['OpenAckConnection']) @@ -98,7 +97,8 @@ class TxConnConfirm(Cmd[TxConnConfirmRes]): def args(self) -> List[str]: return [self.dst_chain_id, self.src_chain_id, self.dst_client_id, self.src_client_id, - self.dst_conn_id, self.src_conn_id] + "--dst-connection-id", self.dst_conn_id, + "--src-connection-id", self.src_conn_id] def process(self, result: Any) -> TxConnConfirmRes: return from_dict(TxConnConfirmRes, result[0]['OpenConfirmConnection']) diff --git a/guide/src/relay_packets.md b/guide/src/relay_packets.md index 68ced236f9..16e9224c45 100644 --- a/guide/src/relay_packets.md +++ b/guide/src/relay_packets.md @@ -135,22 +135,23 @@ hermes -c config.toml tx raw update-client ibc-1 ibc-0 07-tendermint-1 #### 2.1 `conn-init` ```shell -hermes -c config.toml tx raw conn-init ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 dummyconnection dummyconnection +hermes -c config.toml tx raw conn-init ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 ``` Take note of the ID allocated by the chain, e.g. `connection-0` on `ibc-0` in order to use it in the `conn-try` command below. #### 2.2 `conn-try` + __Note__: If this is the first connection to be created on `ibc-1`, prior to the `conn-try` command, you can send a `conn-init` to `ibc-1` and the chain will allocate `connection-0`. This will ensure that the next available ID, `connection-1`, will be allocated in `conn-try`. ```shell -hermes -c config.toml tx raw conn-init ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 dummyconnection dummyconnection +hermes -c config.toml tx raw conn-init ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 ``` To send a `conn-try` message to `ibc-1`: ```shell -hermes -c config.toml tx raw conn-try ibc-1 ibc-0 07-tendermint-0 07-tendermint-1 dummyconnection connection-0 +hermes -c config.toml tx raw conn-try ibc-1 ibc-0 07-tendermint-0 07-tendermint-1 -s connection-0 ``` Take note of the ID allocated by the chain, e.g. `connection-1` on `ibc-1`. Use in the `conn-ack` CLI @@ -158,13 +159,13 @@ Take note of the ID allocated by the chain, e.g. `connection-1` on `ibc-1`. Use #### 2.3 conn-ack ```shell -hermes -c config.toml tx raw conn-ack ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 connection-0 connection-1 +hermes -c config.toml tx raw conn-ack ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 -d connection-0 -s connection-1 ``` #### 2.4 conn-confirm ```shell -hermes -c config.toml tx raw conn-confirm ibc-1 ibc-0 07-tendermint-1 07-tendermint-0 connection-1 connection-0 +hermes -c config.toml tx raw conn-confirm ibc-1 ibc-0 07-tendermint-1 07-tendermint-0 -d connection-1 -s connection-0 ``` #### 2.5 query connection diff --git a/guide/src/tx_connection.md b/guide/src/tx_connection.md index 42d070c720..dd437d58b7 100644 --- a/guide/src/tx_connection.md +++ b/guide/src/tx_connection.md @@ -1 +1,198 @@ -# Connection +# Connection Handshake + +The `tx raw` commands can be used to establish a connection between two clients. + +## Connection Init + +Use the `conn-init` command to initialize a new connection on a chain. + +```shell +USAGE: + hermes tx raw conn-init + +DESCRIPTION: + Initialize a connection attempt on chain A + +POSITIONAL ARGUMENTS: + dst_chain_id identifier of the destination chain + src_chain_id identifier of the source chain + dst_client_id identifier of the destination client + src_client_id identifier of the source client +``` + +__Example__ + +Given that a two clients was previously created on chain `ibc-0` with identifier `07-tendermint-0`, +respectively on chain `ibc-1` with identifier `07-tendermint-1`, we can initialize a connection between +the two clients. + +First, let's initialize the connection on `ibc-0`: + +```shell +$ hermes -c config.toml tx raw conn-init ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 +``` + +```json +{ + "status": "success", + "result": [ + { + "OpenInitConnection": { + "client_id": "07-tendermint-0", + "connection_id": "connection-0", + "counterparty_client_id": "07-tendermint-1", + "counterparty_connection_id": null, + "height": "1" + } + } + ] +} +``` + +A new connection has been initialized on `ibc-0` with identifier `connection-0`. +Note that the `counterparty_connection_id` field is currently empty. + + +## Connection Try + +Use the `conn-try` command to establish a counterparty to the connection on the other chain. + +```shell +USAGE: + hermes tx raw conn-try + +DESCRIPTION: + Relay notice of a connection attempt on chain A to chain B + +POSITIONAL ARGUMENTS: + dst_chain_id identifier of the destination chain + src_chain_id identifier of the source chain + dst_client_id identifier of the destination client + src_client_id identifier of the source client + +FLAGS: + -s, --src-connection-id SRC-CONNECTION-ID +``` + +__Example__ + +Let's now create the counterparty to `connection-0` on chain `ibc-1`: + +```shell +$ hermes -c config.toml tx raw conn-try ibc-1 ibc-0 07-tendermint-1 07-tendermint-0 -s connection-0 | jq +``` + +```json +{ + "status": "success", + "result": [ + { + "type": "OpenTryConnection", + "client_id": "07-tendermint-1", + "connection_id": "connection-1", + "counterparty_client_id": "07-tendermint-0", + "counterparty_connection_id": "connection-0", + "height": "1" + } + ] +} +``` + +A new connection has been created on `ibc-1` with identifier `connection-1`. +Note that the field `counterparty_connection_id` points to the connection on `ibc-0`. + + +## Connection Ack + +Use the `conn-ack` command to acknowledge the connection on the initial chain. + +```shell +USAGE: + hermes tx raw conn-ack + +DESCRIPTION: + Relay acceptance of a connection attempt from chain B back to chain A + +POSITIONAL ARGUMENTS: + dst_chain_id identifier of the destination chain + src_chain_id identifier of the source chain + dst_client_id identifier of the destination client + src_client_id identifier of the source client + +FLAGS: + -d, --dst-connection-id DST-CONNECTION-ID + -s, --src-connection-id SRC-CONNECTION-ID +``` + +__Example__ + +```shell +$ hermes -c config.toml tx raw conn-ack ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 -d connection-0 -s connection-1 | jq +``` + +```json +{ + "status": "success", + "result": [ + { + "type": "OpenAckConnection", + "client_id": "07-tendermint-0", + "connection_id": "connection-0", + "counterparty_client_id": "07-tendermint-1", + "counterparty_connection_id": "connection-1", + "height": "1" + } + ] +} +``` + +Note that the field `counterparty_connection_id` now points to the connection on `ibc-1`. + + +## Connection Confirm + +Use the `conn-confirm` command to confirm that the connection has been acknowledged, +and finish the handshake. + +```shell +USAGE: + hermes tx raw conn-confirm + +DESCRIPTION: + Confirm opening of a connection on chain A to chain B, after which the connection is open on both chains + +POSITIONAL ARGUMENTS: + dst_chain_id identifier of the destination chain + src_chain_id identifier of the source chain + dst_client_id identifier of the destination client + src_client_id identifier of the source client + +FLAGS: + -d, --dst-connection-id DST-CONNECTION-ID + -s, --src-connection-id SRC-CONNECTION-ID +``` + +__Example__ + +```shell +$ hermes -c config.toml tx raw conn-confirm ibc-1 ibc-0 07-tendermint-1 07-tendermint-0 -d connection-1 -s connection-0 | jq +``` + +```json +{ + "status": "success", + "result": [ + { + "type": "OpenConfirmConnection", + "client_id": "07-tendermint-1", + "connection_id": "connection-1", + "counterparty_client_id": "07-tendermint-0", + "counterparty_connection_id": "connection-0", + "height": "1" + } + ] +} +``` + +We have now successfully established a connection between the two chains! + diff --git a/relayer-cli/README.md b/relayer-cli/README.md index f5f331f4de..ccff16751a 100644 --- a/relayer-cli/README.md +++ b/relayer-cli/README.md @@ -17,9 +17,9 @@ relayer-cli -c config.toml tx raw create-client dest_chain_id src_chain_id dest_ relayer-cli -c config.toml tx raw create-client dest_chain_id src_chain_id dest_client_id -relayer-cli -c config.toml tx raw conn-init dest_chain_id src_chain_id dest_client_id src_client_id dest_connection_id -d src_connection_id +relayer-cli -c config.toml tx raw conn-init dest_chain_id src_chain_id dest_client_id src_client_id -relayer-cli -c config.toml tx raw conn-try dest_chain_id src_chain_id dest_client_id src_client_id dest_connection_id src_connection_id +relayer-cli -c config.toml tx raw conn-try dest_chain_id src_chain_id dest_client_id src_client_id -s src_connection_id ``` Note: This is work in progress, more commands will be implemented and tested with gaia `cosmos-test-stargate` chains. @@ -47,7 +47,7 @@ Note: This is work in progress, more commands will be implemented and tested wit * Run the transaction command. In this example, it will try to initialize an `ibczeroconn2` connection on chain `ibc-1` - `$ cargo run --bin hermes -- -c ./relayer-cli/tests/fixtures/two_chains.toml tx raw conn-init ibc-1 ibc-0 ibczeroclient ibconeclient ibczeroconn2 -d ibconeconn` + `$ cargo run --bin hermes -- -c ./relayer-cli/tests/fixtures/two_chains.toml tx raw conn-init ibc-1 ibc-0 ibczeroclient ibconeclient` If you get an empty response it means the tx worked diff --git a/relayer-cli/relayer_operation_instructions.md b/relayer-cli/relayer_operation_instructions.md index c9bf3c3324..e63d9949a5 100644 --- a/relayer-cli/relayer_operation_instructions.md +++ b/relayer-cli/relayer_operation_instructions.md @@ -44,7 +44,7 @@ alias hermes='cargo run --bin hermes --' ```shell script hermes -c config.toml tx raw create-client ibc-1 ibc-0 -hermes -c config.toml tx raw conn-init ibc-1 ibc-0 07-tendermint-0 07-tendermint-0 dummyconnection dummyconnection +hermes -c config.toml tx raw conn-init ibc-1 ibc-0 07-tendermint-0 07-tendermint-0 hermes -c config.toml tx raw chan-open-init ibc-1 ibc-0 connection-0 transfer transfer defaultChannel defaultChannel ``` @@ -73,7 +73,7 @@ hermes -c config.toml tx raw chan-open-init ibc-1 ibc-0 connection-0 transfer tr - init-none: ```shell script - hermes -c config.toml tx raw conn-init ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 dummyconnection dummyconnection + hermes -c config.toml tx raw conn-init ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 ``` Take note of the ID allocated by the chain, e.g. `connection-0` on `ibc-0`. Use in the `conn-try` CLI @@ -81,7 +81,7 @@ hermes -c config.toml tx raw chan-open-init ibc-1 ibc-0 connection-0 transfer tr - init-try: ```shell script - hermes -c config.toml tx raw conn-try ibc-1 ibc-0 07-tendermint-1 07-tendermint-0 dummyconnection connection-0 + hermes -c config.toml tx raw conn-try ibc-1 ibc-0 07-tendermint-1 07-tendermint-0 -s connection-0 ``` Take note of the ID allocated by the chain, e.g. `connection-1` on `ibc-1`. Use in the `conn-ack` CLI @@ -89,13 +89,13 @@ hermes -c config.toml tx raw chan-open-init ibc-1 ibc-0 connection-0 transfer tr - open-try: ```shell script - hermes -c config.toml tx raw conn-ack ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 connection-0 connection-1 + hermes -c config.toml tx raw conn-ack ibc-0 ibc-1 07-tendermint-0 07-tendermint-1 -d connection-0 -s connection-1 ``` - open-open: ```shell script - hermes -c config.toml tx raw conn-confirm ibc-1 ibc-0 07-tendermint-1 07-tendermint-0 connection-1 connection-0 + hermes -c config.toml tx raw conn-confirm ibc-1 ibc-0 07-tendermint-1 07-tendermint-0 -d connection-1 -s connection-0 ``` - verify that the two ends are in Open state: diff --git a/relayer-cli/src/commands/tx.rs b/relayer-cli/src/commands/tx.rs index 16bd544f87..1c8dfc02e2 100644 --- a/relayer-cli/src/commands/tx.rs +++ b/relayer-cli/src/commands/tx.rs @@ -36,19 +36,21 @@ pub enum TxRawCommands { UpdateClient(TxUpdateClientCmd), /// The `tx raw conn-init` subcommand - #[options(help = "tx raw conn-init")] + #[options(help = "Initialize a connection attempt on chain A")] ConnInit(connection::TxRawConnInitCmd), /// The `tx raw conn-try` subcommand - #[options(help = "tx raw conn-try")] + #[options(help = "Relay notice of a connection attempt on chain A to chain B")] ConnTry(connection::TxRawConnTryCmd), /// The `tx raw conn-ack` subcommand - #[options(help = "tx raw conn-ack")] + #[options(help = "Relay acceptance of a connection attempt from chain B back to chain A")] ConnAck(connection::TxRawConnAckCmd), /// The `tx raw conn-confirm` subcommand - #[options(help = "tx raw conn-confirm")] + #[options( + help = "Confirm opening of a connection on chain A to chain B, after which the connection is open on both chains" + )] ConnConfirm(connection::TxRawConnConfirmCmd), /// The `tx raw chan-open-init` subcommand diff --git a/relayer-cli/src/commands/tx/connection.rs b/relayer-cli/src/commands/tx/connection.rs index 18568c5ddf..df0e795677 100644 --- a/relayer-cli/src/commands/tx/connection.rs +++ b/relayer-cli/src/commands/tx/connection.rs @@ -11,44 +11,99 @@ use crate::error::{Error, Kind}; use crate::prelude::*; macro_rules! conn_open_cmd { - ($conn_open_cmd:ident, $dbg_string:literal, $func:ident) => { - #[derive(Clone, Command, Debug, Options)] - pub struct $conn_open_cmd { - #[options(free, required, help = "identifier of the destination chain")] - dst_chain_id: ChainId, + ($dbg_string:literal, $func:ident, $self:expr, $conn:expr) => { + let config = app_config(); + + let spawn_options = SpawnOptions::override_store_config(StoreConfig::memory()); + let chains = match ChainHandlePair::spawn_with( + spawn_options, + &config, + &$self.src_chain_id, + &$self.dst_chain_id, + ) { + Ok(chains) => chains, + Err(e) => return Output::error(format!("{}", e)).exit(), + }; + + let connection = $conn(chains); + + info!("Message {}: {:?}", $dbg_string, connection); + + let res: Result = + connection.$func().map_err(|e| Kind::Tx.context(e).into()); + + match res { + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), + } + }; +} - #[options(free, required, help = "identifier of the source chain")] - src_chain_id: ChainId, +#[derive(Clone, Command, Debug, Options)] +pub struct TxRawConnInitCmd { + #[options(free, required, help = "identifier of the destination chain")] + dst_chain_id: ChainId, - #[options(free, required, help = "identifier of the destination client")] - dst_client_id: ClientId, + #[options(free, required, help = "identifier of the source chain")] + src_chain_id: ChainId, - #[options(free, required, help = "identifier of the source client")] - src_client_id: ClientId, + #[options(free, required, help = "identifier of the destination client")] + dst_client_id: ClientId, - #[options(free, required, help = "identifier of the destination connection")] - dst_connection_id: ConnectionId, + #[options(free, required, help = "identifier of the source client")] + src_client_id: ClientId, +} - #[options(free, required, help = "identifier of the source connection")] - src_connection_id: ConnectionId, - } +impl Runnable for TxRawConnInitCmd { + fn run(&self) { + conn_open_cmd!( + "ConnOpenInit", + build_conn_init_and_send, + self, + |chains: ChainHandlePair| { + Connection { + a_side: ConnectionSide::new( + chains.src, + self.src_client_id.clone(), + ConnectionId::default(), + ), + b_side: ConnectionSide::new( + chains.dst, + self.dst_client_id.clone(), + ConnectionId::default(), + ), + } + } + ); + } +} + +#[derive(Clone, Command, Debug, Options)] +pub struct TxRawConnTryCmd { + #[options(free, required, help = "identifier of the destination chain")] + dst_chain_id: ChainId, + + #[options(free, required, help = "identifier of the source chain")] + src_chain_id: ChainId, + + #[options(free, required, help = "identifier of the destination client")] + dst_client_id: ClientId, - impl Runnable for $conn_open_cmd { - fn run(&self) { - let config = app_config(); - - let spawn_options = SpawnOptions::override_store_config(StoreConfig::memory()); - let chains = match ChainHandlePair::spawn_with( - spawn_options, - &config, - &self.src_chain_id, - &self.dst_chain_id, - ) { - Ok(chains) => chains, - Err(e) => return Output::error(format!("{}", e)).exit(), - }; - - let connection = Connection { + #[options(free, required, help = "identifier of the source client")] + src_client_id: ClientId, + + #[options(required, help = "identifier of the source connection")] + src_connection_id: ConnectionId, +} + +impl Runnable for TxRawConnTryCmd { + fn run(&self) { + conn_open_cmd!( + "ConnOpenTry", + build_conn_try_and_send, + self, + |chains: ChainHandlePair| { + Connection { a_side: ConnectionSide::new( chains.src, self.src_client_id.clone(), @@ -57,32 +112,100 @@ macro_rules! conn_open_cmd { b_side: ConnectionSide::new( chains.dst, self.dst_client_id.clone(), - self.dst_connection_id.clone(), + ConnectionId::default(), ), - }; + } + } + ); + } +} + +#[derive(Clone, Command, Debug, Options)] +pub struct TxRawConnAckCmd { + #[options(free, required, help = "identifier of the destination chain")] + dst_chain_id: ChainId, + + #[options(free, required, help = "identifier of the source chain")] + src_chain_id: ChainId, + + #[options(free, required, help = "identifier of the destination client")] + dst_client_id: ClientId, + + #[options(free, required, help = "identifier of the source client")] + src_client_id: ClientId, - info!("Message {}: {:?}", $dbg_string, connection); + #[options(required, help = "identifier of the destination connection")] + dst_connection_id: ConnectionId, - let res: Result = - connection.$func().map_err(|e| Kind::Tx.context(e).into()); + #[options(required, help = "identifier of the source connection")] + src_connection_id: ConnectionId, +} - match res { - Ok(receipt) => Output::success(receipt).exit(), - Err(e) => Output::error(format!("{}", e)).exit(), +impl Runnable for TxRawConnAckCmd { + fn run(&self) { + conn_open_cmd!( + "ConnOpenAck", + build_conn_ack_and_send, + self, + |chains: ChainHandlePair| { + Connection { + a_side: ConnectionSide::new( + chains.src, + self.src_client_id.clone(), + self.src_connection_id.clone(), + ), + b_side: ConnectionSide::new( + chains.dst, + self.dst_client_id.clone(), + self.dst_connection_id.clone(), + ), } } - } - }; + ); + } } -conn_open_cmd!(TxRawConnInitCmd, "ConnOpenInit", build_conn_init_and_send); +#[derive(Clone, Command, Debug, Options)] +pub struct TxRawConnConfirmCmd { + #[options(free, required, help = "identifier of the destination chain")] + dst_chain_id: ChainId, + + #[options(free, required, help = "identifier of the source chain")] + src_chain_id: ChainId, + + #[options(free, required, help = "identifier of the destination client")] + dst_client_id: ClientId, -conn_open_cmd!(TxRawConnTryCmd, "ConnOpenTry", build_conn_try_and_send); + #[options(free, required, help = "identifier of the source client")] + src_client_id: ClientId, -conn_open_cmd!(TxRawConnAckCmd, "ConnOpenAck", build_conn_ack_and_send); + #[options(required, help = "identifier of the destination connection")] + dst_connection_id: ConnectionId, -conn_open_cmd!( - TxRawConnConfirmCmd, - "ConnOpenConfirm", - build_conn_confirm_and_send -); + #[options(required, help = "identifier of the source connection")] + src_connection_id: ConnectionId, +} + +impl Runnable for TxRawConnConfirmCmd { + fn run(&self) { + conn_open_cmd!( + "ConnOpenConfirm", + build_conn_confirm_and_send, + self, + |chains: ChainHandlePair| { + Connection { + a_side: ConnectionSide::new( + chains.src, + self.src_client_id.clone(), + self.src_connection_id.clone(), + ), + b_side: ConnectionSide::new( + chains.dst, + self.dst_client_id.clone(), + self.dst_connection_id.clone(), + ), + } + } + ); + } +}