From 3549b9dab7f41426f0948b4dab28f0e6ad447fcb Mon Sep 17 00:00:00 2001 From: Kayanski <44806566+Kayanski@users.noreply.github.com> Date: Mon, 9 Sep 2024 14:20:25 +0200 Subject: [PATCH 1/2] Allow setting private key for sender (#482) * Added set mnemonic and set_private_key for sender * Better doc * changelog * Update cw-orch-daemon/src/senders/cosmos.rs Co-authored-by: CyberHoward <88450409+CyberHoward@users.noreply.github.com> * Update cw-orch-daemon/src/senders/cosmos.rs Co-authored-by: CyberHoward <88450409+CyberHoward@users.noreply.github.com> * Nits --------- Co-authored-by: CyberHoward <88450409+CyberHoward@users.noreply.github.com> --- CHANGELOG.md | 2 ++ cw-orch-daemon/src/env.rs | 4 +++- cw-orch-daemon/src/senders/cosmos.rs | 22 ++++++++++++++++++++++ packages/cw-orch-core/src/env.rs | 4 +++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86cd91383..26e3bfb65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unpublished + - Add methods to set the private key and mnemonic of an existing sender + ### Breaking ## 0.25.0 diff --git a/cw-orch-daemon/src/env.rs b/cw-orch-daemon/src/env.rs index 298a7e69e..180da9769 100644 --- a/cw-orch-daemon/src/env.rs +++ b/cw-orch-daemon/src/env.rs @@ -1,4 +1,6 @@ -//! This regroups all env variables used by cw-orch-daemon. It allows for easier documentation and env variable management +//! This regroups all env variables used by cw-orch-daemon. +//! +//! It allows for easier documentation and env variable management //! This is used to import environment variables with safe names (and at a centralized location) //! To get the env variable parsed value, you can use //! ```rust,no_run diff --git a/cw-orch-daemon/src/senders/cosmos.rs b/cw-orch-daemon/src/senders/cosmos.rs index 6fe999bf5..e9d371cc4 100644 --- a/cw-orch-daemon/src/senders/cosmos.rs +++ b/cw-orch-daemon/src/senders/cosmos.rs @@ -132,6 +132,28 @@ impl Wallet { self.options.clone() } + /// Replaces the private key that the [CosmosSender] is using with key derived from the provided 24-word mnemonic. + /// If you want more control over the derived private key, use [Self::set_private_key] + pub fn set_mnemonic(&mut self, mnemonic: impl Into) -> Result<(), DaemonError> { + let secp = Secp256k1::new(); + + let pk = PrivateKey::from_words( + &secp, + &mnemonic.into(), + 0, + self.options.hd_index.unwrap_or(0), + self.chain_info.network_info.coin_type, + )?; + self.set_private_key(pk); + Ok(()) + } + + /// Replaces the private key the sender is using + /// You can use a mnemonic to overwrite the key using [Self::set_mnemonic] + pub fn set_private_key(&mut self, private_key: PrivateKey) { + self.private_key = private_key + } + pub fn set_authz_granter(&mut self, granter: &Addr) { self.options.authz_granter = Some(granter.to_owned()); } diff --git a/packages/cw-orch-core/src/env.rs b/packages/cw-orch-core/src/env.rs index 3f01d6ce8..db83e5c8a 100644 --- a/packages/cw-orch-core/src/env.rs +++ b/packages/cw-orch-core/src/env.rs @@ -1,4 +1,6 @@ -//! This regroups all env variables used by cw-orch-daemon. It allows for easier documentation and env variable management +//! This regroups all env variables used by cw-orch-daemon. +//! +//! It allows for easier documentation and env variable management //! This is used to import environment variables with safe names (and at a centralized location) //! To get the env variable parsed value, you can use //! ```rust,no_run 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 2/2] 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 { () => {