diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 1636c9dce0..f5e0a9df91 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -18,6 +18,7 @@ use tendermint_rpc::query::Query; use tendermint_rpc::{endpoint::broadcast::tx_commit::Response, Client, HttpClient, Order}; use tokio::runtime::Runtime as TokioRuntime; use tonic::codegen::http::Uri; +use tonic::Code; use ibc::downcast; use ibc::events::{from_tx_response_event, IbcEvent}; @@ -751,11 +752,58 @@ impl Chain for CosmosSdkChain { connection_id: &ConnectionId, height: ICSHeight, ) -> Result { - let res = self.query(Path::Connections(connection_id.clone()), height, false)?; - let connection_end = ConnectionEnd::decode_vec(&res.value) - .map_err(|e| Kind::Query(format!("connection '{}'", connection_id)).context(e))?; + async fn do_query_connection( + chain: &CosmosSdkChain, + connection_id: &ConnectionId, + height: ICSHeight, + ) -> Result { + use ibc_proto::ibc::core::connection::v1 as connection; + use tonic::{metadata::MetadataValue, IntoRequest}; + + let mut client = + connection::query_client::QueryClient::connect(chain.grpc_addr.clone()) + .await + .map_err(|e| Kind::Grpc.context(e))?; + + let mut request = connection::QueryConnectionRequest { + connection_id: connection_id.to_string(), + } + .into_request(); + + let height_param = MetadataValue::from_str(&height.revision_height.to_string()) + .map_err(|e| Kind::Grpc.context(e))?; + + request + .metadata_mut() + .insert("x-cosmos-block-height", height_param); + + let response = client.connection(request).await.map_err(|e| { + if e.code() == Code::NotFound { + Kind::ConnectionNotFound(connection_id.clone()).into() + } else { + Kind::Grpc.context(e) + } + })?; + + match response.into_inner().connection { + Some(raw_connection) => { + let connection_end = raw_connection + .try_into() + .map_err(|e| Kind::Grpc.context(e))?; + + Ok(connection_end) + } + None => { + // When no connection is found, the GRPC call itself should return + // the NotFound error code. Nevertheless even if the call is successful, + // the connection field may not be present, because in protobuf3 + // everything is optional. + Err(Kind::ConnectionNotFound(connection_id.clone()).into()) + } + } + } - Ok(connection_end) + self.block_on(async { do_query_connection(self, connection_id, height).await }) } fn query_connection_channels( diff --git a/relayer/src/connection.rs b/relayer/src/connection.rs index b9fb549418..9fa52fdc8b 100644 --- a/relayer/src/connection.rs +++ b/relayer/src/connection.rs @@ -17,7 +17,6 @@ use ibc::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; use ibc::ics24_host::identifier::{ChainId, ClientId, ConnectionId}; use ibc::timestamp::ZERO_DURATION; use ibc::tx_msg::Msg; -use ibc::Height as ICSHeight; use crate::chain::handle::ChainHandle; use crate::error::Error; @@ -389,7 +388,7 @@ impl Connection { // Retrieve existing connection if any let dst_connection = self .dst_chain() - .query_connection(self.dst_connection_id(), ICSHeight::default()) + .query_connection(self.dst_connection_id(), Height::zero()) .map_err(|e| ConnectionError::QueryError(self.dst_chain().id(), e))?; // Check if a connection is expected to exist on destination chain @@ -494,7 +493,7 @@ impl Connection { pub fn build_conn_try(&self) -> Result, ConnectionError> { let src_connection = self .src_chain() - .query_connection(self.src_connection_id(), ICSHeight::default()) + .query_connection(self.src_connection_id(), Height::zero()) .map_err(|e| ConnectionError::QueryError(self.src_chain().id(), e))?; // TODO - check that the src connection is consistent with the try options @@ -626,7 +625,7 @@ impl Connection { let src_connection = self .src_chain() - .query_connection(self.src_connection_id(), ICSHeight::default()) + .query_connection(self.src_connection_id(), Height::zero()) .map_err(|e| ConnectionError::QueryError(self.src_chain().id(), e))?; // TODO - check that the src connection is consistent with the ack options @@ -724,6 +723,7 @@ impl Connection { .src_chain() .query_latest_height() .map_err(|e| ConnectionError::QueryError(self.src_chain().id(), e))?; + let _src_connection = self .src_chain() .query_connection(self.src_connection_id(), query_height) diff --git a/relayer/src/error.rs b/relayer/src/error.rs index cef2d190f3..26c6103275 100644 --- a/relayer/src/error.rs +++ b/relayer/src/error.rs @@ -82,6 +82,9 @@ pub enum Kind { #[error("Failed to create client {0}")] CreateClient(String), + #[error("Connection not found: {0}")] + ConnectionNotFound(ConnectionId), + /// Common failures to all connection messages #[error("Failed to build conn open message {0}: {1}")] ConnOpen(ConnectionId, String),