From 4efe16a5d53fb8239ac78fd2c408409ad2495a88 Mon Sep 17 00:00:00 2001 From: CyberHoward <88450409+CyberHoward@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:22:34 +0200 Subject: [PATCH] Fix TLS issues (#484) * try creating endpoint manually * add roots feature to tonic * tls test * fix tls bug * use archway again * update channel creation logic * Nits --------- Co-authored-by: Buckram Co-authored-by: Kayanski Co-authored-by: Kayanski <44806566+Kayanski@users.noreply.github.com> --- cw-orch-daemon/Cargo.toml | 3 +- cw-orch-daemon/src/channel.rs | 54 ++++++------------- cw-orch-daemon/src/senders/query_only.rs | 12 ++++- .../src/contract/interface_traits.rs | 1 + packages/cw-orch-core/src/contract/paths.rs | 1 + 5 files changed, 31 insertions(+), 40 deletions(-) diff --git a/cw-orch-daemon/Cargo.toml b/cw-orch-daemon/Cargo.toml index 4cefa70c0..0c82f551e 100644 --- a/cw-orch-daemon/Cargo.toml +++ b/cw-orch-daemon/Cargo.toml @@ -45,7 +45,7 @@ bech32 = { version = "0.11.0", default-features = false, features = ["alloc"] } hex = { version = "0.4.3" } ripemd = { version = "0.1.3" } tokio = { workspace = true, features = ["full"] } -tonic = { workspace = true, features = ["tls", "tls-roots"] } +tonic = { workspace = true, features = ["tls"] } reqwest = { version = "0.12.5" } base64 = { version = "0.22.1" } hkd32 = { version = "0.7.0", features = ["bip39", "mnemonic", "bech32"] } @@ -77,6 +77,7 @@ uid = "0.1.7" # Deserialize network config toml = "0.8" +http = "1.1.0" [dev-dependencies] cw-orch-daemon = { path = "." } diff --git a/cw-orch-daemon/src/channel.rs b/cw-orch-daemon/src/channel.rs index dd0c52633..6f58ac461 100644 --- a/cw-orch-daemon/src/channel.rs +++ b/cw-orch-daemon/src/channel.rs @@ -2,7 +2,8 @@ use cosmrs::proto::cosmos::base::tendermint::v1beta1::{ service_client::ServiceClient, GetNodeInfoRequest, }; use cw_orch_core::{environment::ChainInfoOwned, log::connectivity_target}; -use tonic::transport::{Channel, ClientTlsConfig}; +use http::Uri; +use tonic::transport::{Channel, ClientTlsConfig, Endpoint}; use super::error::DaemonError; @@ -21,55 +22,32 @@ impl GrpcChannel { for address in grpc.iter() { log::debug!(target: &connectivity_target(), "Trying to connect to endpoint: {}", address); - // get grpc endpoint - let endpoint = Channel::builder(address.clone().try_into().unwrap()); + let uri = Uri::from_maybe_shared(address.clone()).expect("Invalid URI"); - // try to connect to grpc endpoint - let maybe_client = ServiceClient::connect(endpoint.clone()).await; + let maybe_channel = Endpoint::from(uri) + .tls_config(ClientTlsConfig::new().with_enabled_roots()) + .unwrap() + .connect() + .await; - // connection succeeded - let mut client = if maybe_client.is_ok() { - maybe_client? - } else { + if maybe_channel.is_err() { log::warn!( "Cannot connect to gRPC endpoint: {}, {:?}", address, - maybe_client.unwrap_err() + maybe_channel.unwrap_err() ); - - // try HTTPS approach - // https://github.com/hyperium/tonic/issues/363#issuecomment-638545965 - if !(address.contains("https") || address.contains("443")) { - continue; - }; - - log::debug!(target: &connectivity_target(), "Attempting to connect with TLS"); - - // re attempt to connect - let endpoint = endpoint.clone().tls_config(ClientTlsConfig::new())?; - let maybe_client = ServiceClient::connect(endpoint.clone()).await; - - // connection still fails - if maybe_client.is_err() { - log::warn!( - "Cannot connect to gRPC endpoint: {}, {:?}", - address, - maybe_client.unwrap_err() - ); - continue; - }; - - maybe_client? + continue; }; + let channel = maybe_channel.unwrap(); + + let mut client = ServiceClient::new(channel.clone()); - // get client information for verification down below + // Verify that node is the expected network let node_info = client .get_node_info(GetNodeInfoRequest {}) .await? .into_inner(); - // local juno does not return a proper ChainId with epoch format - // verify we are connected to the expected network if node_info.default_node_info.as_ref().unwrap().network != chain_id { log::error!( "Network mismatch: connection:{} != config:{}", @@ -80,7 +58,7 @@ impl GrpcChannel { } // add endpoint to succesful connections - successful_connections.push(endpoint.connect().await?) + successful_connections.push(channel); } // we could not get any succesful connections diff --git a/cw-orch-daemon/src/senders/query_only.rs b/cw-orch-daemon/src/senders/query_only.rs index eb3f66af4..c2437547b 100644 --- a/cw-orch-daemon/src/senders/query_only.rs +++ b/cw-orch-daemon/src/senders/query_only.rs @@ -46,7 +46,7 @@ impl QuerySender for QueryOnlySender { #[cfg(test)] mod tests { - use cw_orch_networks::networks::JUNO_1; + use cw_orch_networks::networks::{ARCHWAY_1, JUNO_1, VOTA_ASH}; use super::QueryOnlyDaemon; use crate::DaemonBuilder; @@ -57,4 +57,14 @@ mod tests { let _query_only_daemon: QueryOnlyDaemon = DaemonBuilder::new(JUNO_1).build_sender(()).unwrap(); } + + #[test] + #[serial_test::serial] + fn tls_grpc() { + let chain = ARCHWAY_1; + // Make sure this test is up to date + assert!(chain.grpc_urls[0].starts_with("https")); + let _query_only_daemon: QueryOnlyDaemon = + DaemonBuilder::new(chain).build_sender(()).unwrap(); + } } diff --git a/packages/cw-orch-core/src/contract/interface_traits.rs b/packages/cw-orch-core/src/contract/interface_traits.rs index 5748ba8ff..0b0f2a0e6 100644 --- a/packages/cw-orch-core/src/contract/interface_traits.rs +++ b/packages/cw-orch-core/src/contract/interface_traits.rs @@ -241,6 +241,7 @@ pub trait CwOrchMigrate: MigratableContract + ContractInstance impl, Chain: TxHandler> CwOrchMigrate for T {} /// Trait to implement on the contract to enable it to be uploaded +/// /// Should return [`WasmPath`](crate::contract::interface_traits::WasmPath) for `Chain = Daemon` /// and [`Box<&dyn Contract>`] for `Chain = Mock` pub trait Uploadable { diff --git a/packages/cw-orch-core/src/contract/paths.rs b/packages/cw-orch-core/src/contract/paths.rs index 4069bfc94..4b25f82ac 100644 --- a/packages/cw-orch-core/src/contract/paths.rs +++ b/packages/cw-orch-core/src/contract/paths.rs @@ -94,6 +94,7 @@ mod artifacts_dir { #[macro_export] /// Creates an [`ArtifactsDir`] from the current workspace by searching the file tree for a directory named `artifacts`. + /// /// It does this by reading the CARGO_MANIFEST_DIR environment variable and going up the file tree until it finds the `artifacts` directory. macro_rules! from_workspace { () => {