From 1098ac01fe5800eca172d478d9d11bf2f59f2b4f Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Tue, 8 Jun 2021 16:55:34 +0200 Subject: [PATCH 01/13] Countermeasure that fixes #1038 --- relayer/src/channel.rs | 18 +++++++++++++++--- relayer/src/link.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 75bff12ad9..f1fac75d47 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -420,12 +420,24 @@ impl Channel { let a_channel = self .src_chain() .query_channel(&self.src_port_id(), src_channel_id, Height::zero()) - .map_err(|_| ChannelError::Failed("Failed to query source chain".into()))?; + .map_err(|_| { + ChannelError::Failed( + format!("failed to query source chain {}", self.src_chain().id()).into(), + ) + })?; let b_channel = self .dst_chain() .query_channel(&self.dst_port_id(), dst_channel_id, Height::zero()) - .map_err(|_| ChannelError::Failed("Failed to query destination chain".into()))?; + .map_err(|_| { + ChannelError::Failed( + format!( + "failed to query destination chain {}", + self.dst_chain().id() + ) + .into(), + ) + })?; match (a_channel.state(), b_channel.state()) { (State::Init, State::TryOpen) | (State::TryOpen, State::TryOpen) => { @@ -457,7 +469,7 @@ impl Channel { info!("done {} => {:#?}\n", self.src_chain().id(), event) } (State::Open, State::Open) => { - info!("Channel handshake finished for {:#?}\n", self); + info!("channel handshake finished for {:#?}\n", self); } _ => { /* TODO channel close */ } } diff --git a/relayer/src/link.rs b/relayer/src/link.rs index 685451c7c1..0939c043be 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -1634,6 +1634,43 @@ impl Link { ))); } + // Check that the counterparty details on the destination chain matches the source chain + let b_channel = b_chain + .query_channel( + &a_channel.counterparty().port_id, + &b_channel_id, + Height::default(), + ) + .map_err(|e| { + LinkError::Failed(format!( + "channel/port {}/{} does not exist on destination chain {}; context={}", + b_channel_id, + a_channel.counterparty().port_id, + b_chain.id(), + e + )) + })?; + match b_channel.counterparty().channel_id.clone() { + Some(actual_a_channel_id) => { + if actual_a_channel_id.ne(a_channel_id) + || b_channel.counterparty().port_id != opts.src_port_id + { + return Err(LinkError::Failed(format!("conflicting link configuration: channel/port {}/{} on destination chain {} does not point back to the source chain {}:{}/{} (but points to {}/{})", + b_channel_id, a_channel.counterparty().port_id, b_chain.id(), a_chain.id(), + a_channel_id, opts.src_port_id, actual_a_channel_id, b_channel.counterparty().port_id))); + } + } + None => { + return Err(LinkError::Failed(format!( + "the channel/port {}/{} on destination chain {} has no counterparty channel set", + b_channel_id, + a_channel.counterparty().port_id, + b_chain.id() + ))); + } + } + + // Check the underlying connection let a_connection_id = a_channel.connection_hops()[0].clone(); let a_connection = a_chain.query_connection(&a_connection_id, Height::zero())?; From 29fba58e0335838333baef0fa2faec48561d806c Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Tue, 8 Jun 2021 17:50:06 +0200 Subject: [PATCH 02/13] Tentative fix for #1064 --- relayer/src/channel.rs | 63 +++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index f1fac75d47..3f4c97b7b5 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -70,6 +70,9 @@ pub enum ChannelError { "failed during a transaction submission step to chain id {0} with underlying error: {1}" )] SubmitError(ChainId, Error), + + #[error("the channel is partially open ({0}, {1})")] + PartialOpenHandshake(State, State), } #[derive(Clone, Debug, Serialize)] @@ -407,7 +410,10 @@ impl Channel { Ok(()) } - fn do_channel_handshake(&mut self) -> Result<(), ChannelError> { + /// Returns `Ok(())` when both channel ends are in state `Open`. + /// Also returns `Ok(())` if the channel is undergoing a closing handshake. + /// Otherwise, returns an error. + fn do_chan_open_finalize(&self) -> Result<(), ChannelError> { let src_channel_id = self .src_channel_id() .ok_or(ChannelError::MissingLocalChannelId)?; @@ -421,40 +427,45 @@ impl Channel { .src_chain() .query_channel(&self.src_port_id(), src_channel_id, Height::zero()) .map_err(|_| { - ChannelError::Failed( - format!("failed to query source chain {}", self.src_chain().id()).into(), - ) + ChannelError::Failed(format!( + "failed to query source chain {}", + self.src_chain().id() + )) })?; let b_channel = self .dst_chain() .query_channel(&self.dst_port_id(), dst_channel_id, Height::zero()) .map_err(|_| { - ChannelError::Failed( - format!( - "failed to query destination chain {}", - self.dst_chain().id() - ) - .into(), - ) + ChannelError::Failed(format!( + "failed to query destination chain {}", + self.dst_chain().id() + )) })?; match (a_channel.state(), b_channel.state()) { (State::Init, State::TryOpen) | (State::TryOpen, State::TryOpen) => { let event = self.flipped().build_chan_open_ack_and_send().map_err(|e| { - error!("Failed ChanAck {:?}: {}", self.a_side, e); + error!("failed ChanAck {:?}: {}", self.a_side, e); e })?; info!("done {} => {:#?}\n", self.src_chain().id(), event); + // One more step (confirm) left. + // Returning error signals that the caller should retry. + Err(ChannelError::PartialOpenHandshake( + *a_channel.state(), + *b_channel.state(), + )) } (State::Open, State::TryOpen) => { let event = self.build_chan_open_confirm_and_send().map_err(|e| { - error!("Failed ChanConfirm {:?}: {}", self.b_side, e); + error!("failed ChanConfirm {:?}: {}", self.b_side, e); e })?; info!("done {} => {:#?}\n", self.dst_chain().id(), event); + Ok(()) } (State::TryOpen, State::Open) => { // Confirm to a_chain @@ -462,24 +473,30 @@ impl Channel { .flipped() .build_chan_open_confirm_and_send() .map_err(|e| { - error!("Failed ChanConfirm {:?}: {}", self.a_side, e); + error!("failed ChanConfirm {:?}: {}", self.a_side, e); e })?; - info!("done {} => {:#?}\n", self.src_chain().id(), event) + info!("done {} => {:#?}\n", self.src_chain().id(), event); + Ok(()) } (State::Open, State::Open) => { - info!("channel handshake finished for {:#?}\n", self); + info!("channel handshake already finished for {:#?}\n", self); + Ok(()) } - _ => { /* TODO channel close */ } + // In all other conditions, return Ok, since the channel open handshake is done. + _ => Ok(()), } - - info!("successfully opened channel"); - Ok(()) } - fn do_channel_handshake_with_retry(&mut self) -> Result<(), ChannelError> { - retry_with_index(retry_strategy::default(), |_| self.do_channel_handshake()).map_err( + /// Takes a partially open channel and finalizes the open handshake protocol. + /// + /// Pre-condition: the channel identifiers are already established on both ends + /// (i.e., the OpenInit and OpenTry steps have been fulfilled for this channel). + /// + /// Post-condition: the channel state is `Open` on both ends if successful. + fn do_chan_open_finalize_with_retry(&self) -> Result<(), ChannelError> { + retry_with_index(retry_strategy::default(), |_| self.do_chan_open_finalize()).map_err( |err| { error!("failed to open channel after {} retries", err); ChannelError::Failed(format!( @@ -497,7 +514,7 @@ impl Channel { fn handshake(&mut self) -> Result<(), ChannelError> { self.do_chan_open_init_and_send_with_retry()?; self.do_chan_open_try_and_send_with_retry()?; - self.do_channel_handshake_with_retry() + self.do_chan_open_finalize_with_retry() } pub fn counterparty_state(&self) -> Result { From 44af5014f7a2f6c63c3a0e776a28711e978d4937 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 9 Jun 2021 16:09:29 +0200 Subject: [PATCH 03/13] Better fix for the impersonation problem --- modules/src/ics24_host/identifier.rs | 6 ++ relayer-cli/src/commands/tx/transfer.rs | 81 ++++++++++++++----------- relayer/src/channel.rs | 53 +++++++++++++++- relayer/src/link.rs | 49 +++++---------- relayer/src/transfer.rs | 15 ++--- 5 files changed, 127 insertions(+), 77 deletions(-) diff --git a/modules/src/ics24_host/identifier.rs b/modules/src/ics24_host/identifier.rs index cf6b969c29..cdc991427f 100644 --- a/modules/src/ics24_host/identifier.rs +++ b/modules/src/ics24_host/identifier.rs @@ -391,3 +391,9 @@ pub struct PortChannelId { pub channel_id: ChannelId, pub port_id: PortId, } + +impl std::fmt::Display for PortChannelId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{}/{}", self.port_id, self.channel_id) + } +} diff --git a/relayer-cli/src/commands/tx/transfer.rs b/relayer-cli/src/commands/tx/transfer.rs index 65569dc175..a975319b65 100644 --- a/relayer-cli/src/commands/tx/transfer.rs +++ b/relayer-cli/src/commands/tx/transfer.rs @@ -1,18 +1,19 @@ -use std::sync::Arc; - use abscissa_core::{config::Override, Command, FrameworkErrorKind, Options, Runnable}; use anomaly::BoxError; -use tokio::runtime::Runtime as TokioRuntime; -use ibc::events::IbcEvent; -use ibc::ics02_client::height::Height; -use ibc::ics24_host::identifier::{ChainId, ChannelId, PortId}; +use ibc::{ + events::IbcEvent, + ics02_client::client_state::ClientState, + ics02_client::height::Height, + ics24_host::identifier::{ChainId, ChannelId, PortChannelId, PortId}, +}; use ibc_relayer::{ - chain::{Chain, CosmosSdkChain}, + channel::check_channel_counterparty, config::Config, transfer::{build_and_send_transfer_messages, TransferOptions}, }; +use crate::cli_utils::ChainHandlePair; use crate::conclude::{exit_with_unrecoverable_error, Output}; use crate::error::{Error, Kind}; use crate::prelude::*; @@ -132,48 +133,33 @@ impl Runnable for TxIcs20MsgTransferCmd { debug!("Message: {:?}", opts); - let rt = Arc::new(TokioRuntime::new().unwrap()); - - let src_chain_res = - CosmosSdkChain::bootstrap(opts.packet_src_chain_config.clone(), rt.clone()) - .map_err(|e| Kind::Runtime.context(e)); - - let src_chain = match src_chain_res { - Ok(chain) => chain, - Err(e) => return Output::error(format!("{}", e)).exit(), - }; - - let dst_chain_res = CosmosSdkChain::bootstrap(opts.packet_dst_chain_config.clone(), rt) - .map_err(|e| Kind::Runtime.context(e)); - - let dst_chain = match dst_chain_res { - Ok(chain) => chain, - Err(e) => return Output::error(format!("{}", e)).exit(), - }; + let chains = ChainHandlePair::spawn(&config, &self.src_chain_id, &self.dst_chain_id) + .unwrap_or_else(exit_with_unrecoverable_error); // Double check that channels and chain identifiers match. // To do this, fetch from the source chain the channel end, then the associated connection // end, and then the underlying client state; finally, check that this client is verifying // headers for the destination chain. - let channel_end = src_chain + let channel_end_src = chains + .src .query_channel( &opts.packet_src_port_id, &opts.packet_src_channel_id, Height::zero(), ) .unwrap_or_else(exit_with_unrecoverable_error); - if !channel_end.is_open() { + if !channel_end_src.is_open() { return Output::error(format!( "the requested port/channel ('{}'/'{}') on chain id '{}' is in state '{}'; expected 'open' state", opts.packet_src_port_id, opts.packet_src_channel_id, self.src_chain_id, - channel_end.state + channel_end_src.state )) .exit(); } - let conn_id = match channel_end.connection_hops.first() { + let conn_id = match channel_end_src.connection_hops.first() { None => { return Output::error(format!( "could not retrieve the connection hop underlying port/channel '{}'/'{}' on chain '{}'", @@ -184,13 +170,15 @@ impl Runnable for TxIcs20MsgTransferCmd { Some(cid) => cid, }; - let conn_end = src_chain + let conn_end = chains + .src .query_connection(conn_id, Height::zero()) .unwrap_or_else(exit_with_unrecoverable_error); debug!("connection hop underlying the channel: {:?}", conn_end); - let src_chain_client_state = src_chain + let src_chain_client_state = chains + .src .query_client_state(conn_end.client_id(), Height::zero()) .unwrap_or_else(exit_with_unrecoverable_error); @@ -199,18 +187,43 @@ impl Runnable for TxIcs20MsgTransferCmd { src_chain_client_state ); - if src_chain_client_state.chain_id != self.dst_chain_id { + if src_chain_client_state.chain_id() != self.dst_chain_id { return Output::error( format!("the requested port/channel ('{}'/'{}') provides a path from chain '{}' to \ chain '{}' (not to the destination chain '{}'). Bailing due to mismatching arguments.", opts.packet_src_port_id, opts.packet_src_channel_id, self.src_chain_id, - src_chain_client_state.chain_id, self.dst_chain_id)).exit(); + src_chain_client_state.chain_id(), self.dst_chain_id)).exit(); } + // Final verification: + // The socket (i.e., port/channel pair) representing the + // counterparty on the destination chain should match the + // socket on the source chain. + let channel_id_dest = channel_end_src + .counterparty() + .channel_id + .clone() + .ok_or(format!( + "the port/channel '{}'/'{}' on chain '{}' has no counterparty channel id", + opts.packet_src_port_id, opts.packet_src_channel_id, self.src_chain_id + )) + .unwrap_or_else(exit_with_unrecoverable_error); + + let socket_dest = PortChannelId { + channel_id: channel_id_dest, + port_id: channel_end_src.counterparty().port_id.clone(), + }; + let expected = PortChannelId { + channel_id: opts.packet_src_channel_id.clone(), + port_id: opts.packet_src_port_id.clone(), + }; + check_channel_counterparty(chains.dst.clone(), &socket_dest, &expected) + .unwrap_or_else(exit_with_unrecoverable_error); + // Checks pass, build and send the tx let res: Result, Error> = - build_and_send_transfer_messages(src_chain, dst_chain, opts) + build_and_send_transfer_messages(chains.src, chains.dst, opts) .map_err(|e| Kind::Tx.context(e).into()); match res { diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 3f4c97b7b5..8e10027826 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -14,7 +14,9 @@ use ibc::ics04_channel::msgs::chan_open_ack::MsgChannelOpenAck; use ibc::ics04_channel::msgs::chan_open_confirm::MsgChannelOpenConfirm; use ibc::ics04_channel::msgs::chan_open_init::MsgChannelOpenInit; use ibc::ics04_channel::msgs::chan_open_try::MsgChannelOpenTry; -use ibc::ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}; +use ibc::ics24_host::identifier::{ + ChainId, ChannelId, ClientId, ConnectionId, PortChannelId, PortId, +}; use ibc::tx_msg::Msg; use ibc::Height; @@ -73,6 +75,9 @@ pub enum ChannelError { #[error("the channel is partially open ({0}, {1})")] PartialOpenHandshake(State, State), + + #[error("socket {0} on chain {1} expected to have counterparty {2} (but instead has {3})")] + MismatchingChannelEnds(PortChannelId, ChainId, PortChannelId, PortChannelId), } #[derive(Clone, Debug, Serialize)] @@ -1220,3 +1225,49 @@ fn check_destination_channel_state( ))) } } + +// Query the channel end on destination chain, +// and verify that the counterparty channel/port on destination +// matches channel/port id on source. +pub fn check_channel_counterparty( + chain: Box, + local_socket: &PortChannelId, + expected: &PortChannelId, +) -> Result<(), ChannelError> { + let channel_end_dst = chain + .query_channel( + &local_socket.port_id, + &local_socket.channel_id, + Height::zero(), + ) + .map_err(|e| ChannelError::QueryError(chain.id(), e))?; + + match channel_end_dst.counterparty().channel_id.clone() { + Some(actual_remote_channel_id) => { + let actual = PortChannelId { + channel_id: actual_remote_channel_id, + port_id: channel_end_dst.counterparty().port_id.clone(), + }; + if actual.ne(expected) { + return Err(ChannelError::MismatchingChannelEnds( + local_socket.clone(), + chain.id(), + expected.clone(), + actual, + )); + } + } + None => { + error!( + "socket {} on chain {} has no counterparty channel id ", + local_socket, + chain.id() + ); + // TODO: The error `MissingCounterpartyChannelId` should capture its + // context fully (the chain and the socket). + return Err(ChannelError::MissingCounterpartyChannelId); + } + } + + Ok(()) +} diff --git a/relayer/src/link.rs b/relayer/src/link.rs index 0939c043be..cc82658727 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -36,12 +36,13 @@ use ibc_proto::ibc::core::channel::v1::{ }; use crate::chain::handle::ChainHandle; -use crate::channel::{Channel, ChannelError, ChannelSide}; +use crate::channel::{check_channel_counterparty, Channel, ChannelError, ChannelSide}; use crate::connection::ConnectionError; use crate::error::Error; use crate::event::monitor::EventBatch; use crate::foreign_client::{ForeignClient, ForeignClientError}; use crate::transfer::PacketError; +use ibc::ics24_host::identifier::PortChannelId; const MAX_RETRIES: usize = 5; @@ -1635,40 +1636,18 @@ impl Link { } // Check that the counterparty details on the destination chain matches the source chain - let b_channel = b_chain - .query_channel( - &a_channel.counterparty().port_id, - &b_channel_id, - Height::default(), - ) - .map_err(|e| { - LinkError::Failed(format!( - "channel/port {}/{} does not exist on destination chain {}; context={}", - b_channel_id, - a_channel.counterparty().port_id, - b_chain.id(), - e - )) - })?; - match b_channel.counterparty().channel_id.clone() { - Some(actual_a_channel_id) => { - if actual_a_channel_id.ne(a_channel_id) - || b_channel.counterparty().port_id != opts.src_port_id - { - return Err(LinkError::Failed(format!("conflicting link configuration: channel/port {}/{} on destination chain {} does not point back to the source chain {}:{}/{} (but points to {}/{})", - b_channel_id, a_channel.counterparty().port_id, b_chain.id(), a_chain.id(), - a_channel_id, opts.src_port_id, actual_a_channel_id, b_channel.counterparty().port_id))); - } - } - None => { - return Err(LinkError::Failed(format!( - "the channel/port {}/{} on destination chain {} has no counterparty channel set", - b_channel_id, - a_channel.counterparty().port_id, - b_chain.id() - ))); - } - } + check_channel_counterparty( + b_chain.clone(), + &PortChannelId { + channel_id: b_channel_id.clone(), + port_id: a_channel.counterparty().port_id.clone(), + }, + &PortChannelId { + channel_id: a_channel_id.clone(), + port_id: opts.src_port_id.clone(), + }, + ) + .map_err(|e| LinkError::Failed(format!("counterparty verification failed: {}", e)))?; // Check the underlying connection let a_connection_id = a_channel.connection_hops()[0].clone(); diff --git a/relayer/src/transfer.rs b/relayer/src/transfer.rs index 87f1f9beb1..8d1830d65c 100644 --- a/relayer/src/transfer.rs +++ b/relayer/src/transfer.rs @@ -1,17 +1,18 @@ +use std::time::Duration; + use thiserror::Error; use tracing::error; use ibc::application::ics20_fungible_token_transfer::msgs::transfer::MsgTransfer; use ibc::events::IbcEvent; use ibc::ics24_host::identifier::{ChainId, ChannelId, PortId}; +use ibc::timestamp::Timestamp; use ibc::tx_msg::Msg; +use ibc::Height; -use crate::chain::{Chain, CosmosSdkChain}; +use crate::chain::handle::ChainHandle; use crate::config::ChainConfig; use crate::error::Error; -use ibc::timestamp::Timestamp; -use ibc::Height; -use std::time::Duration; #[derive(Debug, Error)] pub enum PacketError { @@ -45,8 +46,8 @@ pub struct TransferOptions { } pub fn build_and_send_transfer_messages( - mut packet_src_chain: CosmosSdkChain, // the chain whose account is debited - mut packet_dst_chain: CosmosSdkChain, // the chain where the transfer is sent + packet_src_chain: Box, // the chain whose account is debited + packet_dst_chain: Box, // the chain whose account eventually gets credited opts: TransferOptions, ) -> Result, PacketError> { let receiver = match &opts.receiver { @@ -90,7 +91,7 @@ pub fn build_and_send_transfer_messages( let events = packet_src_chain .send_msgs(msgs) - .map_err(|e| PacketError::Submit(packet_src_chain.id().clone(), e))?; + .map_err(|e| PacketError::Submit(packet_src_chain.id(), e))?; // Check if the chain rejected the transaction let result = events From 14112f0747c330b862a320bb5718cf6d69494115 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 9 Jun 2021 16:26:20 +0200 Subject: [PATCH 04/13] Better log message. Handle (TryOpen, Init) case --- relayer/src/channel.rs | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 8e10027826..da4c691344 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -449,13 +449,18 @@ impl Channel { })?; match (a_channel.state(), b_channel.state()) { + // Handle sending the Ack message to the source chain (State::Init, State::TryOpen) | (State::TryOpen, State::TryOpen) => { let event = self.flipped().build_chan_open_ack_and_send().map_err(|e| { error!("failed ChanAck {:?}: {}", self.a_side, e); e })?; - info!("done {} => {:#?}\n", self.src_chain().id(), event); + info!( + "done with ChanAck step {} => {:#?}\n", + self.src_chain().id(), + event + ); // One more step (confirm) left. // Returning error signals that the caller should retry. Err(ChannelError::PartialOpenHandshake( @@ -463,6 +468,28 @@ impl Channel { *b_channel.state(), )) } + + // Handle sending the Ack message to the destination chain + (State::TryOpen, State::Init) => { + let event = self.build_chan_open_ack_and_send().map_err(|e| { + error!("failed ChanAck {:?}: {}", self.b_side, e); + e + })?; + + info!( + "done with ChanAck step {} => {:#?}\n", + self.dst_chain().id(), + event + ); + // One more step (confirm) left. + // Returning error signals that the caller should retry. + Err(ChannelError::PartialOpenHandshake( + *a_channel.state(), + *b_channel.state(), + )) + } + + // Handle sending the Confirm message to the destination chain (State::Open, State::TryOpen) => { let event = self.build_chan_open_confirm_and_send().map_err(|e| { error!("failed ChanConfirm {:?}: {}", self.b_side, e); @@ -472,8 +499,9 @@ impl Channel { info!("done {} => {:#?}\n", self.dst_chain().id(), event); Ok(()) } + + // Send Confirm to the source chain (State::TryOpen, State::Open) => { - // Confirm to a_chain let event = self .flipped() .build_chan_open_confirm_and_send() @@ -482,14 +510,18 @@ impl Channel { e })?; - info!("done {} => {:#?}\n", self.src_chain().id(), event); + info!( + "finalized channel open handshake {} => {:#?}\n", + self.src_chain().id(), + event + ); Ok(()) } (State::Open, State::Open) => { info!("channel handshake already finished for {:#?}\n", self); Ok(()) } - // In all other conditions, return Ok, since the channel open handshake is done. + // In all other conditions, return Ok, since the channel open handshake does not apply. _ => Ok(()), } } From d871f28b269cd4b03eefcd949e106a94ef2cb602 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 9 Jun 2021 16:36:00 +0200 Subject: [PATCH 05/13] Changelog --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ea123dcf9..2b5c693e5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,20 @@ - Add `--hd-path` option to `keys restore` and `keys add` commands to specify derivation path when importing keys ([#1049]) +### BUG FIXES + +- [ibc-relayer-cli] + - Fix for chain impersonation bug. ([#1038]) + - Fix for partially open handshake bug of `channel create` CLI. ([#1064]) + ### BREAKING CHANGES - [ibc-relayer-cli] - Removed `--coin-type` option from `keys restore` command. Use `--hd-path` instead. ([#1049]) -[#868]: https://github.com/informalsystems/ibc-rs/issues/1049 +[#1038]: https://github.com/informalsystems/ibc-rs/issues/1038 +[#1049]: https://github.com/informalsystems/ibc-rs/issues/1049 +[#1064]: https://github.com/informalsystems/ibc-rs/issues/1064 ## v0.4.0 *June 3rd, 2021* From ed49a0327df11d5a4fdae638e477b604f9f6dc36 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Thu, 10 Jun 2021 09:53:31 +0200 Subject: [PATCH 06/13] Better error, added doc comment, less clones. --- relayer/src/channel.rs | 38 ++++++++++++++++++++------------------ relayer/src/link.rs | 5 ++++- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index da4c691344..df0c898f6c 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -1258,32 +1258,34 @@ fn check_destination_channel_state( } } -// Query the channel end on destination chain, -// and verify that the counterparty channel/port on destination -// matches channel/port id on source. +/// Queries a channel end on a [`ChainHandle`], and verifies +/// that the counterparty of that channel matches an +/// expected counterparty. +/// Returns `Ok` if the counterparty matches, and `Err` otherwise pub fn check_channel_counterparty( - chain: Box, - local_socket: &PortChannelId, + target_chain: Box, + target_socket: &PortChannelId, expected: &PortChannelId, ) -> Result<(), ChannelError> { - let channel_end_dst = chain + let channel_end_dst = target_chain .query_channel( - &local_socket.port_id, - &local_socket.channel_id, + &target_socket.port_id, + &target_socket.channel_id, Height::zero(), ) - .map_err(|e| ChannelError::QueryError(chain.id(), e))?; + .map_err(|e| ChannelError::QueryError(target_chain.id(), e))?; - match channel_end_dst.counterparty().channel_id.clone() { - Some(actual_remote_channel_id) => { + let counterparty = channel_end_dst.remote; + match counterparty.channel_id { + Some(actual_channel_id) => { let actual = PortChannelId { - channel_id: actual_remote_channel_id, - port_id: channel_end_dst.counterparty().port_id.clone(), + channel_id: actual_channel_id, + port_id: counterparty.port_id, }; - if actual.ne(expected) { + if &actual != expected { return Err(ChannelError::MismatchingChannelEnds( - local_socket.clone(), - chain.id(), + target_socket.clone(), + target_chain.id(), expected.clone(), actual, )); @@ -1292,8 +1294,8 @@ pub fn check_channel_counterparty( None => { error!( "socket {} on chain {} has no counterparty channel id ", - local_socket, - chain.id() + target_socket, + target_chain.id() ); // TODO: The error `MissingCounterpartyChannelId` should capture its // context fully (the chain and the socket). diff --git a/relayer/src/link.rs b/relayer/src/link.rs index cc82658727..65eafd3ea9 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -54,6 +54,9 @@ pub enum LinkError { #[error("failed with underlying error: {0}")] Generic(#[from] Error), + #[error("link initialization failed during channel counterparty verification: {0}")] + Initialization(ChannelError), + #[error("failed to construct packet proofs for chain {0} with error: {1}")] PacketProofsConstructor(ChainId, Error), @@ -1647,7 +1650,7 @@ impl Link { port_id: opts.src_port_id.clone(), }, ) - .map_err(|e| LinkError::Failed(format!("counterparty verification failed: {}", e)))?; + .map_err(LinkError::Initialization)?; // Check the underlying connection let a_connection_id = a_channel.connection_hops()[0].clone(); From 420abb5414cb5579c450efd88fe71ab9bbad3a02 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Thu, 10 Jun 2021 10:07:56 +0200 Subject: [PATCH 07/13] Clarify the intent of method do_chan_open_ack_confirm_step --- relayer/src/channel.rs | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index df0c898f6c..0afe821d37 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -415,10 +415,20 @@ impl Channel { Ok(()) } - /// Returns `Ok(())` when both channel ends are in state `Open`. - /// Also returns `Ok(())` if the channel is undergoing a closing handshake. - /// Otherwise, returns an error. - fn do_chan_open_finalize(&self) -> Result<(), ChannelError> { + /// Does a single step towards finalizing the channel open handshake. + /// Covers only a step of type either Ack or Confirm. + /// (Assumes that the channel open handshake was previously + /// initialized with Init & Try steps.) + /// + /// Returns `Ok` when both channel ends are in state `Open`. + /// Also returns `Ok` if the channel is undergoing a closing handshake. + /// + /// An `Err` can signal two cases: + /// - the attempted handshake step has failed, + /// - the attempted step may have finished successfully, but further + /// steps are necessary to finalize the channel open handshake. + /// In both `Err` cases, there should be retry calling this method. + fn do_chan_open_ack_confirm_step(&self) -> Result<(), ChannelError> { let src_channel_id = self .src_channel_id() .ok_or(ChannelError::MissingLocalChannelId)?; @@ -533,16 +543,17 @@ impl Channel { /// /// Post-condition: the channel state is `Open` on both ends if successful. fn do_chan_open_finalize_with_retry(&self) -> Result<(), ChannelError> { - retry_with_index(retry_strategy::default(), |_| self.do_chan_open_finalize()).map_err( - |err| { - error!("failed to open channel after {} retries", err); - ChannelError::Failed(format!( - "Failed to finish channel handshake in {} iterations for {:?}", - retry_count(&err), - self - )) - }, - )?; + retry_with_index(retry_strategy::default(), |_| { + self.do_chan_open_ack_confirm_step() + }) + .map_err(|err| { + error!("failed to open channel after {} retries", err); + ChannelError::Failed(format!( + "Failed to finish channel handshake in {} iterations for {:?}", + retry_count(&err), + self + )) + })?; Ok(()) } From f91c9ec1a88f6b2facb9abb32803f12ac9026b85 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Thu, 10 Jun 2021 10:22:44 +0200 Subject: [PATCH 08/13] Removed some unnecessary clones --- relayer-cli/src/commands/tx/transfer.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/relayer-cli/src/commands/tx/transfer.rs b/relayer-cli/src/commands/tx/transfer.rs index a975319b65..caf96ab22d 100644 --- a/relayer-cli/src/commands/tx/transfer.rs +++ b/relayer-cli/src/commands/tx/transfer.rs @@ -201,9 +201,8 @@ impl Runnable for TxIcs20MsgTransferCmd { // counterparty on the destination chain should match the // socket on the source chain. let channel_id_dest = channel_end_src - .counterparty() + .remote .channel_id - .clone() .ok_or(format!( "the port/channel '{}'/'{}' on chain '{}' has no counterparty channel id", opts.packet_src_port_id, opts.packet_src_channel_id, self.src_chain_id @@ -212,7 +211,7 @@ impl Runnable for TxIcs20MsgTransferCmd { let socket_dest = PortChannelId { channel_id: channel_id_dest, - port_id: channel_end_src.counterparty().port_id.clone(), + port_id: channel_end_src.remote.port_id, }; let expected = PortChannelId { channel_id: opts.packet_src_channel_id.clone(), From 7243c93a4855fc8e8724d9ba3a8dd67b4657fdd5 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Mon, 14 Jun 2021 11:45:07 +0200 Subject: [PATCH 09/13] Moved check_channel_counterparty to chain::counterparty --- relayer-cli/src/commands/tx/transfer.rs | 2 +- relayer/src/chain/counterparty.rs | 54 ++++++++++++++++++-- relayer/src/channel.rs | 66 ++++--------------------- relayer/src/link.rs | 7 ++- 4 files changed, 65 insertions(+), 64 deletions(-) diff --git a/relayer-cli/src/commands/tx/transfer.rs b/relayer-cli/src/commands/tx/transfer.rs index caf96ab22d..60b1d8e555 100644 --- a/relayer-cli/src/commands/tx/transfer.rs +++ b/relayer-cli/src/commands/tx/transfer.rs @@ -8,7 +8,7 @@ use ibc::{ ics24_host::identifier::{ChainId, ChannelId, PortChannelId, PortId}, }; use ibc_relayer::{ - channel::check_channel_counterparty, + chain::counterparty::check_channel_counterparty, config::Config, transfer::{build_and_send_transfer_messages, TransferOptions}, }; diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index 958bc9b2ff..57e51df7bd 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -1,16 +1,16 @@ use serde::{Deserialize, Serialize}; -use tracing::trace; +use tracing::{error, trace}; use ibc::{ ics02_client::client_state::{ClientState, IdentifiedAnyClientState}, ics03_connection::connection::IdentifiedConnectionEnd, ics04_channel::channel::{ChannelEnd, IdentifiedChannelEnd, State}, - ics24_host::identifier::ConnectionId, - ics24_host::identifier::{ChainId, ChannelId, PortId}, + ics24_host::identifier::{ChainId, ChannelId, ConnectionId, PortChannelId, PortId}, Height, }; use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; +use crate::channel::ChannelError; use crate::supervisor::Error; use super::handle::ChainHandle; @@ -158,3 +158,51 @@ pub fn channel_state_on_destination( }; Ok(counterparty_state) } + +/// Queries a channel end on a [`ChainHandle`], and verifies +/// that the counterparty field on that channel end matches an +/// expected counterparty. +/// Returns `Ok` if the counterparty matches, and `Err` otherwise. +pub fn check_channel_counterparty( + target_chain: Box, + target_socket: &PortChannelId, + expected: &PortChannelId, +) -> Result<(), ChannelError> { + let channel_end_dst = target_chain + .query_channel( + &target_socket.port_id, + &target_socket.channel_id, + Height::zero(), + ) + .map_err(|e| ChannelError::QueryError(target_chain.id(), e))?; + + let counterparty = channel_end_dst.remote; + match counterparty.channel_id { + Some(actual_channel_id) => { + let actual = PortChannelId { + channel_id: actual_channel_id, + port_id: counterparty.port_id, + }; + if &actual != expected { + return Err(ChannelError::MismatchingChannelEnds( + target_socket.clone(), + target_chain.id(), + expected.clone(), + actual, + )); + } + } + None => { + error!( + "socket {} on chain {} has no counterparty channel id ", + target_socket, + target_chain.id() + ); + // TODO: The error `MissingCounterpartyChannelId` should capture its + // context fully (the chain and the socket). + return Err(ChannelError::MissingCounterpartyChannelId); + } + } + + Ok(()) +} diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 0afe821d37..7d63fc1172 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -1,8 +1,10 @@ #![allow(clippy::borrowed_box)] + +use std::time::Duration; + use anomaly::BoxError; use prost_types::Any; use serde::Serialize; -use std::time::Duration; use thiserror::Error; use tracing::{debug, error, info}; @@ -19,21 +21,25 @@ use ibc::ics24_host::identifier::{ }; use ibc::tx_msg::Msg; use ibc::Height; +use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; +use crate::chain::counterparty::{channel_connection_client, channel_state_on_destination}; use crate::chain::handle::ChainHandle; use crate::connection::Connection; use crate::error::Error; use crate::foreign_client::{ForeignClient, ForeignClientError}; use crate::object::Channel as WorkerChannelObject; use crate::supervisor::Error as WorkerChannelError; - +use crate::util::retry::RetryResult; use crate::util::retry::{retry_count, retry_with_index}; mod retry_strategy { - use crate::util::retry::clamp_total; - use retry::delay::Fibonacci; use std::time::Duration; + use retry::delay::Fibonacci; + + use crate::util::retry::clamp_total; + // Default parameters for the retrying mechanism const MAX_DELAY: Duration = Duration::from_secs(60); // 1 minute const MAX_TOTAL_DELAY: Duration = Duration::from_secs(10 * 60); // 10 minutes @@ -44,10 +50,6 @@ mod retry_strategy { } } -use crate::chain::counterparty::{channel_connection_client, channel_state_on_destination}; -use crate::util::retry::RetryResult; -use ibc_proto::ibc::core::channel::v1::QueryConnectionChannelsRequest; - #[derive(Debug, Error)] pub enum ChannelError { #[error("failed with underlying cause: {0}")] @@ -1268,51 +1270,3 @@ fn check_destination_channel_state( ))) } } - -/// Queries a channel end on a [`ChainHandle`], and verifies -/// that the counterparty of that channel matches an -/// expected counterparty. -/// Returns `Ok` if the counterparty matches, and `Err` otherwise -pub fn check_channel_counterparty( - target_chain: Box, - target_socket: &PortChannelId, - expected: &PortChannelId, -) -> Result<(), ChannelError> { - let channel_end_dst = target_chain - .query_channel( - &target_socket.port_id, - &target_socket.channel_id, - Height::zero(), - ) - .map_err(|e| ChannelError::QueryError(target_chain.id(), e))?; - - let counterparty = channel_end_dst.remote; - match counterparty.channel_id { - Some(actual_channel_id) => { - let actual = PortChannelId { - channel_id: actual_channel_id, - port_id: counterparty.port_id, - }; - if &actual != expected { - return Err(ChannelError::MismatchingChannelEnds( - target_socket.clone(), - target_chain.id(), - expected.clone(), - actual, - )); - } - } - None => { - error!( - "socket {} on chain {} has no counterparty channel id ", - target_socket, - target_chain.id() - ); - // TODO: The error `MissingCounterpartyChannelId` should capture its - // context fully (the chain and the socket). - return Err(ChannelError::MissingCounterpartyChannelId); - } - } - - Ok(()) -} diff --git a/relayer/src/link.rs b/relayer/src/link.rs index 65eafd3ea9..0c80fae822 100644 --- a/relayer/src/link.rs +++ b/relayer/src/link.rs @@ -22,27 +22,26 @@ use ibc::{ }, packet::{Packet, PacketMsgType, Sequence}, }, - ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortId}, + ics24_host::identifier::{ChainId, ChannelId, ClientId, ConnectionId, PortChannelId, PortId}, query::QueryTxRequest, signer::Signer, timestamp::ZERO_DURATION, tx_msg::Msg, Height, }; - use ibc_proto::ibc::core::channel::v1::{ QueryNextSequenceReceiveRequest, QueryPacketAcknowledgementsRequest, QueryPacketCommitmentsRequest, QueryUnreceivedAcksRequest, QueryUnreceivedPacketsRequest, }; +use crate::chain::counterparty::check_channel_counterparty; use crate::chain::handle::ChainHandle; -use crate::channel::{check_channel_counterparty, Channel, ChannelError, ChannelSide}; +use crate::channel::{Channel, ChannelError, ChannelSide}; use crate::connection::ConnectionError; use crate::error::Error; use crate::event::monitor::EventBatch; use crate::foreign_client::{ForeignClient, ForeignClientError}; use crate::transfer::PacketError; -use ibc::ics24_host::identifier::PortChannelId; const MAX_RETRIES: usize = 5; From f869bb8096c6129f61778fb8dce18bf3b522aa6c Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Mon, 14 Jun 2021 11:54:01 +0200 Subject: [PATCH 10/13] Fully specified error in case of failure in check_channel_counterparty --- relayer/src/chain/counterparty.rs | 7 ++++--- relayer/src/channel.rs | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index 57e51df7bd..b8f0aea7cd 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -198,9 +198,10 @@ pub fn check_channel_counterparty( target_socket, target_chain.id() ); - // TODO: The error `MissingCounterpartyChannelId` should capture its - // context fully (the chain and the socket). - return Err(ChannelError::MissingCounterpartyChannelId); + return Err(ChannelError::IncompleteSocketState( + target_socket.clone(), + target_chain.id(), + )); } } diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index 7d63fc1172..cf80f799e9 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -78,6 +78,9 @@ pub enum ChannelError { #[error("the channel is partially open ({0}, {1})")] PartialOpenHandshake(State, State), + #[error("socket {0} on chain {1} has not counterparty channel id")] + IncompleteSocketState(PortChannelId, ChainId), + #[error("socket {0} on chain {1} expected to have counterparty {2} (but instead has {3})")] MismatchingChannelEnds(PortChannelId, ChainId, PortChannelId, PortChannelId), } From 4a6e02a3100f6844144656df52f4aa8d181d023e Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Mon, 14 Jun 2021 17:24:14 +0200 Subject: [PATCH 11/13] Used port+channel instead of socket --- relayer-cli/src/commands/tx/transfer.rs | 8 ++++---- relayer/src/chain/counterparty.rs | 16 ++++++++-------- relayer/src/channel.rs | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/relayer-cli/src/commands/tx/transfer.rs b/relayer-cli/src/commands/tx/transfer.rs index 60b1d8e555..9c4b5fe894 100644 --- a/relayer-cli/src/commands/tx/transfer.rs +++ b/relayer-cli/src/commands/tx/transfer.rs @@ -197,9 +197,9 @@ impl Runnable for TxIcs20MsgTransferCmd { } // Final verification: - // The socket (i.e., port/channel pair) representing the + // The port+channel pair representing the // counterparty on the destination chain should match the - // socket on the source chain. + // port+channel pair on the source chain. let channel_id_dest = channel_end_src .remote .channel_id @@ -209,7 +209,7 @@ impl Runnable for TxIcs20MsgTransferCmd { )) .unwrap_or_else(exit_with_unrecoverable_error); - let socket_dest = PortChannelId { + let pchan_dest = PortChannelId { channel_id: channel_id_dest, port_id: channel_end_src.remote.port_id, }; @@ -217,7 +217,7 @@ impl Runnable for TxIcs20MsgTransferCmd { channel_id: opts.packet_src_channel_id.clone(), port_id: opts.packet_src_port_id.clone(), }; - check_channel_counterparty(chains.dst.clone(), &socket_dest, &expected) + check_channel_counterparty(chains.dst.clone(), &pchan_dest, &expected) .unwrap_or_else(exit_with_unrecoverable_error); // Checks pass, build and send the tx diff --git a/relayer/src/chain/counterparty.rs b/relayer/src/chain/counterparty.rs index b8f0aea7cd..4f2338d43b 100644 --- a/relayer/src/chain/counterparty.rs +++ b/relayer/src/chain/counterparty.rs @@ -165,13 +165,13 @@ pub fn channel_state_on_destination( /// Returns `Ok` if the counterparty matches, and `Err` otherwise. pub fn check_channel_counterparty( target_chain: Box, - target_socket: &PortChannelId, + target_pchan: &PortChannelId, expected: &PortChannelId, ) -> Result<(), ChannelError> { let channel_end_dst = target_chain .query_channel( - &target_socket.port_id, - &target_socket.channel_id, + &target_pchan.port_id, + &target_pchan.channel_id, Height::zero(), ) .map_err(|e| ChannelError::QueryError(target_chain.id(), e))?; @@ -185,7 +185,7 @@ pub fn check_channel_counterparty( }; if &actual != expected { return Err(ChannelError::MismatchingChannelEnds( - target_socket.clone(), + target_pchan.clone(), target_chain.id(), expected.clone(), actual, @@ -194,12 +194,12 @@ pub fn check_channel_counterparty( } None => { error!( - "socket {} on chain {} has no counterparty channel id ", - target_socket, + "channel {} on chain {} has no counterparty channel id ", + target_pchan, target_chain.id() ); - return Err(ChannelError::IncompleteSocketState( - target_socket.clone(), + return Err(ChannelError::IncompleteChannelState( + target_pchan.clone(), target_chain.id(), )); } diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index cf80f799e9..d317b56efb 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -78,10 +78,10 @@ pub enum ChannelError { #[error("the channel is partially open ({0}, {1})")] PartialOpenHandshake(State, State), - #[error("socket {0} on chain {1} has not counterparty channel id")] - IncompleteSocketState(PortChannelId, ChainId), + #[error("channel {0} on chain {1} has not counterparty channel id")] + IncompleteChannelState(PortChannelId, ChainId), - #[error("socket {0} on chain {1} expected to have counterparty {2} (but instead has {3})")] + #[error("channel {0} on chain {1} expected to have counterparty {2} (but instead has {3})")] MismatchingChannelEnds(PortChannelId, ChainId, PortChannelId, PortChannelId), } From 51a1afca8ae26e1b02c809e2b09bcce7a113c91d Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Mon, 14 Jun 2021 17:25:21 +0200 Subject: [PATCH 12/13] Fix small typo in error variant --- relayer/src/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relayer/src/channel.rs b/relayer/src/channel.rs index d317b56efb..66f38079b4 100644 --- a/relayer/src/channel.rs +++ b/relayer/src/channel.rs @@ -78,7 +78,7 @@ pub enum ChannelError { #[error("the channel is partially open ({0}, {1})")] PartialOpenHandshake(State, State), - #[error("channel {0} on chain {1} has not counterparty channel id")] + #[error("channel {0} on chain {1} has no counterparty channel id")] IncompleteChannelState(PortChannelId, ChainId), #[error("channel {0} on chain {1} expected to have counterparty {2} (but instead has {3})")] From a091942806173b4951536902bf604415ef27b5b6 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Mon, 14 Jun 2021 17:29:57 +0200 Subject: [PATCH 13/13] Removed chan counterparty verification in ft-transfer. --- relayer-cli/src/commands/tx/transfer.rs | 27 +------------------------ 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/relayer-cli/src/commands/tx/transfer.rs b/relayer-cli/src/commands/tx/transfer.rs index 9c4b5fe894..5b1525d234 100644 --- a/relayer-cli/src/commands/tx/transfer.rs +++ b/relayer-cli/src/commands/tx/transfer.rs @@ -5,10 +5,9 @@ use ibc::{ events::IbcEvent, ics02_client::client_state::ClientState, ics02_client::height::Height, - ics24_host::identifier::{ChainId, ChannelId, PortChannelId, PortId}, + ics24_host::identifier::{ChainId, ChannelId, PortId}, }; use ibc_relayer::{ - chain::counterparty::check_channel_counterparty, config::Config, transfer::{build_and_send_transfer_messages, TransferOptions}, }; @@ -196,30 +195,6 @@ impl Runnable for TxIcs20MsgTransferCmd { src_chain_client_state.chain_id(), self.dst_chain_id)).exit(); } - // Final verification: - // The port+channel pair representing the - // counterparty on the destination chain should match the - // port+channel pair on the source chain. - let channel_id_dest = channel_end_src - .remote - .channel_id - .ok_or(format!( - "the port/channel '{}'/'{}' on chain '{}' has no counterparty channel id", - opts.packet_src_port_id, opts.packet_src_channel_id, self.src_chain_id - )) - .unwrap_or_else(exit_with_unrecoverable_error); - - let pchan_dest = PortChannelId { - channel_id: channel_id_dest, - port_id: channel_end_src.remote.port_id, - }; - let expected = PortChannelId { - channel_id: opts.packet_src_channel_id.clone(), - port_id: opts.packet_src_port_id.clone(), - }; - check_channel_counterparty(chains.dst.clone(), &pchan_dest, &expected) - .unwrap_or_else(exit_with_unrecoverable_error); - // Checks pass, build and send the tx let res: Result, Error> = build_and_send_transfer_messages(chains.src, chains.dst, opts)