From d435985d8c065c74d4c230a63aab6631d93f38a3 Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Tue, 27 Oct 2020 15:46:12 +0100 Subject: [PATCH 1/2] Implement query_header_at_height via RPC (no light client verification) --- relayer-cli/tests/fixtures/two_chains.toml | 8 ++- relayer-cli/tests/integration.rs | 1 + relayer/src/chain.rs | 59 ++++++++----------- relayer/src/chain/cosmos.rs | 58 +++++++++++++----- relayer/src/config.rs | 3 + relayer/src/tx/client.rs | 19 +++--- relayer/src/util.rs | 3 + relayer/src/util/block_on.rs | 13 ++++ .../config/fixtures/relayer_conf_example.toml | 6 ++ .../tests/config/fixtures/simple_config.toml | 6 ++ 10 files changed, 114 insertions(+), 62 deletions(-) create mode 100644 relayer/src/util/block_on.rs diff --git a/relayer-cli/tests/fixtures/two_chains.toml b/relayer-cli/tests/fixtures/two_chains.toml index 4f5be43040..2a7ab212a1 100644 --- a/relayer-cli/tests/fixtures/two_chains.toml +++ b/relayer-cli/tests/fixtures/two_chains.toml @@ -16,6 +16,9 @@ strategy = "naive" gas_price = "0.025stake" trusting_period = "336h" + # TODO: Move to light client config + peer_id = "BADFADAD0BEFEEDC0C0ADEADBEEFC0FFEEFACADE" + [[chains]] id = "ibc1" rpc_addr = "localhost:26557" @@ -26,4 +29,7 @@ strategy = "naive" gas = 200000 gas_adjustement = 1.3 gas_price = "0.025stake" - trusting_period = "336h" \ No newline at end of file + trusting_period = "336h" + + # TODO: Move to light client config + peer_id = "DC0C0ADEADBEEFC0FFEEFACADEBADFADAD0BEFEE" diff --git a/relayer-cli/tests/integration.rs b/relayer-cli/tests/integration.rs index a2eb43c94f..a6416d6e61 100644 --- a/relayer-cli/tests/integration.rs +++ b/relayer-cli/tests/integration.rs @@ -36,6 +36,7 @@ fn simd_config() -> Config { client_ids: vec!["ethbridge".to_string()], gas: 200000, trusting_period: Default::default(), + peer_id: "BADFADAD0BEFEEDC0C0ADEADBEEFC0FFEEFACADE".parse().unwrap(), }]; config } diff --git a/relayer/src/chain.rs b/relayer/src/chain.rs index 1dba7096df..4132d92d85 100644 --- a/relayer/src/chain.rs +++ b/relayer/src/chain.rs @@ -15,6 +15,7 @@ use ibc::ics24_host::Path; use crate::client::LightClient; use crate::config::ChainConfig; use crate::error; +use crate::util::block_on; use std::error::Error; @@ -79,44 +80,30 @@ pub trait Chain { /// Sign message /// TODO - waiting for tendermint-rs upgrade to v0.16 fn sign_tx(&self, _msgs: &[Any]) -> Result, Self::Error>; -} -/// Query the latest height the chain is at via a RPC query -pub async fn query_latest_height(chain: &impl Chain) -> Result { - let status = chain - .rpc_client() - .status() - .await - .map_err(|e| error::Kind::Rpc.context(e))?; - - if status.sync_info.catching_up { - fail!( - error::Kind::LightClient, - "node at {} running chain {} not caught up", - chain.config().rpc_addr, - chain.config().id, - ); - } + /// Query a header at the given height via RPC + fn query_header_at_height(&self, height: Height) -> Result; - Ok(status.sync_info.latest_block_height) -} + /// Query the latest height the chain is at via a RPC query + fn query_latest_height(&self) -> Result { + let status = + block_on(self.rpc_client().status()).map_err(|e| error::Kind::Rpc.context(e))?; -/// Query the latest header -pub async fn query_latest_header(chain: &C) -> Result -where - C: Chain, -{ - let h = query_latest_height(chain).await?; - Ok(query_header_at_height(chain, h).await?) -} + if status.sync_info.catching_up { + fail!( + error::Kind::LightClient, + "node at {} running chain {} not caught up", + self.config().rpc_addr, + self.config().id, + ); + } -/// Query a header at the given height via the RPC requester -pub async fn query_header_at_height( - chain: &C, - height: Height, -) -> Result -where - C: Chain, -{ - todo!() + Ok(status.sync_info.latest_block_height) + } + + /// Query the latest header via RPC + fn query_latest_header(&self) -> Result { + let height = self.query_latest_height()?; + self.query_header_at_height(height) + } } diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index 50d3e5a343..6c4b8d2979 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -1,10 +1,15 @@ +use std::future::Future; use std::str::FromStr; use std::time::Duration; +use bytes::Bytes; +use prost::Message; +use prost_types::Any; + use tendermint::abci::Path as TendermintABCIPath; use tendermint::block::Height; -use tendermint_light_client::types::LightBlock; -use tendermint_light_client::types::TrustThreshold; +use tendermint_light_client::types::{LightBlock, ValidatorSet}; +use tendermint_light_client::types::{SignedHeader, TrustThreshold}; use tendermint_rpc::Client; use tendermint_rpc::HttpClient; @@ -16,11 +21,7 @@ use super::Chain; use crate::client::tendermint::LightClient; use crate::config::ChainConfig; use crate::error::{Error, Kind}; - -use bytes::Bytes; -use prost::Message; -use prost_types::Any; -use std::future::Future; +use crate::util::block_on; pub struct CosmosSDKChain { config: ChainConfig, @@ -103,6 +104,25 @@ impl Chain for CosmosSDKChain { Duration::from_secs(24 * 7 * 3) } + fn query_header_at_height(&self, height: Height) -> Result { + let client = self.rpc_client(); + + let signed_header = fetch_signed_header(client, height)?; + assert_eq!(height, signed_header.header.height); + + let validator_set = fetch_validator_set(client, height)?; + let next_validator_set = fetch_validator_set(client, height.increment())?; + + let light_block = LightBlock::new( + signed_header, + validator_set, + next_validator_set, + self.config().peer_id, + ); + + Ok(light_block) + } + fn sign_tx(&self, _msgs: &[Any]) -> Result, Error> { unimplemented!() @@ -249,12 +269,20 @@ async fn abci_query( Ok(response.value) } -/// block on future -pub fn block_on(future: F) -> F::Output { - tokio::runtime::Builder::new() - .basic_scheduler() - .enable_all() - .build() - .unwrap() - .block_on(future) +fn fetch_signed_header(client: &HttpClient, height: Height) -> Result { + let res = block_on(client.commit(height)); + + match res { + Ok(response) => Ok(response.signed_header), + Err(err) => Err(Kind::Rpc.context(err).into()), + } +} + +fn fetch_validator_set(client: &HttpClient, height: Height) -> Result { + let res = block_on(client.validators(height)); + + match res { + Ok(response) => Ok(ValidatorSet::new(response.validators)), + Err(err) => Err(Kind::Rpc.context(err).into()), + } } diff --git a/relayer/src/config.rs b/relayer/src/config.rs index 96f5a2149b..c90069acae 100644 --- a/relayer/src/config.rs +++ b/relayer/src/config.rs @@ -80,6 +80,9 @@ pub struct ChainConfig { pub gas: u64, #[serde(default = "default::trusting_period", with = "humantime_serde")] pub trusting_period: Duration, + + // TODO: Move the light client config + pub peer_id: node::Id, } #[derive(Clone, Debug, Deserialize, Serialize)] diff --git a/relayer/src/tx/client.rs b/relayer/src/tx/client.rs index 0febc99689..4db1717c4a 100644 --- a/relayer/src/tx/client.rs +++ b/relayer/src/tx/client.rs @@ -8,10 +8,10 @@ use ibc::ics24_host::identifier::{ChainId, ClientId}; use ibc::ics24_host::Path::ClientState as ClientStatePath; use ibc::tx_msg::Msg; -use crate::chain::cosmos::block_on; -use crate::chain::{query_latest_header, Chain, CosmosSDKChain}; +use crate::chain::{Chain, CosmosSDKChain}; use crate::config::ChainConfig; use crate::error::{Error, Kind}; +use crate::util::block_on; use ibc::ics02_client::height::Height; #[derive(Clone, Debug)] @@ -41,14 +41,13 @@ pub fn create_client(opts: CreateClientOptions) -> 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_latest_header = - 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(e) - })?; + let tm_latest_header = src_chain.query_latest_header().map_err(|e| { + Kind::CreateClient( + opts.dest_client_id.clone(), + "failed to get the latest header".into(), + ) + .context(e) + })?; let height = u64::from(tm_latest_header.signed_header.header.height); let version = tm_latest_header.signed_header.header.chain_id.to_string(); diff --git a/relayer/src/util.rs b/relayer/src/util.rs index e7aaf7680e..385b8c82c1 100644 --- a/relayer/src/util.rs +++ b/relayer/src/util.rs @@ -1 +1,4 @@ +mod block_on; +pub use block_on::block_on; + pub mod sled; diff --git a/relayer/src/util/block_on.rs b/relayer/src/util/block_on.rs new file mode 100644 index 0000000000..aed8c9f98e --- /dev/null +++ b/relayer/src/util/block_on.rs @@ -0,0 +1,13 @@ +//! Utility function to execute a future synchronously + +use futures::Future; + +/// Spawns a new tokio runtime and use it to block on the given future. +pub fn block_on(future: F) -> F::Output { + tokio::runtime::Builder::new() + .basic_scheduler() + .enable_all() + .build() + .unwrap() + .block_on(future) +} diff --git a/relayer/tests/config/fixtures/relayer_conf_example.toml b/relayer/tests/config/fixtures/relayer_conf_example.toml index d22e3ee13c..ab381f976a 100644 --- a/relayer/tests/config/fixtures/relayer_conf_example.toml +++ b/relayer/tests/config/fixtures/relayer_conf_example.toml @@ -17,6 +17,9 @@ strategy = "naive" gas_price = "0.025stake" trusting_period = "336h" + # TODO: Move to light client config + peer_id = "BADFADAD0BEFEEDC0C0ADEADBEEFC0FFEEFACADE" + [[chains]] id = "chain_B" rpc_addr = "localhost:26557" @@ -29,6 +32,9 @@ strategy = "naive" gas_price = "0.025stake" trusting_period = "336h" + # TODO: Move to light client config + peer_id = "DC0C0ADEADBEEFC0FFEEFACADEBADFADAD0BEFEE" + [[connections]] [connections.src] diff --git a/relayer/tests/config/fixtures/simple_config.toml b/relayer/tests/config/fixtures/simple_config.toml index 755bf5decc..233a88f31f 100644 --- a/relayer/tests/config/fixtures/simple_config.toml +++ b/relayer/tests/config/fixtures/simple_config.toml @@ -18,6 +18,9 @@ strategy = "naive" gas_price = "0.025stake" trusting_period = "336h" + # TODO: Move to light client config + peer_id = "BADFADAD0BEFEEDC0C0ADEADBEEFC0FFEEFACADE" + [[chains]] id = "chain_B" rpc_addr = "localhost:26557" @@ -30,6 +33,9 @@ strategy = "naive" gas_price = "0.025stake" trusting_period = "336h" + # TODO: Move to light client config + peer_id = "DC0C0ADEADBEEFC0FFEEFACADEBADFADAD0BEFEE" + [[connections]] [connections.src] From d21cad7af7787e98bf8e7a0663127b9f9170bd2b Mon Sep 17 00:00:00 2001 From: Romain Ruetschi Date: Tue, 27 Oct 2020 16:32:23 +0100 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b45e9c1caa..f3c1db8059 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,12 @@ - [changelog] Added "unreleased" section in `CHANGELOG.MD` to help streamline releases ([#274]) - [relayer] Integrate relayer spike into relayer crate ([#335]) - [modules] Implement flexible connection id selection ([#332]) +- [relayer] Implement `query_header_at_height` via plain RPC queries (no light client verification) ([#336]) [#274]: https://github.com/informalsystems/ibc-rs/issues/274 [#332]: https://github.com/informalsystems/ibc-rs/issues/332 [#335]: https://github.com/informalsystems/ibc-rs/pulls/335 +[#336]: https://github.com/informalsystems/ibc-rs/issues/336 ### IMPROVEMENTS