From cc589ebd6db0d0a4afb1ff0f0ffd86f0fb475fd7 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Tue, 19 Jan 2021 19:03:27 +0100 Subject: [PATCH 01/12] Avoid unwraps in client txs. Better LightClient errors. --- relayer-cli/src/commands/tx/client.rs | 46 ++++++++++++++++++++++--- relayer-cli/src/error.rs | 4 +++ relayer/src/chain/cosmos.rs | 2 +- relayer/src/error.rs | 12 ++++--- relayer/src/light_client/tendermint.rs | 47 ++++++++++++++++---------- 5 files changed, 85 insertions(+), 26 deletions(-) diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs index 70266ef7cf..1c9144b10f 100644 --- a/relayer-cli/src/commands/tx/client.rs +++ b/relayer-cli/src/commands/tx/client.rs @@ -39,8 +39,27 @@ impl Runnable for TxCreateClientCmd { dst_chain_config.id ); - let (src_chain, _) = ChainRuntime::::spawn(src_chain_config).unwrap(); - let (dst_chain, _) = ChainRuntime::::spawn(dst_chain_config).unwrap(); + let src_chain_res = ChainRuntime::::spawn(src_chain_config) + .map_err(|e| Kind::Runtime.context(e)); + let src_chain = match src_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; + + let dst_chain_res = ChainRuntime::::spawn(dst_chain_config) + .map_err(|e| Kind::Runtime.context(e)); + let dst_chain = match dst_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; let res: Result = build_create_client_and_send(dst_chain, src_chain) .map_err(|e| Kind::Tx.context(e).into()); @@ -88,8 +107,27 @@ impl Runnable for TxUpdateClientCmd { dst_chain_config.id ); - let (src_chain, _) = ChainRuntime::::spawn(src_chain_config).unwrap(); - let (dst_chain, _) = ChainRuntime::::spawn(dst_chain_config).unwrap(); + let src_chain_res = ChainRuntime::::spawn(src_chain_config) + .map_err(|e| Kind::Runtime.context(e)); + let src_chain = match src_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; + + let dst_chain_res = ChainRuntime::::spawn(dst_chain_config) + .map_err(|e| Kind::Runtime.context(e)); + let dst_chain = match dst_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; let res: Result = build_update_client_and_send(dst_chain, src_chain, &self.dst_client_id) diff --git a/relayer-cli/src/error.rs b/relayer-cli/src/error.rs index f77b0e2324..1630d5697d 100644 --- a/relayer-cli/src/error.rs +++ b/relayer-cli/src/error.rs @@ -21,6 +21,10 @@ pub enum Kind { #[error("query error")] Query, + /// Error while spawning the runtime + #[error("chain runtime/handle error")] + Runtime, + /// Error during transaction submission #[error("tx error")] Tx, diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index d722237710..8ea17b23ca 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -350,7 +350,7 @@ impl Chain for CosmosSDKChain { if status.sync_info.catching_up { fail!( - Kind::LightClient, + Kind::LightClientSupervisor(self.config.id.clone()), "node at {} running chain {} not caught up", self.config().rpc_addr, self.config().id, diff --git a/relayer/src/error.rs b/relayer/src/error.rs index 8c93fb7ba2..32aa1d6ae7 100644 --- a/relayer/src/error.rs +++ b/relayer/src/error.rs @@ -1,7 +1,7 @@ //! This module defines the various errors that be raised in the relayer. use anomaly::{BoxError, Context}; -use ibc::ics24_host::identifier::{ChannelId, ConnectionId}; +use ibc::ics24_host::identifier::{ChainId, ChannelId, ConnectionId}; use thiserror::Error; /// An error that can be raised by the relayer. @@ -30,9 +30,13 @@ pub enum Kind { #[error("GRPC error")] Grpc, - /// Light client error, typically raised by a `Client` - #[error("Light client error")] - LightClient, + /// Light client supervisor error + #[error("Light client supervisor error for chain id {0}")] + LightClientSupervisor(ChainId), + + /// Light client instance error, typically raised by a `Client` + #[error("Light client instance error for rpc address {0}")] + LightClientInstance(String), /// Trusted store error, raised by instances of `Store` #[error("Store error")] diff --git a/relayer/src/light_client/tendermint.rs b/relayer/src/light_client/tendermint.rs index 6ce555a64b..487cb766e2 100644 --- a/relayer/src/light_client/tendermint.rs +++ b/relayer/src/light_client/tendermint.rs @@ -11,31 +11,39 @@ use crate::{ config::{ChainConfig, LightClientConfig, StoreConfig}, error, }; +use ibc::ics24_host::identifier::ChainId; pub struct LightClient { handle: Box, + chain_id: ChainId, } impl super::LightClient for LightClient { fn latest_trusted(&self) -> Result, error::Error> { - self.handle - .latest_trusted() - .map_err(|e| error::Kind::LightClient.context(e).into()) + self.handle.latest_trusted().map_err(|e| { + error::Kind::LightClientSupervisor(self.chain_id.clone()) + .context(e) + .into() + }) } fn verify_to_latest(&self) -> Result { - self.handle - .verify_to_highest() - .map_err(|e| error::Kind::LightClient.context(e).into()) + self.handle.verify_to_highest().map_err(|e| { + error::Kind::LightClientSupervisor(self.chain_id.clone()) + .context(e) + .into() + }) } fn verify_to_target(&self, height: ibc::Height) -> Result { let height = TMHeight::try_from(height.revision_height) .map_err(|e| error::Kind::InvalidHeight.context(e))?; - self.handle - .verify_to_target(height) - .map_err(|e| error::Kind::LightClient.context(e).into()) + self.handle.verify_to_target(height).map_err(|e| { + error::Kind::LightClientSupervisor(self.chain_id.clone()) + .context(e) + .into() + }) } fn get_minimal_set( @@ -48,9 +56,10 @@ impl super::LightClient for LightClient { } impl LightClient { - pub fn new(handle: impl Handle + 'static) -> Self { + fn new(handle: impl Handle + 'static, chain_id: ChainId) -> Self { Self { handle: Box::new(handle), + chain_id, } } @@ -61,7 +70,7 @@ impl LightClient { let supervisor = build_supervisor(&chain_config, reset)?; let handle = supervisor.handle(); - Ok((Self::new(handle), supervisor)) + Ok((Self::new(handle, chain_config.id.clone()), supervisor)) } } @@ -71,11 +80,13 @@ fn build_instance( reset: bool, ) -> Result { let rpc_client = rpc::HttpClient::new(config.address.clone()) - .map_err(|e| error::Kind::LightClient.context(e))?; + .map_err(|e| error::Kind::LightClientInstance(config.address.to_string()).context(e))?; let store: Box = match &config.store { StoreConfig::Disk { path } => { - let db = sled::open(path).map_err(|e| error::Kind::LightClient.context(e))?; + let db = sled::open(path).map_err(|e| { + error::Kind::LightClientInstance(config.address.to_string()).context(e) + })?; Box::new(store::sled::SledStore::new(db)) } StoreConfig::Memory { .. } => Box::new(store::memory::MemoryStore::new()), @@ -94,7 +105,7 @@ fn build_instance( } else { builder.trust_from_store() } - .map_err(|e| error::Kind::LightClient.context(e))?; + .map_err(|e| error::Kind::LightClientInstance(config.address.to_string()).context(e))?; Ok(builder.build()) } @@ -107,11 +118,13 @@ fn build_supervisor(config: &ChainConfig, reset: bool) -> Result Result Date: Wed, 20 Jan 2021 09:41:05 +0100 Subject: [PATCH 02/12] Avoided unwrap calls in tx raw commands --- relayer-cli/src/commands/tx/channel.rs | 25 ++- relayer-cli/src/commands/tx/connection.rs | 25 ++- relayer-cli/src/commands/tx/packet.rs | 54 ++++++- relayer-cli/src/commands/tx/transfer.rs | 27 +++- relayer/src/chain/cosmos.rs | 184 +++++++++++----------- 5 files changed, 203 insertions(+), 112 deletions(-) diff --git a/relayer-cli/src/commands/tx/channel.rs b/relayer-cli/src/commands/tx/channel.rs index c1d0273055..76bfb863ed 100644 --- a/relayer-cli/src/commands/tx/channel.rs +++ b/relayer-cli/src/commands/tx/channel.rs @@ -87,10 +87,27 @@ macro_rules! chan_open_cmd { status_info!("Message ", "{}: {:?}", $dbg_string, opts); - let (src_chain, _) = - ChainRuntime::::spawn(src_chain_config.clone()).unwrap(); - let (dst_chain, _) = - ChainRuntime::::spawn(dst_chain_config.clone()).unwrap(); + let src_chain_res = ChainRuntime::::spawn(src_chain_config.clone()) + .map_err(|e| Kind::Runtime.context(e)); + let src_chain = match src_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; + + let dst_chain_res = ChainRuntime::::spawn(dst_chain_config.clone()) + .map_err(|e| Kind::Runtime.context(e)); + let dst_chain = match dst_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; let res: Result = $func(dst_chain, src_chain, &opts).map_err(|e| Kind::Tx.context(e).into()); diff --git a/relayer-cli/src/commands/tx/connection.rs b/relayer-cli/src/commands/tx/connection.rs index b2f5e226c7..4b168402fc 100644 --- a/relayer-cli/src/commands/tx/connection.rs +++ b/relayer-cli/src/commands/tx/connection.rs @@ -73,10 +73,27 @@ macro_rules! conn_open_cmd { status_info!("Message ", "{}: {:?}", $dbg_string, opts); - let (src_chain, _) = - ChainRuntime::::spawn(src_chain_config.clone()).unwrap(); - let (dst_chain, _) = - ChainRuntime::::spawn(dst_chain_config.clone()).unwrap(); + let src_chain_res = ChainRuntime::::spawn(src_chain_config.clone()) + .map_err(|e| Kind::Runtime.context(e)); + let src_chain = match src_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; + + let dst_chain_res = ChainRuntime::::spawn(dst_chain_config.clone()) + .map_err(|e| Kind::Runtime.context(e)); + let dst_chain = match dst_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; let res: Result = $func(dst_chain, src_chain, &opts).map_err(|e| Kind::Tx.context(e).into()); diff --git a/relayer-cli/src/commands/tx/packet.rs b/relayer-cli/src/commands/tx/packet.rs index 75792484bb..036a08ab34 100644 --- a/relayer-cli/src/commands/tx/packet.rs +++ b/relayer-cli/src/commands/tx/packet.rs @@ -81,10 +81,29 @@ impl Runnable for TxRawPacketRecvCmd { }; status_info!("Message", "{:?}", opts); - let (src_chain, _) = - ChainRuntime::::spawn(opts.packet_src_chain_config.clone()).unwrap(); - let (dst_chain, _) = - ChainRuntime::::spawn(opts.packet_dst_chain_config.clone()).unwrap(); + let src_chain_res = + ChainRuntime::::spawn(opts.packet_src_chain_config.clone()) + .map_err(|e| Kind::Runtime.context(e)); + let src_chain = match src_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; + + let dst_chain_res = + ChainRuntime::::spawn(opts.packet_dst_chain_config.clone()) + .map_err(|e| Kind::Runtime.context(e)); + let dst_chain = match dst_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; let res: Result, Error> = build_and_send_recv_packet_messages(src_chain, dst_chain, &opts) @@ -165,10 +184,29 @@ impl Runnable for TxRawPacketAckCmd { }; status_info!("Message", "{:?}", opts); - let (src_chain, _) = - ChainRuntime::::spawn(opts.packet_src_chain_config.clone()).unwrap(); - let (dst_chain, _) = - ChainRuntime::::spawn(opts.packet_dst_chain_config.clone()).unwrap(); + let src_chain_res = + ChainRuntime::::spawn(opts.packet_src_chain_config.clone()) + .map_err(|e| Kind::Runtime.context(e)); + let src_chain = match src_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; + + let dst_chain_res = + ChainRuntime::::spawn(opts.packet_dst_chain_config.clone()) + .map_err(|e| Kind::Runtime.context(e)); + let dst_chain = match dst_chain_res { + Ok((handle, _)) => handle, + Err(e) => { + return Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; let res: Result, Error> = build_and_send_ack_packet_messages(src_chain, dst_chain, &opts) diff --git a/relayer-cli/src/commands/tx/transfer.rs b/relayer-cli/src/commands/tx/transfer.rs index d97ff21871..d7acaf8f05 100644 --- a/relayer-cli/src/commands/tx/transfer.rs +++ b/relayer-cli/src/commands/tx/transfer.rs @@ -92,10 +92,29 @@ impl Runnable for TxRawSendPacketCmd { status_info!("Message", "{:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); - let src_chain = - CosmosSDKChain::bootstrap(opts.packet_src_chain_config.clone(), rt.clone()).unwrap(); - let dst_chain = - CosmosSDKChain::bootstrap(opts.packet_dst_chain_config.clone(), rt).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::with_error() + .with_result(json!(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::with_error() + .with_result(json!(format!("{}", e))) + .exit(); + } + }; let res: Result, Error> = build_and_send_transfer_messages(src_chain, dst_chain, &opts) diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 8ea17b23ca..796b0a27f5 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -344,6 +344,71 @@ impl Chain for CosmosSDKChain { Ok(res) } + /// Get the account for the signer + fn get_signer(&mut self) -> Result { + // Get the key from key seed file + let key = self + .keybase() + .get_key() + .map_err(|e| Kind::KeyBase.context(e))?; + + let signer: AccountId = + AccountId::from_str(&key.address.to_hex()).map_err(|e| Kind::KeyBase.context(e))?; + + Ok(signer) + } + + /// Get the signing key + fn get_key(&mut self) -> Result { + // Get the key from key seed file + let key = self + .keybase() + .get_key() + .map_err(|e| Kind::KeyBase.context(e))?; + + Ok(key) + } + + fn build_client_state(&self, height: ICSHeight) -> Result { + // Build the client state. + Ok(ibc::ics07_tendermint::client_state::ClientState::new( + self.id().to_string(), + self.config.trust_threshold, + self.config.trusting_period, + self.unbonding_period()?, + Duration::from_millis(3000), // TODO - get it from src config when avail + height, + ICSHeight::zero(), + vec!["upgrade".to_string(), "upgradedIBCState".to_string()], + false, + false, + ) + .map_err(|e| Kind::BuildClientStateFailure.context(e))?) + } + + fn build_consensus_state( + &self, + light_block: Self::LightBlock, + ) -> Result { + Ok(TMConsensusState::from(light_block.signed_header.header)) + } + + fn build_header( + &self, + trusted_light_block: Self::LightBlock, + target_light_block: Self::LightBlock, + ) -> Result { + let trusted_height = + ICSHeight::new(self.id().version(), trusted_light_block.height().into()); + + Ok(TMHeader { + trusted_height, + signed_header: target_light_block.signed_header.clone(), + validator_set: target_light_block.validators, + trusted_validator_set: trusted_light_block.validators, + }) + } + /// Query the latest height the chain is at via a RPC query fn query_latest_height(&self) -> Result { let status = block_on(self.rpc_client().status()).map_err(|e| Kind::Rpc.context(e))?; @@ -447,71 +512,6 @@ impl Chain for CosmosSDKChain { })?, )) } - - fn build_client_state(&self, height: ICSHeight) -> Result { - // Build the client state. - Ok(ibc::ics07_tendermint::client_state::ClientState::new( - self.id().to_string(), - self.config.trust_threshold, - self.config.trusting_period, - self.unbonding_period()?, - Duration::from_millis(3000), // TODO - get it from src config when avail - height, - ICSHeight::zero(), - vec!["upgrade".to_string(), "upgradedIBCState".to_string()], - false, - false, - ) - .map_err(|e| Kind::BuildClientStateFailure.context(e))?) - } - - fn build_consensus_state( - &self, - light_block: Self::LightBlock, - ) -> Result { - Ok(TMConsensusState::from(light_block.signed_header.header)) - } - - fn build_header( - &self, - trusted_light_block: Self::LightBlock, - target_light_block: Self::LightBlock, - ) -> Result { - let trusted_height = - ICSHeight::new(self.id().version(), trusted_light_block.height().into()); - - Ok(TMHeader { - trusted_height, - signed_header: target_light_block.signed_header.clone(), - validator_set: target_light_block.validators, - trusted_validator_set: trusted_light_block.validators, - }) - } - - /// Get the account for the signer - fn get_signer(&mut self) -> Result { - // Get the key from key seed file - let key = self - .keybase() - .get_key() - .map_err(|e| Kind::KeyBase.context(e))?; - - let signer: AccountId = - AccountId::from_str(&key.address.to_hex()).map_err(|e| Kind::KeyBase.context(e))?; - - Ok(signer) - } - - /// Get the signing key - fn get_key(&mut self) -> Result { - // Get the key from key seed file - let key = self - .keybase() - .get_key() - .map_err(|e| Kind::KeyBase.context(e))?; - - Ok(key) - } /// Queries the packet commitment hashes associated with a channel. fn query_packet_commitments( &self, @@ -616,33 +616,6 @@ impl Chain for CosmosSDKChain { Ok(response.sequences) } - /// Queries the packet data for all packets with sequences included in the request. - /// Note - there is no way to format the query such that it asks for Tx-es with either - /// sequence (the query conditions can only be AND-ed) - /// There is a possibility to include "<=" and ">=" conditions but it doesn't work with - /// string attributes (sequence is emmitted as a string). - /// Therefore, here we perform one tx_search for each query. Alternatively, a single query - /// for all packets could be performed but it would return all packets ever sent. - fn query_txs(&self, request: QueryPacketEventDataRequest) -> Result, Error> { - let mut result: Vec = vec![]; - for seq in request.sequences.iter() { - // query all Tx-es that include events related to packet with given port, channel and sequence - let response = block_on(self.rpc_client.tx_search( - packet_query(&request, seq)?, - false, - 1, - 1, - Order::Ascending, - )) - .unwrap(); // todo - - let mut events = packet_from_tx_search_response(&request, *seq, &response)? - .map_or(vec![], |v| vec![v]); - result.append(&mut events); - } - Ok(result) - } - fn query_connection_channels( &self, request: QueryConnectionChannelsRequest, @@ -673,6 +646,33 @@ impl Chain for CosmosSDKChain { Ok(vec_ids) } + + /// Queries the packet data for all packets with sequences included in the request. + /// Note - there is no way to format the query such that it asks for Tx-es with either + /// sequence (the query conditions can only be AND-ed) + /// There is a possibility to include "<=" and ">=" conditions but it doesn't work with + /// string attributes (sequence is emmitted as a string). + /// Therefore, here we perform one tx_search for each query. Alternatively, a single query + /// for all packets could be performed but it would return all packets ever sent. + fn query_txs(&self, request: QueryPacketEventDataRequest) -> Result, Error> { + let mut result: Vec = vec![]; + for seq in request.sequences.iter() { + // query all Tx-es that include events related to packet with given port, channel and sequence + let response = block_on(self.rpc_client.tx_search( + packet_query(&request, seq)?, + false, + 1, + 1, + Order::Ascending, + )) + .unwrap(); // todo + + let mut events = packet_from_tx_search_response(&request, *seq, &response)? + .map_or(vec![], |v| vec![v]); + result.append(&mut events); + } + Ok(result) + } } fn packet_query(request: &QueryPacketEventDataRequest, seq: &Sequence) -> Result { From 855b5faff37aac0f01a94e5bee5f475432174a35 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 20 Jan 2021 10:00:59 +0100 Subject: [PATCH 03/12] Tagged relayer RPC error with the culprit IP address. --- relayer/src/chain/cosmos.rs | 21 ++++++++++++--------- relayer/src/chain/mock.rs | 4 ++-- relayer/src/error.rs | 8 +++++--- relayer/src/event/monitor.rs | 9 ++++----- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 796b0a27f5..2de85696bd 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -117,7 +117,7 @@ impl CosmosSDKChain { /// Specific to the SDK and used only for Tendermint client create pub fn query_consensus_params(&self) -> Result { Ok(block_on(self.rpc_client().genesis()) - .map_err(|e| Kind::Rpc.context(e))? + .map_err(|e| Kind::Rpc(self.config.rpc_addr.clone()).context(e))? .consensus_params) } @@ -210,8 +210,8 @@ impl CosmosSDKChain { let mut txraw_buf = Vec::new(); prost::Message::encode(&tx_raw, &mut txraw_buf).unwrap(); - let response = - block_on(broadcast_tx_commit(self, txraw_buf)).map_err(|e| Kind::Rpc.context(e))?; + let response = block_on(broadcast_tx_commit(self, txraw_buf)) + .map_err(|e| Kind::Rpc(self.config.rpc_addr.clone()).context(e))?; let res = tx_result_to_event(response)?; @@ -238,8 +238,8 @@ impl Chain for CosmosSDKChain { type ClientState = ClientState; fn bootstrap(config: ChainConfig, rt: Arc) -> Result { - let rpc_client = - HttpClient::new(config.rpc_addr.clone()).map_err(|e| Kind::Rpc.context(e))?; + let rpc_client = HttpClient::new(config.rpc_addr.clone()) + .map_err(|e| Kind::Rpc(config.rpc_addr.clone()).context(e))?; // Initialize key store and load key let key_store = KeyRing::init(StoreBackend::Test, config.clone()) @@ -411,7 +411,8 @@ impl Chain for CosmosSDKChain { /// Query the latest height the chain is at via a RPC query fn query_latest_height(&self) -> Result { - let status = block_on(self.rpc_client().status()).map_err(|e| Kind::Rpc.context(e))?; + let status = block_on(self.rpc_client().status()) + .map_err(|e| Kind::Rpc(self.config.rpc_addr.clone()).context(e))?; if status.sync_info.catching_up { fail!( @@ -758,11 +759,13 @@ async fn abci_query( .rpc_client() .abci_query(Some(path), data.into_bytes(), height, prove) .await - .map_err(|e| Kind::Rpc.context(e))?; + .map_err(|e| Kind::Rpc(chain.config.rpc_addr.clone()).context(e))?; if !response.code.is_ok() { // Fail with response log. - return Err(Kind::Rpc.context(response.log.to_string()).into()); + return Err(Kind::Rpc(chain.config.rpc_addr.clone()) + .context(response.log.to_string()) + .into()); } if prove && response.proof.is_none() { @@ -790,7 +793,7 @@ async fn broadcast_tx_commit( .rpc_client() .broadcast_tx_commit(data.into()) .await - .map_err(|e| Kind::Rpc.context(e))?; + .map_err(|e| Kind::Rpc(chain.config.rpc_addr.clone()).context(e))?; Ok(response) } diff --git a/relayer/src/chain/mock.rs b/relayer/src/chain/mock.rs index 07927aded0..f438395fc3 100644 --- a/relayer/src/chain/mock.rs +++ b/relayer/src/chain/mock.rs @@ -105,7 +105,7 @@ impl Chain for MockChain { // Use the ICS18Context interface to submit the set of messages. self.context .send(proto_msgs) - .map_err(|e| Kind::Rpc.context(e))?; + .map_err(|e| Kind::Rpc(self.config.rpc_addr.clone()).context(e))?; // TODO FIX tests with this Ok(vec![]) @@ -255,7 +255,7 @@ pub mod test_utils { pub fn get_basic_chain_config(id: &str) -> ChainConfig { ChainConfig { id: ChainId::from_str(id).unwrap(), - rpc_addr: "35.192.61.41:26656".parse().unwrap(), + rpc_addr: "127.0.0.1:26656".parse().unwrap(), grpc_addr: "".to_string(), account_prefix: "".to_string(), key_name: "".to_string(), diff --git a/relayer/src/error.rs b/relayer/src/error.rs index 32aa1d6ae7..10e7136219 100644 --- a/relayer/src/error.rs +++ b/relayer/src/error.rs @@ -1,9 +1,11 @@ //! This module defines the various errors that be raised in the relayer. use anomaly::{BoxError, Context}; -use ibc::ics24_host::identifier::{ChainId, ChannelId, ConnectionId}; +use tendermint::net; use thiserror::Error; +use ibc::ics24_host::identifier::{ChainId, ChannelId, ConnectionId}; + /// An error that can be raised by the relayer. pub type Error = anomaly::Error; @@ -23,8 +25,8 @@ pub enum Kind { Config, /// RPC error (typically raised by the RPC client or the RPC requester) - #[error("RPC error")] - Rpc, + #[error("RPC error to endpoint {0}")] + Rpc(net::Address), /// GRPC error (typically raised by the GRPC client or the GRPC requester) #[error("GRPC error")] diff --git a/relayer/src/event/monitor.rs b/relayer/src/event/monitor.rs index 0735d5ac71..f8999452aa 100644 --- a/relayer/src/event/monitor.rs +++ b/relayer/src/event/monitor.rs @@ -5,14 +5,13 @@ use crossbeam_channel as channel; use futures::stream::StreamExt; use futures::{stream::select_all, Stream}; use itertools::Itertools; +use tendermint::{block::Height, net}; +use tendermint_rpc::{query::EventType, query::Query, SubscriptionClient, WebSocketClient}; use tokio::runtime::Runtime as TokioRuntime; - use tokio::task::JoinHandle; use tracing::{debug, error, info}; use ibc::{events::IBCEvent, ics24_host::identifier::ChainId}; -use tendermint::{block::Height, net}; -use tendermint_rpc::{query::EventType, query::Query, SubscriptionClient, WebSocketClient}; use crate::error::{Error, Kind}; @@ -58,9 +57,9 @@ impl EventMonitor { let websocket_addr = rpc_addr.clone(); let (websocket_client, websocket_driver) = rt.block_on(async move { - WebSocketClient::new(websocket_addr) + WebSocketClient::new(websocket_addr.clone()) .await - .map_err(|e| Kind::Rpc.context(e)) + .map_err(|e| Kind::Rpc(websocket_addr).context(e)) })?; let websocket_driver_handle = rt.spawn(websocket_driver.run()); From 6da84d63a114882da576c214e3ec4cb7eb7311ee Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 20 Jan 2021 11:06:46 +0100 Subject: [PATCH 04/12] Replaced start with v0 --- relayer-cli/src/commands.rs | 9 +---- relayer-cli/src/commands/start.rs | 54 ++++++++++++++++++-------- relayer-cli/src/commands/v0.rs | 63 ------------------------------- 3 files changed, 41 insertions(+), 85 deletions(-) delete mode 100644 relayer-cli/src/commands/v0.rs diff --git a/relayer-cli/src/commands.rs b/relayer-cli/src/commands.rs index b703a14606..9e696b3698 100644 --- a/relayer-cli/src/commands.rs +++ b/relayer-cli/src/commands.rs @@ -12,12 +12,11 @@ mod listen; mod query; mod start; mod tx; -mod v0; mod version; use self::{ config::ConfigCmd, keys::KeysCmd, light::LightCmd, listen::ListenCmd, query::QueryCmd, - start::StartCmd, tx::TxCmd, v0::V0Cmd, version::VersionCmd, + start::StartCmd, tx::TxCmd, version::VersionCmd, }; use crate::config::Config; @@ -34,12 +33,8 @@ pub enum CliCmd { #[options(help = "get usage information")] Help(Help), - /// The `v0` subcommand - #[options(help = "start the v0 relayer")] - V0(V0Cmd), - /// The `start` subcommand - #[options(help = "start the relayer")] + #[options(help = "start the relayer (currently this refers to the v0 relayer)")] Start(StartCmd), /// The `listen` subcommand diff --git a/relayer-cli/src/commands/start.rs b/relayer-cli/src/commands/start.rs index 8b516c65a9..8519f81704 100644 --- a/relayer-cli/src/commands/start.rs +++ b/relayer-cli/src/commands/start.rs @@ -2,35 +2,59 @@ use std::ops::Deref; use abscissa_core::{application::fatal_error, error::BoxError, Command, Options, Runnable}; +use ibc::ics04_channel::channel::Order; +use relayer::chain::runtime::ChainRuntime; +use relayer::chain::CosmosSDKChain; use relayer::config::Config; +use relayer::relay::channel_relay; use crate::prelude::*; #[derive(Command, Debug, Options)] -pub struct StartCmd { - #[options(help = "reset state from trust options", short = "r")] - reset: bool, -} +pub struct StartCmd {} impl StartCmd { - async fn cmd(&self) -> Result<(), BoxError> { + fn cmd(&self) -> Result<(), BoxError> { let config = app_config().clone(); - start(config, self.reset).await + debug!("launching 'v0' command"); + v0_task(&config) } } impl Runnable for StartCmd { fn run(&self) { - let rt = tokio::runtime::Runtime::new().unwrap(); - - rt.block_on(async move { - self.cmd() - .await - .unwrap_or_else(|e| fatal_error(app_reader().deref(), &*e)); - }); + self.cmd() + .unwrap_or_else(|e| fatal_error(app_reader().deref(), &*e)) } } -async fn start(config: Config, reset: bool) -> Result<(), BoxError> { - todo!() // TODO: Move v0 command here +pub fn v0_task(config: &Config) -> Result<(), BoxError> { + // Relay for a single channel, first on the first connection in configuration + let conn = &config + .connections + .clone() + .ok_or("No connections configured")?[0]; + + let ordering = Order::default(); // TODO - add to config + let path = conn.paths.clone().ok_or("No paths configured")?[0].clone(); + + let src_chain_config = config + .find_chain(&conn.a_chain) + .cloned() + .ok_or("Configuration for source chain not found")?; + + let dst_chain_config = config + .find_chain(&conn.b_chain) + .cloned() + .ok_or("Configuration for source chain not found")?; + + let (src_chain_handle, _) = ChainRuntime::::spawn(src_chain_config)?; + let (dst_chain_handle, _) = ChainRuntime::::spawn(dst_chain_config)?; + + Ok(channel_relay( + src_chain_handle, + dst_chain_handle, + ordering, + path, + )?) } diff --git a/relayer-cli/src/commands/v0.rs b/relayer-cli/src/commands/v0.rs deleted file mode 100644 index c617acf973..0000000000 --- a/relayer-cli/src/commands/v0.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::ops::Deref; - -use abscissa_core::{ - application::fatal_error, error::BoxError, tracing::debug, Command, Options, Runnable, -}; - -use ibc::ics04_channel::channel::Order; - -use relayer::chain::runtime::ChainRuntime; -use relayer::relay::channel_relay; - -use crate::config::Config; -use crate::prelude::*; -use relayer::chain::CosmosSDKChain; - -#[derive(Command, Debug, Options)] -pub struct V0Cmd {} - -impl V0Cmd { - fn cmd(&self) -> Result<(), BoxError> { - let config = app_config().clone(); - debug!("launching 'v0' command"); - v0_task(&config) - } -} - -impl Runnable for V0Cmd { - fn run(&self) { - self.cmd() - .unwrap_or_else(|e| fatal_error(app_reader().deref(), &*e)) - } -} - -pub fn v0_task(config: &Config) -> Result<(), BoxError> { - // Relay for a single channel, first on the first connection in configuration - let conn = &config - .connections - .clone() - .ok_or("No connections configured")?[0]; - - let ordering = Order::default(); // TODO - add to config - let path = conn.paths.clone().ok_or("No paths configured")?[0].clone(); - - let src_chain_config = config - .find_chain(&conn.a_chain) - .cloned() - .ok_or("Configuration for source chain not found")?; - - let dst_chain_config = config - .find_chain(&conn.b_chain) - .cloned() - .ok_or("Configuration for source chain not found")?; - - let (src_chain_handle, _) = ChainRuntime::::spawn(src_chain_config)?; - let (dst_chain_handle, _) = ChainRuntime::::spawn(dst_chain_config)?; - - Ok(channel_relay( - src_chain_handle, - dst_chain_handle, - ordering, - path, - )?) -} From 7534bd77b69933ea58fd7860a2312fcc34df2c79 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 20 Jan 2021 12:44:27 +0100 Subject: [PATCH 05/12] Introduced logging levels. WIP: remove status_ calls --- relayer-cli/src/application.rs | 23 +++++++++++++- relayer-cli/src/commands/query/client.rs | 7 +++-- relayer-cli/src/components.rs | 40 ++++++++++++++++++++++++ relayer-cli/src/lib.rs | 1 + relayer/src/config.rs | 10 ++++-- 5 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 relayer-cli/src/components.rs diff --git a/relayer-cli/src/application.rs b/relayer-cli/src/application.rs index 25cbc278e8..29989f54a5 100644 --- a/relayer-cli/src/application.rs +++ b/relayer-cli/src/application.rs @@ -1,9 +1,12 @@ //! Cli Abscissa Application +use crate::components::Tracing; use crate::{commands::CliCmd, config::Config}; +use abscissa_core::terminal::component::Terminal; use abscissa_core::{ application::{self, AppCell}, - config, trace, Application, EntryPoint, FrameworkError, StandardPaths, + component::Component, + config, trace, Application, Configurable, EntryPoint, FrameworkError, StandardPaths, }; /// Application state @@ -98,6 +101,24 @@ impl Application for CliApp { Ok(()) } + /// Overrides the default abscissa components, so that we can setup tracing on our own. See + /// also `register_components`. + fn framework_components( + &mut self, + command: &Self::Cmd, + ) -> Result>>, FrameworkError> { + let terminal = Terminal::new(self.term_colors(command)); + + let config = command + .config_path() + .map(|path| self.load_config(&path)) + .transpose()? + .unwrap_or_default(); + let tracing = Tracing::new(config.global)?; + + Ok(vec![Box::new(terminal), Box::new(tracing)]) + } + /// Get tracing configuration from command-line options fn tracing_config(&self, command: &EntryPoint) -> trace::Config { if command.verbose { diff --git a/relayer-cli/src/commands/query/client.rs b/relayer-cli/src/commands/query/client.rs index 2083847786..09f9463ff0 100644 --- a/relayer-cli/src/commands/query/client.rs +++ b/relayer-cli/src/commands/query/client.rs @@ -4,6 +4,7 @@ use abscissa_core::{Command, Options, Runnable}; use serde_json::json; use tendermint_proto::Protobuf; use tokio::runtime::Runtime as TokioRuntime; +use tracing::info; use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; use ibc::ics02_client::raw::ConnectionIds as ConnectionIDs; @@ -75,7 +76,7 @@ impl Runnable for QueryClientStateCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); let chain = CosmosSDKChain::bootstrap(chain_config, rt).unwrap(); @@ -169,7 +170,7 @@ impl Runnable for QueryClientConsensusCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); let chain = CosmosSDKChain::bootstrap(chain_config, rt).unwrap(); @@ -280,7 +281,7 @@ impl Runnable for QueryClientConnectionsCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); let chain = CosmosSDKChain::bootstrap(chain_config, rt).unwrap(); diff --git a/relayer-cli/src/components.rs b/relayer-cli/src/components.rs new file mode 100644 index 0000000000..193769a053 --- /dev/null +++ b/relayer-cli/src/components.rs @@ -0,0 +1,40 @@ +use abscissa_core::{Component, FrameworkError}; +use relayer::config::GlobalConfig; +use tracing_subscriber::fmt::{ + format::{Format, Json, JsonFields}, + time::SystemTime, + Formatter, +}; +use tracing_subscriber::util::SubscriberInitExt; +use tracing_subscriber::{reload::Handle, EnvFilter, FmtSubscriber}; + +/// Abscissa component for initializing the `tracing` subsystem +#[derive(Component, Debug)] +pub struct Tracing { + filter_handle: Handle>>, +} + +/// A custom component for parametrizing `tracing` in the relayer. Primarily used for: +/// - customizes the log output level, for filtering the output produced via tracing macros +/// (`debug!`, `info!`, etc.) or abscissa macros (`status_err`, `status_info`, etc.). +/// - enables JSON-formatted output +impl Tracing { + /// Creates a new [`Tracing`] component + pub fn new(cfg: GlobalConfig) -> Result { + let filter = cfg.log_level; + let use_color = false; + + // Construct a tracing subscriber with the supplied filter and enable reloading. + let builder = FmtSubscriber::builder() + .with_env_filter(filter) + .with_ansi(use_color) + .json() + .with_filter_reloading(); + let filter_handle = builder.reload_handle(); + + let subscriber = builder.finish(); + subscriber.init(); + + Ok(Self { filter_handle }) + } +} diff --git a/relayer-cli/src/lib.rs b/relayer-cli/src/lib.rs index 5a1a4f76f3..58e9f0ac04 100644 --- a/relayer-cli/src/lib.rs +++ b/relayer-cli/src/lib.rs @@ -18,6 +18,7 @@ pub mod application; pub mod commands; +mod components; pub(crate) mod conclude; pub mod config; pub mod error; diff --git a/relayer/src/config.rs b/relayer/src/config.rs index a998ea2177..54483f41eb 100644 --- a/relayer/src/config.rs +++ b/relayer/src/config.rs @@ -10,11 +10,11 @@ use std::{ }; use serde_derive::{Deserialize, Serialize}; - -use ibc::ics24_host::identifier::{ChainId, PortId}; use tendermint::{net, Hash}; use tendermint_light_client::types::{Height, PeerId, TrustThreshold}; +use ibc::ics24_host::identifier::{ChainId, PortId}; + use crate::error; /// Defaults for various fields @@ -77,8 +77,13 @@ impl Default for Strategy { pub struct GlobalConfig { #[serde(default = "default::timeout", with = "humantime_serde")] pub timeout: Duration, + #[serde(default)] pub strategy: Strategy, + + /// All valid log levels, as defined in tracing: + /// https://docs.rs/tracing-core/0.1.17/tracing_core/struct.Level.html + pub log_level: String, } impl Default for GlobalConfig { @@ -86,6 +91,7 @@ impl Default for GlobalConfig { Self { timeout: default::timeout(), strategy: Strategy::default(), + log_level: "info".to_string(), } } } From f7764a1f173625d0bb6512a368655a668d2e084d Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 20 Jan 2021 14:51:04 +0100 Subject: [PATCH 06/12] Updated the sample config file --- relayer-cli/tests/fixtures/two_chains.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/relayer-cli/tests/fixtures/two_chains.toml b/relayer-cli/tests/fixtures/two_chains.toml index 0daf7ce18c..b3bd13fa66 100644 --- a/relayer-cli/tests/fixtures/two_chains.toml +++ b/relayer-cli/tests/fixtures/two_chains.toml @@ -1,6 +1,7 @@ [global] timeout = '10s' strategy = 'naive' +log_level = 'error' # valid options: 'error', 'warn', 'info', 'debug', 'trace' [[chains]] id = 'ibc-0' From e6730ef3921ec0a4a0d94faa7cadc8386cf6bb94 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 20 Jan 2021 15:17:21 +0100 Subject: [PATCH 07/12] Adapted keys commands to JSON output --- relayer-cli/src/commands/keys/add.rs | 17 ++++++++++------- relayer-cli/src/commands/keys/list.rs | 17 ++++++++++------- relayer-cli/src/commands/keys/restore.rs | 17 ++++++++++------- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/relayer-cli/src/commands/keys/add.rs b/relayer-cli/src/commands/keys/add.rs index 084d467971..96d03711ed 100644 --- a/relayer-cli/src/commands/keys/add.rs +++ b/relayer-cli/src/commands/keys/add.rs @@ -1,10 +1,12 @@ -use crate::application::app_config; use abscissa_core::{Command, Options, Runnable}; +use serde_json::json; + use relayer::config::Config; +use relayer::keys::add::{add_key, KeysAddOptions}; +use crate::application::app_config; +use crate::conclude::Output; use crate::error::{Error, Kind}; -use crate::prelude::*; -use relayer::keys::add::{add_key, KeysAddOptions}; #[derive(Clone, Command, Debug, Options)] pub struct KeysAddCmd { @@ -47,8 +49,7 @@ impl Runnable for KeysAddCmd { let opts = match self.validate_options(&config) { Err(err) => { - status_err!("invalid options: {}", err); - return; + return Output::with_error().with_result(json!(err)).exit(); } Ok(result) => result, }; @@ -56,8 +57,10 @@ impl Runnable for KeysAddCmd { let res: Result = add_key(opts).map_err(|e| Kind::Keys.context(e).into()); match res { - Ok(r) => status_info!("key add result: ", "{:?}", r), - Err(e) => status_info!("key add failed: ", "{}", e), + Ok(r) => Output::with_success().with_result(json!(r)).exit(), + Err(e) => Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(), } } } diff --git a/relayer-cli/src/commands/keys/list.rs b/relayer-cli/src/commands/keys/list.rs index 5dd1528cfe..61fd5c1f77 100644 --- a/relayer-cli/src/commands/keys/list.rs +++ b/relayer-cli/src/commands/keys/list.rs @@ -1,10 +1,12 @@ -use crate::application::app_config; use abscissa_core::{Command, Options, Runnable}; +use serde_json::json; + use relayer::config::Config; +use relayer::keys::list::{list_keys, KeysListOptions}; +use crate::application::app_config; +use crate::conclude::Output; use crate::error::{Error, Kind}; -use crate::prelude::*; -use relayer::keys::list::{list_keys, KeysListOptions}; #[derive(Clone, Command, Debug, Options)] pub struct KeysListCmd { @@ -37,8 +39,7 @@ impl Runnable for KeysListCmd { let opts = match self.validate_options(&config) { Err(err) => { - status_err!("invalid options: {}", err); - return; + return Output::with_error().with_result(json!(err)).exit(); } Ok(result) => result, }; @@ -46,8 +47,10 @@ impl Runnable for KeysListCmd { let res: Result = list_keys(opts).map_err(|e| Kind::Keys.context(e).into()); match res { - Ok(r) => status_info!("keys list result: ", "{:?}", r), - Err(e) => status_info!("keys list failed: ", "{}", e), + Ok(r) => Output::with_success().with_result(json!(r)).exit(), + Err(e) => Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(), } } } diff --git a/relayer-cli/src/commands/keys/restore.rs b/relayer-cli/src/commands/keys/restore.rs index 562fe803fb..80e083990b 100644 --- a/relayer-cli/src/commands/keys/restore.rs +++ b/relayer-cli/src/commands/keys/restore.rs @@ -1,10 +1,12 @@ -use crate::application::app_config; use abscissa_core::{Command, Options, Runnable}; +use serde_json::json; + use relayer::config::Config; +use relayer::keys::restore::{restore_key, KeysRestoreOptions}; +use crate::application::app_config; +use crate::conclude::Output; use crate::error::{Error, Kind}; -use crate::prelude::*; -use relayer::keys::restore::{restore_key, KeysRestoreOptions}; #[derive(Clone, Command, Debug, Options)] pub struct KeyRestoreCmd { @@ -55,8 +57,7 @@ impl Runnable for KeyRestoreCmd { let opts = match self.validate_options(&config) { Err(err) => { - status_err!("invalid options: {}", err); - return; + return Output::with_error().with_result(json!(err)).exit(); } Ok(result) => result, }; @@ -65,8 +66,10 @@ impl Runnable for KeyRestoreCmd { restore_key(opts).map_err(|e| Kind::Keys.context(e).into()); match res { - Ok(r) => status_info!("key restore result: ", "{:?}", hex::encode(r)), - Err(e) => status_info!("key restore failed: ", "{}", e), + Ok(r) => Output::with_success().with_result(json!(r)).exit(), + Err(e) => Output::with_error() + .with_result(json!(format!("{}", e))) + .exit(), } } } From 1145edb6b52568ae12e0b24f3aa720afc09fae28 Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 20 Jan 2021 16:10:35 +0100 Subject: [PATCH 08/12] Transition to tracing macros & JSON outputs --- relayer-cli/src/commands/config/validate.rs | 9 ++++--- relayer-cli/src/commands/light/rm.rs | 25 ++++++++++++++----- relayer-cli/src/commands/query/channel.rs | 2 +- relayer-cli/src/commands/query/connection.rs | 4 +-- relayer-cli/src/commands/query/packet.rs | 12 ++++----- relayer-cli/src/commands/tx/channel.rs | 2 +- relayer-cli/src/commands/tx/client.rs | 17 +++++-------- relayer-cli/src/commands/tx/connection.rs | 2 +- relayer-cli/src/commands/tx/packet.rs | 4 +-- relayer-cli/src/commands/tx/transfer.rs | 2 +- .../config/fixtures/relayer_conf_example.toml | 1 + 11 files changed, 46 insertions(+), 34 deletions(-) diff --git a/relayer-cli/src/commands/config/validate.rs b/relayer-cli/src/commands/config/validate.rs index 03166eacf3..c642beeaae 100644 --- a/relayer-cli/src/commands/config/validate.rs +++ b/relayer-cli/src/commands/config/validate.rs @@ -1,7 +1,8 @@ -use crate::prelude::*; - use abscissa_core::{Command, Options, Runnable}; +use crate::conclude::Output; +use crate::prelude::*; + #[derive(Command, Debug, Options)] pub struct ValidateCmd {} @@ -9,8 +10,10 @@ impl Runnable for ValidateCmd { /// Validate the loaded configuration. fn run(&self) { let config = app_config(); - status_ok!("Loaded configuration:", "{:#?}", *config); + info!("Loaded configuration: {:?}", *config); // TODO: Validate configuration + + Output::with_success().exit(); } } diff --git a/relayer-cli/src/commands/light/rm.rs b/relayer-cli/src/commands/light/rm.rs index 72f5631a3a..d0b0d04c3c 100644 --- a/relayer-cli/src/commands/light/rm.rs +++ b/relayer-cli/src/commands/light/rm.rs @@ -1,12 +1,14 @@ use std::{io, io::Write, ops::Deref}; -use crate::prelude::*; - use abscissa_core::{application::fatal_error, error::BoxError, Command, Options, Runnable}; +use serde_json::json; +use tendermint_light_client::types::PeerId; use ibc::ics24_host::identifier::ChainId; use relayer::config::PeersConfig; -use tendermint_light_client::types::PeerId; + +use crate::conclude::Output; +use crate::prelude::*; #[derive(Command, Debug, Options)] pub struct RmCmd { @@ -88,20 +90,31 @@ impl RmCmd { .as_mut() .ok_or_else(|| format!("no peers configured for chain: {}", options.chain_id))?; - if options.all && (options.yes || confirm(&options.chain_id)?) { + let rmd_peers = if options.all && (options.yes || confirm(&options.chain_id)?) { let removed_peers = get_all_peer_ids(&peers_config); chain_config.peers = None; - status_ok!("Removed", "light client peers {:?}", removed_peers); + + removed_peers } else { + let mut res: Vec = vec![]; for peer_id in options.peer_ids { let removed_peer = remove_peer(&mut peers_config, peer_id, options.force)?; - status_ok!("Removed", "light client peer '{}'", removed_peer); + res.push(removed_peer.to_string()); } + + res }; let config_path = crate::config::config_path()?; relayer::config::store(&config, config_path)?; + Output::with_success() + .with_result(json!(format!( + "Removed light client peer(s) '{:?}'", + rmd_peers + ))) + .exit(); + Ok(()) } } diff --git a/relayer-cli/src/commands/query/channel.rs b/relayer-cli/src/commands/query/channel.rs index 63eb0995f6..aaab9309b0 100644 --- a/relayer-cli/src/commands/query/channel.rs +++ b/relayer-cli/src/commands/query/channel.rs @@ -90,7 +90,7 @@ impl Runnable for QueryChannelEndCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); // run without proof: // cargo run --bin relayer -- -c relayer/tests/config/fixtures/simple_config.toml query channel end ibc-test firstport firstchannel --height 3 -p false diff --git a/relayer-cli/src/commands/query/connection.rs b/relayer-cli/src/commands/query/connection.rs index 9c2521cf35..a8b57775ea 100644 --- a/relayer-cli/src/commands/query/connection.rs +++ b/relayer-cli/src/commands/query/connection.rs @@ -79,7 +79,7 @@ impl Runnable for QueryConnectionEndCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); let chain = CosmosSDKChain::bootstrap(chain_config, rt).unwrap(); @@ -152,7 +152,7 @@ impl Runnable for QueryConnectionChannelsCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); let chain = CosmosSDKChain::bootstrap(chain_config, rt).unwrap(); diff --git a/relayer-cli/src/commands/query/packet.rs b/relayer-cli/src/commands/query/packet.rs index 2f78f15d6f..4bf0883095 100644 --- a/relayer-cli/src/commands/query/packet.rs +++ b/relayer-cli/src/commands/query/packet.rs @@ -63,7 +63,7 @@ impl Runnable for QueryPacketCommitmentsCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); let chain = CosmosSDKChain::bootstrap(chain_config, rt).unwrap(); @@ -142,7 +142,7 @@ impl Runnable for QueryPacketCommitmentCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); // run without proof: // cargo run --bin relayer -- -c relayer/tests/config/fixtures/simple_config.toml query packet commitment ibc-0 transfer ibconexfer 3 --height 3 @@ -224,7 +224,7 @@ impl Runnable for QueryUnreceivedPacketsCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); let src_chain = CosmosSDKChain::bootstrap(src_chain_config, rt.clone()).unwrap(); @@ -313,7 +313,7 @@ impl Runnable for QueryPacketAcknowledgementsCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); let chain = CosmosSDKChain::bootstrap(chain_config, rt).unwrap(); @@ -392,7 +392,7 @@ impl Runnable for QueryPacketAcknowledgmentCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); // run without proof: // cargo run --bin relayer -- -c relayer/tests/config/fixtures/simple_config.toml query packet acknowledgment ibc-0 transfer ibconexfer --height 3 @@ -471,7 +471,7 @@ impl Runnable for QueryUnreceivedAcknowledgementCmd { } Ok(result) => result, }; - status_info!("Options", "{:?}", opts); + info!("Options {:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); let src_chain = CosmosSDKChain::bootstrap(src_chain_config, rt.clone()).unwrap(); diff --git a/relayer-cli/src/commands/tx/channel.rs b/relayer-cli/src/commands/tx/channel.rs index 76bfb863ed..7cd61bfbd1 100644 --- a/relayer-cli/src/commands/tx/channel.rs +++ b/relayer-cli/src/commands/tx/channel.rs @@ -85,7 +85,7 @@ macro_rules! chan_open_cmd { ), }; - status_info!("Message ", "{}: {:?}", $dbg_string, opts); + info!("Message {}: {:?}", $dbg_string, opts); let src_chain_res = ChainRuntime::::spawn(src_chain_config.clone()) .map_err(|e| Kind::Runtime.context(e)); diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs index 1c9144b10f..6b6a198d23 100644 --- a/relayer-cli/src/commands/tx/client.rs +++ b/relayer-cli/src/commands/tx/client.rs @@ -32,11 +32,9 @@ impl Runnable for TxCreateClientCmd { } }; - status_info!( - "Message CreateClient", - "for source chain: {:?}, on destination chain: {:?}", - src_chain_config.id, - dst_chain_config.id + info!( + "Message CreateClient for source chain: {:?}, on destination chain: {:?}", + src_chain_config.id, dst_chain_config.id ); let src_chain_res = ChainRuntime::::spawn(src_chain_config) @@ -99,12 +97,9 @@ impl Runnable for TxUpdateClientCmd { } }; - status_info!( - "Message UpdateClient", - "id: {:?}, for chain: {:?}, on chain: {:?}", - self.dst_client_id, - src_chain_config.id, - dst_chain_config.id + info!( + "Message UpdateClient id: {:?}, for chain: {:?}, on chain: {:?}", + self.dst_client_id, src_chain_config.id, dst_chain_config.id ); let src_chain_res = ChainRuntime::::spawn(src_chain_config) diff --git a/relayer-cli/src/commands/tx/connection.rs b/relayer-cli/src/commands/tx/connection.rs index 4b168402fc..1e503bd148 100644 --- a/relayer-cli/src/commands/tx/connection.rs +++ b/relayer-cli/src/commands/tx/connection.rs @@ -71,7 +71,7 @@ macro_rules! conn_open_cmd { ), }; - status_info!("Message ", "{}: {:?}", $dbg_string, opts); + info!("Message {}: {:?}", $dbg_string, opts); let src_chain_res = ChainRuntime::::spawn(src_chain_config.clone()) .map_err(|e| Kind::Runtime.context(e)); diff --git a/relayer-cli/src/commands/tx/packet.rs b/relayer-cli/src/commands/tx/packet.rs index 036a08ab34..6c61849152 100644 --- a/relayer-cli/src/commands/tx/packet.rs +++ b/relayer-cli/src/commands/tx/packet.rs @@ -79,7 +79,7 @@ impl Runnable for TxRawPacketRecvCmd { } Ok(result) => result, }; - status_info!("Message", "{:?}", opts); + info!("Message {:?}", opts); let src_chain_res = ChainRuntime::::spawn(opts.packet_src_chain_config.clone()) @@ -182,7 +182,7 @@ impl Runnable for TxRawPacketAckCmd { } Ok(result) => result, }; - status_info!("Message", "{:?}", opts); + info!("Message {:?}", opts); let src_chain_res = ChainRuntime::::spawn(opts.packet_src_chain_config.clone()) diff --git a/relayer-cli/src/commands/tx/transfer.rs b/relayer-cli/src/commands/tx/transfer.rs index d7acaf8f05..5791ca8822 100644 --- a/relayer-cli/src/commands/tx/transfer.rs +++ b/relayer-cli/src/commands/tx/transfer.rs @@ -89,7 +89,7 @@ impl Runnable for TxRawSendPacketCmd { } Ok(result) => result, }; - status_info!("Message", "{:?}", opts); + info!("Message {:?}", opts); let rt = Arc::new(TokioRuntime::new().unwrap()); diff --git a/relayer/tests/config/fixtures/relayer_conf_example.toml b/relayer/tests/config/fixtures/relayer_conf_example.toml index 220e178f5a..7467b67242 100644 --- a/relayer/tests/config/fixtures/relayer_conf_example.toml +++ b/relayer/tests/config/fixtures/relayer_conf_example.toml @@ -1,6 +1,7 @@ [global] timeout = '10s' strategy = 'naive' +log_level = 'error' [[chains]] id = 'chain_A' From 5ffe8230b193f9ca43d1445361f4dfde8135674f Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 20 Jan 2021 16:18:22 +0100 Subject: [PATCH 09/12] Changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1ccd774cb..cd84a98acb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - [relayer-cli] - Replace `ChannelConfig` in `Channel::new` ([#511]) - Add `packet-send` CLI ([#470]) + - UX improvements for relayer txs ([#536, 540]) - [relayer] - Performance improvements ([#514], [#537]) @@ -44,7 +45,9 @@ [#517]: https://github.com/informalsystems/ibc-rs/issues/517 [#525]: https://github.com/informalsystems/ibc-rs/issues/525 [#527]: https://github.com/informalsystems/ibc-rs/issues/527 +[#536]: https://github.com/informalsystems/ibc-rs/issues/536 [#537]: https://github.com/informalsystems/ibc-rs/issues/537 +[#540]: https://github.com/informalsystems/ibc-rs/issues/540 ## v0.0.6 From d638cc33b9547ca9addc8e2897a425d700364ffd Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Wed, 20 Jan 2021 19:25:28 +0100 Subject: [PATCH 10/12] Added operation instructions. --- relayer-cli/relayer_operation_instructions.md | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/relayer-cli/relayer_operation_instructions.md b/relayer-cli/relayer_operation_instructions.md index ca672ff795..ee726f4aed 100644 --- a/relayer-cli/relayer_operation_instructions.md +++ b/relayer-cli/relayer_operation_instructions.md @@ -279,3 +279,44 @@ Jan 20 11:28:47.842 INFO relayer::macros::profiling: ⏳ inner operation - s Jan 20 11:28:49.846 INFO relayer::macros::profiling: ⏳ inner operation - elapsed: 2004ms Jan 20 11:28:49.847 INFO relayer::macros::profiling: ⏳ myfunction: x=42 - elapsed: 3005ms ``` + +## Parametrizing the log output level + +The relayer configuration file, called `loop_config.toml` in the examples above +permits parametrization of output verbosity via the knob called `log_level`. +Relevant snippet: + +```toml +[global] +timeout = '10s' +strategy = 'naive' +log_level = 'error' +``` + +Valid options for `log_level` are: 'error', 'warn', 'info', 'debug', 'trace'. +These levels correspond to the tracing sub-component of the relayer-cli, [see +here](https://docs.rs/tracing-core/0.1.17/tracing_core/struct.Level.html). + +The relayer will _always_ print a last line summarizing the result of its +operation for queries of transactions. In addition to this last line, +arbitrary debug, info, or other outputs may be produced. Example, with +`log_level = 'debug'`: + +```bash +Running `target/debug/relayer -c loop_config.toml query client consensus ibc-0 07-tendermint-X 0 1` +{"timestamp":"Jan 20 19:21:52.070","level":"DEBUG","fields":{"message":"registered component: abscissa_core::terminal::component::Terminal (v0.5.2)"},"target":"abscissa_core::component::registry"} +{"timestamp":"Jan 20 19:21:52.071","level":"DEBUG","fields":{"message":"registered component: relayer_cli::components::Tracing (v0.0.6)"},"target":"abscissa_core::component::registry"} +{"timestamp":"Jan 20 19:21:52.078","level":"INFO","fields":{"message":"Options QueryClientConsensusOptions { client_id: ClientId(\"07-tendermint-X\"), revision_number: 0, revision_height: 1, height: 0, proof: true }"},"target":"relayer_cli::commands::query::client"} +{"timestamp":"Jan 20 19:21:52.080","level":"DEBUG","fields":{"message":"resolving host=\"localhost\""},"target":"hyper::client::connect::dns"} +{"timestamp":"Jan 20 19:21:52.083","level":"DEBUG","fields":{"message":"connecting to [::1]:26657"},"target":"hyper::client::connect::http"} +{"timestamp":"Jan 20 19:21:52.083","level":"DEBUG","fields":{"message":"connecting to 127.0.0.1:26657"},"target":"hyper::client::connect::http"} +{"status":"error","result":["query error: RPC error to endpoint tcp://localhost:26657: error trying to connect: tcp connect error: Connection refused (os error 61) (code: 0)"]} +``` + +For the same command, with `log_level = 'error'`, just the last line will be +produced: + +```bash + Running `target/debug/relayer -c loop_config.toml query client consensus ibc-0 07-tendermint-X 0 1` +{"status":"error","result":["query error: RPC error to endpoint tcp://localhost:26657: error trying to connect: tcp connect error: Connection refused (os error 61) (code: 0)"]} +``` \ No newline at end of file From fc673616841878334f159b229457e122f168a0cd Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Thu, 21 Jan 2021 10:50:55 +0100 Subject: [PATCH 11/12] Simplified Output usage; h/t Romain's suggestions. --- relayer-cli/src/commands/keys/add.rs | 9 +-- relayer-cli/src/commands/keys/list.rs | 9 +-- relayer-cli/src/commands/keys/restore.rs | 9 +-- relayer-cli/src/commands/light/rm.rs | 8 +-- relayer-cli/src/commands/query/channel.rs | 9 +-- relayer-cli/src/commands/query/client.rs | 25 +++----- relayer-cli/src/commands/query/connection.rs | 17 ++---- relayer-cli/src/commands/query/packet.rs | 54 ++++++----------- relayer-cli/src/commands/tx/channel.rs | 23 +++---- relayer-cli/src/commands/tx/client.rs | 42 +++++-------- relayer-cli/src/commands/tx/connection.rs | 18 ++---- relayer-cli/src/commands/tx/packet.rs | 33 +++------- relayer-cli/src/commands/tx/transfer.rs | 17 ++---- relayer-cli/src/conclude.rs | 64 ++++++++++++++++---- 14 files changed, 139 insertions(+), 198 deletions(-) diff --git a/relayer-cli/src/commands/keys/add.rs b/relayer-cli/src/commands/keys/add.rs index 96d03711ed..f4248d0a73 100644 --- a/relayer-cli/src/commands/keys/add.rs +++ b/relayer-cli/src/commands/keys/add.rs @@ -1,5 +1,4 @@ use abscissa_core::{Command, Options, Runnable}; -use serde_json::json; use relayer::config::Config; use relayer::keys::add::{add_key, KeysAddOptions}; @@ -49,7 +48,7 @@ impl Runnable for KeysAddCmd { let opts = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -57,10 +56,8 @@ impl Runnable for KeysAddCmd { let res: Result = add_key(opts).map_err(|e| Kind::Keys.context(e).into()); match res { - Ok(r) => Output::with_success().with_result(json!(r)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(r) => Output::success(r).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/commands/keys/list.rs b/relayer-cli/src/commands/keys/list.rs index 61fd5c1f77..0b0af841ab 100644 --- a/relayer-cli/src/commands/keys/list.rs +++ b/relayer-cli/src/commands/keys/list.rs @@ -1,5 +1,4 @@ use abscissa_core::{Command, Options, Runnable}; -use serde_json::json; use relayer::config::Config; use relayer::keys::list::{list_keys, KeysListOptions}; @@ -39,7 +38,7 @@ impl Runnable for KeysListCmd { let opts = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -47,10 +46,8 @@ impl Runnable for KeysListCmd { let res: Result = list_keys(opts).map_err(|e| Kind::Keys.context(e).into()); match res { - Ok(r) => Output::with_success().with_result(json!(r)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(r) => Output::success(r).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/commands/keys/restore.rs b/relayer-cli/src/commands/keys/restore.rs index 80e083990b..7ace497f6a 100644 --- a/relayer-cli/src/commands/keys/restore.rs +++ b/relayer-cli/src/commands/keys/restore.rs @@ -1,5 +1,4 @@ use abscissa_core::{Command, Options, Runnable}; -use serde_json::json; use relayer::config::Config; use relayer::keys::restore::{restore_key, KeysRestoreOptions}; @@ -57,7 +56,7 @@ impl Runnable for KeyRestoreCmd { let opts = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -66,10 +65,8 @@ impl Runnable for KeyRestoreCmd { restore_key(opts).map_err(|e| Kind::Keys.context(e).into()); match res { - Ok(r) => Output::with_success().with_result(json!(r)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(r) => Output::success(r).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/commands/light/rm.rs b/relayer-cli/src/commands/light/rm.rs index d0b0d04c3c..d0fe40f41f 100644 --- a/relayer-cli/src/commands/light/rm.rs +++ b/relayer-cli/src/commands/light/rm.rs @@ -1,7 +1,6 @@ use std::{io, io::Write, ops::Deref}; use abscissa_core::{application::fatal_error, error::BoxError, Command, Options, Runnable}; -use serde_json::json; use tendermint_light_client::types::PeerId; use ibc::ics24_host::identifier::ChainId; @@ -108,12 +107,7 @@ impl RmCmd { let config_path = crate::config::config_path()?; relayer::config::store(&config, config_path)?; - Output::with_success() - .with_result(json!(format!( - "Removed light client peer(s) '{:?}'", - rmd_peers - ))) - .exit(); + Output::success(format!("Removed light client peer(s) '{:?}'", rmd_peers)).exit(); Ok(()) } diff --git a/relayer-cli/src/commands/query/channel.rs b/relayer-cli/src/commands/query/channel.rs index aaab9309b0..31db1dfe84 100644 --- a/relayer-cli/src/commands/query/channel.rs +++ b/relayer-cli/src/commands/query/channel.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use abscissa_core::{Command, Options, Runnable}; -use serde_json::json; use tendermint_proto::Protobuf; use tokio::runtime::Runtime as TokioRuntime; @@ -86,7 +85,7 @@ impl Runnable for QueryChannelEndCmd { let (chain_config, opts) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -111,10 +110,8 @@ impl Runnable for QueryChannelEndCmd { }); match res { - Ok(ce) => Output::with_success().with_result(json!(ce)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(ce) => Output::success(ce).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/commands/query/client.rs b/relayer-cli/src/commands/query/client.rs index 09f9463ff0..36c23a6b42 100644 --- a/relayer-cli/src/commands/query/client.rs +++ b/relayer-cli/src/commands/query/client.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use abscissa_core::{Command, Options, Runnable}; -use serde_json::json; use tendermint_proto::Protobuf; use tokio::runtime::Runtime as TokioRuntime; use tracing::info; @@ -72,7 +71,7 @@ impl Runnable for QueryClientStateCmd { let (chain_config, opts) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -89,10 +88,8 @@ impl Runnable for QueryClientStateCmd { AnyClientState::decode_vec(&v.value).map_err(|e| Kind::Query.context(e).into()) }); match res { - Ok(cs) => Output::with_success().with_result(json!(cs)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(cs) => Output::success(cs).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -166,7 +163,7 @@ impl Runnable for QueryClientConsensusCmd { let (chain_config, opts) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -192,10 +189,8 @@ impl Runnable for QueryClientConsensusCmd { }); match res { - Ok(cs) => Output::with_success().with_result(json!(cs)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(cs) => Output::success(cs).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -277,7 +272,7 @@ impl Runnable for QueryClientConnectionsCmd { let (chain_config, opts) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -295,10 +290,8 @@ impl Runnable for QueryClientConnectionsCmd { }); match res { - Ok(cs) => Output::with_success().with_result(json!(cs)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(cs) => Output::success(cs).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/commands/query/connection.rs b/relayer-cli/src/commands/query/connection.rs index a8b57775ea..77b099b396 100644 --- a/relayer-cli/src/commands/query/connection.rs +++ b/relayer-cli/src/commands/query/connection.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use abscissa_core::{Command, Options, Runnable}; -use serde_json::json; use tokio::runtime::Runtime as TokioRuntime; use ibc::ics03_connection::connection::ConnectionEnd; @@ -75,7 +74,7 @@ impl Runnable for QueryConnectionEndCmd { let (chain_config, opts) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -91,10 +90,8 @@ impl Runnable for QueryConnectionEndCmd { .map_err(|e| Kind::Query.context(e).into()); match res { - Ok(ce) => Output::with_success().with_result(json!(ce)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(ce) => Output::success(ce).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -148,7 +145,7 @@ impl Runnable for QueryConnectionChannelsCmd { let (chain_config, opts) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -167,10 +164,8 @@ impl Runnable for QueryConnectionChannelsCmd { .map_err(|e| Kind::Query.context(e).into()); match res { - Ok(cids) => Output::with_success().with_result(json!(cids)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(cids) => Output::success(cids).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/commands/query/packet.rs b/relayer-cli/src/commands/query/packet.rs index 4bf0883095..d22a71a6e5 100644 --- a/relayer-cli/src/commands/query/packet.rs +++ b/relayer-cli/src/commands/query/packet.rs @@ -59,7 +59,7 @@ impl Runnable for QueryPacketCommitmentsCmd { let (chain_config, opts) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -83,14 +83,9 @@ impl Runnable for QueryPacketCommitmentsCmd { // Transform the raw packet commitm. state into the list of sequence numbers let seqs: Vec = cs.0.iter().map(|ps| ps.sequence).collect(); - Output::with_success() - .with_result(json!(seqs)) - .with_result(json!(cs.1)) - .exit(); + Output::success(seqs).with_result(json!(cs.1)).exit(); } - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -138,7 +133,7 @@ impl Runnable for QueryPacketCommitmentCmd { let (chain_config, opts, sequence) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -158,10 +153,8 @@ impl Runnable for QueryPacketCommitmentCmd { ); match res { - Ok(cs) => Output::with_success().with_result(json!(cs.1)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(cs) => Output::success(cs.1).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -220,7 +213,7 @@ impl Runnable for QueryUnreceivedPacketsCmd { let (dst_chain_config, src_chain_config, opts) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -260,10 +253,8 @@ impl Runnable for QueryUnreceivedPacketsCmd { let res = dst_chain.query_unreceived_packets(request); match res { - Ok(seqs) => Output::with_success().with_result(json!(seqs)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(seqs) => Output::success(seqs).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -309,7 +300,7 @@ impl Runnable for QueryPacketAcknowledgementsCmd { let (chain_config, opts) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -333,14 +324,9 @@ impl Runnable for QueryPacketAcknowledgementsCmd { // Transform the raw packet state into the list of acks. sequence numbers let seqs: Vec = ps.0.iter().map(|ps| ps.sequence).collect(); - Output::with_success() - .with_result(json!(seqs)) - .with_result(json!(ps.1)) - .exit(); + Output::success(seqs).with_result(json!(ps.1)).exit(); } - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -388,7 +374,7 @@ impl Runnable for QueryPacketAcknowledgmentCmd { let (chain_config, opts, sequence) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -408,10 +394,8 @@ impl Runnable for QueryPacketAcknowledgmentCmd { ); match res { - Ok(out) => Output::with_success().with_result(json!(out)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(out) => Output::success(out).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -467,7 +451,7 @@ impl Runnable for QueryUnreceivedAcknowledgementCmd { let (dst_chain_config, src_chain_config, opts) = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -507,10 +491,8 @@ impl Runnable for QueryUnreceivedAcknowledgementCmd { let res = dst_chain.query_unreceived_acknowledgements(request); match res { - Ok(seqs) => Output::with_success().with_result(json!(seqs)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(seqs) => Output::success(seqs).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/commands/tx/channel.rs b/relayer-cli/src/commands/tx/channel.rs index 7cd61bfbd1..82046969ac 100644 --- a/relayer-cli/src/commands/tx/channel.rs +++ b/relayer-cli/src/commands/tx/channel.rs @@ -59,11 +59,10 @@ macro_rules! chan_open_cmd { let (src_chain_config, dst_chain_config) = match (src_config, dst_config) { (Ok(s), Ok(d)) => (s, d), (_, _) => { - return Output::with_error() - .with_result(json!( - "error occurred in finding the chains' configuration" - )) - .exit(); + return Output::error(json!( + "error occurred in finding the chains' configuration" + )) + .exit(); } }; @@ -92,9 +91,7 @@ macro_rules! chan_open_cmd { let src_chain = match src_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -103,9 +100,7 @@ macro_rules! chan_open_cmd { let dst_chain = match dst_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -113,10 +108,8 @@ macro_rules! chan_open_cmd { $func(dst_chain, src_chain, &opts).map_err(|e| Kind::Tx.context(e).into()); match res { - Ok(receipt) => Output::with_success().with_result(json!(receipt)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs index 6b6a198d23..e0c921ec57 100644 --- a/relayer-cli/src/commands/tx/client.rs +++ b/relayer-cli/src/commands/tx/client.rs @@ -1,5 +1,4 @@ use abscissa_core::{Command, Options, Runnable}; -use serde_json::json; use ibc::events::IBCEvent; use ibc::ics24_host::identifier::ClientId; @@ -28,10 +27,9 @@ impl Runnable for TxCreateClientCmd { match validate_common_options(&self.dst_chain_id, &self.src_chain_id) { Ok(result) => result, Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } }; - info!( "Message CreateClient for source chain: {:?}, on destination chain: {:?}", src_chain_config.id, dst_chain_config.id @@ -42,9 +40,7 @@ impl Runnable for TxCreateClientCmd { let src_chain = match src_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -53,9 +49,7 @@ impl Runnable for TxCreateClientCmd { let dst_chain = match dst_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -63,10 +57,8 @@ impl Runnable for TxCreateClientCmd { .map_err(|e| Kind::Tx.context(e).into()); match res { - Ok(receipt) => Output::with_success().with_result(json!(receipt)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -93,7 +85,7 @@ impl Runnable for TxUpdateClientCmd { let (dst_chain_config, src_chain_config) = match opts { Ok(result) => result, Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } }; @@ -107,9 +99,7 @@ impl Runnable for TxUpdateClientCmd { let src_chain = match src_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -118,9 +108,7 @@ impl Runnable for TxUpdateClientCmd { let dst_chain = match dst_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -129,10 +117,8 @@ impl Runnable for TxUpdateClientCmd { .map_err(|e| Kind::Tx.context(e).into()); match res { - Ok(receipt) => Output::with_success().with_result(json!(receipt)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -146,20 +132,20 @@ fn validate_common_options( // Validate parameters let dst_chain_id = dst_chain_id .parse() - .map_err(|_| "bad destination chain identifier".to_string())?; + .map_err(|_| format!("bad destination chain ({}) identifier", dst_chain_id))?; let src_chain_id = src_chain_id .parse() - .map_err(|_| "bad source chain identifier".to_string())?; + .map_err(|_| format!("bad source chain ({}) identifier", src_chain_id))?; // Get the source and destination chain configuration let dst_chain_config = config .find_chain(&dst_chain_id) - .ok_or_else(|| "missing destination chain configuration".to_string())?; + .ok_or_else(|| format!("missing destination chain ({}) configuration", dst_chain_id))?; let src_chain_config = config .find_chain(&src_chain_id) - .ok_or_else(|| "missing source chain configuration".to_string())?; + .ok_or_else(|| format!("missing source chain ({}) configuration", src_chain_id))?; Ok((dst_chain_config.clone(), src_chain_config.clone())) } diff --git a/relayer-cli/src/commands/tx/connection.rs b/relayer-cli/src/commands/tx/connection.rs index 1e503bd148..315aca24d7 100644 --- a/relayer-cli/src/commands/tx/connection.rs +++ b/relayer-cli/src/commands/tx/connection.rs @@ -52,9 +52,7 @@ macro_rules! conn_open_cmd { let (src_chain_config, dst_chain_config) = match (src_config, dst_config) { (Ok(s), Ok(d)) => (s, d), (_, _) => { - return Output::with_error() - .with_result(json!("invalid options")) - .exit(); + return Output::error(json!("invalid options")).exit(); } }; @@ -78,9 +76,7 @@ macro_rules! conn_open_cmd { let src_chain = match src_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -89,9 +85,7 @@ macro_rules! conn_open_cmd { let dst_chain = match dst_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -99,10 +93,8 @@ macro_rules! conn_open_cmd { $func(dst_chain, src_chain, &opts).map_err(|e| Kind::Tx.context(e).into()); match res { - Ok(receipt) => Output::with_success().with_result(json!(receipt)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(receipt) => Output::success(receipt).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/commands/tx/packet.rs b/relayer-cli/src/commands/tx/packet.rs index 6c61849152..997c9d1100 100644 --- a/relayer-cli/src/commands/tx/packet.rs +++ b/relayer-cli/src/commands/tx/packet.rs @@ -1,5 +1,4 @@ use abscissa_core::{Command, Options, Runnable}; -use serde_json::json; use ibc::events::IBCEvent; use ibc::ics24_host::identifier::{ChannelId, ClientId, PortId}; @@ -75,7 +74,7 @@ impl Runnable for TxRawPacketRecvCmd { let opts = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -87,9 +86,7 @@ impl Runnable for TxRawPacketRecvCmd { let src_chain = match src_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -99,9 +96,7 @@ impl Runnable for TxRawPacketRecvCmd { let dst_chain = match dst_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -110,10 +105,8 @@ impl Runnable for TxRawPacketRecvCmd { .map_err(|e| Kind::Tx.context(e).into()); match res { - Ok(ev) => Output::with_success().with_result(json!(ev)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(ev) => Output::success(ev).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } @@ -178,7 +171,7 @@ impl Runnable for TxRawPacketAckCmd { let opts = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -190,9 +183,7 @@ impl Runnable for TxRawPacketAckCmd { let src_chain = match src_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -202,9 +193,7 @@ impl Runnable for TxRawPacketAckCmd { let dst_chain = match dst_chain_res { Ok((handle, _)) => handle, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -213,10 +202,8 @@ impl Runnable for TxRawPacketAckCmd { .map_err(|e| Kind::Tx.context(e).into()); match res { - Ok(ev) => Output::with_success().with_result(json!(ev)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(ev) => Output::success(ev).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/commands/tx/transfer.rs b/relayer-cli/src/commands/tx/transfer.rs index 5791ca8822..8d4eeb44c2 100644 --- a/relayer-cli/src/commands/tx/transfer.rs +++ b/relayer-cli/src/commands/tx/transfer.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use abscissa_core::{Command, Options, Runnable}; -use serde_json::json; use tokio::runtime::Runtime as TokioRuntime; use ibc::events::IBCEvent; @@ -85,7 +84,7 @@ impl Runnable for TxRawSendPacketCmd { let opts = match self.validate_options(&config) { Err(err) => { - return Output::with_error().with_result(json!(err)).exit(); + return Output::error(err).exit(); } Ok(result) => result, }; @@ -99,9 +98,7 @@ impl Runnable for TxRawSendPacketCmd { let src_chain = match src_chain_res { Ok(chain) => chain, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -110,9 +107,7 @@ impl Runnable for TxRawSendPacketCmd { let dst_chain = match dst_chain_res { Ok(chain) => chain, Err(e) => { - return Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(); + return Output::error(format!("{}", e)).exit(); } }; @@ -121,10 +116,8 @@ impl Runnable for TxRawSendPacketCmd { .map_err(|e| Kind::Tx.context(e).into()); match res { - Ok(ev) => Output::with_success().with_result(json!(ev)).exit(), - Err(e) => Output::with_error() - .with_result(json!(format!("{}", e))) - .exit(), + Ok(ev) => Output::success(ev).exit(), + Err(e) => Output::error(format!("{}", e)).exit(), } } } diff --git a/relayer-cli/src/conclude.rs b/relayer-cli/src/conclude.rs index 17762e12f0..900fa79ddb 100644 --- a/relayer-cli/src/conclude.rs +++ b/relayer-cli/src/conclude.rs @@ -2,18 +2,18 @@ //! from a CLI command. The main use-case for this module is to provide a consistent output for //! queries and transactions. //! -//! The examples below rely on crate-private methods (for this reason, doctests do not compile.) +//! The examples below rely on crate-private methods (for this reason, doctests do not compile). //! They are intended for contributors to crate `relayer-cli`, and _not_ for users of this binary. //! -//! ## Examples: +//! ## Examples on how to use the quick-access constructors: //! -//! - Exit from a query/tx with a string error: +//! - Exit from a query/tx with a `String` error: //! //! ```compile_fail //! let e = String::from("error message"); -//! Output::with_error().with_result(json!(e)).exit(); +//! Output::error(e).exit(); //! // or as an alternative: -//! Output::with_error().with_result(json!("error occurred")).exit(); +//! Output::error(json!("error occurred")).exit(); //! ``` //! //! - Exit from a query/tx with an error of type `anomaly`: @@ -23,14 +23,14 @@ //! //! ```compile_fail //! let e: Error = Kind::Query.into(); -//! Output::with_success().with_result(json!(format!("{}", e))).exit(); +//! Output::error(format!("{}", e)).exit(); //! ``` //! //! - Exit from a query/tx with success: //! //! ```compile_fail //! let cs = ChannelEnd::default(); -//! Output::with_success().with_result(json!(cs)).exit(); +//! Output::success(cs).exit(); //! ``` //! //! - Exit from a query/tx with success and multiple objects in the result: @@ -38,16 +38,18 @@ //! ```compile_fail //! let h = Height::default(); //! let end = ConnectionEnd::default(); -//! Output::with_success().with_result(json!(h)).with_result(end).exit(); +//! Output::success(h).with_result(end).exit(); //! ``` use serde::Serialize; +use tracing::error; /// Functional-style method to exit a program. /// -/// ## Note: See `Output::exit()` for the preferred method of exiting a command. +/// ## Note: See `Output::exit()` for the preferred method of exiting a relayer command. pub fn exit_with(out: Output) { // Handle the output message + // TODO: To unify all relayer output, consider replacing `println` with a `tracing` macro below. println!("{}", serde_json::to_string(&out).unwrap()); // The return code @@ -59,7 +61,9 @@ pub fn exit_with(out: Output) { } /// A CLI output with support for JSON serialization. The only mandatory field is the `status`, -/// which typically signals a success or an error. An optional `result` can be added to an output. +/// which typically signals a success (UNIX process return code `0`) or an error (code `1`). An +/// optional `result` can be added to an output. +/// #[derive(Serialize, Debug)] pub struct Output { /// The return status @@ -71,7 +75,7 @@ pub struct Output { } impl Output { - /// Constructs a new `Output`. + /// Constructs a new `Output` with the provided `status` and an empty `result`. pub fn new(status: Status) -> Self { Output { status, @@ -79,12 +83,12 @@ impl Output { } } - /// Quick-access to a constructor that returns a new `Output` having a `Success` status. + /// Constructor that returns a new `Output` having a `Success` status and empty `result`. pub fn with_success() -> Self { Output::new(Status::Success) } - /// Quick-access to a constructor that returns a new `Output` having an `Error` status. + /// Constructor that returns a new `Output` having an `Error` status and empty `result`. pub fn with_error() -> Self { Output::new(Status::Error) } @@ -96,6 +100,40 @@ impl Output { self } + /// Quick-access constructor for an output signalling a success `status` and tagged with the + /// input `res`. + pub fn success(res: impl Serialize + std::fmt::Debug) -> Self { + let mut out = Output::with_success(); + out.result.push(Self::serialize_result(res)); + out + } + + /// Quick-access constructor for an output signalling a error `status` and tagged with the + /// input `res`. + pub fn error(res: impl Serialize + std::fmt::Debug) -> Self { + let mut out = Output::with_error(); + out.result.push(Self::serialize_result(res)); + out + } + + // Helper to serialize a result into a `serde_json::Value`. + fn serialize_result(res: impl Serialize + std::fmt::Debug) -> serde_json::Value { + let last_resort = format!("{:?}", res); + + match serde_json::to_value(res) { + Ok(json_val) => json_val, + Err(e) => { + // Signal the serialization error + error!( + "Output constructor failed with non-recoverable error {} for input {}", + e, last_resort + ); + // Package the result with the infallible `Debug` instead of `JSON` + serde_json::Value::String(last_resort) + } + } + } + /// Exits from the process with the current output. Convenience wrapper over `exit_with`. pub fn exit(self) { exit_with(self); From fe5b4373d3bbd6588388a8bd4cb6dad3a7723c2d Mon Sep 17 00:00:00 2001 From: Adi Seredinschi Date: Thu, 21 Jan 2021 11:21:39 +0100 Subject: [PATCH 12/12] Better err message for client consensus query --- modules/src/ics02_client/client_def.rs | 3 ++- modules/src/ics02_client/error.rs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/src/ics02_client/client_def.rs b/modules/src/ics02_client/client_def.rs index e28ba50506..88812355d8 100644 --- a/modules/src/ics02_client/client_def.rs +++ b/modules/src/ics02_client/client_def.rs @@ -195,7 +195,6 @@ impl Protobuf for AnyClientState {} impl TryFrom for AnyClientState { type Error = Error; - // TODO Fix type urls: avoid having hardcoded values sprinkled around the whole codebase. fn try_from(raw: Any) -> Result { match raw.type_url.as_str() { "" => Err(Kind::EmptyClientState.into()), @@ -286,6 +285,8 @@ impl TryFrom for AnyConsensusState { fn try_from(value: Any) -> Result { match value.type_url.as_str() { + "" => Err(Kind::EmptyConsensusState.into()), + TENDERMINT_CONSENSUS_STATE_TYPE_URL => Ok(AnyConsensusState::Tendermint( TendermintConsensusState::decode_vec(&value.value) .map_err(|e| Kind::InvalidRawConsensusState.context(e))?, diff --git a/modules/src/ics02_client/error.rs b/modules/src/ics02_client/error.rs index 6599aae95f..7cb20edd3f 100644 --- a/modules/src/ics02_client/error.rs +++ b/modules/src/ics02_client/error.rs @@ -36,6 +36,9 @@ pub enum Kind { #[error("unknown client consensus state type: {0}")] UnknownConsensusStateType(String), + #[error("empty client consensus state")] + EmptyConsensusState, + #[error("unknown header type: {0}")] UnknownHeaderType(String),