From bc346a071e983a4f7f2888c52d7183a1991b1b1b Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Wed, 23 Sep 2020 14:51:41 +0200 Subject: [PATCH 01/13] relayer create client cli --- modules/src/ics02_client/client_def.rs | 31 ++++- modules/src/ics02_client/error.rs | 3 + .../src/ics02_client/handler/create_client.rs | 43 ++++-- .../src/ics02_client/handler/update_client.rs | 17 ++- modules/src/ics02_client/msgs.rs | 129 +++++++++++++++++- .../src/ics07_tendermint/consensus_state.rs | 15 ++ modules/src/ics07_tendermint/error.rs | 6 + modules/src/ics07_tendermint/mod.rs | 2 +- .../ics07_tendermint/msgs/create_client.rs | 32 +++++ relayer-cli/Cargo.toml | 2 + relayer-cli/src/commands.rs | 6 + relayer/Cargo.toml | 1 + relayer/src/chain.rs | 19 +++ relayer/src/chain/cosmos.rs | 13 ++ 14 files changed, 303 insertions(+), 16 deletions(-) diff --git a/modules/src/ics02_client/client_def.rs b/modules/src/ics02_client/client_def.rs index 962d0981c4..5d72f71e60 100644 --- a/modules/src/ics02_client/client_def.rs +++ b/modules/src/ics02_client/client_def.rs @@ -14,8 +14,8 @@ use crate::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProof, Com use crate::ics24_host::identifier::{ClientId, ConnectionId}; use ::tendermint::block::Height; - use prost_types::Any; + use std::convert::TryFrom; use tendermint_proto::{DomainType, Error, Kind}; #[cfg(test)] @@ -464,3 +464,32 @@ impl ClientDef for AnyClient { } } } + + +#[cfg(test)] +mod tests { + use crate::ics02_client::client_def::AnyClientState; + use crate::ics07_tendermint::client_state::ClientState; + use std::time::Duration; + use crate::ics07_tendermint::header::test_util::get_dummy_header; + use prost_types::Any; + use std::convert::TryFrom; + + + #[test] + fn to_and_from_any() { + let tm_header = get_dummy_header(); + let tm_client_state = AnyClientState::Tendermint(ClientState { + chain_id: tm_header.signed_header.header.chain_id.to_string(), + trusting_period: Duration::from_secs(64000), + unbonding_period: Duration::from_secs(128000), + max_clock_drift: Duration::from_millis(3000), + latest_height: tm_header.signed_header.header.height, + frozen_height: 0.into(), + }); + + let raw: Any = tm_client_state.clone().into(); + let tm_client_state_back = AnyClientState::try_from(raw).unwrap(); + assert_eq!(tm_client_state, tm_client_state_back); + } +} \ No newline at end of file diff --git a/modules/src/ics02_client/error.rs b/modules/src/ics02_client/error.rs index 3be580296f..e868d215a2 100644 --- a/modules/src/ics02_client/error.rs +++ b/modules/src/ics02_client/error.rs @@ -48,6 +48,9 @@ pub enum Kind { #[error("mismatch between client and arguments types, expected: {0:?}")] ClientArgsTypeMismatch(ClientType), + + #[error("unknown client message type: {0}")] + UnknownClientMessageType(String), } impl Kind { diff --git a/modules/src/ics02_client/handler/create_client.rs b/modules/src/ics02_client/handler/create_client.rs index cabd34a2a2..0122af462f 100644 --- a/modules/src/ics02_client/handler/create_client.rs +++ b/modules/src/ics02_client/handler/create_client.rs @@ -26,6 +26,7 @@ pub fn process( client_type, client_state, consensus_state, + signer: _, } = msg; if ctx.client_state(&client_id).is_some() { @@ -62,12 +63,14 @@ pub fn keep(keeper: &mut dyn ClientKeeper, result: CreateClientResult) -> Result mod tests { use super::*; use crate::ics02_client::context_mock::MockClientContext; + use crate::ics03_connection::msgs::test_util::get_dummy_account_id; + use crate::ics07_tendermint::client_state::ClientState; use crate::ics07_tendermint::header::test_util::get_dummy_header; - use crate::ics07_tendermint::msgs::create_client::MsgCreateClient; use crate::mock_client::header::MockHeader; use crate::mock_client::state::{MockClientState, MockConsensusState}; - use std::str::FromStr; + use std::str::{from_utf8, FromStr}; use std::time::Duration; + use tendermint::account::Id as AccountId; use tendermint::block::Height; #[test] @@ -75,11 +78,14 @@ mod tests { let client_id: ClientId = "mockclient".parse().unwrap(); let ctx = MockClientContext::default(); + let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let msg = MsgCreateAnyClient { client_id, client_type: ClientType::Mock, client_state: MockClientState(MockHeader(Height(42))).into(), consensus_state: MockConsensusState(MockHeader(Height(42))).into(), + signer, }; let output = process(&ctx, msg.clone()); @@ -113,6 +119,8 @@ mod tests { fn test_create_client_existing_client_type() { let height = Height(42); let client_id: ClientId = "mockclient".parse().unwrap(); + let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let mut ctx = MockClientContext::default(); ctx.with_client_type(&client_id, ClientType::Mock, height); @@ -123,6 +131,7 @@ mod tests { client_type: ClientType::Mock, client_state: MockClientState(MockHeader(height)).into(), consensus_state: MockConsensusState(MockHeader(height)).into(), + signer, }; let output = process(&ctx, msg.clone()); @@ -137,6 +146,8 @@ mod tests { #[test] fn test_create_client_existing_client_state() { let client_id: ClientId = "mockclient".parse().unwrap(); + let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let mut ctx = MockClientContext::default(); let height = Height(30); ctx.with_client_consensus_state(&client_id, height); @@ -146,6 +157,7 @@ mod tests { client_type: ClientType::Tendermint, client_state: MockClientState(MockHeader(Height(42))).into(), consensus_state: MockConsensusState(MockHeader(Height(42))).into(), + signer, }; let output = process(&ctx, msg.clone()); @@ -160,6 +172,7 @@ mod tests { #[test] fn test_create_client_ok_multiple() { let existing_client_id: ClientId = "existingmockclient".parse().unwrap(); + let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); let height = Height(80); let mut ctx = MockClientContext::default(); ctx.with_client_consensus_state(&existing_client_id, height); @@ -170,18 +183,21 @@ mod tests { client_type: ClientType::Mock, client_state: MockClientState(MockHeader(Height(42))).into(), consensus_state: MockConsensusState(MockHeader(Height(42))).into(), + signer, }, MsgCreateAnyClient { client_id: "newmockclient2".parse().unwrap(), client_type: ClientType::Mock, client_state: MockClientState(MockHeader(Height(42))).into(), consensus_state: MockConsensusState(MockHeader(Height(42))).into(), + signer, }, MsgCreateAnyClient { client_id: "newmockclient3".parse().unwrap(), client_type: ClientType::Tendermint, client_state: MockClientState(MockHeader(Height(50))).into(), consensus_state: MockConsensusState(MockHeader(Height(50))).into(), + signer, }, ] .into_iter() @@ -218,24 +234,27 @@ mod tests { #[test] fn test_tm_create_client_ok() { - use tendermint::account::Id as AccountId; let client_id: ClientId = "tendermint".parse().unwrap(); + let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let ctx = MockClientContext::default(); - let ics_msg = MsgCreateClient { - client_id, - header: get_dummy_header(), + let tm_header = get_dummy_header(); + let tm_client_state = AnyClientState::Tendermint(ClientState { + chain_id: tm_header.signed_header.header.chain_id.to_string(), trusting_period: Duration::from_secs(64000), unbonding_period: Duration::from_secs(128000), max_clock_drift: Duration::from_millis(3000), - signer: AccountId::from_str("7C2BB42A8BE69791EC763E51F5A49BCD41E82237").unwrap(), - }; + latest_height: tm_header.signed_header.header.height, + frozen_height: 0.into(), + }); let msg = MsgCreateAnyClient { - client_id: ics_msg.client_id().clone(), - client_type: ics_msg.client_type(), - client_state: ics_msg.client_state(), - consensus_state: ics_msg.consensus_state(), + client_id, + client_type: ClientType::Tendermint, + client_state: tm_client_state, + consensus_state: AnyConsensusState::Tendermint(tm_header.consensus_state()), + signer, }; let output = process(&ctx, msg.clone()); diff --git a/modules/src/ics02_client/handler/update_client.rs b/modules/src/ics02_client/handler/update_client.rs index 778cef9d06..ec1a953552 100644 --- a/modules/src/ics02_client/handler/update_client.rs +++ b/modules/src/ics02_client/handler/update_client.rs @@ -23,7 +23,11 @@ pub fn process( ) -> HandlerResult { let mut output = HandlerOutput::builder(); - let MsgUpdateAnyClient { client_id, header } = msg; + let MsgUpdateAnyClient { + client_id, + header, + signer: _, + } = msg; let client_type = ctx .client_type(&client_id) @@ -68,18 +72,24 @@ mod tests { use super::*; use crate::ics02_client::client_type::ClientType; use crate::ics02_client::context_mock::MockClientContext; + use crate::ics03_connection::msgs::test_util::get_dummy_account_id; use crate::mock_client::header::MockHeader; + use std::str::{from_utf8, FromStr}; + use tendermint::account::Id as AccountId; use tendermint::block::Height; #[test] fn test_update_client_ok() { let client_id: ClientId = "mockclient".parse().unwrap(); + let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let mut ctx = MockClientContext::default(); ctx.with_client(&client_id, ClientType::Mock, Height(42)); let msg = MsgUpdateAnyClient { client_id, header: MockHeader(Height(46)).into(), + signer, }; let output = process(&ctx, msg.clone()); @@ -105,12 +115,15 @@ mod tests { #[test] fn test_update_nonexisting_client() { let client_id: ClientId = "mockclient1".parse().unwrap(); + let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let mut ctx = MockClientContext::default(); ctx.with_client_consensus_state(&client_id, Height(42)); let msg = MsgUpdateAnyClient { client_id: "nonexistingclient".parse().unwrap(), header: MockHeader(Height(46)).into(), + signer, }; let output = process(&ctx, msg.clone()); @@ -132,6 +145,7 @@ mod tests { "mockclient2".parse().unwrap(), "mockclient3".parse().unwrap(), ]; + let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); let initial_height = Height(45); let update_height = Height(49); @@ -146,6 +160,7 @@ mod tests { let msg = MsgUpdateAnyClient { client_id: cid.clone(), header: MockHeader(update_height).into(), + signer, }; let output = process(&ctx, msg.clone()); diff --git a/modules/src/ics02_client/msgs.rs b/modules/src/ics02_client/msgs.rs index a83993688c..d938e0f283 100644 --- a/modules/src/ics02_client/msgs.rs +++ b/modules/src/ics02_client/msgs.rs @@ -6,7 +6,16 @@ use crate::ics02_client::client_def::{AnyClientState, AnyConsensusState, AnyHeader}; use crate::ics02_client::client_type::ClientType; +use crate::ics02_client::error; use crate::ics24_host::identifier::ClientId; +use crate::tx_msg::Msg; +use prost_types::Any; +use tendermint::account::Id as AccountId; + +use std::convert::TryFrom; +use tendermint_proto::{DomainType, Error, Kind}; + +pub const TYPE_MSG_CREATE_CLIENT: &str = "create_client"; #[allow(clippy::large_enum_variant)] pub enum ClientMsg { @@ -15,12 +24,85 @@ pub enum ClientMsg { } /// A type of message that triggers the creation of a new on-chain (IBC) client. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct MsgCreateAnyClient { pub client_id: ClientId, pub client_type: ClientType, pub client_state: AnyClientState, pub consensus_state: AnyConsensusState, + pub signer: AccountId, +} + +impl MsgCreateAnyClient { + pub fn new( + client_id: ClientId, + client_type: ClientType, + client_state: AnyClientState, + consensus_state: AnyConsensusState, + signer: AccountId, + ) -> Self { + MsgCreateAnyClient { + client_id, + client_type, + client_state, + consensus_state, + signer, + } + } +} + +impl Msg for MsgCreateAnyClient { + type ValidationError = crate::ics24_host::error::ValidationError; + + fn route(&self) -> String { + crate::keys::ROUTER_KEY.to_string() + } + + fn get_type(&self) -> String { + TYPE_MSG_CREATE_CLIENT.to_string() + } + + fn validate_basic(&self) -> Result<(), Self::ValidationError> { + // Nothing to validate since all fields are validated on creation. + Ok(()) + } + + fn get_sign_bytes(&self) -> Vec { + let mut buf = Vec::new(); + let raw_msg: Any = self.clone().into(); + prost::Message::encode(&raw_msg, &mut buf).unwrap(); + buf + } + + fn get_signers(&self) -> Vec { + vec![self.signer] + } +} + +impl DomainType for MsgCreateAnyClient {} + +impl TryFrom for MsgCreateAnyClient { + type Error = Error; + + fn try_from(raw: Any) -> Result { + match raw.type_url.as_str() { + "/ibc.client.MsgCreateClient" => Ok(MsgCreateAnyClient::decode_vec(&raw.value)?), + + _ => Err(Kind::DecodeMessage + .context(error::Kind::UnknownClientMessageType(raw.type_url)) + .into()), + } + } +} + +impl From for Any { + fn from(value: MsgCreateAnyClient) -> Self { + let value = value.encode_vec().unwrap(); + Any { + type_url: "/ibc.client.MsgCreateClient".to_string(), + value, + } + } } /// A type of message that triggers the update of an on-chain (IBC) client with new headers. @@ -28,4 +110,49 @@ pub struct MsgCreateAnyClient { pub struct MsgUpdateAnyClient { pub client_id: ClientId, pub header: AnyHeader, + pub signer: AccountId, } + +#[cfg(test)] +mod tests { + use crate::ics02_client::client_def::{AnyClientState, AnyConsensusState}; + use crate::ics07_tendermint::client_state::ClientState; + use std::time::Duration; + use crate::ics07_tendermint::header::test_util::get_dummy_header; + use std::str::{from_utf8, FromStr}; + use crate::ics03_connection::msgs::test_util::get_dummy_account_id; + use crate::ics02_client::msgs::MsgCreateAnyClient; + use crate::ics02_client::client_type::ClientType; + use prost_types::Any; + use tendermint::account::Id as AccountId; + use crate::ics24_host::identifier::ClientId; + use std::convert::TryFrom; + + + #[test] + fn to_and_from_any() { + let client_id: ClientId = "tendermint".parse().unwrap(); + let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let tm_header = get_dummy_header(); + let tm_client_state = AnyClientState::Tendermint(ClientState { + chain_id: tm_header.signed_header.header.chain_id.to_string(), + trusting_period: Duration::from_secs(64000), + unbonding_period: Duration::from_secs(128000), + max_clock_drift: Duration::from_millis(3000), + latest_height: tm_header.signed_header.header.height, + frozen_height: 0.into(), + }); + + let msg = MsgCreateAnyClient { + client_id, + client_type: ClientType::Tendermint, + client_state: tm_client_state, + consensus_state: AnyConsensusState::Tendermint(tm_header.consensus_state()), + signer, + }; + + let raw = Any::from(msg.clone()); + let msg_back = MsgCreateAnyClient::try_from(raw).unwrap(); + assert_eq!(msg, msg_back); + } +} \ No newline at end of file diff --git a/modules/src/ics07_tendermint/consensus_state.rs b/modules/src/ics07_tendermint/consensus_state.rs index b8b98e6747..259cfc4f64 100644 --- a/modules/src/ics07_tendermint/consensus_state.rs +++ b/modules/src/ics07_tendermint/consensus_state.rs @@ -6,7 +6,10 @@ use chrono::{TimeZone, Utc}; use ibc_proto::ibc::tendermint::ConsensusState as RawConsensusState; use serde_derive::{Deserialize, Serialize}; use std::convert::TryFrom; +use tendermint::block::Height; use tendermint::hash::Algorithm; +use tendermint::lite::Header; +use tendermint::lite::SignedHeader; use tendermint::Hash; use tendermint_proto::DomainType; @@ -63,6 +66,8 @@ impl From for RawConsensusState { } } } +use tendermint::block::signed_header::SignedHeader as TMCommit; +use tendermint::block::Header as TMHeader; impl ConsensusState { pub fn new( @@ -78,6 +83,16 @@ impl ConsensusState { next_validators_hash, } } + + pub fn new_from_header(header: SignedHeader) -> Self { + let root = CommitmentRoot::from_bytes(&header.header().app_hash); + Self { + root, // TODO + height: Height::from(header.header().height()), + timestamp: header.header().bft_time(), + next_validators_hash: header.header().next_validators_hash(), + } + } } impl crate::ics02_client::state::ConsensusState for ConsensusState { diff --git a/modules/src/ics07_tendermint/error.rs b/modules/src/ics07_tendermint/error.rs index c7b633d66e..ff5adb51b7 100644 --- a/modules/src/ics07_tendermint/error.rs +++ b/modules/src/ics07_tendermint/error.rs @@ -5,6 +5,9 @@ pub type Error = anomaly::Error; #[derive(Clone, Debug, Error)] pub enum Kind { + #[error("identifier error")] + IdentifierError, + #[error("invalid trusting period")] InvalidTrustingPeriod, @@ -25,6 +28,9 @@ pub enum Kind { #[error("invalid raw client consensus state")] InvalidRawConsensusState, + + #[error("invalid signer")] + InvalidSigner, } impl Kind { diff --git a/modules/src/ics07_tendermint/mod.rs b/modules/src/ics07_tendermint/mod.rs index c2b0fc503e..459fec99fd 100644 --- a/modules/src/ics07_tendermint/mod.rs +++ b/modules/src/ics07_tendermint/mod.rs @@ -5,4 +5,4 @@ pub mod client_state; pub mod consensus_state; pub mod error; pub mod header; -pub mod msgs; +//pub mod msgs; diff --git a/modules/src/ics07_tendermint/msgs/create_client.rs b/modules/src/ics07_tendermint/msgs/create_client.rs index 94489ef169..80a43b9e1a 100644 --- a/modules/src/ics07_tendermint/msgs/create_client.rs +++ b/modules/src/ics07_tendermint/msgs/create_client.rs @@ -9,6 +9,12 @@ use crate::ics02_client::client_type::ClientType; use crate::ics07_tendermint::client_state::ClientState; use serde_derive::{Deserialize, Serialize}; use tendermint::account::Id as AccountId; +use crate::try_from_raw::TryFromRaw; +use ibc_proto::ibc::client::MsgCreateClient as RawMsgCreateClient; +use crate::ics07_tendermint::error::{Error, Kind}; +use serde_derive::{Deserialize, Serialize}; +use std::convert::TryInto; +use std::str::{from_utf8, FromStr}; pub const TYPE_MSG_CREATE_CLIENT: &str = "create_client"; @@ -24,6 +30,32 @@ pub struct MsgCreateClient { pub signer: AccountId, } +impl TryFromRaw for MsgCreateClient { + type RawType = RawMsgCreateClient; + type Error = anomaly::Error; + fn try_from(msg: RawMsgCreateClient) -> Result { + Ok(Self { + client_id: msg + .client_id + .parse() + .map_err(|e| Kind::IdentifierError.context(e))?, + client_state: msg + .client_state + .map(AnyClientState::from_any) + .transpose() + .map_err(|e| Kind::InvalidProof.context(e))?, + counterparty: msg + .counterparty + .ok_or_else(|| Kind::MissingCounterparty)? + .try_into()?, + signer: AccountId::from_str( + from_utf8(&msg.signer).map_err(|e| Kind::InvalidSigner.context(e))?, + ) + .map_err(|e| Kind::InvalidSigner.context(e))?, + }) + } +} + impl MsgCreateClient { pub fn new( client_id: ClientId, diff --git a/relayer-cli/Cargo.toml b/relayer-cli/Cargo.toml index 2e12a87db8..babea3d2e5 100644 --- a/relayer-cli/Cargo.toml +++ b/relayer-cli/Cargo.toml @@ -21,6 +21,8 @@ tokio = { version = "0.2.13", features = ["rt-util", "sync"] } tracing = "0.1.13" tracing-subscriber = "0.2.3" futures = "0.3.5" +prost = "0.6.1" +prost-types = { version = "0.6.1" } [dependencies.abscissa_core] version = "0.5.2" diff --git a/relayer-cli/src/commands.rs b/relayer-cli/src/commands.rs index 4fe335c3ed..85ca222cc4 100644 --- a/relayer-cli/src/commands.rs +++ b/relayer-cli/src/commands.rs @@ -10,6 +10,7 @@ mod light; mod listen; mod query; mod start; +mod tx; mod utils; mod version; @@ -18,6 +19,7 @@ use self::{ version::VersionCmd, }; +use crate::commands::tx::TxCmd; use crate::config::Config; use abscissa_core::{Command, Configurable, FrameworkError, Help, Options, Runnable}; use std::path::PathBuf; @@ -52,6 +54,10 @@ pub enum CliCmd { #[options(help = "query state from chain")] Query(QueryCmd), + /// The `tx` subcommand + #[options(help = "create IBC transaction on configured chains")] + Tx(TxCmd), + /// The `light` subcommand #[options(help = "basic functionality for managing the lite clients")] Light(LightCmd), diff --git a/relayer/Cargo.toml b/relayer/Cargo.toml index 1365a12d80..9ec48ecfdc 100644 --- a/relayer/Cargo.toml +++ b/relayer/Cargo.toml @@ -25,5 +25,6 @@ tokio = "0.2" serde_json = { version = "1" } bytes = "0.5.6" prost = "0.6.1" +prost-types = { version = "0.6.1" } [dev-dependencies] diff --git a/relayer/src/chain.rs b/relayer/src/chain.rs index b9fb5b9e8e..61263fca82 100644 --- a/relayer/src/chain.rs +++ b/relayer/src/chain.rs @@ -18,6 +18,7 @@ use std::error::Error; mod cosmos; pub use cosmos::CosmosSDKChain; +use prost_types::Any; /// Handy type alias for the type of validator set associated with a chain pub type ValidatorSet = <::Commit as tmlite::Commit>::ValidatorSet; @@ -58,6 +59,9 @@ pub trait Chain { /// The naming is foreshadowing for an upcoming `grpc_query` function in the future. fn abci_query(&self, data: Path, height: u64, prove: bool) -> Result, Self::Error>; + /// send a transaction with `msgs` to chain. + fn send(&self, msgs: Vec) -> Result<(), Self::Error>; + /// Returns the chain's identifier fn id(&self) -> &ChainId { &self.config().id @@ -75,6 +79,10 @@ pub trait Chain { /// The trusting period configured for this chain fn trusting_period(&self) -> Duration; + /// The unbonding period of this chain + /// TODO - this is a GRPC query, needs to be implemented + fn unbonding_period(&self) -> Duration; + /// The trust threshold configured for this chain fn trust_threshold(&self) -> TrustThresholdFraction; } @@ -99,6 +107,17 @@ pub async fn query_latest_height(chain: &impl Chain) -> Result( + chain: &C, +) -> Result, error::Error> +where + C: Chain, +{ + let h = query_latest_height(chain).await?; + Ok(query_header_at_height::(chain, h).await?) +} + /// Query a header at the given height via the RPC requester pub async fn query_header_at_height( chain: &C, diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index eb32a50c75..9a4824416a 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -20,6 +20,8 @@ use crate::error::{Error, Kind}; use super::Chain; use bytes::Bytes; use prost::Message; + +use prost_types::Any; use std::str::FromStr; pub struct CosmosSDKChain { @@ -93,6 +95,12 @@ impl Chain for CosmosSDKChain { Ok(response) } + /// Send a transaction that includes the specified messages + fn send(&self, _msgs: Vec) -> Result<(), Error> { + // TODO sign and broadcast_tx + Ok(()) + } + fn config(&self) -> &ChainConfig { &self.config } @@ -109,6 +117,11 @@ impl Chain for CosmosSDKChain { self.config.trusting_period } + fn unbonding_period(&self) -> Duration { + // TODO - query chain + Duration::from_secs(24 * 7 * 3) + } + fn trust_threshold(&self) -> TrustThresholdFraction { TrustThresholdFraction::default() } From 64f9f8601f0958bae5aa9d1cf17db4f301d13a91 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Wed, 23 Sep 2020 20:35:41 +0200 Subject: [PATCH 02/13] Add conversion between MsgCreateClient and MsgCreateAnyClient --- modules/src/ics02_client/client_def.rs | 6 +- modules/src/ics02_client/error.rs | 3 + modules/src/ics02_client/msgs.rs | 81 +++++++++++++++++--------- 3 files changed, 57 insertions(+), 33 deletions(-) diff --git a/modules/src/ics02_client/client_def.rs b/modules/src/ics02_client/client_def.rs index 5d72f71e60..7098f5d651 100644 --- a/modules/src/ics02_client/client_def.rs +++ b/modules/src/ics02_client/client_def.rs @@ -465,16 +465,14 @@ impl ClientDef for AnyClient { } } - #[cfg(test)] mod tests { use crate::ics02_client::client_def::AnyClientState; use crate::ics07_tendermint::client_state::ClientState; - use std::time::Duration; use crate::ics07_tendermint::header::test_util::get_dummy_header; use prost_types::Any; use std::convert::TryFrom; - + use std::time::Duration; #[test] fn to_and_from_any() { @@ -492,4 +490,4 @@ mod tests { let tm_client_state_back = AnyClientState::try_from(raw).unwrap(); assert_eq!(tm_client_state, tm_client_state_back); } -} \ No newline at end of file +} diff --git a/modules/src/ics02_client/error.rs b/modules/src/ics02_client/error.rs index e868d215a2..fc2297db9f 100644 --- a/modules/src/ics02_client/error.rs +++ b/modules/src/ics02_client/error.rs @@ -51,6 +51,9 @@ pub enum Kind { #[error("unknown client message type: {0}")] UnknownClientMessageType(String), + + #[error("invalid signer")] + InvalidSigner, } impl Kind { diff --git a/modules/src/ics02_client/msgs.rs b/modules/src/ics02_client/msgs.rs index d938e0f283..f1bb0246cc 100644 --- a/modules/src/ics02_client/msgs.rs +++ b/modules/src/ics02_client/msgs.rs @@ -6,12 +6,12 @@ use crate::ics02_client::client_def::{AnyClientState, AnyConsensusState, AnyHeader}; use crate::ics02_client::client_type::ClientType; -use crate::ics02_client::error; use crate::ics24_host::identifier::ClientId; use crate::tx_msg::Msg; -use prost_types::Any; use tendermint::account::Id as AccountId; +use crate::ics02_client::error; +use ibc_proto::ibc::client::MsgCreateClient; use std::convert::TryFrom; use tendermint_proto::{DomainType, Error, Kind}; @@ -69,7 +69,7 @@ impl Msg for MsgCreateAnyClient { fn get_sign_bytes(&self) -> Vec { let mut buf = Vec::new(); - let raw_msg: Any = self.clone().into(); + let raw_msg: MsgCreateClient = self.clone().into(); prost::Message::encode(&raw_msg, &mut buf).unwrap(); buf } @@ -79,28 +79,51 @@ impl Msg for MsgCreateAnyClient { } } -impl DomainType for MsgCreateAnyClient {} +impl DomainType for MsgCreateAnyClient {} -impl TryFrom for MsgCreateAnyClient { +impl TryFrom for MsgCreateAnyClient { type Error = Error; - fn try_from(raw: Any) -> Result { - match raw.type_url.as_str() { - "/ibc.client.MsgCreateClient" => Ok(MsgCreateAnyClient::decode_vec(&raw.value)?), - - _ => Err(Kind::DecodeMessage - .context(error::Kind::UnknownClientMessageType(raw.type_url)) - .into()), - } + fn try_from(raw: MsgCreateClient) -> Result { + let raw_client_state = match raw.client_state { + None => Err(Kind::DecodeMessage.context(error::Kind::InvalidRawClientState)), + Some(raw_state) => Ok(raw_state), + }?; + + let client_type = match raw_client_state.type_url.as_str() { + "/ibc.tendermint.ClientState" => Ok(ClientType::Tendermint), + + _ => Err( + Kind::DecodeMessage.context(error::Kind::UnknownConsensusStateType( + raw_client_state.clone().type_url, + )), + ), + }?; + let raw_consensus_state = match raw.consensus_state { + None => Err(Kind::DecodeMessage.context(error::Kind::InvalidRawConsensusState)), + Some(raw_consensus_state) => Ok(raw_consensus_state), + }?; + + Ok(MsgCreateAnyClient { + client_id: raw.client_id.parse().unwrap(), + client_type, + client_state: AnyClientState::try_from(raw_client_state).unwrap(), + consensus_state: AnyConsensusState::try_from(raw_consensus_state).unwrap(), + signer: AccountId::new(<[u8; 20]>::try_from(&raw.signer[..20]).unwrap()), + }) } } -impl From for Any { - fn from(value: MsgCreateAnyClient) -> Self { - let value = value.encode_vec().unwrap(); - Any { - type_url: "/ibc.client.MsgCreateClient".to_string(), - value, +impl From for MsgCreateClient { + fn from(ics_msg: MsgCreateAnyClient) -> Self { + let signer = ics_msg.signer; + let signerb = signer.as_bytes(); + + MsgCreateClient { + client_id: ics_msg.client_id.to_string(), + client_state: Some(ics_msg.client_state.into()), + consensus_state: Some(ics_msg.consensus_state.into()), + signer: Vec::from(signerb), } } } @@ -116,23 +139,23 @@ pub struct MsgUpdateAnyClient { #[cfg(test)] mod tests { use crate::ics02_client::client_def::{AnyClientState, AnyConsensusState}; + use crate::ics02_client::client_type::ClientType; + use crate::ics02_client::msgs::MsgCreateAnyClient; + use crate::ics03_connection::msgs::test_util::get_dummy_account_id; use crate::ics07_tendermint::client_state::ClientState; - use std::time::Duration; use crate::ics07_tendermint::header::test_util::get_dummy_header; - use std::str::{from_utf8, FromStr}; - use crate::ics03_connection::msgs::test_util::get_dummy_account_id; - use crate::ics02_client::msgs::MsgCreateAnyClient; - use crate::ics02_client::client_type::ClientType; - use prost_types::Any; - use tendermint::account::Id as AccountId; use crate::ics24_host::identifier::ClientId; + use ibc_proto::ibc::client::MsgCreateClient; use std::convert::TryFrom; - + use std::str::{from_utf8, FromStr}; + use std::time::Duration; + use tendermint::account::Id as AccountId; #[test] fn to_and_from_any() { let client_id: ClientId = "tendermint".parse().unwrap(); let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let tm_header = get_dummy_header(); let tm_client_state = AnyClientState::Tendermint(ClientState { chain_id: tm_header.signed_header.header.chain_id.to_string(), @@ -151,8 +174,8 @@ mod tests { signer, }; - let raw = Any::from(msg.clone()); + let raw = MsgCreateClient::from(msg.clone()); let msg_back = MsgCreateAnyClient::try_from(raw).unwrap(); assert_eq!(msg, msg_back); } -} \ No newline at end of file +} From c4db96b539ba0e310d844bb738c9f30db4368e71 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Wed, 23 Sep 2020 20:47:26 +0200 Subject: [PATCH 03/13] added forgotten file --- relayer-cli/src/commands/tx.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 relayer-cli/src/commands/tx.rs diff --git a/relayer-cli/src/commands/tx.rs b/relayer-cli/src/commands/tx.rs new file mode 100644 index 0000000000..1bce1972cd --- /dev/null +++ b/relayer-cli/src/commands/tx.rs @@ -0,0 +1,21 @@ +//! `tx` subcommand + +use crate::commands::tx::client::TxCreateClientCmd; +use abscissa_core::{Command, Options, Runnable}; + +mod client; + +/// `tx` subcommand +#[derive(Command, Debug, Options, Runnable)] +pub enum TxCmd { + /// The `tx raw` subcommand + #[options(help = "tx raw")] + Raw(TxRawCommands), +} + +#[derive(Command, Debug, Options, Runnable)] +pub enum TxRawCommands { + /// The `tx raw client-create` subcommand + #[options(help = "tx raw create-client")] + CreateClient(TxCreateClientCmd), +} From 396c7dcb8951bb1a7150965bd39e19b507023ce3 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Wed, 23 Sep 2020 20:49:43 +0200 Subject: [PATCH 04/13] added forgotten file --- relayer-cli/src/commands/tx/client.rs | 166 ++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 relayer-cli/src/commands/tx/client.rs diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs new file mode 100644 index 0000000000..c1c26342f2 --- /dev/null +++ b/relayer-cli/src/commands/tx/client.rs @@ -0,0 +1,166 @@ +use crate::prelude::*; + +use crate::application::app_config; +use crate::commands::utils::block_on; +use abscissa_core::{Command, Options, Runnable}; +use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; +use ibc::ics02_client::client_type::ClientType; +use ibc::ics02_client::msgs::MsgCreateAnyClient; +use ibc::ics24_host::identifier::ClientId; +use ibc::ics24_host::Path::ClientState as ClientStatePath; +use ibc::tx_msg::Msg; +use prost_types::Any; +use relayer::chain::{query_latest_header, Chain, CosmosSDKChain}; +use relayer::config::{ChainConfig, Config}; +use std::time::Duration; +use tendermint::block::Height; + +#[derive(Clone, Command, Debug, Options)] +pub struct TxCreateClientCmd { + #[options(free, help = "identifier of the destination chain")] + dest_chain_id: Option, + + #[options(free, help = "identifier of the source chain")] + src_chain_id: Option, + + #[options( + free, + help = "identifier of the client for source chain to be created on destination chain" + )] + dest_client_id: Option, +} + +#[derive(Clone, Debug)] +struct CreateClientStateOptions { + dest_client_id: ClientId, + dest_chain_config: ChainConfig, + src_chain_config: ChainConfig, +} + +impl TxCreateClientCmd { + fn validate_options(&self, config: &Config) -> Result { + let dest_chain_id = self + .dest_chain_id + .clone() + .ok_or_else(|| "missing destination chain identifier".to_string())?; + + let dest_chain_config = config + .chains + .iter() + .find(|c| c.id == dest_chain_id.parse().unwrap()) + .ok_or_else(|| "missing destination chain configuration".to_string())?; + + let src_chain_id = self + .src_chain_id + .clone() + .ok_or_else(|| "missing source chain identifier".to_string())?; + + let src_chain_config = config + .chains + .iter() + .find(|c| c.id == src_chain_id.parse().unwrap()) + .ok_or_else(|| "missing source chain configuration".to_string())?; + + let dest_client_id = self + .dest_client_id + .as_ref() + .ok_or_else(|| "missing destination client identifier".to_string())? + .parse() + .map_err(|_| "bad client identifier".to_string())?; + + Ok(CreateClientStateOptions { + dest_client_id, + dest_chain_config: dest_chain_config.clone(), + src_chain_config: src_chain_config.clone(), + }) + } +} + +impl Runnable for TxCreateClientCmd { + fn run(&self) { + let config = app_config(); + + let opts = match self.validate_options(&config) { + Err(err) => { + status_err!("invalid options: {}", err); + return; + } + Ok(result) => result, + }; + status_info!("Message", "{:?}", opts); + + // Query the client state on destination chain. + let dest_chain = CosmosSDKChain::from_config(opts.clone().dest_chain_config).unwrap(); + if dest_chain + .abci_query(ClientStatePath(opts.clone().dest_client_id), 0, false) + .is_ok() + { + status_info!( + "client ", + "{:?} {}", + opts.dest_client_id.to_string(), + "is already created" + ); + return; + } + + status_info!("creating client", "{:?}", opts.dest_client_id.to_string()); + + // Get the latest header from the source chain and build the consensus state. + let src_chain = CosmosSDKChain::from_config(opts.clone().src_chain_config).unwrap(); + let tm_consensus_state = match block_on(query_latest_header::(&src_chain)) { + Err(err) => { + status_info!( + "failed to retrieve latest header from source chain", + "{}: {}", + src_chain.id(), + err + ); + return; + } + Ok(header) => { + ibc::ics07_tendermint::consensus_state::ConsensusState::new_from_header(header) + } + }; + let any_consensus_state = AnyConsensusState::Tendermint(tm_consensus_state.clone()); + + // Build the client state. + let any_client_state = match ibc::ics07_tendermint::client_state::ClientState::new( + src_chain.id().to_string(), + src_chain.trusting_period(), + src_chain.unbonding_period(), + Duration::from_millis(3000), + tm_consensus_state.height, + Height(0), + ) { + Err(err) => { + status_info!("failed to build client state", "{}", err); + return; + } + Ok(tm_state) => AnyClientState::Tendermint(tm_state), + }; + + let mut proto_msgs: Vec = Vec::new(); + let new_msg = MsgCreateAnyClient::new( + opts.dest_client_id, + ClientType::Tendermint, + any_client_state, + any_consensus_state, + dest_chain.config().account_prefix.parse().unwrap(), + ); + + // Create a proto any message + let any_msg = Any { + // TODO - add get_url_type() to prepend proper string to get_type() + type_url: "/ibc.client.MsgCreateClient".to_ascii_lowercase(), + value: new_msg.get_sign_bytes(), + }; + + proto_msgs.push(any_msg); + let res = dest_chain.send(proto_msgs); + match res { + Ok(receipt) => status_info!("client created, result: ", "{:?}", receipt), + Err(e) => status_info!("client create failed, error: ", "{:?}", e), + } + } +} From 1773d94a751cef9d62bdacdabf64a3da87be3062 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Thu, 24 Sep 2020 09:15:26 +0200 Subject: [PATCH 05/13] Move functionality in create_clien() to be used by the relayer --- relayer-cli/src/commands/tx/client.rs | 149 ++++++++++++++------------ relayer/src/error.rs | 5 + 2 files changed, 85 insertions(+), 69 deletions(-) diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs index c1c26342f2..221e329970 100644 --- a/relayer-cli/src/commands/tx/client.rs +++ b/relayer-cli/src/commands/tx/client.rs @@ -12,6 +12,7 @@ use ibc::tx_msg::Msg; use prost_types::Any; use relayer::chain::{query_latest_header, Chain, CosmosSDKChain}; use relayer::config::{ChainConfig, Config}; +use relayer::error::{Error, Kind}; use std::time::Duration; use tendermint::block::Height; @@ -31,7 +32,7 @@ pub struct TxCreateClientCmd { } #[derive(Clone, Debug)] -struct CreateClientStateOptions { +pub struct CreateClientStateOptions { dest_client_id: ClientId, dest_chain_config: ChainConfig, src_chain_config: ChainConfig, @@ -89,78 +90,88 @@ impl Runnable for TxCreateClientCmd { }; status_info!("Message", "{:?}", opts); - // Query the client state on destination chain. - let dest_chain = CosmosSDKChain::from_config(opts.clone().dest_chain_config).unwrap(); - if dest_chain - .abci_query(ClientStatePath(opts.clone().dest_client_id), 0, false) - .is_ok() - { - status_info!( - "client ", - "{:?} {}", - opts.dest_client_id.to_string(), - "is already created" - ); - return; + match create_client(opts) { + Ok(receipt) => status_info!("client created, result: ", "{:?}", receipt), + Err(e) => status_info!("client create failed, error: ", "{:?}", e), } + } +} - status_info!("creating client", "{:?}", opts.dest_client_id.to_string()); +pub fn create_client(opts: CreateClientStateOptions) -> Result<(), Error> { + // Ger the destination + let dest_chain = CosmosSDKChain::from_config(opts.clone().dest_chain_config)?; - // Get the latest header from the source chain and build the consensus state. - let src_chain = CosmosSDKChain::from_config(opts.clone().src_chain_config).unwrap(); - let tm_consensus_state = match block_on(query_latest_header::(&src_chain)) { - Err(err) => { - status_info!( - "failed to retrieve latest header from source chain", - "{}: {}", - src_chain.id(), - err - ); - return; - } - Ok(header) => { - ibc::ics07_tendermint::consensus_state::ConsensusState::new_from_header(header) - } - }; - let any_consensus_state = AnyConsensusState::Tendermint(tm_consensus_state.clone()); - - // Build the client state. - let any_client_state = match ibc::ics07_tendermint::client_state::ClientState::new( - src_chain.id().to_string(), - src_chain.trusting_period(), - src_chain.unbonding_period(), - Duration::from_millis(3000), - tm_consensus_state.height, - Height(0), - ) { - Err(err) => { - status_info!("failed to build client state", "{}", err); - return; - } - Ok(tm_state) => AnyClientState::Tendermint(tm_state), - }; - - let mut proto_msgs: Vec = Vec::new(); - let new_msg = MsgCreateAnyClient::new( + // Query the client state on destination chain. + if dest_chain + .abci_query(ClientStatePath(opts.clone().dest_client_id), 0, false) + .is_ok() + { + return Err(Into::::into(Kind::CreateClient( opts.dest_client_id, - ClientType::Tendermint, - any_client_state, - any_consensus_state, - dest_chain.config().account_prefix.parse().unwrap(), - ); - - // Create a proto any message - let any_msg = Any { - // TODO - add get_url_type() to prepend proper string to get_type() - type_url: "/ibc.client.MsgCreateClient".to_ascii_lowercase(), - value: new_msg.get_sign_bytes(), - }; + "client already exists".into(), + ))); + } - proto_msgs.push(any_msg); - let res = dest_chain.send(proto_msgs); - match res { - Ok(receipt) => status_info!("client created, result: ", "{:?}", receipt), - Err(e) => status_info!("client create failed, error: ", "{:?}", e), + // Get the latest header from the source chain and build the consensus state. + let src_chain = CosmosSDKChain::from_config(opts.clone().src_chain_config)?; + let tm_consensus_state = match block_on(query_latest_header::(&src_chain)) { + Err(err) => Err(Into::::into( + Kind::CreateClient( + opts.dest_client_id.clone(), + "failed to get the latest header".into(), + ) + .context(err), + )), + Ok(header) => { + Ok(ibc::ics07_tendermint::consensus_state::ConsensusState::new_from_header(header)) } - } + }?; + let any_consensus_state = AnyConsensusState::Tendermint(tm_consensus_state.clone()); + + // Build the client state. + let any_client_state = match ibc::ics07_tendermint::client_state::ClientState::new( + src_chain.id().to_string(), + src_chain.trusting_period(), + src_chain.unbonding_period(), + Duration::from_millis(3000), + tm_consensus_state.height, + Height(0), + ) { + Err(err) => Err(Into::::into( + Kind::CreateClient( + opts.dest_client_id.clone(), + "failed to build the client state".into(), + ) + .context(err), + )), + Ok(tm_state) => Ok(AnyClientState::Tendermint(tm_state)), + }?; + + // Get the signer + let signer = match dest_chain.config().account_prefix.parse() { + Err(err) => Err(Into::::into( + Kind::CreateClient(opts.dest_client_id.clone(), "bad signer".into()).context(err), + )), + Ok(signer) => Ok(signer), + }?; + + // Build the domain type message + let new_msg = MsgCreateAnyClient::new( + opts.dest_client_id, + ClientType::Tendermint, + any_client_state, + any_consensus_state, + signer, + ); + + // Create a proto any message + let mut proto_msgs: Vec = Vec::new(); + let any_msg = Any { + // TODO - add get_url_type() to prepend proper string to get_type() + type_url: "/ibc.client.MsgCreateClient".to_ascii_lowercase(), + value: new_msg.get_sign_bytes(), + }; + + proto_msgs.push(any_msg); + dest_chain.send(proto_msgs) } diff --git a/relayer/src/error.rs b/relayer/src/error.rs index 1f3ac6a191..6a14c71086 100644 --- a/relayer/src/error.rs +++ b/relayer/src/error.rs @@ -1,6 +1,7 @@ //! This module defines the various errors that be raised in the relayer. use anomaly::{BoxError, Context}; +use ibc::ics24_host::identifier::ClientId; use thiserror::Error; /// An error that can be raised by the relayer. @@ -40,6 +41,10 @@ pub enum Kind { /// Response does not contain data #[error("Empty response value")] EmptyResponseValue, + + /// Create client failure + #[error("Failed to create client {0}: {1}")] + CreateClient(ClientId, String), } impl Kind { From ea598ae2b14338c79eee2558a4b7717a4ad4d476 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Thu, 24 Sep 2020 09:18:21 +0200 Subject: [PATCH 06/13] Remove ics07 messages --- modules/src/ics07_tendermint/mod.rs | 1 - modules/src/ics07_tendermint/msgs.rs | 2 - .../ics07_tendermint/msgs/create_client.rs | 127 ------------------ .../ics07_tendermint/msgs/update_client.rs | 63 --------- 4 files changed, 193 deletions(-) delete mode 100644 modules/src/ics07_tendermint/msgs.rs delete mode 100644 modules/src/ics07_tendermint/msgs/create_client.rs delete mode 100644 modules/src/ics07_tendermint/msgs/update_client.rs diff --git a/modules/src/ics07_tendermint/mod.rs b/modules/src/ics07_tendermint/mod.rs index 459fec99fd..0c5a0a311c 100644 --- a/modules/src/ics07_tendermint/mod.rs +++ b/modules/src/ics07_tendermint/mod.rs @@ -5,4 +5,3 @@ pub mod client_state; pub mod consensus_state; pub mod error; pub mod header; -//pub mod msgs; diff --git a/modules/src/ics07_tendermint/msgs.rs b/modules/src/ics07_tendermint/msgs.rs deleted file mode 100644 index da5faf53d9..0000000000 --- a/modules/src/ics07_tendermint/msgs.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod create_client; -pub mod update_client; diff --git a/modules/src/ics07_tendermint/msgs/create_client.rs b/modules/src/ics07_tendermint/msgs/create_client.rs deleted file mode 100644 index 80a43b9e1a..0000000000 --- a/modules/src/ics07_tendermint/msgs/create_client.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::ics07_tendermint::header::Header; -use crate::ics24_host::identifier::ClientId; -use crate::tx_msg::Msg; - -use std::time::Duration; - -use crate::ics02_client::client_def::{AnyClientState, AnyConsensusState}; -use crate::ics02_client::client_type::ClientType; -use crate::ics07_tendermint::client_state::ClientState; -use serde_derive::{Deserialize, Serialize}; -use tendermint::account::Id as AccountId; -use crate::try_from_raw::TryFromRaw; -use ibc_proto::ibc::client::MsgCreateClient as RawMsgCreateClient; -use crate::ics07_tendermint::error::{Error, Kind}; -use serde_derive::{Deserialize, Serialize}; -use std::convert::TryInto; -use std::str::{from_utf8, FromStr}; - -pub const TYPE_MSG_CREATE_CLIENT: &str = "create_client"; - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct MsgCreateClient { - pub client_id: ClientId, - pub header: Header, - // trust_level: Fraction, - pub trusting_period: Duration, - pub unbonding_period: Duration, - pub max_clock_drift: Duration, - // proof_specs: ProofSpecs, - pub signer: AccountId, -} - -impl TryFromRaw for MsgCreateClient { - type RawType = RawMsgCreateClient; - type Error = anomaly::Error; - fn try_from(msg: RawMsgCreateClient) -> Result { - Ok(Self { - client_id: msg - .client_id - .parse() - .map_err(|e| Kind::IdentifierError.context(e))?, - client_state: msg - .client_state - .map(AnyClientState::from_any) - .transpose() - .map_err(|e| Kind::InvalidProof.context(e))?, - counterparty: msg - .counterparty - .ok_or_else(|| Kind::MissingCounterparty)? - .try_into()?, - signer: AccountId::from_str( - from_utf8(&msg.signer).map_err(|e| Kind::InvalidSigner.context(e))?, - ) - .map_err(|e| Kind::InvalidSigner.context(e))?, - }) - } -} - -impl MsgCreateClient { - pub fn new( - client_id: ClientId, - header: Header, - // trust_level: Fraction, - trusting_period: Duration, - unbonding_period: Duration, - max_clock_drift: Duration, - // proof_specs: ProofSpecs, - signer: AccountId, - ) -> Self { - Self { - client_id, - header, - trusting_period, - unbonding_period, - max_clock_drift, - signer, - } - } - - pub(crate) fn client_id(&self) -> &ClientId { - &self.client_id - } - - pub(crate) fn client_type(&self) -> ClientType { - ClientType::Tendermint - } - - pub(crate) fn consensus_state(&self) -> AnyConsensusState { - AnyConsensusState::Tendermint(self.header.consensus_state()) - } - - pub(crate) fn client_state(&self) -> AnyClientState { - AnyClientState::Tendermint(ClientState { - chain_id: self.header.signed_header.header.chain_id.to_string(), - trusting_period: self.trusting_period, - unbonding_period: self.unbonding_period, - max_clock_drift: self.max_clock_drift, - latest_height: self.header.signed_header.header.height, - frozen_height: 0.into(), - }) - } -} - -impl Msg for MsgCreateClient { - type ValidationError = crate::ics24_host::error::ValidationError; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn get_type(&self) -> String { - TYPE_MSG_CREATE_CLIENT.to_string() - } - - fn validate_basic(&self) -> Result<(), Self::ValidationError> { - // Nothing to validate since both ClientId and AccountId perform validation on creation. - Ok(()) - } - - fn get_sign_bytes(&self) -> Vec { - todo!() - } - - fn get_signers(&self) -> Vec { - vec![self.signer] - } -} diff --git a/modules/src/ics07_tendermint/msgs/update_client.rs b/modules/src/ics07_tendermint/msgs/update_client.rs deleted file mode 100644 index 597e4d88f0..0000000000 --- a/modules/src/ics07_tendermint/msgs/update_client.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::ics07_tendermint::header::Header; -use crate::ics24_host::identifier::ClientId; -use crate::tx_msg::Msg; - -use crate::ics07_tendermint::consensus_state::ConsensusState; -use serde_derive::{Deserialize, Serialize}; -use tendermint::account::Id as AccountId; - -pub const TYPE_MSG_UPDATE_CLIENT: &str = "update_client"; - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct MsgUpdateClient { - client_id: ClientId, - header: Header, - signer: AccountId, -} - -impl MsgUpdateClient { - pub fn new(client_id: ClientId, header: Header, signer: AccountId) -> Self { - Self { - client_id, - header, - signer, - } - } - - fn client_id(&self) -> &ClientId { - &self.client_id - } - - fn header(&self) -> &Header { - &self.header - } - - fn consensus_state(&self) -> ConsensusState { - self.header.consensus_state() - } -} - -impl Msg for MsgUpdateClient { - type ValidationError = crate::ics24_host::error::ValidationError; - - fn route(&self) -> String { - crate::keys::ROUTER_KEY.to_string() - } - - fn get_type(&self) -> String { - TYPE_MSG_UPDATE_CLIENT.to_string() - } - - fn validate_basic(&self) -> Result<(), Self::ValidationError> { - // Nothing to validate since both ClientId and AccountId perform validation on creation. - Ok(()) - } - - fn get_sign_bytes(&self) -> Vec { - todo!() - } - - fn get_signers(&self) -> Vec { - vec![self.signer] - } -} From 9805a1217827d8eded9c396d2b71baac11eecf07 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Thu, 24 Sep 2020 09:42:17 +0200 Subject: [PATCH 07/13] Cleanup --- modules/src/ics02_client/msgs.rs | 5 +---- modules/src/ics07_tendermint/consensus_state.rs | 3 +-- relayer-cli/src/commands.rs | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/modules/src/ics02_client/msgs.rs b/modules/src/ics02_client/msgs.rs index f1bb0246cc..44016f7010 100644 --- a/modules/src/ics02_client/msgs.rs +++ b/modules/src/ics02_client/msgs.rs @@ -116,14 +116,11 @@ impl TryFrom for MsgCreateAnyClient { impl From for MsgCreateClient { fn from(ics_msg: MsgCreateAnyClient) -> Self { - let signer = ics_msg.signer; - let signerb = signer.as_bytes(); - MsgCreateClient { client_id: ics_msg.client_id.to_string(), client_state: Some(ics_msg.client_state.into()), consensus_state: Some(ics_msg.consensus_state.into()), - signer: Vec::from(signerb), + signer: Vec::from(ics_msg.signer.as_bytes()), } } } diff --git a/modules/src/ics07_tendermint/consensus_state.rs b/modules/src/ics07_tendermint/consensus_state.rs index 259cfc4f64..f6887e9bea 100644 --- a/modules/src/ics07_tendermint/consensus_state.rs +++ b/modules/src/ics07_tendermint/consensus_state.rs @@ -85,9 +85,8 @@ impl ConsensusState { } pub fn new_from_header(header: SignedHeader) -> Self { - let root = CommitmentRoot::from_bytes(&header.header().app_hash); Self { - root, // TODO + root: CommitmentRoot::from_bytes(&header.header().app_hash), height: Height::from(header.header().height()), timestamp: header.header().bft_time(), next_validators_hash: header.header().next_validators_hash(), diff --git a/relayer-cli/src/commands.rs b/relayer-cli/src/commands.rs index 85ca222cc4..8394fef90f 100644 --- a/relayer-cli/src/commands.rs +++ b/relayer-cli/src/commands.rs @@ -55,7 +55,7 @@ pub enum CliCmd { Query(QueryCmd), /// The `tx` subcommand - #[options(help = "create IBC transaction on configured chains")] + #[options(help = "create IBC transactions on configured chains")] Tx(TxCmd), /// The `light` subcommand From dd71c56ace3182b180f607f2c57d7d7af3ac46c4 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Thu, 24 Sep 2020 10:46:46 +0200 Subject: [PATCH 08/13] Move create_clien() in the relayer --- relayer-cli/src/commands/tx/client.rs | 103 +------------------------- relayer/src/chain.rs | 2 +- relayer/src/lib.rs | 1 + relayer/src/tx.rs | 1 + relayer/src/tx/client.rs | 100 +++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 101 deletions(-) create mode 100644 relayer/src/tx.rs create mode 100644 relayer/src/tx/client.rs diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs index 221e329970..75913e30d3 100644 --- a/relayer-cli/src/commands/tx/client.rs +++ b/relayer-cli/src/commands/tx/client.rs @@ -1,20 +1,9 @@ use crate::prelude::*; use crate::application::app_config; -use crate::commands::utils::block_on; use abscissa_core::{Command, Options, Runnable}; -use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; -use ibc::ics02_client::client_type::ClientType; -use ibc::ics02_client::msgs::MsgCreateAnyClient; -use ibc::ics24_host::identifier::ClientId; -use ibc::ics24_host::Path::ClientState as ClientStatePath; -use ibc::tx_msg::Msg; -use prost_types::Any; -use relayer::chain::{query_latest_header, Chain, CosmosSDKChain}; -use relayer::config::{ChainConfig, Config}; -use relayer::error::{Error, Kind}; -use std::time::Duration; -use tendermint::block::Height; +use relayer::config::Config; +use relayer::tx::client::{create_client, CreateClientStateOptions}; #[derive(Clone, Command, Debug, Options)] pub struct TxCreateClientCmd { @@ -26,18 +15,11 @@ pub struct TxCreateClientCmd { #[options( free, - help = "identifier of the client for source chain to be created on destination chain" + help = "identifier of the client to be created on destination chain" )] dest_client_id: Option, } -#[derive(Clone, Debug)] -pub struct CreateClientStateOptions { - dest_client_id: ClientId, - dest_chain_config: ChainConfig, - src_chain_config: ChainConfig, -} - impl TxCreateClientCmd { fn validate_options(&self, config: &Config) -> Result { let dest_chain_id = self @@ -96,82 +78,3 @@ impl Runnable for TxCreateClientCmd { } } } - -pub fn create_client(opts: CreateClientStateOptions) -> Result<(), Error> { - // Ger the destination - let dest_chain = CosmosSDKChain::from_config(opts.clone().dest_chain_config)?; - - // Query the client state on destination chain. - if dest_chain - .abci_query(ClientStatePath(opts.clone().dest_client_id), 0, false) - .is_ok() - { - return Err(Into::::into(Kind::CreateClient( - opts.dest_client_id, - "client already exists".into(), - ))); - } - - // Get the latest header from the source chain and build the consensus state. - let src_chain = CosmosSDKChain::from_config(opts.clone().src_chain_config)?; - let tm_consensus_state = match block_on(query_latest_header::(&src_chain)) { - Err(err) => Err(Into::::into( - Kind::CreateClient( - opts.dest_client_id.clone(), - "failed to get the latest header".into(), - ) - .context(err), - )), - Ok(header) => { - Ok(ibc::ics07_tendermint::consensus_state::ConsensusState::new_from_header(header)) - } - }?; - let any_consensus_state = AnyConsensusState::Tendermint(tm_consensus_state.clone()); - - // Build the client state. - let any_client_state = match ibc::ics07_tendermint::client_state::ClientState::new( - src_chain.id().to_string(), - src_chain.trusting_period(), - src_chain.unbonding_period(), - Duration::from_millis(3000), - tm_consensus_state.height, - Height(0), - ) { - Err(err) => Err(Into::::into( - Kind::CreateClient( - opts.dest_client_id.clone(), - "failed to build the client state".into(), - ) - .context(err), - )), - Ok(tm_state) => Ok(AnyClientState::Tendermint(tm_state)), - }?; - - // Get the signer - let signer = match dest_chain.config().account_prefix.parse() { - Err(err) => Err(Into::::into( - Kind::CreateClient(opts.dest_client_id.clone(), "bad signer".into()).context(err), - )), - Ok(signer) => Ok(signer), - }?; - - // Build the domain type message - let new_msg = MsgCreateAnyClient::new( - opts.dest_client_id, - ClientType::Tendermint, - any_client_state, - any_consensus_state, - signer, - ); - - // Create a proto any message - let mut proto_msgs: Vec = Vec::new(); - let any_msg = Any { - // TODO - add get_url_type() to prepend proper string to get_type() - type_url: "/ibc.client.MsgCreateClient".to_ascii_lowercase(), - value: new_msg.get_sign_bytes(), - }; - - proto_msgs.push(any_msg); - dest_chain.send(proto_msgs) -} diff --git a/relayer/src/chain.rs b/relayer/src/chain.rs index 61263fca82..50193330a9 100644 --- a/relayer/src/chain.rs +++ b/relayer/src/chain.rs @@ -16,7 +16,7 @@ use crate::config::ChainConfig; use crate::error; use std::error::Error; -mod cosmos; +pub(crate) mod cosmos; pub use cosmos::CosmosSDKChain; use prost_types::Any; diff --git a/relayer/src/lib.rs b/relayer/src/lib.rs index ea2e5c7797..e6f035adec 100644 --- a/relayer/src/lib.rs +++ b/relayer/src/lib.rs @@ -18,4 +18,5 @@ pub mod error; pub mod event_handler; pub mod event_monitor; pub mod store; +pub mod tx; pub mod util; diff --git a/relayer/src/tx.rs b/relayer/src/tx.rs new file mode 100644 index 0000000000..b9babe5bc1 --- /dev/null +++ b/relayer/src/tx.rs @@ -0,0 +1 @@ +pub mod client; diff --git a/relayer/src/tx/client.rs b/relayer/src/tx/client.rs new file mode 100644 index 0000000000..942d5a0485 --- /dev/null +++ b/relayer/src/tx/client.rs @@ -0,0 +1,100 @@ +use crate::chain::{query_latest_header, Chain, CosmosSDKChain}; +use crate::config::ChainConfig; +use crate::error::{Error, Kind}; +use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; +use ibc::ics02_client::client_type::ClientType; +use ibc::ics02_client::msgs::MsgCreateAnyClient; +use ibc::ics24_host::identifier::ClientId; +use ibc::ics24_host::Path::ClientState as ClientStatePath; +use ibc::tx_msg::Msg; +use prost_types::Any; +use std::time::Duration; +use tendermint::block::Height; + +use crate::chain::cosmos::block_on; + +#[derive(Clone, Debug)] +pub struct CreateClientStateOptions { + pub dest_client_id: ClientId, + pub dest_chain_config: ChainConfig, + pub src_chain_config: ChainConfig, +} + +pub fn create_client(opts: CreateClientStateOptions) -> Result<(), Error> { + // Ger the destination + let dest_chain = CosmosSDKChain::from_config(opts.clone().dest_chain_config)?; + + // Query the client state on destination chain. + if dest_chain + .abci_query(ClientStatePath(opts.clone().dest_client_id), 0, false) + .is_ok() + { + return Err(Into::::into(Kind::CreateClient( + opts.dest_client_id, + "client already exists".into(), + ))); + } + + // Get the latest header from the source chain and build the consensus state. + let src_chain = CosmosSDKChain::from_config(opts.clone().src_chain_config)?; + let tm_consensus_state = match block_on(query_latest_header::(&src_chain)) { + Err(err) => Err(Into::::into( + Kind::CreateClient( + opts.dest_client_id.clone(), + "failed to get the latest header".into(), + ) + .context(err), + )), + Ok(header) => { + Ok(ibc::ics07_tendermint::consensus_state::ConsensusState::new_from_header(header)) + } + }?; + let any_consensus_state = AnyConsensusState::Tendermint(tm_consensus_state.clone()); + + // Build the client state. + let any_client_state = match ibc::ics07_tendermint::client_state::ClientState::new( + src_chain.id().to_string(), + src_chain.trusting_period(), + src_chain.unbonding_period(), + Duration::from_millis(3000), + tm_consensus_state.height, + Height(0), + ) { + Err(err) => Err(Into::::into( + Kind::CreateClient( + opts.dest_client_id.clone(), + "failed to build the client state".into(), + ) + .context(err), + )), + Ok(tm_state) => Ok(AnyClientState::Tendermint(tm_state)), + }?; + + // Get the signer + let signer = match dest_chain.config().account_prefix.parse() { + Err(err) => Err(Into::::into( + Kind::CreateClient(opts.dest_client_id.clone(), "bad signer".into()).context(err), + )), + Ok(signer) => Ok(signer), + }?; + + // Build the domain type message + let new_msg = MsgCreateAnyClient::new( + opts.dest_client_id, + ClientType::Tendermint, + any_client_state, + any_consensus_state, + signer, + ); + + // Create a proto any message + let mut proto_msgs: Vec = Vec::new(); + let any_msg = Any { + // TODO - add get_url_type() to prepend proper string to get_type() + type_url: "/ibc.client.MsgCreateClient".to_ascii_lowercase(), + value: new_msg.get_sign_bytes(), + }; + + proto_msgs.push(any_msg); + dest_chain.send(proto_msgs) +} From dbf3a653816c4934c870c11ca64a2770fa7e3e66 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Thu, 24 Sep 2020 11:52:23 +0200 Subject: [PATCH 09/13] Review comments --- modules/src/ics02_client/client_def.rs | 10 +++++----- modules/src/ics02_client/handler/create_client.rs | 12 ++++++------ modules/src/ics02_client/handler/update_client.rs | 8 ++++---- modules/src/ics02_client/msgs.rs | 10 +++++----- modules/src/ics07_tendermint/client_state.rs | 2 +- modules/src/ics07_tendermint/consensus_state.rs | 2 +- modules/src/ics23_commitment/commitment.rs | 2 +- relayer-cli/src/commands/tx.rs | 4 ++-- relayer/src/chain.rs | 2 +- relayer/src/chain/cosmos.rs | 2 +- relayer/src/tx/client.rs | 2 +- 11 files changed, 28 insertions(+), 28 deletions(-) diff --git a/modules/src/ics02_client/client_def.rs b/modules/src/ics02_client/client_def.rs index 7098f5d651..0842204cb8 100644 --- a/modules/src/ics02_client/client_def.rs +++ b/modules/src/ics02_client/client_def.rs @@ -1,4 +1,6 @@ +use prost_types::Any; use serde_derive::{Deserialize, Serialize}; +use std::convert::TryFrom; use crate::downcast; use crate::ics02_client::client_type::ClientType; @@ -14,10 +16,8 @@ use crate::ics23_commitment::commitment::{CommitmentPrefix, CommitmentProof, Com use crate::ics24_host::identifier::{ClientId, ConnectionId}; use ::tendermint::block::Height; -use prost_types::Any; - -use std::convert::TryFrom; use tendermint_proto::{DomainType, Error, Kind}; + #[cfg(test)] use { crate::mock_client::client_def::MockClient, @@ -110,7 +110,7 @@ impl Header for AnyHeader { } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum AnyClientState { Tendermint(TendermintClientState), @@ -191,7 +191,7 @@ impl ClientState for AnyClientState { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum AnyConsensusState { Tendermint(crate::ics07_tendermint::consensus_state::ConsensusState), diff --git a/modules/src/ics02_client/handler/create_client.rs b/modules/src/ics02_client/handler/create_client.rs index 0122af462f..57b72fc50a 100644 --- a/modules/src/ics02_client/handler/create_client.rs +++ b/modules/src/ics02_client/handler/create_client.rs @@ -68,7 +68,7 @@ mod tests { use crate::ics07_tendermint::header::test_util::get_dummy_header; use crate::mock_client::header::MockHeader; use crate::mock_client::state::{MockClientState, MockConsensusState}; - use std::str::{from_utf8, FromStr}; + use std::str::{self, FromStr}; use std::time::Duration; use tendermint::account::Id as AccountId; use tendermint::block::Height; @@ -78,7 +78,7 @@ mod tests { let client_id: ClientId = "mockclient".parse().unwrap(); let ctx = MockClientContext::default(); - let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); let msg = MsgCreateAnyClient { client_id, @@ -119,7 +119,7 @@ mod tests { fn test_create_client_existing_client_type() { let height = Height(42); let client_id: ClientId = "mockclient".parse().unwrap(); - let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); let mut ctx = MockClientContext::default(); ctx.with_client_type(&client_id, ClientType::Mock, height); @@ -146,7 +146,7 @@ mod tests { #[test] fn test_create_client_existing_client_state() { let client_id: ClientId = "mockclient".parse().unwrap(); - let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); let mut ctx = MockClientContext::default(); let height = Height(30); @@ -172,7 +172,7 @@ mod tests { #[test] fn test_create_client_ok_multiple() { let existing_client_id: ClientId = "existingmockclient".parse().unwrap(); - let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); let height = Height(80); let mut ctx = MockClientContext::default(); ctx.with_client_consensus_state(&existing_client_id, height); @@ -235,7 +235,7 @@ mod tests { #[test] fn test_tm_create_client_ok() { let client_id: ClientId = "tendermint".parse().unwrap(); - let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); let ctx = MockClientContext::default(); diff --git a/modules/src/ics02_client/handler/update_client.rs b/modules/src/ics02_client/handler/update_client.rs index ec1a953552..bc9d60ee89 100644 --- a/modules/src/ics02_client/handler/update_client.rs +++ b/modules/src/ics02_client/handler/update_client.rs @@ -74,14 +74,14 @@ mod tests { use crate::ics02_client::context_mock::MockClientContext; use crate::ics03_connection::msgs::test_util::get_dummy_account_id; use crate::mock_client::header::MockHeader; - use std::str::{from_utf8, FromStr}; + use std::str::{self, FromStr}; use tendermint::account::Id as AccountId; use tendermint::block::Height; #[test] fn test_update_client_ok() { let client_id: ClientId = "mockclient".parse().unwrap(); - let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); let mut ctx = MockClientContext::default(); ctx.with_client(&client_id, ClientType::Mock, Height(42)); @@ -115,7 +115,7 @@ mod tests { #[test] fn test_update_nonexisting_client() { let client_id: ClientId = "mockclient1".parse().unwrap(); - let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); let mut ctx = MockClientContext::default(); ctx.with_client_consensus_state(&client_id, Height(42)); @@ -145,7 +145,7 @@ mod tests { "mockclient2".parse().unwrap(), "mockclient3".parse().unwrap(), ]; - let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); let initial_height = Height(45); let update_height = Height(49); diff --git a/modules/src/ics02_client/msgs.rs b/modules/src/ics02_client/msgs.rs index 44016f7010..fe338942ba 100644 --- a/modules/src/ics02_client/msgs.rs +++ b/modules/src/ics02_client/msgs.rs @@ -3,16 +3,16 @@ //! handles these messages in two layers: first with the general ICS 02 client handler, which //! subsequently calls into the chain-specific (e.g., ICS 07) client handler. See: //! https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create. +use std::convert::{TryFrom, TryInto}; use crate::ics02_client::client_def::{AnyClientState, AnyConsensusState, AnyHeader}; use crate::ics02_client::client_type::ClientType; +use crate::ics02_client::error; use crate::ics24_host::identifier::ClientId; use crate::tx_msg::Msg; -use tendermint::account::Id as AccountId; -use crate::ics02_client::error; use ibc_proto::ibc::client::MsgCreateClient; -use std::convert::TryFrom; +use tendermint::account::Id as AccountId; use tendermint_proto::{DomainType, Error, Kind}; pub const TYPE_MSG_CREATE_CLIENT: &str = "create_client"; @@ -24,7 +24,7 @@ pub enum ClientMsg { } /// A type of message that triggers the creation of a new on-chain (IBC) client. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct MsgCreateAnyClient { pub client_id: ClientId, pub client_type: ClientType, @@ -109,7 +109,7 @@ impl TryFrom for MsgCreateAnyClient { client_type, client_state: AnyClientState::try_from(raw_client_state).unwrap(), consensus_state: AnyConsensusState::try_from(raw_consensus_state).unwrap(), - signer: AccountId::new(<[u8; 20]>::try_from(&raw.signer[..20]).unwrap()), + signer: AccountId::new(raw.signer[..20].try_into().unwrap()), }) } } diff --git a/modules/src/ics07_tendermint/client_state.rs b/modules/src/ics07_tendermint/client_state.rs index abbd713609..bff18ef4e7 100644 --- a/modules/src/ics07_tendermint/client_state.rs +++ b/modules/src/ics07_tendermint/client_state.rs @@ -11,7 +11,7 @@ use ibc_proto::ibc::tendermint::ClientState as RawClientState; use tendermint::block::Height; use tendermint_proto::DomainType; -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct ClientState { pub chain_id: String, // pub trust_level: TrustLevel, diff --git a/modules/src/ics07_tendermint/consensus_state.rs b/modules/src/ics07_tendermint/consensus_state.rs index f6887e9bea..c1f273102a 100644 --- a/modules/src/ics07_tendermint/consensus_state.rs +++ b/modules/src/ics07_tendermint/consensus_state.rs @@ -13,7 +13,7 @@ use tendermint::lite::SignedHeader; use tendermint::Hash; use tendermint_proto::DomainType; -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct ConsensusState { pub height: crate::Height, pub timestamp: tendermint::time::Time, diff --git a/modules/src/ics23_commitment/commitment.rs b/modules/src/ics23_commitment/commitment.rs index 6b2112a4f2..3842a6955d 100644 --- a/modules/src/ics23_commitment/commitment.rs +++ b/modules/src/ics23_commitment/commitment.rs @@ -2,7 +2,7 @@ use serde_derive::{Deserialize, Serialize}; use std::fmt; -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct CommitmentRoot(pub Vec); // Todo: write constructor impl CommitmentRoot { pub fn from_bytes(bytes: &[u8]) -> Self { diff --git a/relayer-cli/src/commands/tx.rs b/relayer-cli/src/commands/tx.rs index 1bce1972cd..1db3f69228 100644 --- a/relayer-cli/src/commands/tx.rs +++ b/relayer-cli/src/commands/tx.rs @@ -8,14 +8,14 @@ mod client; /// `tx` subcommand #[derive(Command, Debug, Options, Runnable)] pub enum TxCmd { - /// The `tx raw` subcommand + /// The `tx raw` subcommand submits IBC transactions to a chain #[options(help = "tx raw")] Raw(TxRawCommands), } #[derive(Command, Debug, Options, Runnable)] pub enum TxRawCommands { - /// The `tx raw client-create` subcommand + /// The `tx raw client-create` subcommand submits a MsgCreateClient in a transaction to a chain #[options(help = "tx raw create-client")] CreateClient(TxCreateClientCmd), } diff --git a/relayer/src/chain.rs b/relayer/src/chain.rs index 50193330a9..ed1bc10a1b 100644 --- a/relayer/src/chain.rs +++ b/relayer/src/chain.rs @@ -60,7 +60,7 @@ pub trait Chain { fn abci_query(&self, data: Path, height: u64, prove: bool) -> Result, Self::Error>; /// send a transaction with `msgs` to chain. - fn send(&self, msgs: Vec) -> Result<(), Self::Error>; + fn send(&self, _msgs: &[Any]) -> Result<(), Self::Error>; /// Returns the chain's identifier fn id(&self) -> &ChainId { diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 9a4824416a..9843a77eb7 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -96,7 +96,7 @@ impl Chain for CosmosSDKChain { } /// Send a transaction that includes the specified messages - fn send(&self, _msgs: Vec) -> Result<(), Error> { + fn send(&self, _msgs: &[Any]) -> Result<(), Error> { // TODO sign and broadcast_tx Ok(()) } diff --git a/relayer/src/tx/client.rs b/relayer/src/tx/client.rs index 942d5a0485..f46418b144 100644 --- a/relayer/src/tx/client.rs +++ b/relayer/src/tx/client.rs @@ -96,5 +96,5 @@ pub fn create_client(opts: CreateClientStateOptions) -> Result<(), Error> { }; proto_msgs.push(any_msg); - dest_chain.send(proto_msgs) + dest_chain.send(&proto_msgs) } From 3d3135c01ebb0f1defb5f7e0cc3feb652d92e35d Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 25 Sep 2020 09:28:03 +0200 Subject: [PATCH 10/13] Review comments --- modules/src/ics02_client/error.rs | 6 -- modules/src/ics02_client/msgs.rs | 31 ++++--- .../src/ics07_tendermint/consensus_state.rs | 86 ++++++++++--------- modules/src/ics07_tendermint/error.rs | 6 -- relayer-cli/src/commands/tx.rs | 1 - relayer-cli/src/commands/tx/client.rs | 6 +- relayer/src/tx/client.rs | 57 ++++++------ 7 files changed, 89 insertions(+), 104 deletions(-) diff --git a/modules/src/ics02_client/error.rs b/modules/src/ics02_client/error.rs index fc2297db9f..3be580296f 100644 --- a/modules/src/ics02_client/error.rs +++ b/modules/src/ics02_client/error.rs @@ -48,12 +48,6 @@ pub enum Kind { #[error("mismatch between client and arguments types, expected: {0:?}")] ClientArgsTypeMismatch(ClientType), - - #[error("unknown client message type: {0}")] - UnknownClientMessageType(String), - - #[error("invalid signer")] - InvalidSigner, } impl Kind { diff --git a/modules/src/ics02_client/msgs.rs b/modules/src/ics02_client/msgs.rs index fe338942ba..fdbf996284 100644 --- a/modules/src/ics02_client/msgs.rs +++ b/modules/src/ics02_client/msgs.rs @@ -11,11 +11,11 @@ use crate::ics02_client::error; use crate::ics24_host::identifier::ClientId; use crate::tx_msg::Msg; -use ibc_proto::ibc::client::MsgCreateClient; +use ibc_proto::ibc::client::MsgCreateClient as RawMsgCreateClient; use tendermint::account::Id as AccountId; use tendermint_proto::{DomainType, Error, Kind}; -pub const TYPE_MSG_CREATE_CLIENT: &str = "create_client"; +const TYPE_MSG_CREATE_CLIENT: &str = "create_client"; #[allow(clippy::large_enum_variant)] pub enum ClientMsg { @@ -69,7 +69,7 @@ impl Msg for MsgCreateAnyClient { fn get_sign_bytes(&self) -> Vec { let mut buf = Vec::new(); - let raw_msg: MsgCreateClient = self.clone().into(); + let raw_msg: RawMsgCreateClient = self.clone().into(); prost::Message::encode(&raw_msg, &mut buf).unwrap(); buf } @@ -79,16 +79,15 @@ impl Msg for MsgCreateAnyClient { } } -impl DomainType for MsgCreateAnyClient {} +impl DomainType for MsgCreateAnyClient {} -impl TryFrom for MsgCreateAnyClient { +impl TryFrom for MsgCreateAnyClient { type Error = Error; - fn try_from(raw: MsgCreateClient) -> Result { - let raw_client_state = match raw.client_state { - None => Err(Kind::DecodeMessage.context(error::Kind::InvalidRawClientState)), - Some(raw_state) => Ok(raw_state), - }?; + fn try_from(raw: RawMsgCreateClient) -> Result { + let raw_client_state = raw + .client_state + .ok_or_else(|| Kind::DecodeMessage.context(error::Kind::InvalidRawClientState))?; let client_type = match raw_client_state.type_url.as_str() { "/ibc.tendermint.ClientState" => Ok(ClientType::Tendermint), @@ -99,10 +98,10 @@ impl TryFrom for MsgCreateAnyClient { )), ), }?; - let raw_consensus_state = match raw.consensus_state { - None => Err(Kind::DecodeMessage.context(error::Kind::InvalidRawConsensusState)), - Some(raw_consensus_state) => Ok(raw_consensus_state), - }?; + + let raw_consensus_state = raw + .consensus_state + .ok_or_else(|| Kind::DecodeMessage.context(error::Kind::InvalidRawConsensusState))?; Ok(MsgCreateAnyClient { client_id: raw.client_id.parse().unwrap(), @@ -114,9 +113,9 @@ impl TryFrom for MsgCreateAnyClient { } } -impl From for MsgCreateClient { +impl From for RawMsgCreateClient { fn from(ics_msg: MsgCreateAnyClient) -> Self { - MsgCreateClient { + RawMsgCreateClient { client_id: ics_msg.client_id.to_string(), client_state: Some(ics_msg.client_state.into()), consensus_state: Some(ics_msg.consensus_state.into()), diff --git a/modules/src/ics07_tendermint/consensus_state.rs b/modules/src/ics07_tendermint/consensus_state.rs index c1f273102a..e0e802e26d 100644 --- a/modules/src/ics07_tendermint/consensus_state.rs +++ b/modules/src/ics07_tendermint/consensus_state.rs @@ -1,11 +1,11 @@ -use crate::ics02_client::client_type::ClientType; -use crate::ics23_commitment::commitment::CommitmentRoot; - -use crate::ics07_tendermint::error::{Error, Kind}; use chrono::{TimeZone, Utc}; -use ibc_proto::ibc::tendermint::ConsensusState as RawConsensusState; use serde_derive::{Deserialize, Serialize}; use std::convert::TryFrom; + +use ibc_proto::ibc::tendermint::ConsensusState as RawConsensusState; + +use tendermint::block::signed_header::SignedHeader as TMCommit; +use tendermint::block::Header as TMHeader; use tendermint::block::Height; use tendermint::hash::Algorithm; use tendermint::lite::Header; @@ -13,6 +13,10 @@ use tendermint::lite::SignedHeader; use tendermint::Hash; use tendermint_proto::DomainType; +use crate::ics02_client::client_type::ClientType; +use crate::ics07_tendermint::error::{Error, Kind}; +use crate::ics23_commitment::commitment::CommitmentRoot; + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct ConsensusState { pub height: crate::Height, @@ -21,6 +25,40 @@ pub struct ConsensusState { pub next_validators_hash: Hash, } +impl ConsensusState { + pub fn new( + root: CommitmentRoot, + height: crate::Height, + timestamp: tendermint::time::Time, + next_validators_hash: Hash, + ) -> Self { + Self { + root, + height, + timestamp, + next_validators_hash, + } + } +} + +impl crate::ics02_client::state::ConsensusState for ConsensusState { + fn client_type(&self) -> ClientType { + ClientType::Tendermint + } + + fn height(&self) -> crate::Height { + self.height + } + + fn root(&self) -> &CommitmentRoot { + &self.root + } + + fn validate_basic(&self) -> Result<(), Box> { + unimplemented!() + } +} + impl DomainType for ConsensusState {} impl TryFrom for ConsensusState { @@ -66,25 +104,9 @@ impl From for RawConsensusState { } } } -use tendermint::block::signed_header::SignedHeader as TMCommit; -use tendermint::block::Header as TMHeader; -impl ConsensusState { - pub fn new( - root: CommitmentRoot, - height: crate::Height, - timestamp: tendermint::time::Time, - next_validators_hash: Hash, - ) -> Self { - Self { - root, - height, - timestamp, - next_validators_hash, - } - } - - pub fn new_from_header(header: SignedHeader) -> Self { +impl From> for ConsensusState { + fn from(header: SignedHeader) -> Self { Self { root: CommitmentRoot::from_bytes(&header.header().app_hash), height: Height::from(header.header().height()), @@ -94,24 +116,6 @@ impl ConsensusState { } } -impl crate::ics02_client::state::ConsensusState for ConsensusState { - fn client_type(&self) -> ClientType { - ClientType::Tendermint - } - - fn height(&self) -> crate::Height { - self.height - } - - fn root(&self) -> &CommitmentRoot { - &self.root - } - - fn validate_basic(&self) -> Result<(), Box> { - unimplemented!() - } -} - #[cfg(test)] mod tests { use crate::test::test_serialization_roundtrip; diff --git a/modules/src/ics07_tendermint/error.rs b/modules/src/ics07_tendermint/error.rs index ff5adb51b7..c7b633d66e 100644 --- a/modules/src/ics07_tendermint/error.rs +++ b/modules/src/ics07_tendermint/error.rs @@ -5,9 +5,6 @@ pub type Error = anomaly::Error; #[derive(Clone, Debug, Error)] pub enum Kind { - #[error("identifier error")] - IdentifierError, - #[error("invalid trusting period")] InvalidTrustingPeriod, @@ -28,9 +25,6 @@ pub enum Kind { #[error("invalid raw client consensus state")] InvalidRawConsensusState, - - #[error("invalid signer")] - InvalidSigner, } impl Kind { diff --git a/relayer-cli/src/commands/tx.rs b/relayer-cli/src/commands/tx.rs index 1db3f69228..d766abf169 100644 --- a/relayer-cli/src/commands/tx.rs +++ b/relayer-cli/src/commands/tx.rs @@ -1,5 +1,4 @@ //! `tx` subcommand - use crate::commands::tx::client::TxCreateClientCmd; use abscissa_core::{Command, Options, Runnable}; diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs index 75913e30d3..33123bc508 100644 --- a/relayer-cli/src/commands/tx/client.rs +++ b/relayer-cli/src/commands/tx/client.rs @@ -1,10 +1,10 @@ -use crate::prelude::*; - -use crate::application::app_config; use abscissa_core::{Command, Options, Runnable}; use relayer::config::Config; use relayer::tx::client::{create_client, CreateClientStateOptions}; +use crate::application::app_config; +use crate::prelude::*; + #[derive(Clone, Command, Debug, Options)] pub struct TxCreateClientCmd { #[options(free, help = "identifier of the destination chain")] diff --git a/relayer/src/tx/client.rs b/relayer/src/tx/client.rs index e125a42194..f662731d7f 100644 --- a/relayer/src/tx/client.rs +++ b/relayer/src/tx/client.rs @@ -1,17 +1,19 @@ -use crate::chain::{query_latest_header, Chain, CosmosSDKChain}; -use crate::config::ChainConfig; -use crate::error::{Error, Kind}; +use prost_types::Any; +use std::time::Duration; + use ibc::ics02_client::client_def::{AnyClientState, AnyConsensusState}; use ibc::ics02_client::client_type::ClientType; use ibc::ics02_client::msgs::MsgCreateAnyClient; use ibc::ics24_host::identifier::ClientId; use ibc::ics24_host::Path::ClientState as ClientStatePath; use ibc::tx_msg::Msg; -use prost_types::Any; -use std::time::Duration; + use tendermint::block::Height; use crate::chain::cosmos::block_on; +use crate::chain::{query_latest_header, Chain, CosmosSDKChain}; +use crate::config::ChainConfig; +use crate::error::{Error, Kind}; #[derive(Clone, Debug)] pub struct CreateClientStateOptions { @@ -37,46 +39,39 @@ pub fn create_client(opts: CreateClientStateOptions) -> Result<(), Error> { // Get the latest header from the source chain and build the consensus state. let src_chain = CosmosSDKChain::from_config(opts.clone().src_chain_config)?; - let tm_consensus_state = match block_on(query_latest_header::(&src_chain)) { - Err(err) => Err(Into::::into( + let tm_consensus_state = block_on(query_latest_header::(&src_chain)) + .map_err(|e| { Kind::CreateClient( opts.dest_client_id.clone(), "failed to get the latest header".into(), ) - .context(err), - )), - Ok(header) => { - Ok(ibc::ics07_tendermint::consensus_state::ConsensusState::new_from_header(header)) - } - }?; + .context(e) + }) + .map(ibc::ics07_tendermint::consensus_state::ConsensusState::from)?; + let any_consensus_state = AnyConsensusState::Tendermint(tm_consensus_state.clone()); // Build the client state. - let any_client_state = match ibc::ics07_tendermint::client_state::ClientState::new( + let any_client_state = ibc::ics07_tendermint::client_state::ClientState::new( src_chain.id().to_string(), src_chain.trusting_period(), src_chain.unbonding_period(), Duration::from_millis(3000), tm_consensus_state.height, Height(0), - ) { - Err(err) => Err(Into::::into( - Kind::CreateClient( - opts.dest_client_id.clone(), - "failed to build the client state".into(), - ) - .context(err), - )), - Ok(tm_state) => Ok(AnyClientState::Tendermint(tm_state)), - }?; + ) + .map_err(|e| { + Kind::CreateClient( + opts.dest_client_id.clone(), + "failed to build the client state".into(), + ) + .context(e) + }) + .map(AnyClientState::Tendermint)?; - // Get the signer - let signer = match dest_chain.config().account_prefix.parse() { - Err(err) => Err(Into::::into( - Kind::CreateClient(opts.dest_client_id.clone(), "bad signer".into()).context(err), - )), - Ok(signer) => Ok(signer), - }?; + let signer = dest_chain.config().account_prefix.parse().map_err(|e| { + Kind::CreateClient(opts.dest_client_id.clone(), "bad signer".into()).context(e) + })?; // Build the domain type message let new_msg = MsgCreateAnyClient::new( From b58c5516f52d01fde4ed037200c4ca95f090676e Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 25 Sep 2020 09:53:10 +0200 Subject: [PATCH 11/13] Add new get_dummy_.. helper function --- .../src/ics02_client/handler/create_client.rs | 17 ++++----- .../src/ics02_client/handler/update_client.rs | 11 +++--- modules/src/ics02_client/msgs.rs | 11 +++--- modules/src/ics03_connection/msgs.rs | 38 +++++++++++-------- relayer-cli/src/commands/tx/client.rs | 5 ++- relayer-cli/src/error.rs | 4 ++ 6 files changed, 49 insertions(+), 37 deletions(-) diff --git a/modules/src/ics02_client/handler/create_client.rs b/modules/src/ics02_client/handler/create_client.rs index 57b72fc50a..102d2c07fc 100644 --- a/modules/src/ics02_client/handler/create_client.rs +++ b/modules/src/ics02_client/handler/create_client.rs @@ -61,6 +61,9 @@ pub fn keep(keeper: &mut dyn ClientKeeper, result: CreateClientResult) -> Result #[cfg(test)] mod tests { + use std::time::Duration; + use tendermint::block::Height; + use super::*; use crate::ics02_client::context_mock::MockClientContext; use crate::ics03_connection::msgs::test_util::get_dummy_account_id; @@ -68,17 +71,13 @@ mod tests { use crate::ics07_tendermint::header::test_util::get_dummy_header; use crate::mock_client::header::MockHeader; use crate::mock_client::state::{MockClientState, MockConsensusState}; - use std::str::{self, FromStr}; - use std::time::Duration; - use tendermint::account::Id as AccountId; - use tendermint::block::Height; #[test] fn test_create_client_ok() { let client_id: ClientId = "mockclient".parse().unwrap(); let ctx = MockClientContext::default(); - let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = get_dummy_account_id(); let msg = MsgCreateAnyClient { client_id, @@ -119,7 +118,7 @@ mod tests { fn test_create_client_existing_client_type() { let height = Height(42); let client_id: ClientId = "mockclient".parse().unwrap(); - let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = get_dummy_account_id(); let mut ctx = MockClientContext::default(); ctx.with_client_type(&client_id, ClientType::Mock, height); @@ -146,7 +145,7 @@ mod tests { #[test] fn test_create_client_existing_client_state() { let client_id: ClientId = "mockclient".parse().unwrap(); - let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = get_dummy_account_id(); let mut ctx = MockClientContext::default(); let height = Height(30); @@ -172,7 +171,7 @@ mod tests { #[test] fn test_create_client_ok_multiple() { let existing_client_id: ClientId = "existingmockclient".parse().unwrap(); - let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = get_dummy_account_id(); let height = Height(80); let mut ctx = MockClientContext::default(); ctx.with_client_consensus_state(&existing_client_id, height); @@ -235,7 +234,7 @@ mod tests { #[test] fn test_tm_create_client_ok() { let client_id: ClientId = "tendermint".parse().unwrap(); - let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = get_dummy_account_id(); let ctx = MockClientContext::default(); diff --git a/modules/src/ics02_client/handler/update_client.rs b/modules/src/ics02_client/handler/update_client.rs index bc9d60ee89..66577e3a5f 100644 --- a/modules/src/ics02_client/handler/update_client.rs +++ b/modules/src/ics02_client/handler/update_client.rs @@ -69,19 +69,18 @@ pub fn keep(keeper: &mut dyn ClientKeeper, result: UpdateClientResult) -> Result #[cfg(test)] mod tests { + use tendermint::block::Height; + use super::*; use crate::ics02_client::client_type::ClientType; use crate::ics02_client::context_mock::MockClientContext; use crate::ics03_connection::msgs::test_util::get_dummy_account_id; use crate::mock_client::header::MockHeader; - use std::str::{self, FromStr}; - use tendermint::account::Id as AccountId; - use tendermint::block::Height; #[test] fn test_update_client_ok() { let client_id: ClientId = "mockclient".parse().unwrap(); - let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = get_dummy_account_id(); let mut ctx = MockClientContext::default(); ctx.with_client(&client_id, ClientType::Mock, Height(42)); @@ -115,7 +114,7 @@ mod tests { #[test] fn test_update_nonexisting_client() { let client_id: ClientId = "mockclient1".parse().unwrap(); - let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = get_dummy_account_id(); let mut ctx = MockClientContext::default(); ctx.with_client_consensus_state(&client_id, Height(42)); @@ -145,7 +144,7 @@ mod tests { "mockclient2".parse().unwrap(), "mockclient3".parse().unwrap(), ]; - let signer = AccountId::from_str(str::from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = get_dummy_account_id(); let initial_height = Height(45); let update_height = Height(49); diff --git a/modules/src/ics02_client/msgs.rs b/modules/src/ics02_client/msgs.rs index fdbf996284..9b881f4e6b 100644 --- a/modules/src/ics02_client/msgs.rs +++ b/modules/src/ics02_client/msgs.rs @@ -134,6 +134,10 @@ pub struct MsgUpdateAnyClient { #[cfg(test)] mod tests { + use ibc_proto::ibc::client::MsgCreateClient; + use std::convert::TryFrom; + use std::time::Duration; + use crate::ics02_client::client_def::{AnyClientState, AnyConsensusState}; use crate::ics02_client::client_type::ClientType; use crate::ics02_client::msgs::MsgCreateAnyClient; @@ -141,16 +145,11 @@ mod tests { use crate::ics07_tendermint::client_state::ClientState; use crate::ics07_tendermint::header::test_util::get_dummy_header; use crate::ics24_host::identifier::ClientId; - use ibc_proto::ibc::client::MsgCreateClient; - use std::convert::TryFrom; - use std::str::{from_utf8, FromStr}; - use std::time::Duration; - use tendermint::account::Id as AccountId; #[test] fn to_and_from_any() { let client_id: ClientId = "tendermint".parse().unwrap(); - let signer = AccountId::from_str(from_utf8(&get_dummy_account_id()).unwrap()).unwrap(); + let signer = get_dummy_account_id(); let tm_header = get_dummy_header(); let tm_client_state = AnyClientState::Tendermint(ClientState { diff --git a/modules/src/ics03_connection/msgs.rs b/modules/src/ics03_connection/msgs.rs index d1c5b21f22..c3796d9c1b 100644 --- a/modules/src/ics03_connection/msgs.rs +++ b/modules/src/ics03_connection/msgs.rs @@ -469,27 +469,33 @@ impl TryFrom for MsgConnectionOpenConfirm { #[cfg(test)] pub mod test_util { + use std::str::{from_utf8, FromStr}; + use tendermint::account::Id as AccountId; + + use ibc_proto::ibc::client::Height; + use ibc_proto::ibc::commitment::MerklePrefix; use ibc_proto::ibc::connection::Counterparty as RawCounterparty; use ibc_proto::ibc::connection::MsgConnectionOpenAck as RawMsgConnectionOpenAck; use ibc_proto::ibc::connection::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; use ibc_proto::ibc::connection::MsgConnectionOpenInit as RawMsgConnectionOpenInit; use ibc_proto::ibc::connection::MsgConnectionOpenTry as RawMsgConnectionOpenTry; - use ibc_proto::ibc::client::Height; - use ibc_proto::ibc::commitment::MerklePrefix; - pub fn get_dummy_proof() -> Vec { "Y29uc2Vuc3VzU3RhdGUvaWJjb25lY2xpZW50LzIy" .as_bytes() .to_vec() } - pub fn get_dummy_account_id() -> Vec { + pub fn get_dummy_account_id_bytes() -> Vec { "0CDA3F47EF3C4906693B170EF650EB968C5F4B2C" .as_bytes() .to_vec() } + pub fn get_dummy_account_id() -> AccountId { + AccountId::from_str(from_utf8(&get_dummy_account_id_bytes()).unwrap()).unwrap() + } + pub fn get_dummy_counterparty() -> RawCounterparty { RawCounterparty { client_id: "destclient".to_string(), @@ -507,7 +513,7 @@ pub mod test_util { client_id: "srcclient".to_string(), connection_id: "srcconnection".to_string(), counterparty: Some(get_dummy_counterparty()), - signer: get_dummy_account_id(), + signer: get_dummy_account_id_bytes(), } } @@ -531,7 +537,7 @@ pub mod test_util { epoch_number: 1, epoch_height: consensus_height, }), - signer: get_dummy_account_id(), + signer: get_dummy_account_id_bytes(), proof_client: vec![], } } @@ -550,7 +556,7 @@ pub mod test_util { epoch_number: 1, epoch_height: 10, }), - signer: get_dummy_account_id(), + signer: get_dummy_account_id_bytes(), client_state: None, proof_client: vec![], } @@ -564,13 +570,22 @@ pub mod test_util { epoch_number: 1, epoch_height: 10, }), - signer: get_dummy_account_id(), + signer: get_dummy_account_id_bytes(), } } } #[cfg(test)] mod tests { + use std::convert::TryFrom; + + use ibc_proto::ibc::client::Height; + use ibc_proto::ibc::connection::Counterparty as RawCounterparty; + use ibc_proto::ibc::connection::MsgConnectionOpenAck as RawMsgConnectionOpenAck; + use ibc_proto::ibc::connection::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; + use ibc_proto::ibc::connection::MsgConnectionOpenInit as RawMsgConnectionOpenInit; + use ibc_proto::ibc::connection::MsgConnectionOpenTry as RawMsgConnectionOpenTry; + use super::MsgConnectionOpenInit; use crate::ics03_connection::msgs::test_util::{ get_dummy_counterparty, get_dummy_msg_conn_open_ack, get_dummy_msg_conn_open_confirm, @@ -579,13 +594,6 @@ mod tests { use crate::ics03_connection::msgs::{ MsgConnectionOpenAck, MsgConnectionOpenConfirm, MsgConnectionOpenTry, }; - use ibc_proto::ibc::client::Height; - use ibc_proto::ibc::connection::Counterparty as RawCounterparty; - use ibc_proto::ibc::connection::MsgConnectionOpenAck as RawMsgConnectionOpenAck; - use ibc_proto::ibc::connection::MsgConnectionOpenConfirm as RawMsgConnectionOpenConfirm; - use ibc_proto::ibc::connection::MsgConnectionOpenInit as RawMsgConnectionOpenInit; - use ibc_proto::ibc::connection::MsgConnectionOpenTry as RawMsgConnectionOpenTry; - use std::convert::TryFrom; #[test] fn parse_connection_open_init_msg() { diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs index 33123bc508..203f196833 100644 --- a/relayer-cli/src/commands/tx/client.rs +++ b/relayer-cli/src/commands/tx/client.rs @@ -3,6 +3,7 @@ use relayer::config::Config; use relayer::tx::client::{create_client, CreateClientStateOptions}; use crate::application::app_config; +use crate::error::{Error, Kind}; use crate::prelude::*; #[derive(Clone, Command, Debug, Options)] @@ -72,7 +73,9 @@ impl Runnable for TxCreateClientCmd { }; status_info!("Message", "{:?}", opts); - match create_client(opts) { + let res: Result<(), Error> = create_client(opts).map_err(|e| Kind::Tx.context(e).into()); + + match res { Ok(receipt) => status_info!("client created, result: ", "{:?}", receipt), Err(e) => status_info!("client create failed, error: ", "{:?}", e), } diff --git a/relayer-cli/src/error.rs b/relayer-cli/src/error.rs index 870541bf8a..1ca66be639 100644 --- a/relayer-cli/src/error.rs +++ b/relayer-cli/src/error.rs @@ -20,6 +20,10 @@ pub enum Kind { /// Error during network query #[error("query error")] Query, + + /// Error during transaction submission + #[error("tx error")] + Tx, } impl Kind { From c6624058b44a539283a77e00c08effa953107705 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 25 Sep 2020 09:57:44 +0200 Subject: [PATCH 12/13] Remove backtrace from the output --- relayer-cli/src/commands/tx/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs index 203f196833..c9c302bba2 100644 --- a/relayer-cli/src/commands/tx/client.rs +++ b/relayer-cli/src/commands/tx/client.rs @@ -77,7 +77,7 @@ impl Runnable for TxCreateClientCmd { match res { Ok(receipt) => status_info!("client created, result: ", "{:?}", receipt), - Err(e) => status_info!("client create failed, error: ", "{:?}", e), + Err(e) => status_info!("client create failed, error: ", "{}", e), } } } From 31afb4978d2bb8c407ef67391c371a2a119ca428 Mon Sep 17 00:00:00 2001 From: Anca Zamfir Date: Fri, 25 Sep 2020 18:47:12 +0200 Subject: [PATCH 13/13] Review comment --- relayer-cli/src/commands/tx/client.rs | 6 +++--- relayer/src/tx/client.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/relayer-cli/src/commands/tx/client.rs b/relayer-cli/src/commands/tx/client.rs index c9c302bba2..9f3fdf77f6 100644 --- a/relayer-cli/src/commands/tx/client.rs +++ b/relayer-cli/src/commands/tx/client.rs @@ -1,6 +1,6 @@ use abscissa_core::{Command, Options, Runnable}; use relayer::config::Config; -use relayer::tx::client::{create_client, CreateClientStateOptions}; +use relayer::tx::client::{create_client, CreateClientOptions}; use crate::application::app_config; use crate::error::{Error, Kind}; @@ -22,7 +22,7 @@ pub struct TxCreateClientCmd { } impl TxCreateClientCmd { - fn validate_options(&self, config: &Config) -> Result { + fn validate_options(&self, config: &Config) -> Result { let dest_chain_id = self .dest_chain_id .clone() @@ -52,7 +52,7 @@ impl TxCreateClientCmd { .parse() .map_err(|_| "bad client identifier".to_string())?; - Ok(CreateClientStateOptions { + Ok(CreateClientOptions { dest_client_id, dest_chain_config: dest_chain_config.clone(), src_chain_config: src_chain_config.clone(), diff --git a/relayer/src/tx/client.rs b/relayer/src/tx/client.rs index f662731d7f..90d4a2ed4b 100644 --- a/relayer/src/tx/client.rs +++ b/relayer/src/tx/client.rs @@ -16,13 +16,13 @@ use crate::config::ChainConfig; use crate::error::{Error, Kind}; #[derive(Clone, Debug)] -pub struct CreateClientStateOptions { +pub struct CreateClientOptions { pub dest_client_id: ClientId, pub dest_chain_config: ChainConfig, pub src_chain_config: ChainConfig, } -pub fn create_client(opts: CreateClientStateOptions) -> Result<(), Error> { +pub fn create_client(opts: CreateClientOptions) -> Result<(), Error> { // Ger the destination let dest_chain = CosmosSDKChain::from_config(opts.clone().dest_chain_config)?;