From 7995aa124f6634c4d766c8f72d2b3af65d128f11 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 13 Nov 2024 15:38:33 +0000 Subject: [PATCH 01/34] tmep --- rs/bitcoin/adapter/src/connectionmanager.rs | 10 +++++++++- rs/https_outcalls/adapter/src/rpc_server.rs | 10 ++++++++++ rs/https_outcalls/client/src/client.rs | 5 ++++- rs/https_outcalls/consensus/src/pool_manager.rs | 11 +++++++++++ .../proto/https_outcalls_service/v1/proto.proto | 1 + rs/types/types/src/canister_http.rs | 2 ++ 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/rs/bitcoin/adapter/src/connectionmanager.rs b/rs/bitcoin/adapter/src/connectionmanager.rs index 077b850bb3f..91b5d605ba7 100644 --- a/rs/bitcoin/adapter/src/connectionmanager.rs +++ b/rs/bitcoin/adapter/src/connectionmanager.rs @@ -428,7 +428,15 @@ impl ConnectionManager { .get_connection(address) .map_err(|_| ProcessBitcoinNetworkMessageError::InvalidMessage)?; if !conn.is_seed() && !self.validate_received_version(message) { - warn!(self.logger, "Received an invalid version from {}", address); + warn!( + self.logger, + "Received an invalid version from {}. Version: {}; Height: {}; Services: {}, while current height is: {}", + address, + message.version, + message.start_height, + message.services, + self.current_height, + ); return Err(ProcessBitcoinNetworkMessageError::InvalidMessage); } self.send_verack(address).ok(); diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 9310e9b97a9..40d58bd4fc9 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -53,6 +53,12 @@ pub struct CanisterHttp { } impl CanisterHttp { + + fn generate_socks_clients(&self, api_bn_ips: Vec) -> Vec>, OutboundRequestBody>> { + //TODO(mihailjianu): implement this. + return vec![]; + } + pub fn new(config: Config, logger: ReplicaLogger, metrics: &MetricsRegistry) -> Self { // Socks client setup let mut http_connector = HttpConnector::new(); @@ -114,6 +120,10 @@ impl HttpsOutcallsService for CanisterHttp { let req = request.into_inner(); + let api_bn_ips = req.api_bn_ips; + + let socks_clients = self.generate_socks_clients(api_bn_ips); + let uri = req.url.parse::().map_err(|err| { debug!(self.logger, "Failed to parse URL: {}", err); self.metrics diff --git a/rs/https_outcalls/client/src/client.rs b/rs/https_outcalls/client/src/client.rs index 9cde92fe7a3..bfbe07c3db3 100644 --- a/rs/https_outcalls/client/src/client.rs +++ b/rs/https_outcalls/client/src/client.rs @@ -147,6 +147,7 @@ impl NonBlockingChannel for CanisterHttpAdapterClientImpl { transform: request_transform, .. }, + api_bn_ips, } = canister_http_request; let adapter_req_timer = Instant::now(); @@ -169,7 +170,8 @@ impl NonBlockingChannel for CanisterHttpAdapterClientImpl { .collect(), body: request_body.unwrap_or_default(), // Socks proxy is only enabled on system subnets. - socks_proxy_allowed: matches!(subnet_type, SubnetType::System) + socks_proxy_allowed: matches!(subnet_type, SubnetType::System), + api_bn_ips, }) .map_err(|grpc_status| { ( @@ -448,6 +450,7 @@ mod tests { }), time: UNIX_EPOCH, }, + api_bn_ips: vec![], } } diff --git a/rs/https_outcalls/consensus/src/pool_manager.rs b/rs/https_outcalls/consensus/src/pool_manager.rs index 502bb3b2a37..632dc6af029 100644 --- a/rs/https_outcalls/consensus/src/pool_manager.rs +++ b/rs/https_outcalls/consensus/src/pool_manager.rs @@ -14,6 +14,8 @@ use ic_interfaces_registry::RegistryClient; use ic_interfaces_state_manager::StateReader; use ic_logger::*; use ic_metrics::MetricsRegistry; +use ic_registry_client_helpers::api_boundary_node::ApiBoundaryNodeRegistry; +use ic_registry_client_helpers::node::NodeRegistry; use ic_registry_client_helpers::subnet::SubnetRegistry; use ic_replicated_state::ReplicatedState; use ic_types::{ @@ -181,6 +183,13 @@ impl CanisterHttpPoolManagerImpl { .cloned() .collect(); + //TODO(mihailjianu): handle errors. + let api_bn_ids = self.registry_client.get_api_boundary_node_ids(self.registry_client.get_latest_version()).unwrap(); + let api_bn_ips = api_bn_ids.iter().map(|id| { + let record = self.registry_client.get_node_record(*id, self.registry_client.get_latest_version()).unwrap(); + record.unwrap().http.unwrap().ip_addr + }).collect::>(); + for (id, context) in http_requests { if !request_ids_already_made.contains(&id) { let timeout = context.time + Duration::from_secs(5 * 60); @@ -192,6 +201,7 @@ impl CanisterHttpPoolManagerImpl { id, timeout, context, + api_bn_ips: api_bn_ips.clone(), }) { warn!( @@ -902,6 +912,7 @@ pub mod test { timeout: ic_types::Time::from_nanos_since_unix_epoch(10) + Duration::from_secs(60 * 5), context: request.clone(), + api_bn_ips: vec![], })) .times(1) .return_const(Ok(())); diff --git a/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto b/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto index 138e0251e0a..495be4f3c0f 100644 --- a/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto +++ b/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto @@ -21,6 +21,7 @@ message HttpsOutcallRequest { HttpMethod method = 4; uint64 max_response_size_bytes = 5; bool socks_proxy_allowed = 6; + repeated string api_bn_ips = 7; } message HttpsOutcallResponse { diff --git a/rs/types/types/src/canister_http.rs b/rs/types/types/src/canister_http.rs index 52c90e66516..feb24c0a7bc 100644 --- a/rs/types/types/src/canister_http.rs +++ b/rs/types/types/src/canister_http.rs @@ -457,6 +457,8 @@ pub struct CanisterHttpRequest { pub id: CanisterHttpRequestId, /// The context of the request which captures all the metadata about this request pub context: CanisterHttpRequestContext, + /// The api boundary nodes that should be used as a socks proxy in the case of a request to an IPv4 address. + pub api_bn_ips: Vec, } /// The content of a response after the transformation From 0a06cf0e54036929b20423a7f4d7accc0a803c31 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Thu, 14 Nov 2024 10:31:53 +0000 Subject: [PATCH 02/34] add socks caches --- Cargo.lock | 1 + rs/https_outcalls/adapter/BUILD.bazel | 1 + rs/https_outcalls/adapter/Cargo.toml | 1 + rs/https_outcalls/adapter/src/rpc_server.rs | 114 +++++++++++++----- .../adapter/tests/server_test.rs | 12 ++ 5 files changed, 101 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a35bd09bd13..b5669217246 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8529,6 +8529,7 @@ dependencies = [ name = "ic-https-outcalls-adapter" version = "0.1.0" dependencies = [ + "arc-swap", "async-stream", "byte-unit", "bytes", diff --git a/rs/https_outcalls/adapter/BUILD.bazel b/rs/https_outcalls/adapter/BUILD.bazel index c89e2625020..dba7dd07f85 100644 --- a/rs/https_outcalls/adapter/BUILD.bazel +++ b/rs/https_outcalls/adapter/BUILD.bazel @@ -9,6 +9,7 @@ DEPENDENCIES = [ "//rs/https_outcalls/service", "//rs/monitoring/logger", "//rs/monitoring/metrics", + "@crate_index//:arc-swap", "@crate_index//:byte-unit", "@crate_index//:clap", "@crate_index//:futures", diff --git a/rs/https_outcalls/adapter/Cargo.toml b/rs/https_outcalls/adapter/Cargo.toml index 4de76bd7dce..536a7f951e5 100644 --- a/rs/https_outcalls/adapter/Cargo.toml +++ b/rs/https_outcalls/adapter/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +arc-swap = "1" byte-unit = "4.0.14" clap = { workspace = true } futures = { workspace = true } diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 40d58bd4fc9..8998e93bb53 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -4,6 +4,7 @@ use crate::metrics::{ LABEL_UPLOAD, LABEL_URL_PARSE, }; use crate::Config; +use arc_swap::ArcSwap; use core::convert::TryFrom; use http::{header::USER_AGENT, HeaderName, HeaderValue, Uri}; use http_body_util::{BodyExt, Full}; @@ -24,8 +25,10 @@ use ic_https_outcalls_service::{ use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; use std::str::FromStr; +use std::sync::Arc; use std::time::Duration; use tonic::{Request, Response, Status}; +use std::sync::atomic::{AtomicUsize, Ordering}; /// Hyper only supports a maximum of 32768 headers https://docs.rs/hyper/1.5.0/hyper/header/index.html /// and it panics if we try to allocate more headers. And since hyper sometimes grows the map by doubling the entries @@ -47,16 +50,55 @@ type OutboundRequestBody = Full; // TODO: consider making this private pub struct CanisterHttp { client: Client, OutboundRequestBody>, - socks_client: Client>, OutboundRequestBody>, + socks_clients: ArcSwap>, OutboundRequestBody>>>, + /// This should always be sorted. + /// This is a list of IPs that are SOCKS proxies. The IPs are used to check whether the socks_client need updating. + current_socks_ips: ArcSwap>, logger: ReplicaLogger, metrics: AdapterMetrics, + http_connect_timeout_secs: u64, + next_proxy_index: AtomicUsize, } impl CanisterHttp { - fn generate_socks_clients(&self, api_bn_ips: Vec) -> Vec>, OutboundRequestBody>> { - //TODO(mihailjianu): implement this. - return vec![]; + fn generate_socks_clients( + &self, + api_bn_ips: Vec, + ) -> Vec>, OutboundRequestBody>> { + let mut http_connector = HttpConnector::new(); + //TODO: mihailjianu: think about persisting the clients in a local cache + // to avoid recreating them on every request. + http_connector.enforce_http(false); + http_connector.set_connect_timeout(Some(Duration::from_secs( + self.http_connect_timeout_secs, + ))); + + let mut socks_clients = Vec::new(); + + for ip in api_bn_ips { + let proxy_addr = ip.parse().expect("Failed to parse SOCKS IP."); + + let proxy_connector = SocksConnector { + proxy_addr, + auth: None, + connector: http_connector.clone(), + }; + + let proxied_https_connector = HttpsConnectorBuilder::new() + .with_native_roots() + .expect("Failed to set native roots") + .https_only() + .enable_all_versions() + .wrap_connector(proxy_connector); + + let socks_client = Client::builder(TokioExecutor::new()) + .build::<_, Full>(proxied_https_connector); + + socks_clients.push(socks_client); + } + + socks_clients } pub fn new(config: Config, logger: ReplicaLogger, metrics: &MetricsRegistry) -> Self { @@ -65,24 +107,6 @@ impl CanisterHttp { http_connector.enforce_http(false); http_connector .set_connect_timeout(Some(Duration::from_secs(config.http_connect_timeout_secs))); - // The proxy connnector requires a the URL scheme to be specified. I.e socks5:// - // Config validity check ensures that url includes scheme, host and port. - // Therefore the parse 'Uri' will be in the correct format. I.e socks5://somehost.com:1080 - let proxy_connector = SocksConnector { - proxy_addr: config - .socks_proxy - .parse() - .expect("Failed to parse socks url."), - auth: None, - connector: http_connector.clone(), - }; - let proxied_https_connector = HttpsConnectorBuilder::new() - .with_native_roots() - .expect("Failed to set native roots") - .https_only() - .enable_all_versions() - .wrap_connector(proxy_connector); - // Https client setup. let builder = HttpsConnectorBuilder::new() .with_native_roots() @@ -95,19 +119,37 @@ impl CanisterHttp { let builder = builder.enable_all_versions(); let direct_https_connector = builder.wrap_connector(http_connector); - let socks_client = - Client::builder(TokioExecutor::new()).build::<_, Full>(proxied_https_connector); let client = Client::builder(TokioExecutor::new()) .http2_max_header_list_size(MAX_HEADER_LIST_SIZE) .build::<_, Full>(direct_https_connector); Self { client, - socks_client, + socks_clients: ArcSwap::new(Arc::new(vec![])), + current_socks_ips: ArcSwap::new(Arc::new(vec![])), logger, metrics: AdapterMetrics::new(metrics), + http_connect_timeout_secs: config.http_connect_timeout_secs, + next_proxy_index: AtomicUsize::new(0), } } + + fn update_socks_clients(&self, api_bn_ips: Vec) { + let new_clients = self.generate_socks_clients(api_bn_ips); + self.socks_clients.store(Arc::new(new_clients)); + } + + fn get_next_socks_client(&self) -> Option>, OutboundRequestBody>> { + let socks_clients = self.socks_clients.load(); + let socks_clients_ref = &*socks_clients; + + if socks_clients_ref.is_empty() { + return None; + } + + let index = self.next_proxy_index.fetch_add(1, Ordering::SeqCst); + Some(socks_clients_ref[index % socks_clients_ref.len()].clone()) + } } #[tonic::async_trait] @@ -120,9 +162,18 @@ impl HttpsOutcallsService for CanisterHttp { let req = request.into_inner(); - let api_bn_ips = req.api_bn_ips; + //TODO(mihailjianu): check if all this cloning is necessary + let mut sorted_incoming_ips = req.api_bn_ips.clone(); + sorted_incoming_ips.sort(); + sorted_incoming_ips.dedup(); + let cached_ips = self.current_socks_ips.load().clone(); + + // Check if incoming IPs differ from cached IPs + let needs_update = *cached_ips != sorted_incoming_ips; - let socks_clients = self.generate_socks_clients(api_bn_ips); + if needs_update { + self.update_socks_clients(sorted_incoming_ips); + } let uri = req.url.parse::().map_err(|err| { debug!(self.logger, "Failed to parse URL: {}", err); @@ -208,7 +259,14 @@ impl HttpsOutcallsService for CanisterHttp { // fail fast because our interface does not have an ipv4 assigned. Err(direct_err) => { self.metrics.requests_socks.inc(); - self.socks_client.request(http_req_clone).await.map_err(|e| { + let client = self.get_next_socks_client().ok_or_else(|| { + Status::new( + tonic::Code::Unavailable, + "No SOCKS proxy available".to_string(), + ) + })?; + //TODO(mihailjianu): consider retrying with a different proxy if the first one fails + client.request(http_req_clone).await.map_err(|e| { format!("Request failed direct connect {direct_err} and connect through socks {e}") }) } diff --git a/rs/https_outcalls/adapter/tests/server_test.rs b/rs/https_outcalls/adapter/tests/server_test.rs index b5e2b8ad066..1f570c19773 100644 --- a/rs/https_outcalls/adapter/tests/server_test.rs +++ b/rs/https_outcalls/adapter/tests/server_test.rs @@ -166,6 +166,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; let http_response = response.unwrap().into_inner(); @@ -192,6 +193,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; assert_eq!( @@ -224,6 +226,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; let http_response = response.unwrap().into_inner(); @@ -248,6 +251,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "420".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; @@ -274,6 +278,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; @@ -301,6 +306,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: format!("{}", response_limit + 1).as_bytes().to_vec(), max_response_size_bytes: response_limit, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; @@ -333,6 +339,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: format!("{}", response_size).as_bytes().to_vec(), max_response_size_bytes: response_size * 2, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; @@ -360,6 +367,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: format!("{}", delay).as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; @@ -396,6 +404,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 64, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; assert_eq!( @@ -435,6 +444,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".as_bytes().to_vec(), max_response_size_bytes: response_limit, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; @@ -460,6 +470,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; let _ = response.unwrap_err(); @@ -563,6 +574,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, + api_bn_ips: vec![], }); let response = client.https_outcall(request).await; From bce7d5437e464bc693ab53e1623b4698290434c2 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Tue, 19 Nov 2024 09:42:25 +0000 Subject: [PATCH 03/34] fixes --- rs/https_outcalls/adapter/src/rpc_server.rs | 6 ++++-- .../consensus/src/pool_manager.rs | 19 ++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 8998e93bb53..2721600596b 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -134,11 +134,13 @@ impl CanisterHttp { } } + // This happens extremely rarely, only when there are changes to the api boundary nodes. fn update_socks_clients(&self, api_bn_ips: Vec) { - let new_clients = self.generate_socks_clients(api_bn_ips); + let new_clients = self.generate_socks_clients(api_bn_ips.clone()); self.socks_clients.store(Arc::new(new_clients)); + self.current_socks_ips.store(Arc::new(api_bn_ips)); } - + fn get_next_socks_client(&self) -> Option>, OutboundRequestBody>> { let socks_clients = self.socks_clients.load(); let socks_clients_ref = &*socks_clients; diff --git a/rs/https_outcalls/consensus/src/pool_manager.rs b/rs/https_outcalls/consensus/src/pool_manager.rs index 632dc6af029..f2c62382b9b 100644 --- a/rs/https_outcalls/consensus/src/pool_manager.rs +++ b/rs/https_outcalls/consensus/src/pool_manager.rs @@ -184,11 +184,20 @@ impl CanisterHttpPoolManagerImpl { .collect(); //TODO(mihailjianu): handle errors. - let api_bn_ids = self.registry_client.get_api_boundary_node_ids(self.registry_client.get_latest_version()).unwrap(); - let api_bn_ips = api_bn_ids.iter().map(|id| { - let record = self.registry_client.get_node_record(*id, self.registry_client.get_latest_version()).unwrap(); - record.unwrap().http.unwrap().ip_addr - }).collect::>(); + let api_bn_ids = self + .registry_client + .get_api_boundary_node_ids(self.registry_client.get_latest_version()) + .unwrap(); + let api_bn_ips = api_bn_ids + .iter() + .map(|id| { + let record = self + .registry_client + .get_node_record(*id, self.registry_client.get_latest_version()) + .unwrap(); + record.unwrap().http.unwrap().ip_addr + }) + .collect::>(); for (id, context) in http_requests { if !request_ids_already_made.contains(&id) { From 2088183c7bb40fd716a262c22bd3d828cef219e3 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Tue, 19 Nov 2024 15:43:24 +0000 Subject: [PATCH 04/34] fix things --- rs/https_outcalls/adapter/src/rpc_server.rs | 109 +++++++++--------- .../consensus/src/pool_manager.rs | 53 ++++++--- rs/pocket_ic_server/src/pocket_ic.rs | 2 + rs/types/types/src/canister_http.rs | 3 +- 4 files changed, 97 insertions(+), 70 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 2721600596b..b6d604ae58b 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -25,10 +25,10 @@ use ic_https_outcalls_service::{ use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; use std::str::FromStr; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::time::Duration; use tonic::{Request, Response, Status}; -use std::sync::atomic::{AtomicUsize, Ordering}; /// Hyper only supports a maximum of 32768 headers https://docs.rs/hyper/1.5.0/hyper/header/index.html /// and it panics if we try to allocate more headers. And since hyper sometimes grows the map by doubling the entries @@ -50,7 +50,9 @@ type OutboundRequestBody = Full; // TODO: consider making this private pub struct CanisterHttp { client: Client, OutboundRequestBody>, - socks_clients: ArcSwap>, OutboundRequestBody>>>, + /// Cached socks clients. This is updated when the api boundary nodes change. + socks_clients: + ArcSwap>, OutboundRequestBody>>>, /// This should always be sorted. /// This is a list of IPs that are SOCKS proxies. The IPs are used to check whether the socks_client need updating. current_socks_ips: ArcSwap>, @@ -61,46 +63,6 @@ pub struct CanisterHttp { } impl CanisterHttp { - - fn generate_socks_clients( - &self, - api_bn_ips: Vec, - ) -> Vec>, OutboundRequestBody>> { - let mut http_connector = HttpConnector::new(); - //TODO: mihailjianu: think about persisting the clients in a local cache - // to avoid recreating them on every request. - http_connector.enforce_http(false); - http_connector.set_connect_timeout(Some(Duration::from_secs( - self.http_connect_timeout_secs, - ))); - - let mut socks_clients = Vec::new(); - - for ip in api_bn_ips { - let proxy_addr = ip.parse().expect("Failed to parse SOCKS IP."); - - let proxy_connector = SocksConnector { - proxy_addr, - auth: None, - connector: http_connector.clone(), - }; - - let proxied_https_connector = HttpsConnectorBuilder::new() - .with_native_roots() - .expect("Failed to set native roots") - .https_only() - .enable_all_versions() - .wrap_connector(proxy_connector); - - let socks_client = Client::builder(TokioExecutor::new()) - .build::<_, Full>(proxied_https_connector); - - socks_clients.push(socks_client); - } - - socks_clients - } - pub fn new(config: Config, logger: ReplicaLogger, metrics: &MetricsRegistry) -> Self { // Socks client setup let mut http_connector = HttpConnector::new(); @@ -134,23 +96,60 @@ impl CanisterHttp { } } + fn generate_socks_clients( + &self, + api_bn_ips: &Vec, + ) -> Vec>, OutboundRequestBody>> { + let mut http_connector = HttpConnector::new(); + http_connector.enforce_http(false); + http_connector + .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); + + let mut socks_clients = Vec::new(); + + for ip in api_bn_ips { + let proxy_addr = ip.parse().expect("Failed to parse SOCKS IP."); + + let proxy_connector = SocksConnector { + proxy_addr, + auth: None, + connector: http_connector.clone(), + }; + + let proxied_https_connector = HttpsConnectorBuilder::new() + .with_native_roots() + .expect("Failed to set native roots") + .https_only() + .enable_all_versions() + .wrap_connector(proxy_connector); + + let socks_client = Client::builder(TokioExecutor::new()) + .build::<_, Full>(proxied_https_connector); + + socks_clients.push(socks_client); + } + + socks_clients + } + // This happens extremely rarely, only when there are changes to the api boundary nodes. fn update_socks_clients(&self, api_bn_ips: Vec) { - let new_clients = self.generate_socks_clients(api_bn_ips.clone()); + let new_clients = self.generate_socks_clients(&api_bn_ips); self.socks_clients.store(Arc::new(new_clients)); self.current_socks_ips.store(Arc::new(api_bn_ips)); } - - fn get_next_socks_client(&self) -> Option>, OutboundRequestBody>> { - let socks_clients = self.socks_clients.load(); - let socks_clients_ref = &*socks_clients; - if socks_clients_ref.is_empty() { + fn get_next_socks_client( + &self, + ) -> Option>, OutboundRequestBody>> { + let socks_clients = self.socks_clients.load_full(); + + if socks_clients.is_empty() { return None; } let index = self.next_proxy_index.fetch_add(1, Ordering::SeqCst); - Some(socks_clients_ref[index % socks_clients_ref.len()].clone()) + Some(socks_clients[index % socks_clients.len()].clone()) } } @@ -164,16 +163,18 @@ impl HttpsOutcallsService for CanisterHttp { let req = request.into_inner(); - //TODO(mihailjianu): check if all this cloning is necessary - let mut sorted_incoming_ips = req.api_bn_ips.clone(); + let mut sorted_incoming_ips = req.api_bn_ips; sorted_incoming_ips.sort(); sorted_incoming_ips.dedup(); - let cached_ips = self.current_socks_ips.load().clone(); + let cached_ips = self.current_socks_ips.load_full(); // Check if incoming IPs differ from cached IPs - let needs_update = *cached_ips != sorted_incoming_ips; + // If the registry / consensus messes up (no ips present), we want to keep using the current cache for as long as possible. + let needs_update = !sorted_incoming_ips.is_empty() && *cached_ips != sorted_incoming_ips; if needs_update { + // Multiple threads could be updating the socks clients at the same time. + // This is fine because the update should be idempotent and cheap. self.update_socks_clients(sorted_incoming_ips); } @@ -267,7 +268,7 @@ impl HttpsOutcallsService for CanisterHttp { "No SOCKS proxy available".to_string(), ) })?; - //TODO(mihailjianu): consider retrying with a different proxy if the first one fails + //TODO: consider retrying with a different proxy if the first one fails client.request(http_req_clone).await.map_err(|e| { format!("Request failed direct connect {direct_err} and connect through socks {e}") }) diff --git a/rs/https_outcalls/consensus/src/pool_manager.rs b/rs/https_outcalls/consensus/src/pool_manager.rs index f2c62382b9b..e8a9dc99886 100644 --- a/rs/https_outcalls/consensus/src/pool_manager.rs +++ b/rs/https_outcalls/consensus/src/pool_manager.rs @@ -146,6 +146,43 @@ impl CanisterHttpPoolManagerImpl { .collect() } + fn generate_api_boundary_node_ips(&self) -> Vec { + let latest_registry_version = self.registry_client.get_latest_version(); + + self.registry_client + .get_api_boundary_node_ids(latest_registry_version) + .unwrap_or_else(|e| { + warn!(self.log, "Failed to get API boundary node IDs: {:?}", e); + Vec::new() + }) + .into_iter() + .filter_map(|id| { + self.registry_client + .get_node_record(id, latest_registry_version) + .map_err(|e| { + warn!( + self.log, + "Failed to get node record for node ID {:?}: {:?}", id, e + ); + }) + .ok() + .and_then(|opt_record| { + opt_record.or_else(|| { + warn!(self.log, "No node record found for node ID {:?}", id); + None + }) + }) + .and_then(|record| { + record.http.or_else(|| { + warn!(self.log, "HTTP information missing for node ID {:?}", id); + None + }) + }) + .map(|http_info| http_info.ip_addr) + }) + .collect::>() + } + /// Inform the HttpAdapterShim of any new requests that must be made. fn make_new_requests(&self, canister_http_pool: &dyn CanisterHttpPool) { let _time = self @@ -183,21 +220,7 @@ impl CanisterHttpPoolManagerImpl { .cloned() .collect(); - //TODO(mihailjianu): handle errors. - let api_bn_ids = self - .registry_client - .get_api_boundary_node_ids(self.registry_client.get_latest_version()) - .unwrap(); - let api_bn_ips = api_bn_ids - .iter() - .map(|id| { - let record = self - .registry_client - .get_node_record(*id, self.registry_client.get_latest_version()) - .unwrap(); - record.unwrap().http.unwrap().ip_addr - }) - .collect::>(); + let api_bn_ips = self.generate_api_boundary_node_ips(); for (id, context) in http_requests { if !request_ids_already_made.contains(&id) { diff --git a/rs/pocket_ic_server/src/pocket_ic.rs b/rs/pocket_ic_server/src/pocket_ic.rs index 75d2663793b..4eacb80a22e 100644 --- a/rs/pocket_ic_server/src/pocket_ic.rs +++ b/rs/pocket_ic_server/src/pocket_ic.rs @@ -1248,6 +1248,7 @@ impl Operation for ProcessCanisterHttpInternal { timeout: context.time + Duration::from_secs(5 * 60), id, context, + api_bn_ips: vec![], }) { canister_http.pending.insert(id); } @@ -1401,6 +1402,7 @@ fn process_mock_canister_https_response( timeout, id: canister_http_request_id, context: context.clone(), + api_bn_ips: vec![], }) .unwrap(); let response = loop { diff --git a/rs/types/types/src/canister_http.rs b/rs/types/types/src/canister_http.rs index feb24c0a7bc..11acf75f84a 100644 --- a/rs/types/types/src/canister_http.rs +++ b/rs/types/types/src/canister_http.rs @@ -457,7 +457,8 @@ pub struct CanisterHttpRequest { pub id: CanisterHttpRequestId, /// The context of the request which captures all the metadata about this request pub context: CanisterHttpRequestContext, - /// The api boundary nodes that should be used as a socks proxy in the case of a request to an IPv4 address. + /// The most up to date api boundary nodes that should be used as a socks proxy in the case of a request to an IPv4 address. + /// The adapter does not guarantee that the request will be sent through these nodes. pub api_bn_ips: Vec, } From 2116a1f7046bba7ee40bfa179036e4b054bd0cc0 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Tue, 19 Nov 2024 17:23:10 +0000 Subject: [PATCH 05/34] cache --- rs/https_outcalls/adapter/src/rpc_server.rs | 58 ++++++++------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index b6d604ae58b..e809e09ffcf 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -24,6 +24,7 @@ use ic_https_outcalls_service::{ }; use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; +use std::collections::BTreeMap; use std::str::FromStr; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -46,16 +47,14 @@ const MAX_HEADER_LIST_SIZE: u32 = 52 * 1024; type OutboundRequestBody = Full; +type Cache = + BTreeMap>, OutboundRequestBody>>; + /// Implements HttpsOutcallsService // TODO: consider making this private pub struct CanisterHttp { client: Client, OutboundRequestBody>, - /// Cached socks clients. This is updated when the api boundary nodes change. - socks_clients: - ArcSwap>, OutboundRequestBody>>>, - /// This should always be sorted. - /// This is a list of IPs that are SOCKS proxies. The IPs are used to check whether the socks_client need updating. - current_socks_ips: ArcSwap>, + cache: ArcSwap, logger: ReplicaLogger, metrics: AdapterMetrics, http_connect_timeout_secs: u64, @@ -87,8 +86,7 @@ impl CanisterHttp { Self { client, - socks_clients: ArcSwap::new(Arc::new(vec![])), - current_socks_ips: ArcSwap::new(Arc::new(vec![])), + cache: ArcSwap::new(Arc::new(BTreeMap::new())), logger, metrics: AdapterMetrics::new(metrics), http_connect_timeout_secs: config.http_connect_timeout_secs, @@ -96,17 +94,14 @@ impl CanisterHttp { } } - fn generate_socks_clients( - &self, - api_bn_ips: &Vec, - ) -> Vec>, OutboundRequestBody>> { + fn create_cache(&self, api_bn_ips: Vec) -> Cache { + let mut new_cache = BTreeMap::new(); + let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); http_connector .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); - let mut socks_clients = Vec::new(); - for ip in api_bn_ips { let proxy_addr = ip.parse().expect("Failed to parse SOCKS IP."); @@ -126,30 +121,21 @@ impl CanisterHttp { let socks_client = Client::builder(TokioExecutor::new()) .build::<_, Full>(proxied_https_connector); - socks_clients.push(socks_client); + new_cache.insert(ip.clone(), socks_client); } - - socks_clients - } - - // This happens extremely rarely, only when there are changes to the api boundary nodes. - fn update_socks_clients(&self, api_bn_ips: Vec) { - let new_clients = self.generate_socks_clients(&api_bn_ips); - self.socks_clients.store(Arc::new(new_clients)); - self.current_socks_ips.store(Arc::new(api_bn_ips)); + new_cache } fn get_next_socks_client( &self, + cache: &Cache, ) -> Option>, OutboundRequestBody>> { - let socks_clients = self.socks_clients.load_full(); - - if socks_clients.is_empty() { + if cache.is_empty() { return None; } let index = self.next_proxy_index.fetch_add(1, Ordering::SeqCst); - Some(socks_clients[index % socks_clients.len()].clone()) + Some(cache.values().nth(index % cache.len()).unwrap().clone()) } } @@ -166,16 +152,14 @@ impl HttpsOutcallsService for CanisterHttp { let mut sorted_incoming_ips = req.api_bn_ips; sorted_incoming_ips.sort(); sorted_incoming_ips.dedup(); - let cached_ips = self.current_socks_ips.load_full(); - // Check if incoming IPs differ from cached IPs - // If the registry / consensus messes up (no ips present), we want to keep using the current cache for as long as possible. - let needs_update = !sorted_incoming_ips.is_empty() && *cached_ips != sorted_incoming_ips; + let mut cache = self.cache.load_full(); + + let ordered_cached_ips = cache.keys().cloned().collect::>(); - if needs_update { - // Multiple threads could be updating the socks clients at the same time. - // This is fine because the update should be idempotent and cheap. - self.update_socks_clients(sorted_incoming_ips); + if !sorted_incoming_ips.is_empty() && ordered_cached_ips != sorted_incoming_ips { + cache = Arc::new(self.create_cache(sorted_incoming_ips)); + self.cache.store(cache.clone()); } let uri = req.url.parse::().map_err(|err| { @@ -262,7 +246,7 @@ impl HttpsOutcallsService for CanisterHttp { // fail fast because our interface does not have an ipv4 assigned. Err(direct_err) => { self.metrics.requests_socks.inc(); - let client = self.get_next_socks_client().ok_or_else(|| { + let client = self.get_next_socks_client(&cache).ok_or_else(|| { Status::new( tonic::Code::Unavailable, "No SOCKS proxy available".to_string(), From 0d4cb864f4219cf3eeedefa77c5e8a57bd1f574a Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Tue, 19 Nov 2024 17:29:16 +0000 Subject: [PATCH 06/34] comments --- rs/https_outcalls/adapter/src/rpc_server.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index e809e09ffcf..0d69a1d47f2 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -158,10 +158,13 @@ impl HttpsOutcallsService for CanisterHttp { let ordered_cached_ips = cache.keys().cloned().collect::>(); if !sorted_incoming_ips.is_empty() && ordered_cached_ips != sorted_incoming_ips { + // multiple threads can enter this block, but it's fine, as the whole cache is lightweight. cache = Arc::new(self.create_cache(sorted_incoming_ips)); self.cache.store(cache.clone()); } + // "cache" now points to BTreeMap with the IPs from the request. + let uri = req.url.parse::().map_err(|err| { debug!(self.logger, "Failed to parse URL: {}", err); self.metrics From 4e579808408166946cdf210a785aeab92b546def Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Tue, 19 Nov 2024 17:50:25 +0000 Subject: [PATCH 07/34] remove btreemap --- rs/https_outcalls/adapter/src/rpc_server.rs | 45 ++++++++++++++++----- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 0d69a1d47f2..a0f6c2db7c4 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -24,7 +24,6 @@ use ic_https_outcalls_service::{ }; use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; -use std::collections::BTreeMap; use std::str::FromStr; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -47,8 +46,36 @@ const MAX_HEADER_LIST_SIZE: u32 = 52 * 1024; type OutboundRequestBody = Full; -type Cache = - BTreeMap>, OutboundRequestBody>>; +struct Cache { + api_bn_ips: Vec, + clients: Vec>, OutboundRequestBody>>, +} + +impl Cache { + fn new() -> Self { + Self { + api_bn_ips: Vec::new(), + clients: Vec::new(), + } + } + + fn insert( + &mut self, + ip: String, + client: Client>, OutboundRequestBody>, + ) { + self.api_bn_ips.push(ip); + self.clients.push(client); + } + + fn is_empty(&self) -> bool { + self.clients.is_empty() + } + + fn len(&self) -> usize { + self.clients.len() + } +} /// Implements HttpsOutcallsService // TODO: consider making this private @@ -86,7 +113,7 @@ impl CanisterHttp { Self { client, - cache: ArcSwap::new(Arc::new(BTreeMap::new())), + cache: ArcSwap::new(Arc::new(Cache::new())), logger, metrics: AdapterMetrics::new(metrics), http_connect_timeout_secs: config.http_connect_timeout_secs, @@ -95,7 +122,7 @@ impl CanisterHttp { } fn create_cache(&self, api_bn_ips: Vec) -> Cache { - let mut new_cache = BTreeMap::new(); + let mut new_cache = Cache::new(); let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); @@ -135,7 +162,7 @@ impl CanisterHttp { } let index = self.next_proxy_index.fetch_add(1, Ordering::SeqCst); - Some(cache.values().nth(index % cache.len()).unwrap().clone()) + Some(cache.clients[index % cache.len()].clone()) } } @@ -155,15 +182,15 @@ impl HttpsOutcallsService for CanisterHttp { let mut cache = self.cache.load_full(); - let ordered_cached_ips = cache.keys().cloned().collect::>(); + let cached_ips = cache.api_bn_ips.clone(); - if !sorted_incoming_ips.is_empty() && ordered_cached_ips != sorted_incoming_ips { + if !sorted_incoming_ips.is_empty() && cached_ips != sorted_incoming_ips { // multiple threads can enter this block, but it's fine, as the whole cache is lightweight. cache = Arc::new(self.create_cache(sorted_incoming_ips)); self.cache.store(cache.clone()); } - // "cache" now points to BTreeMap with the IPs from the request. + // "cache" now points to Cache with the IPs from the request. let uri = req.url.parse::().map_err(|err| { debug!(self.logger, "Failed to parse URL: {}", err); From 1ada60daa52ab06c735bf910730e5073fa420c6c Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Tue, 19 Nov 2024 17:55:59 +0000 Subject: [PATCH 08/34] renamings --- rs/https_outcalls/adapter/src/rpc_server.rs | 24 ++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index a0f6c2db7c4..3583987e68c 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -48,14 +48,14 @@ type OutboundRequestBody = Full; struct Cache { api_bn_ips: Vec, - clients: Vec>, OutboundRequestBody>>, + socks_clients: Vec>, OutboundRequestBody>>, } impl Cache { fn new() -> Self { Self { api_bn_ips: Vec::new(), - clients: Vec::new(), + socks_clients: Vec::new(), } } @@ -65,15 +65,15 @@ impl Cache { client: Client>, OutboundRequestBody>, ) { self.api_bn_ips.push(ip); - self.clients.push(client); + self.socks_clients.push(client); } fn is_empty(&self) -> bool { - self.clients.is_empty() + self.socks_clients.is_empty() } fn len(&self) -> usize { - self.clients.len() + self.socks_clients.len() } } @@ -162,7 +162,7 @@ impl CanisterHttp { } let index = self.next_proxy_index.fetch_add(1, Ordering::SeqCst); - Some(cache.clients[index % cache.len()].clone()) + Some(cache.socks_clients[index % cache.len()].clone()) } } @@ -180,17 +180,17 @@ impl HttpsOutcallsService for CanisterHttp { sorted_incoming_ips.sort(); sorted_incoming_ips.dedup(); - let mut cache = self.cache.load_full(); + let mut current_cache = self.cache.load_full(); - let cached_ips = cache.api_bn_ips.clone(); + let cached_ips = current_cache.api_bn_ips.clone(); if !sorted_incoming_ips.is_empty() && cached_ips != sorted_incoming_ips { // multiple threads can enter this block, but it's fine, as the whole cache is lightweight. - cache = Arc::new(self.create_cache(sorted_incoming_ips)); - self.cache.store(cache.clone()); + current_cache = Arc::new(self.create_cache(sorted_incoming_ips)); + self.cache.store(current_cache.clone()); } - // "cache" now points to Cache with the IPs from the request. + // "current_cache" now points to the Cache with the IPs from the request. let uri = req.url.parse::().map_err(|err| { debug!(self.logger, "Failed to parse URL: {}", err); @@ -276,7 +276,7 @@ impl HttpsOutcallsService for CanisterHttp { // fail fast because our interface does not have an ipv4 assigned. Err(direct_err) => { self.metrics.requests_socks.inc(); - let client = self.get_next_socks_client(&cache).ok_or_else(|| { + let client = self.get_next_socks_client(¤t_cache).ok_or_else(|| { Status::new( tonic::Code::Unavailable, "No SOCKS proxy available".to_string(), From 6cc0bc6350881e66e68906439ca4bbd30fb1aa4c Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 20 Nov 2024 09:42:50 +0000 Subject: [PATCH 09/34] . --- rs/https_outcalls/adapter/src/rpc_server.rs | 139 ++++++++++---------- rs/types/types/src/canister_http.rs | 1 - 2 files changed, 71 insertions(+), 69 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 3583987e68c..b3f050c7630 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -46,37 +46,12 @@ const MAX_HEADER_LIST_SIZE: u32 = 52 * 1024; type OutboundRequestBody = Full; +#[derive(Default)] struct Cache { api_bn_ips: Vec, socks_clients: Vec>, OutboundRequestBody>>, } -impl Cache { - fn new() -> Self { - Self { - api_bn_ips: Vec::new(), - socks_clients: Vec::new(), - } - } - - fn insert( - &mut self, - ip: String, - client: Client>, OutboundRequestBody>, - ) { - self.api_bn_ips.push(ip); - self.socks_clients.push(client); - } - - fn is_empty(&self) -> bool { - self.socks_clients.is_empty() - } - - fn len(&self) -> usize { - self.socks_clients.len() - } -} - /// Implements HttpsOutcallsService // TODO: consider making this private pub struct CanisterHttp { @@ -113,7 +88,7 @@ impl CanisterHttp { Self { client, - cache: ArcSwap::new(Arc::new(Cache::new())), + cache: ArcSwap::new(Arc::new(Cache::default())), logger, metrics: AdapterMetrics::new(metrics), http_connect_timeout_secs: config.http_connect_timeout_secs, @@ -121,8 +96,20 @@ impl CanisterHttp { } } + // Round robin over the available clients, starting from the next index. + fn socks_clients_iter( + &self, + cache: &Cache, + ) -> impl Iterator>, OutboundRequestBody>> + { + let len = cache.socks_clients.len(); + let start_index = self.next_proxy_index.fetch_add(1, Ordering::SeqCst) % len; + let clients = cache.socks_clients.clone(); + clients.into_iter().cycle().skip(start_index).take(len) + } + fn create_cache(&self, api_bn_ips: Vec) -> Cache { - let mut new_cache = Cache::new(); + let mut new_cache = Cache::default(); let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); @@ -130,40 +117,34 @@ impl CanisterHttp { .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); for ip in api_bn_ips { - let proxy_addr = ip.parse().expect("Failed to parse SOCKS IP."); - - let proxy_connector = SocksConnector { - proxy_addr, - auth: None, - connector: http_connector.clone(), - }; - - let proxied_https_connector = HttpsConnectorBuilder::new() - .with_native_roots() - .expect("Failed to set native roots") - .https_only() - .enable_all_versions() - .wrap_connector(proxy_connector); - - let socks_client = Client::builder(TokioExecutor::new()) - .build::<_, Full>(proxied_https_connector); - - new_cache.insert(ip.clone(), socks_client); + match ip.parse() { + Ok(proxy_addr) => { + let proxy_connector = SocksConnector { + proxy_addr, + auth: None, + connector: http_connector.clone(), + }; + + let proxied_https_connector = HttpsConnectorBuilder::new() + .with_native_roots() + .expect("Failed to set native roots") + .https_only() + .enable_all_versions() + .wrap_connector(proxy_connector); + + let socks_client = Client::builder(TokioExecutor::new()) + .build::<_, Full>(proxied_https_connector); + + new_cache.api_bn_ips.push(ip); + new_cache.socks_clients.push(socks_client); + } + Err(e) => { + debug!(self.logger, "Failed to parse SOCKS IP: {}", e); + } + } } new_cache } - - fn get_next_socks_client( - &self, - cache: &Cache, - ) -> Option>, OutboundRequestBody>> { - if cache.is_empty() { - return None; - } - - let index = self.next_proxy_index.fetch_add(1, Ordering::SeqCst); - Some(cache.socks_clients[index % cache.len()].clone()) - } } #[tonic::async_trait] @@ -184,8 +165,9 @@ impl HttpsOutcallsService for CanisterHttp { let cached_ips = current_cache.api_bn_ips.clone(); - if !sorted_incoming_ips.is_empty() && cached_ips != sorted_incoming_ips { - // multiple threads can enter this block, but it's fine, as the whole cache is lightweight. + if cached_ips != sorted_incoming_ips { + // Cache miss. We need to update the cache and make sure that current_cache points to the IPs in the request. + // Multiple threads can enter this block, but it's fine, as the whole cache is lightweight. current_cache = Arc::new(self.create_cache(sorted_incoming_ips)); self.cache.store(current_cache.clone()); } @@ -276,15 +258,36 @@ impl HttpsOutcallsService for CanisterHttp { // fail fast because our interface does not have an ipv4 assigned. Err(direct_err) => { self.metrics.requests_socks.inc(); - let client = self.get_next_socks_client(¤t_cache).ok_or_else(|| { - Status::new( + + let clients_iter = self.socks_clients_iter(¤t_cache); + + let mut response = None; + + if current_cache.socks_clients.is_empty() { + return Err(Status::new( tonic::Code::Unavailable, "No SOCKS proxy available".to_string(), - ) - })?; - //TODO: consider retrying with a different proxy if the first one fails - client.request(http_req_clone).await.map_err(|e| { - format!("Request failed direct connect {direct_err} and connect through socks {e}") + )); + } + + for client in clients_iter { + let http_req = http_req_clone.clone(); + match client.request(http_req).await { + Ok(resp) => { + response = Some(resp); + break; + } + Err(e) => { + debug!(self.logger, "Failed to connect through SOCKS: {}", e); + //TODO(mihailjiau1): add some metrics. + continue; + } + } + } + + //TODO(mihailjianu1): bubble up the errors from the socks proxy. + response.ok_or_else(|| { + format!("Request failed direct connect {direct_err} and connect through all socks proxies") }) } Ok(resp)=> Ok(resp), diff --git a/rs/types/types/src/canister_http.rs b/rs/types/types/src/canister_http.rs index 11acf75f84a..275bf14ac05 100644 --- a/rs/types/types/src/canister_http.rs +++ b/rs/types/types/src/canister_http.rs @@ -458,7 +458,6 @@ pub struct CanisterHttpRequest { /// The context of the request which captures all the metadata about this request pub context: CanisterHttpRequestContext, /// The most up to date api boundary nodes that should be used as a socks proxy in the case of a request to an IPv4 address. - /// The adapter does not guarantee that the request will be sent through these nodes. pub api_bn_ips: Vec, } From 66f24464922c35e19217ec261ac73b380907e1ef Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 20 Nov 2024 11:26:19 +0000 Subject: [PATCH 10/34] mutex --- rs/https_outcalls/adapter/src/rpc_server.rs | 112 +++++++++----------- 1 file changed, 50 insertions(+), 62 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index b3f050c7630..4fd688ed29b 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -4,7 +4,6 @@ use crate::metrics::{ LABEL_UPLOAD, LABEL_URL_PARSE, }; use crate::Config; -use arc_swap::ArcSwap; use core::convert::TryFrom; use http::{header::USER_AGENT, HeaderName, HeaderValue, Uri}; use http_body_util::{BodyExt, Full}; @@ -24,6 +23,7 @@ use ic_https_outcalls_service::{ }; use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; +use std::collections::BTreeMap; use std::str::FromStr; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -46,17 +46,14 @@ const MAX_HEADER_LIST_SIZE: u32 = 52 * 1024; type OutboundRequestBody = Full; -#[derive(Default)] -struct Cache { - api_bn_ips: Vec, - socks_clients: Vec>, OutboundRequestBody>>, -} +type Cache = + BTreeMap>, OutboundRequestBody>>; + +use std::sync::Mutex; -/// Implements HttpsOutcallsService -// TODO: consider making this private pub struct CanisterHttp { client: Client, OutboundRequestBody>, - cache: ArcSwap, + cache: Arc>, logger: ReplicaLogger, metrics: AdapterMetrics, http_connect_timeout_secs: u64, @@ -88,7 +85,7 @@ impl CanisterHttp { Self { client, - cache: ArcSwap::new(Arc::new(Cache::default())), + cache: Arc::new(Mutex::new(BTreeMap::new())), logger, metrics: AdapterMetrics::new(metrics), http_connect_timeout_secs: config.http_connect_timeout_secs, @@ -96,20 +93,8 @@ impl CanisterHttp { } } - // Round robin over the available clients, starting from the next index. - fn socks_clients_iter( - &self, - cache: &Cache, - ) -> impl Iterator>, OutboundRequestBody>> - { - let len = cache.socks_clients.len(); - let start_index = self.next_proxy_index.fetch_add(1, Ordering::SeqCst) % len; - let clients = cache.socks_clients.clone(); - clients.into_iter().cycle().skip(start_index).take(len) - } - - fn create_cache(&self, api_bn_ips: Vec) -> Cache { - let mut new_cache = Cache::default(); + fn create_cache(&self, api_bn_ips: &[String]) -> Cache { + let mut new_cache = Cache::new(); let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); @@ -135,8 +120,7 @@ impl CanisterHttp { let socks_client = Client::builder(TokioExecutor::new()) .build::<_, Full>(proxied_https_connector); - new_cache.api_bn_ips.push(ip); - new_cache.socks_clients.push(socks_client); + new_cache.insert(ip.clone(), socks_client); } Err(e) => { debug!(self.logger, "Failed to parse SOCKS IP: {}", e); @@ -161,19 +145,22 @@ impl HttpsOutcallsService for CanisterHttp { sorted_incoming_ips.sort(); sorted_incoming_ips.dedup(); - let mut current_cache = self.cache.load_full(); - - let cached_ips = current_cache.api_bn_ips.clone(); + // Lock the cache and clone the relevant data + let clients = { + let mut cache_guard = self.cache.lock().unwrap(); - if cached_ips != sorted_incoming_ips { - // Cache miss. We need to update the cache and make sure that current_cache points to the IPs in the request. - // Multiple threads can enter this block, but it's fine, as the whole cache is lightweight. - current_cache = Arc::new(self.create_cache(sorted_incoming_ips)); - self.cache.store(current_cache.clone()); - } + // Check if the cache needs to be updated + let cached_ips: Vec = cache_guard.keys().cloned().collect(); + if cached_ips != sorted_incoming_ips { + // Update the cache + *cache_guard = self.create_cache(&sorted_incoming_ips); + } - // "current_cache" now points to the Cache with the IPs from the request. + // Clone the clients to avoid holding the lock during async operations + cache_guard.values().cloned().collect::>() + }; + // Proceed with the rest of the method using `clients` let uri = req.url.parse::().map_err(|err| { debug!(self.logger, "Failed to parse URL: {}", err); self.metrics @@ -190,7 +177,7 @@ impl HttpsOutcallsService for CanisterHttp { if uri.scheme() != Some(&http::uri::Scheme::HTTPS) { use crate::metrics::LABEL_HTTP_SCHEME; debug!( - self.logger, + self.logger, "Got request with no or http scheme specified. {}", uri ); self.metrics @@ -199,7 +186,7 @@ impl HttpsOutcallsService for CanisterHttp { .inc(); return Err(Status::new( tonic::Code::InvalidArgument, - "Url need to specify https scheme", + "URL needs to specify HTTPS scheme", )); } @@ -226,7 +213,7 @@ impl HttpsOutcallsService for CanisterHttp { } })?; - // Build Http Request. + // Build HTTP Request let mut headers = validate_headers(req.headers).inspect_err(|_| { self.metrics .request_errors @@ -234,7 +221,7 @@ impl HttpsOutcallsService for CanisterHttp { .inc(); })?; - // Add user-agent header if not present. + // Add user-agent header if not present add_fallback_user_agent_header(&mut headers); let mut request_size = req.body.len(); @@ -243,33 +230,31 @@ impl HttpsOutcallsService for CanisterHttp { .map(|(name, value)| name.as_str().len() + value.len()) .sum::(); - // If we are allowed to use socks and condition described in `should_use_socks_proxy` hold, - // we do the requests through the socks proxy. If not we use the default IPv6 route. + // Determine if we should use the SOCKS proxy let http_resp = if req.socks_proxy_allowed { - // Http request does not implement clone. So we have to manually construct a clone. let mut http_req = hyper::Request::new(Full::new(Bytes::from(req.body))); - *http_req.headers_mut() = headers; - *http_req.method_mut() = method; + *http_req.headers_mut() = headers.clone(); + *http_req.method_mut() = method.clone(); *http_req.uri_mut() = uri.clone(); let http_req_clone = http_req.clone(); match self.client.request(http_req).await { - // If we fail we try with the socks proxy. For destinations that are ipv4 only this should - // fail fast because our interface does not have an ipv4 assigned. Err(direct_err) => { self.metrics.requests_socks.inc(); - let clients_iter = self.socks_clients_iter(¤t_cache); - - let mut response = None; - - if current_cache.socks_clients.is_empty() { + let len = clients.len(); + if len == 0 { return Err(Status::new( tonic::Code::Unavailable, "No SOCKS proxy available".to_string(), )); } + let start_index = self.next_proxy_index.fetch_add(1, Ordering::SeqCst) % len; + let clients_iter = clients.into_iter().cycle().skip(start_index).take(len); + + let mut response = None; + for client in clients_iter { let http_req = http_req_clone.clone(); match client.request(http_req).await { @@ -279,25 +264,28 @@ impl HttpsOutcallsService for CanisterHttp { } Err(e) => { debug!(self.logger, "Failed to connect through SOCKS: {}", e); - //TODO(mihailjiau1): add some metrics. continue; } } } - //TODO(mihailjianu1): bubble up the errors from the socks proxy. response.ok_or_else(|| { - format!("Request failed direct connect {direct_err} and connect through all socks proxies") + format!( + "Request failed direct connect {direct_err} and connect through all SOCKS proxies" + ) }) } - Ok(resp)=> Ok(resp), + Ok(resp) => Ok(resp), } } else { let mut http_req = hyper::Request::new(Full::new(Bytes::from(req.body))); *http_req.headers_mut() = headers; *http_req.method_mut() = method; *http_req.uri_mut() = uri.clone(); - self.client.request(http_req).await.map_err(|e| format!("Failed to directly connect: {:?}", e)) + self.client + .request(http_req) + .await + .map_err(|e| format!("Failed to directly connect: {:?}", e)) } .map_err(|err| { debug!(self.logger, "Failed to connect: {}", err); @@ -314,6 +302,7 @@ impl HttpsOutcallsService for CanisterHttp { ), ) })?; + self.metrics .network_traffic .with_label_values(&[LABEL_UPLOAD]) @@ -321,15 +310,13 @@ impl HttpsOutcallsService for CanisterHttp { let status = http_resp.status().as_u16() as u32; - // Parse received headers. + // Parse received headers let mut headers_size_bytes = 0; let headers = http_resp .headers() .iter() .map(|(k, v)| { let name = k.to_string(); - // Use the header value in bytes for the size. - // It is possible that bytes.len() > str.len(). headers_size_bytes += name.len() + v.len(); let value = v.to_str()?.to_string(); Ok(HttpHeader { name, value }) @@ -347,7 +334,7 @@ impl HttpsOutcallsService for CanisterHttp { ) })?; - // We don't need a timeout here because there is a global timeout on the entire request. + // Collect the body with a size limit let body_bytes = http_body_util::Limited::new( http_resp.into_body(), req.max_response_size_bytes @@ -378,7 +365,7 @@ impl HttpsOutcallsService for CanisterHttp { Status::new( tonic::Code::OutOfRange, format!( - "Http body exceeds size limit of {} bytes.", + "HTTP body exceeds size limit of {} bytes.", req.max_response_size_bytes ), ) @@ -388,6 +375,7 @@ impl HttpsOutcallsService for CanisterHttp { .network_traffic .with_label_values(&[LABEL_DOWNLOAD]) .inc_by(body_bytes.len() as u64 + headers_size_bytes as u64); + Ok(Response::new(HttpsOutcallResponse { status, headers, From f28f4d4762eeb641e7ea5c6c7becfb945391317b Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 20 Nov 2024 11:33:49 +0000 Subject: [PATCH 11/34] fix --- rs/https_outcalls/adapter/src/rpc_server.rs | 34 ++++++++++++--------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 4fd688ed29b..4bb8eab5fa3 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -93,7 +93,7 @@ impl CanisterHttp { } } - fn create_cache(&self, api_bn_ips: &[String]) -> Cache { + fn create_cache(&self, api_bn_ips: Vec) -> Cache { let mut new_cache = Cache::new(); let mut http_connector = HttpConnector::new(); @@ -120,9 +120,11 @@ impl CanisterHttp { let socks_client = Client::builder(TokioExecutor::new()) .build::<_, Full>(proxied_https_connector); - new_cache.insert(ip.clone(), socks_client); + new_cache.insert(ip, socks_client); } Err(e) => { + // TODO(mihailjianu): this might invalidate the cache very often + // We should consider storing two vectors (one for IPs, one for clients). debug!(self.logger, "Failed to parse SOCKS IP: {}", e); } } @@ -153,14 +155,14 @@ impl HttpsOutcallsService for CanisterHttp { let cached_ips: Vec = cache_guard.keys().cloned().collect(); if cached_ips != sorted_incoming_ips { // Update the cache - *cache_guard = self.create_cache(&sorted_incoming_ips); + *cache_guard = self.create_cache(sorted_incoming_ips); } // Clone the clients to avoid holding the lock during async operations cache_guard.values().cloned().collect::>() }; - // Proceed with the rest of the method using `clients` + // "clients" now contains the clients we need to use for this request let uri = req.url.parse::().map_err(|err| { debug!(self.logger, "Failed to parse URL: {}", err); self.metrics @@ -186,7 +188,7 @@ impl HttpsOutcallsService for CanisterHttp { .inc(); return Err(Status::new( tonic::Code::InvalidArgument, - "URL needs to specify HTTPS scheme", + "Url need to specify https scheme", )); } @@ -213,7 +215,7 @@ impl HttpsOutcallsService for CanisterHttp { } })?; - // Build HTTP Request + // Build Http Request. let mut headers = validate_headers(req.headers).inspect_err(|_| { self.metrics .request_errors @@ -221,7 +223,7 @@ impl HttpsOutcallsService for CanisterHttp { .inc(); })?; - // Add user-agent header if not present + // Add user-agent header if not present. add_fallback_user_agent_header(&mut headers); let mut request_size = req.body.len(); @@ -230,11 +232,13 @@ impl HttpsOutcallsService for CanisterHttp { .map(|(name, value)| name.as_str().len() + value.len()) .sum::(); - // Determine if we should use the SOCKS proxy + // If we are allowed to use socks and condition described in `should_use_socks_proxy` hold, + // we do the requests through the socks proxy. If not we use the default IPv6 route. let http_resp = if req.socks_proxy_allowed { + // Http request does not implement clone. So we have to manually construct a clone. let mut http_req = hyper::Request::new(Full::new(Bytes::from(req.body))); - *http_req.headers_mut() = headers.clone(); - *http_req.method_mut() = method.clone(); + *http_req.headers_mut() = headers; + *http_req.method_mut() = method; *http_req.uri_mut() = uri.clone(); let http_req_clone = http_req.clone(); @@ -302,7 +306,6 @@ impl HttpsOutcallsService for CanisterHttp { ), ) })?; - self.metrics .network_traffic .with_label_values(&[LABEL_UPLOAD]) @@ -310,13 +313,15 @@ impl HttpsOutcallsService for CanisterHttp { let status = http_resp.status().as_u16() as u32; - // Parse received headers + // Parse received headers. let mut headers_size_bytes = 0; let headers = http_resp .headers() .iter() .map(|(k, v)| { let name = k.to_string(); + // Use the header value in bytes for the size. + // It is possible that bytes.len() > str.len(). headers_size_bytes += name.len() + v.len(); let value = v.to_str()?.to_string(); Ok(HttpHeader { name, value }) @@ -334,7 +339,7 @@ impl HttpsOutcallsService for CanisterHttp { ) })?; - // Collect the body with a size limit + // We don't need a timeout here because there is a global timeout on the entire request. let body_bytes = http_body_util::Limited::new( http_resp.into_body(), req.max_response_size_bytes @@ -365,7 +370,7 @@ impl HttpsOutcallsService for CanisterHttp { Status::new( tonic::Code::OutOfRange, format!( - "HTTP body exceeds size limit of {} bytes.", + "Http body exceeds size limit of {} bytes.", req.max_response_size_bytes ), ) @@ -375,7 +380,6 @@ impl HttpsOutcallsService for CanisterHttp { .network_traffic .with_label_values(&[LABEL_DOWNLOAD]) .inc_by(body_bytes.len() as u64 + headers_size_bytes as u64); - Ok(Response::new(HttpsOutcallResponse { status, headers, From ae1469a8ff18b09bbf1fe20538381893951358c1 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Thu, 21 Nov 2024 09:58:27 +0000 Subject: [PATCH 12/34] mutex, retry --- rs/https_outcalls/adapter/BUILD.bazel | 2 +- rs/https_outcalls/adapter/Cargo.toml | 2 +- rs/https_outcalls/adapter/src/rpc_server.rs | 140 ++++++++++---------- 3 files changed, 69 insertions(+), 75 deletions(-) diff --git a/rs/https_outcalls/adapter/BUILD.bazel b/rs/https_outcalls/adapter/BUILD.bazel index dba7dd07f85..f45fa5981d1 100644 --- a/rs/https_outcalls/adapter/BUILD.bazel +++ b/rs/https_outcalls/adapter/BUILD.bazel @@ -20,6 +20,7 @@ DEPENDENCIES = [ "@crate_index//:hyper-socks2", "@crate_index//:hyper-util", "@crate_index//:prometheus", + "@crate_index//:rand", "@crate_index//:serde", "@crate_index//:serde_json", "@crate_index//:slog", @@ -36,7 +37,6 @@ DEV_DEPENDENCIES = [ "@crate_index//:async-stream", "@crate_index//:bytes", "@crate_index//:once_cell", - "@crate_index//:rand", "@crate_index//:rstest", "@crate_index//:rustls", "@crate_index//:rustls-pemfile", diff --git a/rs/https_outcalls/adapter/Cargo.toml b/rs/https_outcalls/adapter/Cargo.toml index 536a7f951e5..e5c189d2156 100644 --- a/rs/https_outcalls/adapter/Cargo.toml +++ b/rs/https_outcalls/adapter/Cargo.toml @@ -22,6 +22,7 @@ ic-https-outcalls-service = { path = "../service" } ic-logger = { path = "../../monitoring/logger" } ic-metrics = { path = "../../monitoring/metrics" } prometheus = { workspace = true } +rand = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } slog = { workspace = true } @@ -34,7 +35,6 @@ tower = { workspace = true } async-stream = { workspace = true } bytes = { workspace = true } once_cell = "1.13.1" -rand = { workspace = true } rustls = { workspace = true } rustls-pemfile = "2.1.2" rstest = { workspace = true } diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 4bb8eab5fa3..5a3be7f829f 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -23,9 +23,9 @@ use ic_https_outcalls_service::{ }; use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; +use rand::{seq::SliceRandom, thread_rng}; use std::collections::BTreeMap; use std::str::FromStr; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::time::Duration; use tonic::{Request, Response, Status}; @@ -57,7 +57,6 @@ pub struct CanisterHttp { logger: ReplicaLogger, metrics: AdapterMetrics, http_connect_timeout_secs: u64, - next_proxy_index: AtomicUsize, } impl CanisterHttp { @@ -89,47 +88,44 @@ impl CanisterHttp { logger, metrics: AdapterMetrics::new(metrics), http_connect_timeout_secs: config.http_connect_timeout_secs, - next_proxy_index: AtomicUsize::new(0), } } - fn create_cache(&self, api_bn_ips: Vec) -> Cache { - let mut new_cache = Cache::new(); - + fn create_socks_client_for_ip( + &self, + ip: &str, + ) -> Option>, OutboundRequestBody>> { + // Create a new HTTP connector let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); http_connector .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); - for ip in api_bn_ips { - match ip.parse() { - Ok(proxy_addr) => { - let proxy_connector = SocksConnector { - proxy_addr, - auth: None, - connector: http_connector.clone(), - }; - - let proxied_https_connector = HttpsConnectorBuilder::new() - .with_native_roots() - .expect("Failed to set native roots") - .https_only() - .enable_all_versions() - .wrap_connector(proxy_connector); - - let socks_client = Client::builder(TokioExecutor::new()) - .build::<_, Full>(proxied_https_connector); - - new_cache.insert(ip, socks_client); - } - Err(e) => { - // TODO(mihailjianu): this might invalidate the cache very often - // We should consider storing two vectors (one for IPs, one for clients). - debug!(self.logger, "Failed to parse SOCKS IP: {}", e); - } + match ip.parse() { + Ok(proxy_addr) => { + let proxy_connector = SocksConnector { + proxy_addr, + auth: None, + connector: http_connector, + }; + + let proxied_https_connector = HttpsConnectorBuilder::new() + .with_native_roots() + .expect("Failed to set native roots") + .https_only() + .enable_all_versions() + .wrap_connector(proxy_connector); + + let socks_client = Client::builder(TokioExecutor::new()) + .build::<_, Full>(proxied_https_connector); + + Some(socks_client) + } + Err(e) => { + debug!(self.logger, "Failed to parse SOCKS IP: {}", e); + None } } - new_cache } } @@ -143,25 +139,6 @@ impl HttpsOutcallsService for CanisterHttp { let req = request.into_inner(); - let mut sorted_incoming_ips = req.api_bn_ips; - sorted_incoming_ips.sort(); - sorted_incoming_ips.dedup(); - - // Lock the cache and clone the relevant data - let clients = { - let mut cache_guard = self.cache.lock().unwrap(); - - // Check if the cache needs to be updated - let cached_ips: Vec = cache_guard.keys().cloned().collect(); - if cached_ips != sorted_incoming_ips { - // Update the cache - *cache_guard = self.create_cache(sorted_incoming_ips); - } - - // Clone the clients to avoid holding the lock during async operations - cache_guard.values().cloned().collect::>() - }; - // "clients" now contains the clients we need to use for this request let uri = req.url.parse::().map_err(|err| { debug!(self.logger, "Failed to parse URL: {}", err); @@ -179,7 +156,7 @@ impl HttpsOutcallsService for CanisterHttp { if uri.scheme() != Some(&http::uri::Scheme::HTTPS) { use crate::metrics::LABEL_HTTP_SCHEME; debug!( - self.logger, + self.logger, "Got request with no or http scheme specified. {}", uri ); self.metrics @@ -244,39 +221,56 @@ impl HttpsOutcallsService for CanisterHttp { match self.client.request(http_req).await { Err(direct_err) => { + // Try to proxy the request through SOCKS self.metrics.requests_socks.inc(); - let len = clients.len(); - if len == 0 { - return Err(Status::new( - tonic::Code::Unavailable, - "No SOCKS proxy available".to_string(), - )); - } - - let start_index = self.next_proxy_index.fetch_add(1, Ordering::SeqCst) % len; - let clients_iter = clients.into_iter().cycle().skip(start_index).take(len); + let mut api_bn_ips = req.api_bn_ips; + api_bn_ips.shuffle(&mut thread_rng()); let mut response = None; - for client in clients_iter { - let http_req = http_req_clone.clone(); - match client.request(http_req).await { + // We try all the IPs only once in random order until we get a response + for api_bn_ip in api_bn_ips { + let next_socks_proxy_ip = api_bn_ip.clone(); + + let socks_client = { + let mut cache_guard = self.cache.lock().unwrap(); + + // Check if the client already exists in the cache + if let Some(client) = cache_guard.get(&next_socks_proxy_ip) { + client.clone() + } else { + // Create a new client and insert it into the cache + match self.create_socks_client_for_ip(&next_socks_proxy_ip) { + Some(client) => { + cache_guard.insert(next_socks_proxy_ip.clone(), client.clone()); + client + } + None => { + debug!(self.logger, "Failed to create SOCKS client for IP {}", next_socks_proxy_ip); + //TODO(mihailjianu): add some metrics + continue; + } + } + } + }; + + match socks_client.request(http_req_clone.clone()).await.map_err(|e| { + format!("Request failed direct connect {direct_err} and connect through socks {e}") + }) { Ok(resp) => { response = Some(resp); break; } - Err(e) => { - debug!(self.logger, "Failed to connect through SOCKS: {}", e); - continue; + Err(socks_err) => { + debug!(self.logger, "Failed to connect through SOCKS with IP {}: {}", next_socks_proxy_ip, socks_err); + //TODO(mihailjianu): add some metrics } } } - response.ok_or_else(|| { - format!( - "Request failed direct connect {direct_err} and connect through all SOCKS proxies" - ) + debug!(self.logger, "Failed to connect through SOCKS with all IPs"); + "Failed to connect through SOCKS with all IPs".to_string() }) } Ok(resp) => Ok(resp), From 91bafd8738a9018a4d41a6e95ba51eff72dd25fd Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Fri, 22 Nov 2024 10:36:15 +0000 Subject: [PATCH 13/34] parking_lot --- Cargo.lock | 1 + rs/https_outcalls/adapter/Cargo.toml | 2 ++ rs/https_outcalls/adapter/src/rpc_server.rs | 10 +++++----- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5669217246..fc10252118a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8548,6 +8548,7 @@ dependencies = [ "ic-logger", "ic-metrics", "once_cell", + "parking_lot 0.12.3", "prometheus", "rand 0.8.5", "rstest", diff --git a/rs/https_outcalls/adapter/Cargo.toml b/rs/https_outcalls/adapter/Cargo.toml index e5c189d2156..c307b948dd6 100644 --- a/rs/https_outcalls/adapter/Cargo.toml +++ b/rs/https_outcalls/adapter/Cargo.toml @@ -21,6 +21,7 @@ ic-config = { path = "../../config" } ic-https-outcalls-service = { path = "../service" } ic-logger = { path = "../../monitoring/logger" } ic-metrics = { path = "../../monitoring/metrics" } +parking_lot = { workspace = true } prometheus = { workspace = true } rand = { workspace = true } serde = { workspace = true } @@ -31,6 +32,7 @@ tokio = { workspace = true } tonic = { workspace = true } tower = { workspace = true } + [dev-dependencies] async-stream = { workspace = true } bytes = { workspace = true } diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 5a3be7f829f..8247f66db59 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -23,6 +23,7 @@ use ic_https_outcalls_service::{ }; use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; +use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use rand::{seq::SliceRandom, thread_rng}; use std::collections::BTreeMap; use std::str::FromStr; @@ -49,11 +50,9 @@ type OutboundRequestBody = Full; type Cache = BTreeMap>, OutboundRequestBody>>; -use std::sync::Mutex; - pub struct CanisterHttp { client: Client, OutboundRequestBody>, - cache: Arc>, + cache: Arc>, logger: ReplicaLogger, metrics: AdapterMetrics, http_connect_timeout_secs: u64, @@ -84,7 +83,7 @@ impl CanisterHttp { Self { client, - cache: Arc::new(Mutex::new(BTreeMap::new())), + cache: Arc::new(RwLock::new(BTreeMap::new())), logger, metrics: AdapterMetrics::new(metrics), http_connect_timeout_secs: config.http_connect_timeout_secs, @@ -234,12 +233,13 @@ impl HttpsOutcallsService for CanisterHttp { let next_socks_proxy_ip = api_bn_ip.clone(); let socks_client = { - let mut cache_guard = self.cache.lock().unwrap(); + let cache_guard = self.cache.upgradable_read(); // Check if the client already exists in the cache if let Some(client) = cache_guard.get(&next_socks_proxy_ip) { client.clone() } else { + let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); // Create a new client and insert it into the cache match self.create_socks_client_for_ip(&next_socks_proxy_ip) { Some(client) => { From 8de8072c01740db69836ec359cb881083616fc1a Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Fri, 22 Nov 2024 15:46:32 +0000 Subject: [PATCH 14/34] metrics --- rs/https_outcalls/adapter/src/metrics.rs | 27 ++++++++++++- rs/https_outcalls/adapter/src/rpc_server.rs | 43 +++++++++++++++++---- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/rs/https_outcalls/adapter/src/metrics.rs b/rs/https_outcalls/adapter/src/metrics.rs index 272894e5d8f..f8099527321 100644 --- a/rs/https_outcalls/adapter/src/metrics.rs +++ b/rs/https_outcalls/adapter/src/metrics.rs @@ -1,5 +1,5 @@ use ic_metrics::MetricsRegistry; -use prometheus::{IntCounter, IntCounterVec}; +use prometheus::{IntCounter, IntCounterVec, IntGauge}; /// Labels for request errors pub(crate) const LABEL_BODY_RECEIVE_SIZE: &str = "body_receive_size"; @@ -20,6 +20,14 @@ pub struct AdapterMetrics { pub requests: IntCounter, /// The number of requests served via a SOCKS proxy. pub requests_socks: IntCounter, + /// The number of socks connections attempts + pub socks_connections_attempts: IntCounter, + /// The number of socks clients in the cache + pub socks_cache_size: IntGauge, + /// The number of cache misses for socks clients + pub socks_cache_miss: IntCounter, + /// The number of successful socks connections + pub succesful_socks_connections: IntCounterVec, /// Network traffic generated by adapter. pub network_traffic: IntCounterVec, /// Request failure types. @@ -38,6 +46,23 @@ impl AdapterMetrics { "requests_socks_total", "Total number of requests served via a SOCKS proxy", ), + socks_connections_attempts: metrics_registry.int_counter( + "socks_connections_attempts", + "Total number of time the adapter tries to proxy a request via a SOCKS proxy", + ), + socks_cache_size: metrics_registry.int_gauge( + "socks_cache_size", + "The size of the cache for SOCKS clients", + ), + socks_cache_miss: metrics_registry.int_counter( + "socks_cache_miss", + "Total number of times the adapter failed to find a SOCKS client in the cache", + ), + succesful_socks_connections: metrics_registry.int_counter_vec( + "successful_socks_connections_total", + "Total number of successful SOCKS connections", + &["number_of_tries"], + ), network_traffic: metrics_registry.int_counter_vec( "network_traffic_bytes_total", "Network traffic generated by adapter.", diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 8247f66db59..8e616116387 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -25,7 +25,7 @@ use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use rand::{seq::SliceRandom, thread_rng}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashSet}; use std::str::FromStr; use std::sync::Arc; use std::time::Duration; @@ -45,6 +45,8 @@ const USER_AGENT_ADAPTER: &str = "ic/1.0"; /// "the total number of bytes representing the header names and values must not exceed 48KiB". const MAX_HEADER_LIST_SIZE: u32 = 52 * 1024; +const MAX_SOCKS_PROXY_RETRIES: usize = 3; + type OutboundRequestBody = Full; type Cache = @@ -208,6 +210,8 @@ impl HttpsOutcallsService for CanisterHttp { .map(|(name, value)| name.as_str().len() + value.len()) .sum::(); + println!("debuggg"); + // If we are allowed to use socks and condition described in `should_use_socks_proxy` hold, // we do the requests through the socks proxy. If not we use the default IPv6 route. let http_resp = if req.socks_proxy_allowed { @@ -226,10 +230,18 @@ impl HttpsOutcallsService for CanisterHttp { let mut api_bn_ips = req.api_bn_ips; api_bn_ips.shuffle(&mut thread_rng()); + let request_ips: HashSet<&String> = api_bn_ips.iter().collect(); + let mut response = None; - // We try all the IPs only once in random order until we get a response - for api_bn_ip in api_bn_ips { + let mut tries = 0; + + // We try the IPs only once in random order until we get a response + for api_bn_ip in &api_bn_ips { + tries += 1; + if tries > MAX_SOCKS_PROXY_RETRIES { + break; + } let next_socks_proxy_ip = api_bn_ip.clone(); let socks_client = { @@ -240,37 +252,54 @@ impl HttpsOutcallsService for CanisterHttp { client.clone() } else { let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); + self.metrics.socks_cache_miss.inc(); + // Remove clients that are not in the request_ips + for ip in cache_guard.keys().cloned().collect::>() { + if !request_ips.contains(&ip) { + cache_guard.remove(&ip); + debug!(self.logger, "Removed SOCKS client for IP {}", ip); + } + } + // Create a new client and insert it into the cache match self.create_socks_client_for_ip(&next_socks_proxy_ip) { Some(client) => { cache_guard.insert(next_socks_proxy_ip.clone(), client.clone()); + debug!(self.logger, "Created SOCKS client for IP {}", next_socks_proxy_ip); client } None => { debug!(self.logger, "Failed to create SOCKS client for IP {}", next_socks_proxy_ip); - //TODO(mihailjianu): add some metrics continue; } } } }; + self.metrics.socks_connections_attempts.inc(); match socks_client.request(http_req_clone.clone()).await.map_err(|e| { format!("Request failed direct connect {direct_err} and connect through socks {e}") }) { Ok(resp) => { response = Some(resp); + self.metrics.succesful_socks_connections.with_label_values(&[&tries.to_string()]).inc(); break; } Err(socks_err) => { debug!(self.logger, "Failed to connect through SOCKS with IP {}: {}", next_socks_proxy_ip, socks_err); - //TODO(mihailjianu): add some metrics + println!("debuggg Failed to connect through SOCKS with IP {}: {}", next_socks_proxy_ip, socks_err); + // Retry with a different socks client + // TODO: only retry if the error couldn've been caused by the proxy itself } } } + self.metrics.socks_cache_size.set(self.cache.read().len() as i64); response.ok_or_else(|| { - debug!(self.logger, "Failed to connect through SOCKS with all IPs"); - "Failed to connect through SOCKS with all IPs".to_string() + if api_bn_ips.is_empty() { + "No IPs to connect through SOCKS in the request".to_string() + } else { + "Failed to connect through SOCKS with all IPs".to_string() + } }) } Ok(resp) => Ok(resp), From c85671a5d6a50db06633334dd3c7c106cdd75dbe Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Fri, 22 Nov 2024 16:12:05 +0000 Subject: [PATCH 15/34] clippy --- Cargo.lock | 1 - rs/https_outcalls/adapter/BUILD.bazel | 4 ++-- rs/https_outcalls/adapter/Cargo.toml | 1 - rs/https_outcalls/adapter/src/rpc_server.rs | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 110ff694850..19e7b3700b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8561,7 +8561,6 @@ dependencies = [ name = "ic-https-outcalls-adapter" version = "0.1.0" dependencies = [ - "arc-swap", "async-stream", "byte-unit", "bytes", diff --git a/rs/https_outcalls/adapter/BUILD.bazel b/rs/https_outcalls/adapter/BUILD.bazel index f45fa5981d1..c52c65e0061 100644 --- a/rs/https_outcalls/adapter/BUILD.bazel +++ b/rs/https_outcalls/adapter/BUILD.bazel @@ -8,8 +8,7 @@ DEPENDENCIES = [ "//rs/config", "//rs/https_outcalls/service", "//rs/monitoring/logger", - "//rs/monitoring/metrics", - "@crate_index//:arc-swap", + "//rs/monitoring/metrics", "@crate_index//:byte-unit", "@crate_index//:clap", "@crate_index//:futures", @@ -19,6 +18,7 @@ DEPENDENCIES = [ "@crate_index//:hyper-rustls", "@crate_index//:hyper-socks2", "@crate_index//:hyper-util", + "@crate_index//:parking_lot", "@crate_index//:prometheus", "@crate_index//:rand", "@crate_index//:serde", diff --git a/rs/https_outcalls/adapter/Cargo.toml b/rs/https_outcalls/adapter/Cargo.toml index c307b948dd6..eeab5efaf60 100644 --- a/rs/https_outcalls/adapter/Cargo.toml +++ b/rs/https_outcalls/adapter/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -arc-swap = "1" byte-unit = "4.0.14" clap = { workspace = true } futures = { workspace = true } diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 8e616116387..766ae00f0d1 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -276,7 +276,7 @@ impl HttpsOutcallsService for CanisterHttp { } }; - self.metrics.socks_connections_attempts.inc(); + self.metrics.socks_connections_attempts.inc(); match socks_client.request(http_req_clone.clone()).await.map_err(|e| { format!("Request failed direct connect {direct_err} and connect through socks {e}") }) { From 0aae15c1e1c046a0cb37c8069bd12275f5263c94 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Fri, 22 Nov 2024 16:43:15 +0000 Subject: [PATCH 16/34] buildifier --- rs/https_outcalls/adapter/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/https_outcalls/adapter/BUILD.bazel b/rs/https_outcalls/adapter/BUILD.bazel index c52c65e0061..0934b236646 100644 --- a/rs/https_outcalls/adapter/BUILD.bazel +++ b/rs/https_outcalls/adapter/BUILD.bazel @@ -8,7 +8,7 @@ DEPENDENCIES = [ "//rs/config", "//rs/https_outcalls/service", "//rs/monitoring/logger", - "//rs/monitoring/metrics", + "//rs/monitoring/metrics", "@crate_index//:byte-unit", "@crate_index//:clap", "@crate_index//:futures", From e68ebd169d1d85f0f96ac5fcaee315e77a763e43 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 27 Nov 2024 22:39:25 +0000 Subject: [PATCH 17/34] attempt --- rs/https_outcalls/adapter/src/rpc_server.rs | 27 ++++++++++++++++--- rs/tests/networking/BUILD.bazel | 1 + .../networking/canister_http_socks_test.rs | 14 ++++++++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 766ae00f0d1..0fd546b4fd3 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -21,7 +21,7 @@ use ic_https_outcalls_service::{ https_outcalls_service_server::HttpsOutcallsService, HttpHeader, HttpMethod, HttpsOutcallRequest, HttpsOutcallResponse, }; -use ic_logger::{debug, ReplicaLogger}; +use ic_logger::{debug, warn, info, ReplicaLogger}; use ic_metrics::MetricsRegistry; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use rand::{seq::SliceRandom, thread_rng}; @@ -63,6 +63,12 @@ pub struct CanisterHttp { impl CanisterHttp { pub fn new(config: Config, logger: ReplicaLogger, metrics: &MetricsRegistry) -> Self { // Socks client setup + eprintln!("debuggg"); + + warn!(logger, "debuggg new warn!"); + info!(logger, "debuggg new info!"); + debug!(logger, "debuggg new debug!"); + let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); http_connector @@ -102,6 +108,8 @@ impl CanisterHttp { http_connector .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); + let ip = format!("[{}]:1080", ip); + match ip.parse() { Ok(proxy_addr) => { let proxy_connector = SocksConnector { @@ -136,6 +144,11 @@ impl HttpsOutcallsService for CanisterHttp { &self, request: Request, ) -> Result, Status> { + + warn!(self.logger, "debuggg warn!"); + info!(self.logger, "debuggg info!"); + debug!(self.logger, "debuggg debug!"); + self.metrics.requests.inc(); let req = request.into_inner(); @@ -236,6 +249,8 @@ impl HttpsOutcallsService for CanisterHttp { let mut tries = 0; + let mut errors = format!(""); + // We try the IPs only once in random order until we get a response for api_bn_ip in &api_bn_ips { tries += 1; @@ -270,6 +285,10 @@ impl HttpsOutcallsService for CanisterHttp { } None => { debug!(self.logger, "Failed to create SOCKS client for IP {}", next_socks_proxy_ip); + return Err(Status::new( + tonic::Code::InvalidArgument, + format!("could not create client {}", next_socks_proxy_ip), + )); continue; } } @@ -278,7 +297,7 @@ impl HttpsOutcallsService for CanisterHttp { self.metrics.socks_connections_attempts.inc(); match socks_client.request(http_req_clone.clone()).await.map_err(|e| { - format!("Request failed direct connect {direct_err} and connect through socks {e}") + format!("failied socks {e}") }) { Ok(resp) => { response = Some(resp); @@ -286,8 +305,8 @@ impl HttpsOutcallsService for CanisterHttp { break; } Err(socks_err) => { + errors += &socks_err; debug!(self.logger, "Failed to connect through SOCKS with IP {}: {}", next_socks_proxy_ip, socks_err); - println!("debuggg Failed to connect through SOCKS with IP {}: {}", next_socks_proxy_ip, socks_err); // Retry with a different socks client // TODO: only retry if the error couldn've been caused by the proxy itself } @@ -298,7 +317,7 @@ impl HttpsOutcallsService for CanisterHttp { if api_bn_ips.is_empty() { "No IPs to connect through SOCKS in the request".to_string() } else { - "Failed to connect through SOCKS with all IPs".to_string() + format!("all IPS: {}, with error {}", api_bn_ips.join(", "), errors) } }) } diff --git a/rs/tests/networking/BUILD.bazel b/rs/tests/networking/BUILD.bazel index 468fdda5f63..3301e79eb53 100644 --- a/rs/tests/networking/BUILD.bazel +++ b/rs/tests/networking/BUILD.bazel @@ -72,6 +72,7 @@ system_test_nns( deps = CANISTER_HTTP_BASE_DEPS + [ "//rs/registry/subnet_features", "//rs/registry/subnet_type", + "//rs/tests/consensus/utils", # needed for starting the nns. ], ) diff --git a/rs/tests/networking/canister_http_socks_test.rs b/rs/tests/networking/canister_http_socks_test.rs index ed926ac4078..21ce8e66cfe 100644 --- a/rs/tests/networking/canister_http_socks_test.rs +++ b/rs/tests/networking/canister_http_socks_test.rs @@ -16,6 +16,7 @@ Success:: end::catalog[] */ +use ic_consensus_system_test_utils::rw_message::install_nns_with_customizations_and_check_progress; use anyhow::bail; use anyhow::Result; use canister_http::*; @@ -27,7 +28,7 @@ use ic_management_canister_types::{ use ic_registry_subnet_features::SubnetFeatures; use ic_registry_subnet_type::SubnetType; use ic_system_test_driver::driver::group::SystemTestGroup; -use ic_system_test_driver::driver::test_env_api::{HasPublicApiUrl, RetrieveIpv4Addr}; +use ic_system_test_driver::driver::test_env_api::{HasPublicApiUrl, HasTopologySnapshot, NnsCustomizations, RetrieveIpv4Addr}; use ic_system_test_driver::driver::{ boundary_node::{BoundaryNode, BoundaryNodeVm}, ic::{InternetComputer, Subnet}, @@ -52,6 +53,7 @@ fn main() -> Result<()> { } pub fn setup(env: TestEnv) { + let logger = env.logger(); // Set up Universal VM with HTTP Bin testing service @@ -94,11 +96,17 @@ pub fn setup(env: TestEnv) { }) .add_nodes(4), ) + .with_api_boundary_nodes(1) .setup_and_start(&env) .expect("failed to setup IC under test"); + install_nns_with_customizations_and_check_progress( + env.topology_snapshot(), + NnsCustomizations::default(), + ); + await_nodes_healthy(&env); - install_nns_canisters(&env); + //install_nns_canisters(&env); // Start BN. bn_vm @@ -130,6 +138,8 @@ pub fn test(env: TestEnv) { let webserver_ipv4 = get_universal_vm_ipv4_address(&env); let webserver_url = format!("https://{webserver_ipv4}:20443"); + info!(&logger, "debuggg in test"); + // Request from system subnet. let mut system_nodes = get_system_subnet_node_snapshots(&env); let system_node = system_nodes.next().expect("there is no system subnet node"); From 6a4e052649b6e9cdd8c9d3d0bd9997cbc97bf6fc Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Fri, 29 Nov 2024 13:38:19 +0000 Subject: [PATCH 18/34] ch --- rs/https_outcalls/adapter/src/rpc_server.rs | 13 +++++++++++-- rs/tests/networking/canister_http_socks_test.rs | 4 ++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 0fd546b4fd3..0cd8ccf0fcc 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -58,6 +58,7 @@ pub struct CanisterHttp { logger: ReplicaLogger, metrics: AdapterMetrics, http_connect_timeout_secs: u64, + proxy_url: String, } impl CanisterHttp { @@ -95,6 +96,7 @@ impl CanisterHttp { logger, metrics: AdapterMetrics::new(metrics), http_connect_timeout_secs: config.http_connect_timeout_secs, + proxy_url: config.socks_proxy, } } @@ -108,7 +110,11 @@ impl CanisterHttp { http_connector .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); - let ip = format!("[{}]:1080", ip); + let mut ip = ip.to_string(); + + if !ip.starts_with("socks5") { + ip = format!("socks5://[{}]:1080", ip); + } match ip.parse() { Ok(proxy_addr) => { @@ -243,6 +249,9 @@ impl HttpsOutcallsService for CanisterHttp { let mut api_bn_ips = req.api_bn_ips; api_bn_ips.shuffle(&mut thread_rng()); + //TODO(mihailjianu): we should not try with the proxy from the config. + //api_bn_ips.push(self.proxy_url.clone()); + let request_ips: HashSet<&String> = api_bn_ips.iter().collect(); let mut response = None; @@ -317,7 +326,7 @@ impl HttpsOutcallsService for CanisterHttp { if api_bn_ips.is_empty() { "No IPs to connect through SOCKS in the request".to_string() } else { - format!("all IPS: {}, with error {}", api_bn_ips.join(", "), errors) + format!("all IPS: {}, real ip: {}, with error {}", api_bn_ips.join(", "), self.proxy_url, errors) } }) } diff --git a/rs/tests/networking/canister_http_socks_test.rs b/rs/tests/networking/canister_http_socks_test.rs index 21ce8e66cfe..e507ade2819 100644 --- a/rs/tests/networking/canister_http_socks_test.rs +++ b/rs/tests/networking/canister_http_socks_test.rs @@ -79,7 +79,7 @@ pub fn setup(env: TestEnv) { // Create IC with injected socks proxy. InternetComputer::new() - .with_socks_proxy(format!("socks5://[{bn_ipv6}]:1080")) + .with_socks_proxy(format!("socks5://[{}]:1080", bn_ipv6)) .add_subnet( Subnet::new(SubnetType::System) .with_features(SubnetFeatures { @@ -96,7 +96,7 @@ pub fn setup(env: TestEnv) { }) .add_nodes(4), ) - .with_api_boundary_nodes(1) + .with_api_boundary_nodes(1) .setup_and_start(&env) .expect("failed to setup IC under test"); From 9433d02fb042f0fa410114a2cd648c69999afd18 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Mon, 2 Dec 2024 12:06:38 +0000 Subject: [PATCH 19/34] debug --- Cargo.lock | 2 +- rs/https_outcalls/adapter/src/lib.rs | 2 +- rs/https_outcalls/adapter/src/rpc_server.rs | 21 +++++++++---------- .../consensus/src/pool_manager.rs | 3 ++- rs/tests/networking/BUILD.bazel | 2 ++ .../networking/canister_http_socks_test.rs | 3 +-- .../testing_verification/testnets/BUILD.bazel | 3 +++ 7 files changed, 20 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e1b413cbd8..8b6850d364a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14763,7 +14763,7 @@ dependencies = [ "regex", "regex-syntax 0.6.29", "string_cache", - "term 0.7.0", + "term", "tiny-keccak", "unicode-xid", ] diff --git a/rs/https_outcalls/adapter/src/lib.rs b/rs/https_outcalls/adapter/src/lib.rs index 4a6bc2134fe..0c7c759d686 100644 --- a/rs/https_outcalls/adapter/src/lib.rs +++ b/rs/https_outcalls/adapter/src/lib.rs @@ -31,7 +31,7 @@ pub fn start_server( ) { let log = log.clone(); let metrics_registry = metrics_registry.clone(); - let canister_http = CanisterHttp::new(config.clone(), log, &metrics_registry); + let canister_http: CanisterHttp = CanisterHttp::new(config.clone(), log, &metrics_registry); let server = Server::builder() .timeout(Duration::from_secs(config.http_request_timeout_secs)) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 0cd8ccf0fcc..5547158a3b0 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -110,12 +110,6 @@ impl CanisterHttp { http_connector .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); - let mut ip = ip.to_string(); - - if !ip.starts_with("socks5") { - ip = format!("socks5://[{}]:1080", ip); - } - match ip.parse() { Ok(proxy_addr) => { let proxy_connector = SocksConnector { @@ -250,7 +244,7 @@ impl HttpsOutcallsService for CanisterHttp { api_bn_ips.shuffle(&mut thread_rng()); //TODO(mihailjianu): we should not try with the proxy from the config. - //api_bn_ips.push(self.proxy_url.clone()); + api_bn_ips.push(self.proxy_url.clone()); let request_ips: HashSet<&String> = api_bn_ips.iter().collect(); @@ -311,22 +305,27 @@ impl HttpsOutcallsService for CanisterHttp { Ok(resp) => { response = Some(resp); self.metrics.succesful_socks_connections.with_label_values(&[&tries.to_string()]).inc(); - break; + errors += format!("c{}", next_socks_proxy_ip).as_str(); + //TODO(mihailjianu): we should break if it worked. + //break; } Err(socks_err) => { - errors += &socks_err; + errors += format!("f{}", next_socks_proxy_ip).as_str(); debug!(self.logger, "Failed to connect through SOCKS with IP {}: {}", next_socks_proxy_ip, socks_err); // Retry with a different socks client // TODO: only retry if the error couldn've been caused by the proxy itself } } } - self.metrics.socks_cache_size.set(self.cache.read().len() as i64); + self.metrics.socks_cache_size.set(self.cache.read().len() as i64); + + response = None; + response.ok_or_else(|| { if api_bn_ips.is_empty() { "No IPs to connect through SOCKS in the request".to_string() } else { - format!("all IPS: {}, real ip: {}, with error {}", api_bn_ips.join(", "), self.proxy_url, errors) + format!("e{}", errors) } }) } diff --git a/rs/https_outcalls/consensus/src/pool_manager.rs b/rs/https_outcalls/consensus/src/pool_manager.rs index e8a9dc99886..b832464824d 100644 --- a/rs/https_outcalls/consensus/src/pool_manager.rs +++ b/rs/https_outcalls/consensus/src/pool_manager.rs @@ -178,7 +178,8 @@ impl CanisterHttpPoolManagerImpl { None }) }) - .map(|http_info| http_info.ip_addr) + //TODO(mihailjianu): This should be replaced with a more robust way of + .map(|http_info| format!("socks5://[{0}]:1080", http_info.ip_addr)) }) .collect::>() } diff --git a/rs/tests/networking/BUILD.bazel b/rs/tests/networking/BUILD.bazel index 3301e79eb53..b3936283aed 100644 --- a/rs/tests/networking/BUILD.bazel +++ b/rs/tests/networking/BUILD.bazel @@ -61,6 +61,8 @@ system_test_nns( # TODO(NET-1710): enable on CI again when the problematic firewall rule in the IC node has been removed. #"system_test_hourly", #"system_test_nightly", + #TODO(mihailjianu): remove this. + "dynamic_testnet", "manual", ], target_compatible_with = ["@platforms//os:linux"], # requires libssh that does not build on Mac OS diff --git a/rs/tests/networking/canister_http_socks_test.rs b/rs/tests/networking/canister_http_socks_test.rs index e507ade2819..5a00f34e3b3 100644 --- a/rs/tests/networking/canister_http_socks_test.rs +++ b/rs/tests/networking/canister_http_socks_test.rs @@ -66,7 +66,7 @@ pub fn setup(env: TestEnv) { .start(&env) .expect("failed to set up universal VM"); - canister_http::start_httpbin_on_uvm(&env); + start_httpbin_on_uvm(&env); info!(&logger, "Started Universal VM!"); // Create raw BN vm to get ipv6 address with which we configure IC. @@ -106,7 +106,6 @@ pub fn setup(env: TestEnv) { ); await_nodes_healthy(&env); - //install_nns_canisters(&env); // Start BN. bn_vm diff --git a/rs/tests/testing_verification/testnets/BUILD.bazel b/rs/tests/testing_verification/testnets/BUILD.bazel index 5fbfe633167..bfa8e760161 100644 --- a/rs/tests/testing_verification/testnets/BUILD.bazel +++ b/rs/tests/testing_verification/testnets/BUILD.bazel @@ -163,11 +163,14 @@ system_test_nns( ], deps = [ # Keep sorted. + "//rs/registry/subnet_features", "//rs/registry/subnet_type", "//rs/tests/consensus/utils", "//rs/tests/driver:ic-system-test-driver", + "//rs/tests/networking/canister_http", "//rs/tests/nns/nns_dapp", "@crate_index//:anyhow", + "@crate_index//:slog", ], ) From a1f32a1011134892cad50f754e1ef89dc0767f02 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 4 Dec 2024 13:32:05 +0000 Subject: [PATCH 20/34] final changes --- rs/https_outcalls/adapter/src/rpc_server.rs | 245 ++++++++++-------- .../consensus/src/pool_manager.rs | 1 - rs/tests/networking/BUILD.bazel | 2 - .../networking/canister_http_socks_test.rs | 16 +- 4 files changed, 140 insertions(+), 124 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 5547158a3b0..6503db5ed26 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -3,6 +3,7 @@ use crate::metrics::{ LABEL_HEADER_RECEIVE_SIZE, LABEL_HTTP_METHOD, LABEL_REQUEST_HEADERS, LABEL_RESPONSE_HEADERS, LABEL_UPLOAD, LABEL_URL_PARSE, }; +use rand::Rng; use crate::Config; use core::convert::TryFrom; use http::{header::USER_AGENT, HeaderName, HeaderValue, Uri}; @@ -12,6 +13,8 @@ use hyper::{ header::{HeaderMap, ToStrError}, Method, }; + +use hyper::body::Incoming; use hyper_rustls::HttpsConnector; use hyper_rustls::HttpsConnectorBuilder; use hyper_socks2::SocksConnector; @@ -21,11 +24,11 @@ use ic_https_outcalls_service::{ https_outcalls_service_server::HttpsOutcallsService, HttpHeader, HttpMethod, HttpsOutcallRequest, HttpsOutcallResponse, }; -use ic_logger::{debug, warn, info, ReplicaLogger}; +use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; use rand::{seq::SliceRandom, thread_rng}; -use std::collections::{BTreeMap, HashSet}; +use std::collections::BTreeMap; use std::str::FromStr; use std::sync::Arc; use std::time::Duration; @@ -45,8 +48,12 @@ const USER_AGENT_ADAPTER: &str = "ic/1.0"; /// "the total number of bytes representing the header names and values must not exceed 48KiB". const MAX_HEADER_LIST_SIZE: u32 = 52 * 1024; +/// The maximum number of times we will try to connect to a SOCKS proxy. const MAX_SOCKS_PROXY_RETRIES: usize = 3; +/// The probability of using api boundary node IPs for SOCKS proxy dark launch. +const REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE: u32 = 0; + type OutboundRequestBody = Full; type Cache = @@ -54,26 +61,38 @@ type Cache = pub struct CanisterHttp { client: Client, OutboundRequestBody>, + socks_client: Client>, OutboundRequestBody>, cache: Arc>, logger: ReplicaLogger, metrics: AdapterMetrics, http_connect_timeout_secs: u64, - proxy_url: String, } impl CanisterHttp { pub fn new(config: Config, logger: ReplicaLogger, metrics: &MetricsRegistry) -> Self { // Socks client setup - eprintln!("debuggg"); - - warn!(logger, "debuggg new warn!"); - info!(logger, "debuggg new info!"); - debug!(logger, "debuggg new debug!"); - let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); http_connector .set_connect_timeout(Some(Duration::from_secs(config.http_connect_timeout_secs))); + // The proxy connnector requires a the URL scheme to be specified. I.e socks5:// + // Config validity check ensures that url includes scheme, host and port. + // Therefore the parse 'Uri' will be in the correct format. I.e socks5://somehost.com:1080 + let proxy_connector = SocksConnector { + proxy_addr: config + .socks_proxy + .parse() + .expect("Failed to parse socks url."), + auth: None, + connector: http_connector.clone(), + }; + let proxied_https_connector = HttpsConnectorBuilder::new() + .with_native_roots() + .expect("Failed to set native roots") + .https_only() + .enable_all_versions() + .wrap_connector(proxy_connector); + // Https client setup. let builder = HttpsConnectorBuilder::new() .with_native_roots() @@ -86,17 +105,19 @@ impl CanisterHttp { let builder = builder.enable_all_versions(); let direct_https_connector = builder.wrap_connector(http_connector); + let socks_client = + Client::builder(TokioExecutor::new()).build::<_, Full>(proxied_https_connector); let client = Client::builder(TokioExecutor::new()) .http2_max_header_list_size(MAX_HEADER_LIST_SIZE) .build::<_, Full>(direct_https_connector); Self { client, + socks_client, cache: Arc::new(RwLock::new(BTreeMap::new())), logger, metrics: AdapterMetrics::new(metrics), http_connect_timeout_secs: config.http_connect_timeout_secs, - proxy_url: config.socks_proxy, } } @@ -110,7 +131,7 @@ impl CanisterHttp { http_connector .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); - match ip.parse() { + match ip.parse() { Ok(proxy_addr) => { let proxy_connector = SocksConnector { proxy_addr, @@ -144,16 +165,10 @@ impl HttpsOutcallsService for CanisterHttp { &self, request: Request, ) -> Result, Status> { - - warn!(self.logger, "debuggg warn!"); - info!(self.logger, "debuggg info!"); - debug!(self.logger, "debuggg debug!"); - self.metrics.requests.inc(); let req = request.into_inner(); - // "clients" now contains the clients we need to use for this request let uri = req.url.parse::().map_err(|err| { debug!(self.logger, "Failed to parse URL: {}", err); self.metrics @@ -223,8 +238,6 @@ impl HttpsOutcallsService for CanisterHttp { .map(|(name, value)| name.as_str().len() + value.len()) .sum::(); - println!("debuggg"); - // If we are allowed to use socks and condition described in `should_use_socks_proxy` hold, // we do the requests through the socks proxy. If not we use the default IPv6 route. let http_resp = if req.socks_proxy_allowed { @@ -236,110 +249,31 @@ impl HttpsOutcallsService for CanisterHttp { let http_req_clone = http_req.clone(); match self.client.request(http_req).await { + // If we fail we try with the socks proxy. For destinations that are ipv4 only this should + // fail fast because our interface does not have an ipv4 assigned. Err(direct_err) => { - // Try to proxy the request through SOCKS self.metrics.requests_socks.inc(); - let mut api_bn_ips = req.api_bn_ips; - api_bn_ips.shuffle(&mut thread_rng()); - - //TODO(mihailjianu): we should not try with the proxy from the config. - api_bn_ips.push(self.proxy_url.clone()); - - let request_ips: HashSet<&String> = api_bn_ips.iter().collect(); - - let mut response = None; - - let mut tries = 0; + let result = self.socks_client.request(http_req_clone.clone()).await.map_err(|e| { + format!("Request failed direct connect {direct_err} and connect through socks {e}") + }); - let mut errors = format!(""); + if should_dl_socks_proxy() { + let dl_result= self.https_outcall_dl_socks_proxy(&req.api_bn_ips, http_req_clone).await; - // We try the IPs only once in random order until we get a response - for api_bn_ip in &api_bn_ips { - tries += 1; - if tries > MAX_SOCKS_PROXY_RETRIES { - break; - } - let next_socks_proxy_ip = api_bn_ip.clone(); - - let socks_client = { - let cache_guard = self.cache.upgradable_read(); - - // Check if the client already exists in the cache - if let Some(client) = cache_guard.get(&next_socks_proxy_ip) { - client.clone() - } else { - let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); - self.metrics.socks_cache_miss.inc(); - // Remove clients that are not in the request_ips - for ip in cache_guard.keys().cloned().collect::>() { - if !request_ips.contains(&ip) { - cache_guard.remove(&ip); - debug!(self.logger, "Removed SOCKS client for IP {}", ip); - } - } - - // Create a new client and insert it into the cache - match self.create_socks_client_for_ip(&next_socks_proxy_ip) { - Some(client) => { - cache_guard.insert(next_socks_proxy_ip.clone(), client.clone()); - debug!(self.logger, "Created SOCKS client for IP {}", next_socks_proxy_ip); - client - } - None => { - debug!(self.logger, "Failed to create SOCKS client for IP {}", next_socks_proxy_ip); - return Err(Status::new( - tonic::Code::InvalidArgument, - format!("could not create client {}", next_socks_proxy_ip), - )); - continue; - } - } - } - }; - - self.metrics.socks_connections_attempts.inc(); - match socks_client.request(http_req_clone.clone()).await.map_err(|e| { - format!("failied socks {e}") - }) { - Ok(resp) => { - response = Some(resp); - self.metrics.succesful_socks_connections.with_label_values(&[&tries.to_string()]).inc(); - errors += format!("c{}", next_socks_proxy_ip).as_str(); - //TODO(mihailjianu): we should break if it worked. - //break; - } - Err(socks_err) => { - errors += format!("f{}", next_socks_proxy_ip).as_str(); - debug!(self.logger, "Failed to connect through SOCKS with IP {}: {}", next_socks_proxy_ip, socks_err); - // Retry with a different socks client - // TODO: only retry if the error couldn've been caused by the proxy itself - } - } + self.compare_results(&result, &dl_result); } - self.metrics.socks_cache_size.set(self.cache.read().len() as i64); - - response = None; - response.ok_or_else(|| { - if api_bn_ips.is_empty() { - "No IPs to connect through SOCKS in the request".to_string() - } else { - format!("e{}", errors) - } - }) + result } - Ok(resp) => Ok(resp), + Ok(resp)=> Ok(resp), } } else { let mut http_req = hyper::Request::new(Full::new(Bytes::from(req.body))); *http_req.headers_mut() = headers; *http_req.method_mut() = method; *http_req.uri_mut() = uri.clone(); - self.client - .request(http_req) - .await - .map_err(|e| format!("Failed to directly connect: {:?}", e)) + self.client.request(http_req).await.map_err(|e| format!("Failed to directly connect: {:?}", e)) } .map_err(|err| { debug!(self.logger, "Failed to connect: {}", err); @@ -436,6 +370,99 @@ impl HttpsOutcallsService for CanisterHttp { content: body_bytes.to_vec(), })) } +} + +fn should_dl_socks_proxy() -> bool { + let mut rng = rand::thread_rng(); + let random_number: u32 = rng.gen_range(0..100); + random_number < REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE +} + +impl CanisterHttp { + + fn compare_results(&self, result: &Result, String>, dl_result: &Result, String>) { + match (result, dl_result) { + (Ok(_), Ok(_)) => { + debug!(self.logger, "SOCKS_PROXY_DL: Both requests succeeded"); + } + (Err(_), Err(_)) => { + debug!(self.logger, "SOCKS_PROXY_DL: Both requests failed"); + } + (Ok(_), Err(_)) => { + debug!(self.logger, "SOCKS_PROXY_DL: regular request succeeded, DL request failed"); + } + (Err(_), Ok(_)) => { + debug!(self.logger, "SOCKS_PROXY_DL: regular request failed, DL request succeeded"); + } + } + } + + async fn https_outcall_dl_socks_proxy( + &self, + api_bn_ips: &Vec, + request: http::Request>, + ) -> Result, String> { + let mut api_bn_ips = api_bn_ips.clone(); + + api_bn_ips.shuffle(&mut thread_rng()); + + let mut last_error = None; + + let mut tries = 0; + + for api_bn_ip in &api_bn_ips { + tries += 1; + if tries > MAX_SOCKS_PROXY_RETRIES { + break; + } + let next_socks_proxy_ip = api_bn_ip.clone(); + + let socks_client = { + let cache_guard = self.cache.upgradable_read(); + + if let Some(client) = cache_guard.get(&next_socks_proxy_ip) { + client.clone() + } else { + let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); + self.metrics.socks_cache_miss.inc(); + + match self.create_socks_client_for_ip(&next_socks_proxy_ip) { + Some(client) => { + cache_guard.insert(next_socks_proxy_ip.clone(), client.clone()); + self.metrics.socks_cache_size.set(cache_guard.len() as i64); + client + } + None => { + debug!(self.logger, "Failed to create SOCKS client for IP {}", next_socks_proxy_ip); + // there is something wrong with this IP, try another one. + continue; + } + } + } + }; + + self.metrics.socks_connections_attempts.inc(); + + match socks_client.request(request.clone()).await { + Ok(resp) => { + self.metrics.succesful_socks_connections + .with_label_values(&[&tries.to_string()]) + .inc(); + return Ok(resp); + } + Err(socks_err) => { + debug!(self.logger, "Failed to connect through SOCKS with IP {}: {}", next_socks_proxy_ip, socks_err); + last_error = Some(socks_err); + } + } + } + + if last_error.is_some() { + return Err(last_error.unwrap().to_string()); + } else { + return Err("No API BN IPs provided".to_string()); + } + } } fn validate_headers(raw_headers: Vec) -> Result { diff --git a/rs/https_outcalls/consensus/src/pool_manager.rs b/rs/https_outcalls/consensus/src/pool_manager.rs index b832464824d..88469161a07 100644 --- a/rs/https_outcalls/consensus/src/pool_manager.rs +++ b/rs/https_outcalls/consensus/src/pool_manager.rs @@ -178,7 +178,6 @@ impl CanisterHttpPoolManagerImpl { None }) }) - //TODO(mihailjianu): This should be replaced with a more robust way of .map(|http_info| format!("socks5://[{0}]:1080", http_info.ip_addr)) }) .collect::>() diff --git a/rs/tests/networking/BUILD.bazel b/rs/tests/networking/BUILD.bazel index b3936283aed..3301e79eb53 100644 --- a/rs/tests/networking/BUILD.bazel +++ b/rs/tests/networking/BUILD.bazel @@ -61,8 +61,6 @@ system_test_nns( # TODO(NET-1710): enable on CI again when the problematic firewall rule in the IC node has been removed. #"system_test_hourly", #"system_test_nightly", - #TODO(mihailjianu): remove this. - "dynamic_testnet", "manual", ], target_compatible_with = ["@platforms//os:linux"], # requires libssh that does not build on Mac OS diff --git a/rs/tests/networking/canister_http_socks_test.rs b/rs/tests/networking/canister_http_socks_test.rs index 5a00f34e3b3..5e3af452cbc 100644 --- a/rs/tests/networking/canister_http_socks_test.rs +++ b/rs/tests/networking/canister_http_socks_test.rs @@ -16,7 +16,6 @@ Success:: end::catalog[] */ -use ic_consensus_system_test_utils::rw_message::install_nns_with_customizations_and_check_progress; use anyhow::bail; use anyhow::Result; use canister_http::*; @@ -28,7 +27,7 @@ use ic_management_canister_types::{ use ic_registry_subnet_features::SubnetFeatures; use ic_registry_subnet_type::SubnetType; use ic_system_test_driver::driver::group::SystemTestGroup; -use ic_system_test_driver::driver::test_env_api::{HasPublicApiUrl, HasTopologySnapshot, NnsCustomizations, RetrieveIpv4Addr}; +use ic_system_test_driver::driver::test_env_api::{HasPublicApiUrl, RetrieveIpv4Addr}; use ic_system_test_driver::driver::{ boundary_node::{BoundaryNode, BoundaryNodeVm}, ic::{InternetComputer, Subnet}, @@ -53,7 +52,6 @@ fn main() -> Result<()> { } pub fn setup(env: TestEnv) { - let logger = env.logger(); // Set up Universal VM with HTTP Bin testing service @@ -66,7 +64,7 @@ pub fn setup(env: TestEnv) { .start(&env) .expect("failed to set up universal VM"); - start_httpbin_on_uvm(&env); + canister_http::start_httpbin_on_uvm(&env); info!(&logger, "Started Universal VM!"); // Create raw BN vm to get ipv6 address with which we configure IC. @@ -79,7 +77,7 @@ pub fn setup(env: TestEnv) { // Create IC with injected socks proxy. InternetComputer::new() - .with_socks_proxy(format!("socks5://[{}]:1080", bn_ipv6)) + .with_socks_proxy(format!("socks5://[{bn_ipv6}]:1080")) .add_subnet( Subnet::new(SubnetType::System) .with_features(SubnetFeatures { @@ -100,12 +98,8 @@ pub fn setup(env: TestEnv) { .setup_and_start(&env) .expect("failed to setup IC under test"); - install_nns_with_customizations_and_check_progress( - env.topology_snapshot(), - NnsCustomizations::default(), - ); - await_nodes_healthy(&env); + install_nns_canisters(&env); // Start BN. bn_vm @@ -137,8 +131,6 @@ pub fn test(env: TestEnv) { let webserver_ipv4 = get_universal_vm_ipv4_address(&env); let webserver_url = format!("https://{webserver_ipv4}:20443"); - info!(&logger, "debuggg in test"); - // Request from system subnet. let mut system_nodes = get_system_subnet_node_snapshots(&env); let system_node = system_nodes.next().expect("there is no system subnet node"); From dd401e921583a95b130cd84db2fbbf9b249c6762 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 4 Dec 2024 13:41:38 +0000 Subject: [PATCH 21/34] clippy --- rs/https_outcalls/adapter/src/rpc_server.rs | 202 +++++++++++--------- 1 file changed, 111 insertions(+), 91 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 6503db5ed26..84c57a04371 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -3,7 +3,6 @@ use crate::metrics::{ LABEL_HEADER_RECEIVE_SIZE, LABEL_HTTP_METHOD, LABEL_REQUEST_HEADERS, LABEL_RESPONSE_HEADERS, LABEL_UPLOAD, LABEL_URL_PARSE, }; -use rand::Rng; use crate::Config; use core::convert::TryFrom; use http::{header::USER_AGENT, HeaderName, HeaderValue, Uri}; @@ -13,6 +12,7 @@ use hyper::{ header::{HeaderMap, ToStrError}, Method, }; +use rand::Rng; use hyper::body::Incoming; use hyper_rustls::HttpsConnector; @@ -131,7 +131,7 @@ impl CanisterHttp { http_connector .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); - match ip.parse() { + match ip.parse() { Ok(proxy_addr) => { let proxy_connector = SocksConnector { proxy_addr, @@ -157,6 +157,109 @@ impl CanisterHttp { } } } + + fn compare_results( + &self, + result: &Result, String>, + dl_result: &Result, String>, + ) { + match (result, dl_result) { + (Ok(_), Ok(_)) => { + debug!(self.logger, "SOCKS_PROXY_DL: Both requests succeeded"); + } + (Err(_), Err(_)) => { + debug!(self.logger, "SOCKS_PROXY_DL: Both requests failed"); + } + (Ok(_), Err(_)) => { + debug!( + self.logger, + "SOCKS_PROXY_DL: regular request succeeded, DL request failed" + ); + } + (Err(_), Ok(_)) => { + debug!( + self.logger, + "SOCKS_PROXY_DL: regular request failed, DL request succeeded" + ); + } + } + } + + async fn https_outcall_dl_socks_proxy( + &self, + api_bn_ips: &[String], + request: http::Request>, + ) -> Result, String> { + let mut api_bn_ips = api_bn_ips.to_owned(); + + api_bn_ips.shuffle(&mut thread_rng()); + + let mut last_error = None; + + let mut tries = 0; + + for api_bn_ip in &api_bn_ips { + tries += 1; + if tries > MAX_SOCKS_PROXY_RETRIES { + break; + } + let next_socks_proxy_ip = api_bn_ip.clone(); + + let socks_client = { + let cache_guard = self.cache.upgradable_read(); + + if let Some(client) = cache_guard.get(&next_socks_proxy_ip) { + client.clone() + } else { + let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); + self.metrics.socks_cache_miss.inc(); + + match self.create_socks_client_for_ip(&next_socks_proxy_ip) { + Some(client) => { + cache_guard.insert(next_socks_proxy_ip.clone(), client.clone()); + self.metrics.socks_cache_size.set(cache_guard.len() as i64); + client + } + None => { + debug!( + self.logger, + "Failed to create SOCKS client for IP {}", next_socks_proxy_ip + ); + // there is something wrong with this IP, try another one. + continue; + } + } + } + }; + + self.metrics.socks_connections_attempts.inc(); + + match socks_client.request(request.clone()).await { + Ok(resp) => { + self.metrics + .succesful_socks_connections + .with_label_values(&[&tries.to_string()]) + .inc(); + return Ok(resp); + } + Err(socks_err) => { + debug!( + self.logger, + "Failed to connect through SOCKS with IP {}: {}", + next_socks_proxy_ip, + socks_err + ); + last_error = Some(socks_err); + } + } + } + + if let Some(last_error) = last_error { + Err(last_error.to_string()) + } else { + Err("No API BN IPs provided".to_string()) + } + } } #[tonic::async_trait] @@ -370,99 +473,16 @@ impl HttpsOutcallsService for CanisterHttp { content: body_bytes.to_vec(), })) } -} +} +#[allow(clippy::absurd_extreme_comparisons)] fn should_dl_socks_proxy() -> bool { let mut rng = rand::thread_rng(); let random_number: u32 = rng.gen_range(0..100); - random_number < REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE -} - -impl CanisterHttp { - - fn compare_results(&self, result: &Result, String>, dl_result: &Result, String>) { - match (result, dl_result) { - (Ok(_), Ok(_)) => { - debug!(self.logger, "SOCKS_PROXY_DL: Both requests succeeded"); - } - (Err(_), Err(_)) => { - debug!(self.logger, "SOCKS_PROXY_DL: Both requests failed"); - } - (Ok(_), Err(_)) => { - debug!(self.logger, "SOCKS_PROXY_DL: regular request succeeded, DL request failed"); - } - (Err(_), Ok(_)) => { - debug!(self.logger, "SOCKS_PROXY_DL: regular request failed, DL request succeeded"); - } - } - } - - async fn https_outcall_dl_socks_proxy( - &self, - api_bn_ips: &Vec, - request: http::Request>, - ) -> Result, String> { - let mut api_bn_ips = api_bn_ips.clone(); - - api_bn_ips.shuffle(&mut thread_rng()); - - let mut last_error = None; - - let mut tries = 0; - - for api_bn_ip in &api_bn_ips { - tries += 1; - if tries > MAX_SOCKS_PROXY_RETRIES { - break; - } - let next_socks_proxy_ip = api_bn_ip.clone(); - - let socks_client = { - let cache_guard = self.cache.upgradable_read(); - - if let Some(client) = cache_guard.get(&next_socks_proxy_ip) { - client.clone() - } else { - let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); - self.metrics.socks_cache_miss.inc(); - - match self.create_socks_client_for_ip(&next_socks_proxy_ip) { - Some(client) => { - cache_guard.insert(next_socks_proxy_ip.clone(), client.clone()); - self.metrics.socks_cache_size.set(cache_guard.len() as i64); - client - } - None => { - debug!(self.logger, "Failed to create SOCKS client for IP {}", next_socks_proxy_ip); - // there is something wrong with this IP, try another one. - continue; - } - } - } - }; - - self.metrics.socks_connections_attempts.inc(); - - match socks_client.request(request.clone()).await { - Ok(resp) => { - self.metrics.succesful_socks_connections - .with_label_values(&[&tries.to_string()]) - .inc(); - return Ok(resp); - } - Err(socks_err) => { - debug!(self.logger, "Failed to connect through SOCKS with IP {}: {}", next_socks_proxy_ip, socks_err); - last_error = Some(socks_err); - } - } - } - - if last_error.is_some() { - return Err(last_error.unwrap().to_string()); - } else { - return Err("No API BN IPs provided".to_string()); - } - } + // This is a dark launch feature. We want to test the SOCKS proxy with a small percentage of requests. + // Currently this is set to 0%, hence always false. + random_number + < REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE } fn validate_headers(raw_headers: Vec) -> Result { From 4169bf03585cbc1918d2dcf16e95912f86136feb Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 4 Dec 2024 13:51:11 +0000 Subject: [PATCH 22/34] better debug messages --- rs/https_outcalls/adapter/src/rpc_server.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 84c57a04371..7d4efa57062 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -170,16 +170,18 @@ impl CanisterHttp { (Err(_), Err(_)) => { debug!(self.logger, "SOCKS_PROXY_DL: Both requests failed"); } - (Ok(_), Err(_)) => { + (Ok(_), Err(err)) => { debug!( self.logger, - "SOCKS_PROXY_DL: regular request succeeded, DL request failed" + "SOCKS_PROXY_DL: regular request succeeded, DL request failed with error {}", + err, ); } - (Err(_), Ok(_)) => { + (Err(err), Ok(_)) => { debug!( self.logger, - "SOCKS_PROXY_DL: regular request failed, DL request succeeded" + "SOCKS_PROXY_DL: DL request succeeded, regular request failed with error {}", + err, ); } } @@ -221,10 +223,6 @@ impl CanisterHttp { client } None => { - debug!( - self.logger, - "Failed to create SOCKS client for IP {}", next_socks_proxy_ip - ); // there is something wrong with this IP, try another one. continue; } @@ -481,8 +479,7 @@ fn should_dl_socks_proxy() -> bool { let random_number: u32 = rng.gen_range(0..100); // This is a dark launch feature. We want to test the SOCKS proxy with a small percentage of requests. // Currently this is set to 0%, hence always false. - random_number - < REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE + random_number < REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE } fn validate_headers(raw_headers: Vec) -> Result { From ed73d7b1d2edccb0c688e70a2533d5dd6b8f1a77 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 4 Dec 2024 14:17:55 +0000 Subject: [PATCH 23/34] renaming --- rs/https_outcalls/adapter/src/lib.rs | 2 +- rs/https_outcalls/adapter/src/rpc_server.rs | 36 +++++++++---------- .../adapter/tests/server_test.rs | 24 ++++++------- rs/https_outcalls/client/src/client.rs | 6 ++-- .../consensus/src/pool_manager.rs | 7 ++-- .../https_outcalls_service/v1/proto.proto | 2 +- rs/pocket_ic_server/src/pocket_ic.rs | 4 +-- rs/tests/networking/BUILD.bazel | 1 - .../testing_verification/testnets/BUILD.bazel | 3 -- rs/types/types/src/canister_http.rs | 6 ++-- 10 files changed, 45 insertions(+), 46 deletions(-) diff --git a/rs/https_outcalls/adapter/src/lib.rs b/rs/https_outcalls/adapter/src/lib.rs index 0c7c759d686..4a6bc2134fe 100644 --- a/rs/https_outcalls/adapter/src/lib.rs +++ b/rs/https_outcalls/adapter/src/lib.rs @@ -31,7 +31,7 @@ pub fn start_server( ) { let log = log.clone(); let metrics_registry = metrics_registry.clone(); - let canister_http: CanisterHttp = CanisterHttp::new(config.clone(), log, &metrics_registry); + let canister_http = CanisterHttp::new(config.clone(), log, &metrics_registry); let server = Server::builder() .timeout(Duration::from_secs(config.http_request_timeout_secs)) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 7d4efa57062..cdc0f9da7a4 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -51,7 +51,7 @@ const MAX_HEADER_LIST_SIZE: u32 = 52 * 1024; /// The maximum number of times we will try to connect to a SOCKS proxy. const MAX_SOCKS_PROXY_RETRIES: usize = 3; -/// The probability of using api boundary node IPs for SOCKS proxy dark launch. +/// The probability of using api boundary node addresses for SOCKS proxy dark launch. const REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE: u32 = 0; type OutboundRequestBody = Full; @@ -121,9 +121,9 @@ impl CanisterHttp { } } - fn create_socks_client_for_ip( + fn create_socks_client_for_address( &self, - ip: &str, + address: &str, ) -> Option>, OutboundRequestBody>> { // Create a new HTTP connector let mut http_connector = HttpConnector::new(); @@ -131,7 +131,7 @@ impl CanisterHttp { http_connector .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); - match ip.parse() { + match address.parse() { Ok(proxy_addr) => { let proxy_connector = SocksConnector { proxy_addr, @@ -152,7 +152,7 @@ impl CanisterHttp { Some(socks_client) } Err(e) => { - debug!(self.logger, "Failed to parse SOCKS IP: {}", e); + debug!(self.logger, "Failed to parse SOCKS address: {}", e); None } } @@ -189,41 +189,41 @@ impl CanisterHttp { async fn https_outcall_dl_socks_proxy( &self, - api_bn_ips: &[String], + socks_proxy_addrs: &[String], request: http::Request>, ) -> Result, String> { - let mut api_bn_ips = api_bn_ips.to_owned(); + let mut socks_proxy_addrs = socks_proxy_addrs.to_owned(); - api_bn_ips.shuffle(&mut thread_rng()); + socks_proxy_addrs.shuffle(&mut thread_rng()); let mut last_error = None; let mut tries = 0; - for api_bn_ip in &api_bn_ips { + for socks_proxy_addr in &socks_proxy_addrs { tries += 1; if tries > MAX_SOCKS_PROXY_RETRIES { break; } - let next_socks_proxy_ip = api_bn_ip.clone(); + let next_socks_proxy_addr = socks_proxy_addr.clone(); let socks_client = { let cache_guard = self.cache.upgradable_read(); - if let Some(client) = cache_guard.get(&next_socks_proxy_ip) { + if let Some(client) = cache_guard.get(&next_socks_proxy_addr) { client.clone() } else { let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); self.metrics.socks_cache_miss.inc(); - match self.create_socks_client_for_ip(&next_socks_proxy_ip) { + match self.create_socks_client_for_ip(&next_socks_proxy_addr) { Some(client) => { - cache_guard.insert(next_socks_proxy_ip.clone(), client.clone()); + cache_guard.insert(next_socks_proxy_addr.clone(), client.clone()); self.metrics.socks_cache_size.set(cache_guard.len() as i64); client } None => { - // there is something wrong with this IP, try another one. + // there is something wrong with this address, try another one. continue; } } @@ -243,8 +243,8 @@ impl CanisterHttp { Err(socks_err) => { debug!( self.logger, - "Failed to connect through SOCKS with IP {}: {}", - next_socks_proxy_ip, + "Failed to connect through SOCKS with address {}: {}", + next_socks_proxy_addr, socks_err ); last_error = Some(socks_err); @@ -255,7 +255,7 @@ impl CanisterHttp { if let Some(last_error) = last_error { Err(last_error.to_string()) } else { - Err("No API BN IPs provided".to_string()) + Err("No SOCKS proxy addresses provided".to_string()) } } } @@ -360,7 +360,7 @@ impl HttpsOutcallsService for CanisterHttp { }); if should_dl_socks_proxy() { - let dl_result= self.https_outcall_dl_socks_proxy(&req.api_bn_ips, http_req_clone).await; + let dl_result= self.https_outcall_dl_socks_proxy(&req.socks_proxy_addrs, http_req_clone).await; self.compare_results(&result, &dl_result); } diff --git a/rs/https_outcalls/adapter/tests/server_test.rs b/rs/https_outcalls/adapter/tests/server_test.rs index 1f570c19773..a0e83dbb7c0 100644 --- a/rs/https_outcalls/adapter/tests/server_test.rs +++ b/rs/https_outcalls/adapter/tests/server_test.rs @@ -166,7 +166,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; let http_response = response.unwrap().into_inner(); @@ -193,7 +193,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; assert_eq!( @@ -226,7 +226,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; let http_response = response.unwrap().into_inner(); @@ -251,7 +251,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "420".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; @@ -278,7 +278,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; @@ -306,7 +306,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: format!("{}", response_limit + 1).as_bytes().to_vec(), max_response_size_bytes: response_limit, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; @@ -339,7 +339,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: format!("{}", response_size).as_bytes().to_vec(), max_response_size_bytes: response_size * 2, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; @@ -367,7 +367,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: format!("{}", delay).as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; @@ -404,7 +404,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 64, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; assert_eq!( @@ -444,7 +444,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".as_bytes().to_vec(), max_response_size_bytes: response_limit, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; @@ -470,7 +470,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; let _ = response.unwrap_err(); @@ -574,7 +574,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }); let response = client.https_outcall(request).await; diff --git a/rs/https_outcalls/client/src/client.rs b/rs/https_outcalls/client/src/client.rs index bfbe07c3db3..8914ce54943 100644 --- a/rs/https_outcalls/client/src/client.rs +++ b/rs/https_outcalls/client/src/client.rs @@ -147,7 +147,7 @@ impl NonBlockingChannel for CanisterHttpAdapterClientImpl { transform: request_transform, .. }, - api_bn_ips, + socks_proxy_addrs, } = canister_http_request; let adapter_req_timer = Instant::now(); @@ -171,7 +171,7 @@ impl NonBlockingChannel for CanisterHttpAdapterClientImpl { body: request_body.unwrap_or_default(), // Socks proxy is only enabled on system subnets. socks_proxy_allowed: matches!(subnet_type, SubnetType::System), - api_bn_ips, + socks_proxy_addrs, }) .map_err(|grpc_status| { ( @@ -450,7 +450,7 @@ mod tests { }), time: UNIX_EPOCH, }, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], } } diff --git a/rs/https_outcalls/consensus/src/pool_manager.rs b/rs/https_outcalls/consensus/src/pool_manager.rs index 88469161a07..0eea3f1aa57 100644 --- a/rs/https_outcalls/consensus/src/pool_manager.rs +++ b/rs/https_outcalls/consensus/src/pool_manager.rs @@ -147,6 +147,7 @@ impl CanisterHttpPoolManagerImpl { } fn generate_api_boundary_node_ips(&self) -> Vec { + //TODO(mihailjianu): return vec![] if DL is disabled. let latest_registry_version = self.registry_client.get_latest_version(); self.registry_client @@ -220,7 +221,7 @@ impl CanisterHttpPoolManagerImpl { .cloned() .collect(); - let api_bn_ips = self.generate_api_boundary_node_ips(); + let socks_proxy_addrs = self.generate_api_boundary_node_ips(); for (id, context) in http_requests { if !request_ids_already_made.contains(&id) { @@ -233,7 +234,7 @@ impl CanisterHttpPoolManagerImpl { id, timeout, context, - api_bn_ips: api_bn_ips.clone(), + socks_proxy_addrs: socks_proxy_addrs.clone(), }) { warn!( @@ -944,7 +945,7 @@ pub mod test { timeout: ic_types::Time::from_nanos_since_unix_epoch(10) + Duration::from_secs(60 * 5), context: request.clone(), - api_bn_ips: vec![], + socks_proxy_addrs: vec![], })) .times(1) .return_const(Ok(())); diff --git a/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto b/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto index 495be4f3c0f..35430d021e0 100644 --- a/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto +++ b/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto @@ -21,7 +21,7 @@ message HttpsOutcallRequest { HttpMethod method = 4; uint64 max_response_size_bytes = 5; bool socks_proxy_allowed = 6; - repeated string api_bn_ips = 7; + repeated string socks_proxy_addrs = 7; } message HttpsOutcallResponse { diff --git a/rs/pocket_ic_server/src/pocket_ic.rs b/rs/pocket_ic_server/src/pocket_ic.rs index c478f1377cd..29924f01326 100644 --- a/rs/pocket_ic_server/src/pocket_ic.rs +++ b/rs/pocket_ic_server/src/pocket_ic.rs @@ -1248,7 +1248,7 @@ impl Operation for ProcessCanisterHttpInternal { timeout: context.time + Duration::from_secs(5 * 60), id, context, - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }) { canister_http.pending.insert(id); } @@ -1416,7 +1416,7 @@ fn process_mock_canister_https_response( timeout, id: canister_http_request_id, context: context.clone(), - api_bn_ips: vec![], + socks_proxy_addrs: vec![], }) .unwrap(); let response = loop { diff --git a/rs/tests/networking/BUILD.bazel b/rs/tests/networking/BUILD.bazel index 3301e79eb53..468fdda5f63 100644 --- a/rs/tests/networking/BUILD.bazel +++ b/rs/tests/networking/BUILD.bazel @@ -72,7 +72,6 @@ system_test_nns( deps = CANISTER_HTTP_BASE_DEPS + [ "//rs/registry/subnet_features", "//rs/registry/subnet_type", - "//rs/tests/consensus/utils", # needed for starting the nns. ], ) diff --git a/rs/tests/testing_verification/testnets/BUILD.bazel b/rs/tests/testing_verification/testnets/BUILD.bazel index bfa8e760161..5fbfe633167 100644 --- a/rs/tests/testing_verification/testnets/BUILD.bazel +++ b/rs/tests/testing_verification/testnets/BUILD.bazel @@ -163,14 +163,11 @@ system_test_nns( ], deps = [ # Keep sorted. - "//rs/registry/subnet_features", "//rs/registry/subnet_type", "//rs/tests/consensus/utils", "//rs/tests/driver:ic-system-test-driver", - "//rs/tests/networking/canister_http", "//rs/tests/nns/nns_dapp", "@crate_index//:anyhow", - "@crate_index//:slog", ], ) diff --git a/rs/types/types/src/canister_http.rs b/rs/types/types/src/canister_http.rs index fb453cbdbd9..4228260ccde 100644 --- a/rs/types/types/src/canister_http.rs +++ b/rs/types/types/src/canister_http.rs @@ -457,8 +457,10 @@ pub struct CanisterHttpRequest { pub id: CanisterHttpRequestId, /// The context of the request which captures all the metadata about this request pub context: CanisterHttpRequestContext, - /// The most up to date api boundary nodes that should be used as a socks proxy in the case of a request to an IPv4 address. - pub api_bn_ips: Vec, + /// The most up to date api boundary nodes address that should be used as a socks proxy in the case of a request to an IPv4 address. + /// The addresses should be sent in the following format: "socks5://[]:", for example: + /// "socks5://[2602:fb2b:110:10:506f:cff:feff:fe69]:1080" + pub socks_proxy_addrs: Vec, } /// The content of a response after the transformation From 2ea658b9cf0cd7e30a21681fb1c230ddec25e108 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 4 Dec 2024 15:05:58 +0000 Subject: [PATCH 24/34] fix --- rs/https_outcalls/adapter/src/rpc_server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index cdc0f9da7a4..cf38c0c1b66 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -216,7 +216,7 @@ impl CanisterHttp { let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); self.metrics.socks_cache_miss.inc(); - match self.create_socks_client_for_ip(&next_socks_proxy_addr) { + match self.create_socks_client_for_address(&next_socks_proxy_addr) { Some(client) => { cache_guard.insert(next_socks_proxy_addr.clone(), client.clone()); self.metrics.socks_cache_size.set(cache_guard.len() as i64); From 5b146286bc86a7816d9b0e1eb9827c6e5f2132e5 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 4 Dec 2024 15:21:06 +0000 Subject: [PATCH 25/34] fix --- rs/https_outcalls/consensus/src/pool_manager.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rs/https_outcalls/consensus/src/pool_manager.rs b/rs/https_outcalls/consensus/src/pool_manager.rs index 0eea3f1aa57..c996c1aa6e3 100644 --- a/rs/https_outcalls/consensus/src/pool_manager.rs +++ b/rs/https_outcalls/consensus/src/pool_manager.rs @@ -33,6 +33,8 @@ use std::{ pub type CanisterHttpAdapterClient = Box + Send>; +const SOCKS_PROXY_DL_ACTIVE: bool = false; + /// [`CanisterHttpPoolManagerImpl`] implements the pool and state monitoring /// functionality that is necessary to ensure that http requests are made and /// responses can be inserted into consensus. Concretely, it has the following responsibilities: @@ -147,7 +149,10 @@ impl CanisterHttpPoolManagerImpl { } fn generate_api_boundary_node_ips(&self) -> Vec { - //TODO(mihailjianu): return vec![] if DL is disabled. + if !SOCKS_PROXY_DL_ACTIVE { + return Vec::new(); + } + let latest_registry_version = self.registry_client.get_latest_version(); self.registry_client From 9054a99bf3700b83c9c468e245a56399026fb1e0 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Fri, 13 Dec 2024 14:01:36 +0000 Subject: [PATCH 26/34] coments --- rs/https_outcalls/adapter/src/metrics.rs | 14 +--- rs/https_outcalls/adapter/src/rpc_server.rs | 77 ++++++++----------- .../adapter/tests/server_test.rs | 24 +++--- .../consensus/src/pool_manager.rs | 7 +- .../https_outcalls_service/v1/proto.proto | 1 + 5 files changed, 56 insertions(+), 67 deletions(-) diff --git a/rs/https_outcalls/adapter/src/metrics.rs b/rs/https_outcalls/adapter/src/metrics.rs index f8099527321..a2482cc0705 100644 --- a/rs/https_outcalls/adapter/src/metrics.rs +++ b/rs/https_outcalls/adapter/src/metrics.rs @@ -21,13 +21,11 @@ pub struct AdapterMetrics { /// The number of requests served via a SOCKS proxy. pub requests_socks: IntCounter, /// The number of socks connections attempts - pub socks_connections_attempts: IntCounter, + pub socks_connections_attempts: IntCounterVec, /// The number of socks clients in the cache pub socks_cache_size: IntGauge, /// The number of cache misses for socks clients pub socks_cache_miss: IntCounter, - /// The number of successful socks connections - pub succesful_socks_connections: IntCounterVec, /// Network traffic generated by adapter. pub network_traffic: IntCounterVec, /// Request failure types. @@ -46,9 +44,10 @@ impl AdapterMetrics { "requests_socks_total", "Total number of requests served via a SOCKS proxy", ), - socks_connections_attempts: metrics_registry.int_counter( - "socks_connections_attempts", + socks_connections_attempts: metrics_registry.int_counter_vec( + "socks_connections_attempts_total", "Total number of time the adapter tries to proxy a request via a SOCKS proxy", + &["number_of_tries", "status"], ), socks_cache_size: metrics_registry.int_gauge( "socks_cache_size", @@ -58,11 +57,6 @@ impl AdapterMetrics { "socks_cache_miss", "Total number of times the adapter failed to find a SOCKS client in the cache", ), - succesful_socks_connections: metrics_registry.int_counter_vec( - "successful_socks_connections_total", - "Total number of successful SOCKS connections", - &["number_of_tries"], - ), network_traffic: metrics_registry.int_counter_vec( "network_traffic_bytes_total", "Network traffic generated by adapter.", diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index cf38c0c1b66..c34da306684 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -7,14 +7,12 @@ use crate::Config; use core::convert::TryFrom; use http::{header::USER_AGENT, HeaderName, HeaderValue, Uri}; use http_body_util::{BodyExt, Full}; +use hyper::body::Incoming; use hyper::{ body::Bytes, header::{HeaderMap, ToStrError}, Method, }; -use rand::Rng; - -use hyper::body::Incoming; use hyper_rustls::HttpsConnector; use hyper_rustls::HttpsConnectorBuilder; use hyper_socks2::SocksConnector; @@ -27,7 +25,7 @@ use ic_https_outcalls_service::{ use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; -use rand::{seq::SliceRandom, thread_rng}; +use rand::{seq::SliceRandom, thread_rng, Rng}; use std::collections::BTreeMap; use std::str::FromStr; use std::sync::Arc; @@ -51,6 +49,7 @@ const MAX_HEADER_LIST_SIZE: u32 = 52 * 1024; /// The maximum number of times we will try to connect to a SOCKS proxy. const MAX_SOCKS_PROXY_RETRIES: usize = 3; +//TODO(SOCKS_PROXY_DL): Make this > 0. /// The probability of using api boundary node addresses for SOCKS proxy dark launch. const REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE: u32 = 0; @@ -121,40 +120,27 @@ impl CanisterHttp { } } - fn create_socks_client_for_address( - &self, - address: &str, - ) -> Option>, OutboundRequestBody>> { - // Create a new HTTP connector + fn maybe_add_socks_client_for_address(&self, cache: &mut Cache, address: &str) { let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); http_connector .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); - match address.parse() { - Ok(proxy_addr) => { - let proxy_connector = SocksConnector { - proxy_addr, - auth: None, - connector: http_connector, - }; - - let proxied_https_connector = HttpsConnectorBuilder::new() + if let Ok(proxy_addr) = address.parse() { + let client = Client::builder(TokioExecutor::new()).build::<_, Full>( + HttpsConnectorBuilder::new() .with_native_roots() .expect("Failed to set native roots") .https_only() .enable_all_versions() - .wrap_connector(proxy_connector); - - let socks_client = Client::builder(TokioExecutor::new()) - .build::<_, Full>(proxied_https_connector); - - Some(socks_client) - } - Err(e) => { - debug!(self.logger, "Failed to parse SOCKS address: {}", e); - None - } + .wrap_connector(SocksConnector { + proxy_addr, + auth: None, + connector: http_connector, + }), + ); + cache.insert(address.to_string(), client); + self.metrics.socks_cache_size.set(cache.len() as i64); } } @@ -187,7 +173,7 @@ impl CanisterHttp { } } - async fn https_outcall_dl_socks_proxy( + async fn https_outcall_socks_proxy( &self, socks_proxy_addrs: &[String], request: http::Request>, @@ -215,32 +201,37 @@ impl CanisterHttp { } else { let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); self.metrics.socks_cache_miss.inc(); - - match self.create_socks_client_for_address(&next_socks_proxy_addr) { - Some(client) => { - cache_guard.insert(next_socks_proxy_addr.clone(), client.clone()); - self.metrics.socks_cache_size.set(cache_guard.len() as i64); - client - } + self.maybe_add_socks_client_for_address( + &mut cache_guard, + &next_socks_proxy_addr, + ); + match cache_guard.get(&next_socks_proxy_addr) { + Some(client) => client.clone(), None => { - // there is something wrong with this address, try another one. + debug!( + self.logger, + "Failed to create SOCKS client for address: {}", + next_socks_proxy_addr + ); continue; } } } }; - self.metrics.socks_connections_attempts.inc(); - match socks_client.request(request.clone()).await { Ok(resp) => { self.metrics - .succesful_socks_connections - .with_label_values(&[&tries.to_string()]) + .socks_connections_attempts + .with_label_values(&[&tries.to_string(), "success"]) .inc(); return Ok(resp); } Err(socks_err) => { + self.metrics + .socks_connections_attempts + .with_label_values(&[&tries.to_string(), "failure"]) + .inc(); debug!( self.logger, "Failed to connect through SOCKS with address {}: {}", @@ -360,7 +351,7 @@ impl HttpsOutcallsService for CanisterHttp { }); if should_dl_socks_proxy() { - let dl_result= self.https_outcall_dl_socks_proxy(&req.socks_proxy_addrs, http_req_clone).await; + let dl_result = self.https_outcall_socks_proxy(&req.socks_proxy_addrs, http_req_clone).await; self.compare_results(&result, &dl_result); } diff --git a/rs/https_outcalls/adapter/tests/server_test.rs b/rs/https_outcalls/adapter/tests/server_test.rs index a0e83dbb7c0..2d22fd5eddd 100644 --- a/rs/https_outcalls/adapter/tests/server_test.rs +++ b/rs/https_outcalls/adapter/tests/server_test.rs @@ -166,7 +166,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; let http_response = response.unwrap().into_inner(); @@ -193,7 +193,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; assert_eq!( @@ -226,7 +226,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; let http_response = response.unwrap().into_inner(); @@ -251,7 +251,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "420".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; @@ -278,7 +278,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; @@ -306,7 +306,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: format!("{}", response_limit + 1).as_bytes().to_vec(), max_response_size_bytes: response_limit, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; @@ -339,7 +339,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: format!("{}", response_size).as_bytes().to_vec(), max_response_size_bytes: response_size * 2, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; @@ -367,7 +367,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: format!("{}", delay).as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; @@ -404,7 +404,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 64, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; assert_eq!( @@ -444,7 +444,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".as_bytes().to_vec(), max_response_size_bytes: response_limit, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; @@ -470,7 +470,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; let _ = response.unwrap_err(); @@ -574,7 +574,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE body: "hello".to_string().as_bytes().to_vec(), max_response_size_bytes: 512, socks_proxy_allowed: false, - socks_proxy_addrs: vec![], + ..Default::default() }); let response = client.https_outcall(request).await; diff --git a/rs/https_outcalls/consensus/src/pool_manager.rs b/rs/https_outcalls/consensus/src/pool_manager.rs index c996c1aa6e3..dcf69ac5198 100644 --- a/rs/https_outcalls/consensus/src/pool_manager.rs +++ b/rs/https_outcalls/consensus/src/pool_manager.rs @@ -33,6 +33,7 @@ use std::{ pub type CanisterHttpAdapterClient = Box + Send>; +//TODO(SOCKS_PROXY_DL): Make this true. const SOCKS_PROXY_DL_ACTIVE: bool = false; /// [`CanisterHttpPoolManagerImpl`] implements the pool and state monitoring @@ -148,7 +149,7 @@ impl CanisterHttpPoolManagerImpl { .collect() } - fn generate_api_boundary_node_ips(&self) -> Vec { + fn generate_api_boundary_node_addrs(&self) -> Vec { if !SOCKS_PROXY_DL_ACTIVE { return Vec::new(); } @@ -226,7 +227,9 @@ impl CanisterHttpPoolManagerImpl { .cloned() .collect(); - let socks_proxy_addrs = self.generate_api_boundary_node_ips(); + //TODO: this happens farely rarely. However ideally we should only try to get the + // boundary node addresses if the subnet is a system subnet. + let socks_proxy_addrs = self.generate_api_boundary_node_addrs(); for (id, context) in http_requests { if !request_ids_already_made.contains(&id) { diff --git a/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto b/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto index 35430d021e0..939195bf64a 100644 --- a/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto +++ b/rs/https_outcalls/service/proto/https_outcalls_service/v1/proto.proto @@ -20,6 +20,7 @@ message HttpsOutcallRequest { repeated HttpHeader headers = 3; HttpMethod method = 4; uint64 max_response_size_bytes = 5; + // After the dark launch, this will be removed in favour of socks_proxy_addrs. bool socks_proxy_allowed = 6; repeated string socks_proxy_addrs = 7; } From 117a763bf95a7b5313b386e1fbb33dbe1dca3972 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Fri, 13 Dec 2024 14:16:12 +0000 Subject: [PATCH 27/34] refactor --- rs/https_outcalls/adapter/src/rpc_server.rs | 57 ++++++++++++--------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index c34da306684..b170dd0e968 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -173,6 +173,32 @@ impl CanisterHttp { } } + // Attemts to load socks the client from the cache. If not present, creates a new socks client and adds it to the cache. + fn get_socks_client( + &self, + address: &str, + ) -> Option>, OutboundRequestBody>> { + let cache_guard = self.cache.upgradable_read(); + + if let Some(client) = cache_guard.get(address) { + Some(client.clone()) + } else { + let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); + self.metrics.socks_cache_miss.inc(); + self.maybe_add_socks_client_for_address(&mut cache_guard, address); + match cache_guard.get(address) { + Some(client) => Some(client.clone()), + None => { + debug!( + self.logger, + "Failed to create SOCKS client for address: {}", address + ); + None + } + } + } + } + async fn https_outcall_socks_proxy( &self, socks_proxy_addrs: &[String], @@ -193,31 +219,12 @@ impl CanisterHttp { } let next_socks_proxy_addr = socks_proxy_addr.clone(); - let socks_client = { - let cache_guard = self.cache.upgradable_read(); - - if let Some(client) = cache_guard.get(&next_socks_proxy_addr) { - client.clone() - } else { - let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); - self.metrics.socks_cache_miss.inc(); - self.maybe_add_socks_client_for_address( - &mut cache_guard, - &next_socks_proxy_addr, - ); - match cache_guard.get(&next_socks_proxy_addr) { - Some(client) => client.clone(), - None => { - debug!( - self.logger, - "Failed to create SOCKS client for address: {}", - next_socks_proxy_addr - ); - continue; - } - } - } - }; + let socks_client = self.get_socks_client(&next_socks_proxy_addr); + + if socks_client.is_none() { + continue; + } + let socks_client = socks_client.unwrap(); match socks_client.request(request.clone()).await { Ok(resp) => { From 3a650a72a2c5ab5e6e8644824e6432bfcb52727a Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Fri, 13 Dec 2024 14:17:42 +0000 Subject: [PATCH 28/34] rename metric --- rs/https_outcalls/adapter/src/metrics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rs/https_outcalls/adapter/src/metrics.rs b/rs/https_outcalls/adapter/src/metrics.rs index a2482cc0705..faf847adce8 100644 --- a/rs/https_outcalls/adapter/src/metrics.rs +++ b/rs/https_outcalls/adapter/src/metrics.rs @@ -47,7 +47,7 @@ impl AdapterMetrics { socks_connections_attempts: metrics_registry.int_counter_vec( "socks_connections_attempts_total", "Total number of time the adapter tries to proxy a request via a SOCKS proxy", - &["number_of_tries", "status"], + &["attempt_number", "status"], ), socks_cache_size: metrics_registry.int_gauge( "socks_cache_size", From a40e10d3ba2c280e98d047ac4821407b7da4f2f3 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Mon, 23 Dec 2024 09:09:59 +0000 Subject: [PATCH 29/34] comments --- rs/https_outcalls/adapter/src/metrics.rs | 12 ++-- rs/https_outcalls/adapter/src/rpc_server.rs | 67 +++++++------------ rs/https_outcalls/consensus/BUILD.bazel | 2 +- rs/https_outcalls/consensus/Cargo.toml | 1 + .../consensus/src/pool_manager.rs | 30 ++++++--- 5 files changed, 54 insertions(+), 58 deletions(-) diff --git a/rs/https_outcalls/adapter/src/metrics.rs b/rs/https_outcalls/adapter/src/metrics.rs index faf847adce8..5c89c4380c5 100644 --- a/rs/https_outcalls/adapter/src/metrics.rs +++ b/rs/https_outcalls/adapter/src/metrics.rs @@ -20,8 +20,8 @@ pub struct AdapterMetrics { pub requests: IntCounter, /// The number of requests served via a SOCKS proxy. pub requests_socks: IntCounter, - /// The number of socks connections attempts - pub socks_connections_attempts: IntCounterVec, + /// The number of socks connection attempts + pub socks_connection_attempts: IntCounterVec, /// The number of socks clients in the cache pub socks_cache_size: IntGauge, /// The number of cache misses for socks clients @@ -44,17 +44,17 @@ impl AdapterMetrics { "requests_socks_total", "Total number of requests served via a SOCKS proxy", ), - socks_connections_attempts: metrics_registry.int_counter_vec( - "socks_connections_attempts_total", + socks_connection_attempts: metrics_registry.int_counter_vec( + "socks_connection_attempts_total", "Total number of time the adapter tries to proxy a request via a SOCKS proxy", - &["attempt_number", "status"], + &["attempt_number", "status", "socks_proxy_address"], ), socks_cache_size: metrics_registry.int_gauge( "socks_cache_size", "The size of the cache for SOCKS clients", ), socks_cache_miss: metrics_registry.int_counter( - "socks_cache_miss", + "socks_cache_miss_total", "Total number of times the adapter failed to find a SOCKS client in the cache", ), network_traffic: metrics_registry.int_counter_vec( diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index b170dd0e968..5c28e27b426 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -25,7 +25,7 @@ use ic_https_outcalls_service::{ use ic_logger::{debug, ReplicaLogger}; use ic_metrics::MetricsRegistry; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; -use rand::{seq::SliceRandom, thread_rng, Rng}; +use rand::{seq::SliceRandom, thread_rng}; use std::collections::BTreeMap; use std::str::FromStr; use std::sync::Arc; @@ -49,10 +49,6 @@ const MAX_HEADER_LIST_SIZE: u32 = 52 * 1024; /// The maximum number of times we will try to connect to a SOCKS proxy. const MAX_SOCKS_PROXY_RETRIES: usize = 3; -//TODO(SOCKS_PROXY_DL): Make this > 0. -/// The probability of using api boundary node addresses for SOCKS proxy dark launch. -const REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE: u32 = 0; - type OutboundRequestBody = Full; type Cache = @@ -173,7 +169,7 @@ impl CanisterHttp { } } - // Attemts to load socks the client from the cache. If not present, creates a new socks client and adds it to the cache. + // Attempts to load the socks client from the cache. If not present, creates a new socks client and adds it to the cache. fn get_socks_client( &self, address: &str, @@ -221,31 +217,28 @@ impl CanisterHttp { let socks_client = self.get_socks_client(&next_socks_proxy_addr); - if socks_client.is_none() { - continue; - } - let socks_client = socks_client.unwrap(); - - match socks_client.request(request.clone()).await { - Ok(resp) => { - self.metrics - .socks_connections_attempts - .with_label_values(&[&tries.to_string(), "success"]) - .inc(); - return Ok(resp); - } - Err(socks_err) => { - self.metrics - .socks_connections_attempts - .with_label_values(&[&tries.to_string(), "failure"]) - .inc(); - debug!( - self.logger, - "Failed to connect through SOCKS with address {}: {}", - next_socks_proxy_addr, - socks_err - ); - last_error = Some(socks_err); + if let Some(socks_client) = socks_client { + match socks_client.request(request.clone()).await { + Ok(resp) => { + self.metrics + .socks_connection_attempts + .with_label_values(&[&tries.to_string(), "success", socks_proxy_addr]) + .inc(); + return Ok(resp); + } + Err(socks_err) => { + self.metrics + .socks_connection_attempts + .with_label_values(&[&tries.to_string(), "failure", socks_proxy_addr]) + .inc(); + debug!( + self.logger, + "Failed to connect through SOCKS with address {}: {}", + next_socks_proxy_addr, + socks_err + ); + last_error = Some(socks_err); + } } } } @@ -357,7 +350,8 @@ impl HttpsOutcallsService for CanisterHttp { format!("Request failed direct connect {direct_err} and connect through socks {e}") }); - if should_dl_socks_proxy() { + //TODO(SOCKS_PROXY_DL): Remove the compare_results once we are confident in the SOCKS proxy implementation. + if !req.socks_proxy_addrs.is_empty() { let dl_result = self.https_outcall_socks_proxy(&req.socks_proxy_addrs, http_req_clone).await; self.compare_results(&result, &dl_result); @@ -471,15 +465,6 @@ impl HttpsOutcallsService for CanisterHttp { } } -#[allow(clippy::absurd_extreme_comparisons)] -fn should_dl_socks_proxy() -> bool { - let mut rng = rand::thread_rng(); - let random_number: u32 = rng.gen_range(0..100); - // This is a dark launch feature. We want to test the SOCKS proxy with a small percentage of requests. - // Currently this is set to 0%, hence always false. - random_number < REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE -} - fn validate_headers(raw_headers: Vec) -> Result { // Check we are within limit for number of headers. if raw_headers.len() > HEADERS_LIMIT { diff --git a/rs/https_outcalls/consensus/BUILD.bazel b/rs/https_outcalls/consensus/BUILD.bazel index a03e49facc0..1332a9ff997 100644 --- a/rs/https_outcalls/consensus/BUILD.bazel +++ b/rs/https_outcalls/consensus/BUILD.bazel @@ -18,6 +18,7 @@ DEPENDENCIES = [ "//rs/types/types", "@crate_index//:hex", "@crate_index//:prometheus", + "@crate_index//:rand", "@crate_index//:slog", ] @@ -35,7 +36,6 @@ DEV_DEPENDENCIES = [ "//rs/test_utilities/types", "@crate_index//:mockall", "@crate_index//:proptest", - "@crate_index//:rand", "@crate_index//:rand_chacha", ] diff --git a/rs/https_outcalls/consensus/Cargo.toml b/rs/https_outcalls/consensus/Cargo.toml index 2c8a6e4681f..c611119681c 100644 --- a/rs/https_outcalls/consensus/Cargo.toml +++ b/rs/https_outcalls/consensus/Cargo.toml @@ -21,6 +21,7 @@ ic-registry-client-helpers = { path = "../../registry/helpers" } ic-replicated-state = { path = "../../replicated_state" } ic-types = { path = "../../types/types" } prometheus = { workspace = true } +rand = { workspace = true } slog = { workspace = true } [dev-dependencies] diff --git a/rs/https_outcalls/consensus/src/pool_manager.rs b/rs/https_outcalls/consensus/src/pool_manager.rs index dcf69ac5198..2c0f34fe6cf 100644 --- a/rs/https_outcalls/consensus/src/pool_manager.rs +++ b/rs/https_outcalls/consensus/src/pool_manager.rs @@ -22,6 +22,7 @@ use ic_types::{ canister_http::*, consensus::HasHeight, crypto::Signed, messages::CallbackId, replica_config::ReplicaConfig, Height, }; +use rand::Rng; use std::{ cell::RefCell, collections::{BTreeSet, HashSet}, @@ -33,8 +34,9 @@ use std::{ pub type CanisterHttpAdapterClient = Box + Send>; -//TODO(SOCKS_PROXY_DL): Make this true. -const SOCKS_PROXY_DL_ACTIVE: bool = false; +//TODO(SOCKS_PROXY_DL): Make this > 0. +/// The probability of using api boundary node addresses for SOCKS proxy dark launch. +const REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE: u32 = 0; /// [`CanisterHttpPoolManagerImpl`] implements the pool and state monitoring /// functionality that is necessary to ensure that http requests are made and @@ -56,6 +58,16 @@ pub struct CanisterHttpPoolManagerImpl { log: ReplicaLogger, } +//TODO(SOCKS_PROXY_DL): Remove this function. +#[allow(clippy::absurd_extreme_comparisons)] +fn should_dl_socks_proxy() -> bool { + let mut rng = rand::thread_rng(); + let random_number: u32 = rng.gen_range(0..100); + // This is a dark launch feature. We want to test the SOCKS proxy with a small percentage of requests. + // Currently this is set to 0%, hence always false. + random_number < REGISTRY_SOCKS_PROXY_DARK_LAUNCH_PERCENTAGE +} + impl CanisterHttpPoolManagerImpl { /// Create a new [`CanisterHttpPoolManagerImpl`] pub fn new( @@ -149,11 +161,7 @@ impl CanisterHttpPoolManagerImpl { .collect() } - fn generate_api_boundary_node_addrs(&self) -> Vec { - if !SOCKS_PROXY_DL_ACTIVE { - return Vec::new(); - } - + fn get_socks_proxy_addrs(&self) -> Vec { let latest_registry_version = self.registry_client.get_latest_version(); self.registry_client @@ -227,9 +235,11 @@ impl CanisterHttpPoolManagerImpl { .cloned() .collect(); - //TODO: this happens farely rarely. However ideally we should only try to get the - // boundary node addresses if the subnet is a system subnet. - let socks_proxy_addrs = self.generate_api_boundary_node_addrs(); + let socks_proxy_addrs = if should_dl_socks_proxy() { + self.get_socks_proxy_addrs() + } else { + Vec::new() + }; for (id, context) in http_requests { if !request_ids_already_made.contains(&id) { From a4329d95867b2c176dfdf620440a118d484d7d39 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Fri, 27 Dec 2024 10:35:31 +0000 Subject: [PATCH 30/34] lock --- Cargo.lock | 1193 +++++++++++++++++++++++----------------------------- 1 file changed, 530 insertions(+), 663 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8190b76586e..055bfd21060 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "abnf" @@ -299,7 +299,7 @@ dependencies = [ "axum", "bytes", "cfg-if 1.0.0", - "http 1.1.0", + "http 1.2.0", "indexmap 2.6.0", "schemars", "serde", @@ -372,6 +372,7 @@ dependencies = [ "candid", "ic-canister-client", "ic-types", + "prometheus", "rand 0.8.5", "rsa", "thiserror 2.0.3", @@ -649,7 +650,7 @@ checksum = "096146020b08dbc4587685b0730a7ba905625af13c65f8028035cdfd69573c91" dependencies = [ "anyhow", "futures", - "http 1.1.0", + "http 1.2.0", "httparse", "log", ] @@ -695,17 +696,6 @@ dependencies = [ "futures-lite", ] -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "async-scoped" version = "0.9.0" @@ -776,7 +766,7 @@ dependencies = [ "async-net", "futures", "futures-rustls", - "http 1.1.0", + "http 1.2.0", "lazy_static", "log", "rustls-pki-types", @@ -837,7 +827,7 @@ dependencies = [ "axum-core", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -870,7 +860,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", @@ -893,7 +883,7 @@ dependencies = [ "bytes", "futures-util", "headers 0.4.0", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", @@ -914,7 +904,7 @@ dependencies = [ "arc-swap", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -1558,9 +1548,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -1684,7 +1674,7 @@ dependencies = [ "bytes", "clap 4.5.20", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -1817,18 +1807,6 @@ dependencies = [ "wat", ] -[[package]] -name = "canister_client" -version = "0.9.0" -dependencies = [ - "candid", - "ic-agent 0.37.1", - "k256", - "rate-limits-api", - "regex", - "tokio", -] - [[package]] name = "canister_http" version = "0.9.0" @@ -1928,7 +1906,7 @@ dependencies = [ "cloudflare 0.12.0 (git+https://github.com/dfinity/cloudflare-rs.git?rev=a6538a036926bd756986c9c0a5de356daef48881)", "flate2", "futures", - "http 1.1.0", + "http 1.2.0", "ic-agent 0.37.1", "ic-http-certification", "ic-response-verification", @@ -2207,7 +2185,7 @@ dependencies = [ [[package]] name = "cloner-canister-types" -version = "0.1.0" +version = "0.9.0" dependencies = [ "candid", "futures", @@ -2409,7 +2387,6 @@ version = "0.9.0" dependencies = [ "anyhow", "canister-test", - "canister_http", "ic-agent 0.37.1", "ic-base-types", "ic-interfaces-registry", @@ -2666,18 +2643,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5e7afe85cadb55c4c1176268a2ac046fdff8dfaeca39e18581b9dc319ca9e" +checksum = "2ba4f80548f22dc9c43911907b5e322c5555544ee85f785115701e6a28c9abe1" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ab25ef3be935a80680e393183e1f94ef507e93a24a8369494d2c6818aedb3e3" +checksum = "005884e3649c3e5ff2dc79e8a94b138f11569cc08a91244a292714d2a86e9156" dependencies = [ "serde", "serde_derive", @@ -2685,9 +2662,9 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900a19b84545924f1851cbfe386962edfc4ecbc3366a254825cf1ecbcda8ba08" +checksum = "fe4036255ec33ce9a37495dfbcfc4e1118fd34e693eff9a1e106336b7cd16a9b" dependencies = [ "bumpalo", "cranelift-bforest", @@ -2702,39 +2679,40 @@ dependencies = [ "log", "regalloc2", "rustc-hash 2.0.0", + "serde", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c73b2395ffe9e7b4fdf7e2ebc052e7e27af13f68a964985346be4da477a5fc" +checksum = "f7ca74f4b68319da11d39e894437cb6e20ec7c2e11fbbda823c3bf207beedff7" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d9ed0854e96a4ff0879bff39d078de8dea7f002721c9494c1fdb4e1baa86ccc" +checksum = "897e54f433a0269c4187871aa06d452214d5515d228d5bdc22219585e9eef895" [[package]] name = "cranelift-control" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4aca921dd422e781409de0129c255768fec5dec1dae83239b497fb9138abb89" +checksum = "29cb4018f5bf59fb53f515fa9d80e6f8c5ce19f198dc538984ebd23ecf8965ec" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d770e6605eccee15b49decdd82cd26f2b6404767802471459ea49c57379a98" +checksum = "305399fd781a2953ac78c1396f02ff53144f39c33eb7fc7789cf4e8936d13a96" dependencies = [ "cranelift-bitset", "serde", @@ -2743,9 +2721,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29268711cb889cb39215b10faf88b9087d4c9e1d2633581e4f722a2bf4bb4ef9" +checksum = "9230b460a128d53653456137751d27baf567947a3ab8c0c4d6e31fd08036d81e" dependencies = [ "cranelift-codegen", "log", @@ -2755,15 +2733,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc65156f010aed1985767ad1bff0eb8d186743b7b03e23d0c17604a253e3f356" +checksum = "b961e24ae3ec9813a24a15ae64bbd2a42e4de4d79a7f3225a412e3b94e78d1c8" [[package]] name = "cranelift-native" -version = "0.113.0" +version = "0.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8bf9b361eaf5a7627647270fabf1dc910d993edbeaf272a652c107861ebe9c2" +checksum = "4d5bd76df6c9151188dfa428c863b33da5b34561b67f43c0cf3f24a794f9fa1f" dependencies = [ "cranelift-codegen", "libc", @@ -3809,16 +3787,6 @@ dependencies = [ "log", ] -[[package]] -name = "env_logger" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" -dependencies = [ - "log", - "regex", -] - [[package]] name = "env_logger" version = "0.11.5" @@ -4423,7 +4391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pki-types", ] @@ -4636,7 +4604,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http 1.2.0", "indexmap 2.6.0", "slab", "tokio", @@ -4732,7 +4700,7 @@ dependencies = [ "base64 0.21.7", "bytes", "headers-core 0.3.0", - "http 1.1.0", + "http 1.2.0", "httpdate", "mime", "sha1", @@ -4753,7 +4721,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -4968,9 +4936,9 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -4995,7 +4963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -5017,7 +4985,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] @@ -5047,7 +5015,7 @@ dependencies = [ "clap 4.5.20", "hyper 1.5.1", "hyper-util", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pemfile 2.2.0", "serde_json", "tokio", @@ -5120,7 +5088,7 @@ dependencies = [ "futures-channel", "futures-util", "h2 0.4.6", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "httparse", "httpdate", @@ -5140,7 +5108,7 @@ dependencies = [ "bytes", "futures-util", "headers 0.4.0", - "http 1.1.0", + "http 1.2.0", "hyper 1.5.1", "hyper-rustls 0.27.3", "hyper-util", @@ -5172,11 +5140,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.1.0", + "http 1.2.0", "hyper 1.5.1", "hyper-util", "log", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-native-certs 0.8.0", "rustls-pki-types", "tokio", @@ -5192,7 +5160,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51c227614c208f7e7c2e040526912604a1a957fe467c9c2f5b06c5d032337dab" dependencies = [ "async-socks5", - "http 1.1.0", + "http 1.2.0", "hyper 1.5.1", "hyper-util", "thiserror 1.0.68", @@ -5222,7 +5190,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "hyper 1.5.1", "pin-project-lite", @@ -5261,7 +5229,7 @@ version = "0.9.0" dependencies = [ "hyper-util", "ic-adapter-metrics-service", - "ic-async-utils", + "ic-http-endpoints-async-utils", "prometheus", "protobuf", "slog", @@ -5272,7 +5240,7 @@ dependencies = [ [[package]] name = "ic-adapter-metrics-server" -version = "0.1.0" +version = "0.9.0" dependencies = [ "futures", "ic-adapter-metrics-service", @@ -5286,7 +5254,7 @@ dependencies = [ [[package]] name = "ic-adapter-metrics-service" -version = "0.1.0" +version = "0.9.0" dependencies = [ "prost 0.13.3", "prost-build 0.13.3", @@ -5385,7 +5353,7 @@ dependencies = [ "ed25519-consensus", "futures-util", "hex", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-to-bytes", "http-body-util", @@ -5436,7 +5404,7 @@ dependencies = [ "elliptic-curve", "futures-util", "hex", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "ic-certification 2.6.0", "ic-transport-types 0.39.1", @@ -5465,7 +5433,7 @@ dependencies = [ [[package]] name = "ic-artifact-downloader" -version = "0.1.0" +version = "0.9.0" dependencies = [ "anyhow", "axum", @@ -5558,23 +5526,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "ic-async-utils" -version = "0.9.0" -dependencies = [ - "anyhow", - "async-stream", - "byte-unit", - "bytes", - "futures", - "futures-util", - "hyper 1.5.1", - "rand 0.8.5", - "slog", - "tokio", - "tonic", -] - [[package]] name = "ic-backup" version = "0.9.0" @@ -5664,7 +5615,7 @@ dependencies = [ [[package]] name = "ic-bn-lib" version = "0.1.0" -source = "git+https://github.com/dfinity/ic-bn-lib?rev=526d34d15cfbf369d8baf2dae9932aa18d570a1d#526d34d15cfbf369d8baf2dae9932aa18d570a1d" +source = "git+https://github.com/dfinity/ic-bn-lib?rev=d74a6527fbaf8a2c1a7076983cc84f5c5a727923#d74a6527fbaf8a2c1a7076983cc84f5c5a727923" dependencies = [ "ahash 0.8.11", "anyhow", @@ -5684,14 +5635,13 @@ dependencies = [ "futures-util", "hickory-proto", "hickory-resolver", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "humantime", "hyper 1.5.1", "hyper-util", "instant-acme", - "mockall", "moka", "parse-size", "prometheus", @@ -5700,7 +5650,7 @@ dependencies = [ "rand 0.8.5", "rcgen", "reqwest 0.12.9", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-acme", "rustls-pemfile 2.2.0", "rustls-platform-verifier", @@ -5710,9 +5660,8 @@ dependencies = [ "sha1", "strum", "strum_macros", - "sync_wrapper 1.0.1", "systemstat", - "thiserror 1.0.68", + "thiserror 2.0.3", "tokio", "tokio-io-timeout", "tokio-rustls 0.26.0", @@ -5748,7 +5697,7 @@ dependencies = [ "futures", "futures-util", "hex", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "humantime", "ic-agent 0.39.1", @@ -5780,6 +5729,7 @@ dependencies = [ "ic-registry-subnet-type", "ic-types", "indoc", + "ipnet", "lazy_static", "maxminddb", "mockall", @@ -5788,11 +5738,12 @@ dependencies = [ "nix 0.24.3", "prometheus", "rand 0.8.5", + "rate-limits-api", "ratelimit", "rcgen", "regex", "reqwest 0.12.9", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pemfile 2.2.0", "serde", "serde_bytes", @@ -5813,7 +5764,7 @@ dependencies = [ "tower-http 0.6.2", "tower_governor", "tracing", - "tracing-serde", + "tracing-serde 0.1.3", "tracing-slog", "tracing-subscriber", "url", @@ -5920,10 +5871,9 @@ dependencies = [ "futures", "hashlink", "hex", - "http 1.1.0", + "http 1.2.0", "hyper-util", "ic-adapter-metrics-server", - "ic-async-utils", "ic-btc-adapter-client", "ic-btc-adapter-test-utils", "ic-btc-interface", @@ -5931,6 +5881,7 @@ dependencies = [ "ic-btc-service", "ic-btc-validation", "ic-config", + "ic-http-endpoints-async-utils", "ic-interfaces-adapter-client", "ic-logger", "ic-metrics", @@ -5957,10 +5908,10 @@ version = "0.9.0" dependencies = [ "hyper-util", "ic-adapter-metrics-client", - "ic-async-utils", "ic-btc-replica-types", "ic-btc-service", "ic-config", + "ic-http-endpoints-async-utils", "ic-interfaces-adapter-client", "ic-logger", "ic-metrics", @@ -5986,6 +5937,39 @@ dependencies = [ "tokio", ] +[[package]] +name = "ic-btc-checker" +version = "0.9.0" +dependencies = [ + "askama", + "base64 0.13.1", + "bitcoin 0.32.3", + "candid", + "candid_parser", + "ciborium", + "futures", + "hex", + "ic-base-types", + "ic-btc-interface", + "ic-canister-log 0.2.0", + "ic-canisters-http-types", + "ic-cdk 0.16.0", + "ic-metrics-encoder", + "ic-stable-structures", + "ic-test-utilities-load-wasm", + "ic-types", + "ic-universal-canister", + "pocket-ic", + "proptest", + "regex", + "scraper", + "serde", + "serde_json", + "time", + "tokio", + "url", +] + [[package]] name = "ic-btc-consensus" version = "0.9.0" @@ -6031,38 +6015,6 @@ dependencies = [ "serde_bytes", ] -[[package]] -name = "ic-btc-kyt" -version = "0.9.0" -dependencies = [ - "askama", - "base64 0.13.1", - "bitcoin 0.32.3", - "candid", - "candid_parser", - "ciborium", - "futures", - "hex", - "ic-base-types", - "ic-btc-interface", - "ic-canister-log 0.2.0", - "ic-canisters-http-types", - "ic-cdk 0.16.0", - "ic-metrics-encoder", - "ic-stable-structures", - "ic-test-utilities-load-wasm", - "ic-types", - "ic-universal-canister", - "num-traits", - "pocket-ic", - "scraper", - "serde", - "serde_json", - "time", - "tokio", - "url", -] - [[package]] name = "ic-btc-replica-types" version = "0.9.0" @@ -6084,18 +6036,9 @@ dependencies = [ "tonic-build", ] -[[package]] -name = "ic-btc-test-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8e0a43145188ba239150f8460d314b0dd6e0ddf7d753c0ef99296103c622dd" -dependencies = [ - "bitcoin 0.28.2", -] - [[package]] name = "ic-btc-validation" -version = "0.1.0" +version = "0.9.0" dependencies = [ "bitcoin 0.28.2", "csv", @@ -6132,7 +6075,7 @@ dependencies = [ "prost 0.13.3", "rand 0.8.5", "rand_chacha 0.3.1", - "rustls 0.23.18", + "rustls 0.23.19", "serde", "serde_cbor", "tokio", @@ -6632,8 +6575,8 @@ dependencies = [ "ic-agent 0.37.1", "ic-base-types", "ic-bitcoin-canister-mock", + "ic-btc-checker", "ic-btc-interface", - "ic-btc-kyt", "ic-canister-log 0.2.0", "ic-canisters-http-types", "ic-cdk 0.16.0", @@ -6662,6 +6605,7 @@ dependencies = [ "mockall", "num-traits", "proptest", + "regex", "ripemd", "scopeguard", "serde", @@ -6673,7 +6617,7 @@ dependencies = [ [[package]] name = "ic-cketh-minter" -version = "0.1.0" +version = "0.9.0" dependencies = [ "askama", "assert_matches", @@ -6855,7 +6799,7 @@ dependencies = [ [[package]] name = "ic-consensus-manager" -version = "0.1.0" +version = "0.9.0" dependencies = [ "anyhow", "axum", @@ -6947,7 +6891,6 @@ dependencies = [ "criterion", "hex", "ic-adapter-metrics-server", - "ic-async-utils", "ic-base-types", "ic-certification-test-utils", "ic-config", @@ -6995,6 +6938,7 @@ dependencies = [ "ic-crypto-utils-basic-sig", "ic-crypto-utils-canister-threshold-sig", "ic-crypto-utils-tls", + "ic-http-endpoints-async-utils", "ic-interfaces", "ic-interfaces-registry", "ic-interfaces-registry-mocks", @@ -7022,7 +6966,7 @@ dependencies = [ "rand 0.8.5", "rand_chacha 0.3.1", "rsa", - "rustls 0.23.18", + "rustls 0.23.19", "serde", "sha2 0.10.8", "simple_asn1", @@ -7096,7 +7040,7 @@ dependencies = [ [[package]] name = "ic-crypto-iccsa" -version = "0.1.0" +version = "0.9.0" dependencies = [ "ic-crypto-internal-basic-sig-iccsa", ] @@ -7110,7 +7054,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-basic-sig-cose" -version = "0.1.0" +version = "0.9.0" dependencies = [ "hex", "ic-crypto-internal-basic-sig-der-utils", @@ -7313,6 +7257,7 @@ dependencies = [ "ic-crypto-internal-basic-sig-ecdsa-secp256r1", "ic-crypto-internal-basic-sig-ed25519", "ic-crypto-internal-basic-sig-rsa-pkcs1", + "ic-crypto-internal-bls12-381-vetkd", "ic-crypto-internal-csp-proptest-utils", "ic-crypto-internal-csp-protobuf-generator", "ic-crypto-internal-csp-test-utils", @@ -7619,7 +7564,7 @@ dependencies = [ [[package]] name = "ic-crypto-node-key-generation" -version = "0.1.0" +version = "0.9.0" dependencies = [ "assert_matches", "hex", @@ -7675,7 +7620,7 @@ dependencies = [ [[package]] name = "ic-crypto-prng" -version = "0.1.0" +version = "0.9.0" dependencies = [ "ic-crypto-sha2", "ic-types", @@ -7782,7 +7727,7 @@ dependencies = [ "ic-types-test-utils", "rand 0.8.5", "rand_chacha 0.3.1", - "rustls 0.23.18", + "rustls 0.23.19", "tempfile", "tokio", ] @@ -7982,7 +7927,7 @@ dependencies = [ "ic-types", "pkcs8", "rand 0.8.5", - "rustls 0.23.18", + "rustls 0.23.19", "signature", "time", "tokio", @@ -8018,7 +7963,7 @@ dependencies = [ "ic-types", "json5", "maplit", - "rustls 0.23.18", + "rustls 0.23.19", "serde", "thiserror 2.0.3", "x509-parser", @@ -8031,7 +7976,7 @@ dependencies = [ "ic-base-types", "ic-crypto-tls-interfaces", "mockall", - "rustls 0.23.18", + "rustls 0.23.19", ] [[package]] @@ -8089,7 +8034,7 @@ dependencies = [ [[package]] name = "ic-crypto-utils-ni-dkg" -version = "0.8.0" +version = "0.9.0" dependencies = [ "ic-base-types", "ic-config", @@ -8177,7 +8122,7 @@ dependencies = [ [[package]] name = "ic-dashboard" -version = "0.1.0" +version = "0.9.0" dependencies = [ "async-trait", "tokio", @@ -8354,7 +8299,6 @@ dependencies = [ "hex", "ic-base-types", "ic-btc-interface", - "ic-btc-test-utils", "ic-canister-sandbox-backend-lib", "ic-config", "ic-crypto-prng", @@ -8425,7 +8369,7 @@ dependencies = [ [[package]] name = "ic-exhaustive-derive" -version = "0.1.0" +version = "0.9.0" dependencies = [ "proc-macro2", "quote", @@ -8463,13 +8407,30 @@ dependencies = [ "urlencoding", ] +[[package]] +name = "ic-http-endpoints-async-utils" +version = "0.9.0" +dependencies = [ + "anyhow", + "async-stream", + "byte-unit", + "bytes", + "futures", + "futures-util", + "hyper 1.5.1", + "rand 0.8.5", + "slog", + "tokio", + "tonic", +] + [[package]] name = "ic-http-endpoints-metrics" version = "0.9.0" dependencies = [ "axum", - "ic-async-utils", "ic-config", + "ic-http-endpoints-async-utils", "ic-metrics", "ic-test-utilities-logger", "prometheus", @@ -8495,12 +8456,11 @@ dependencies = [ "futures", "futures-util", "hex", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", "hyper-util", - "ic-async-utils", "ic-canister-client", "ic-canister-client-sender", "ic-canonical-state", @@ -8514,6 +8474,7 @@ dependencies = [ "ic-crypto-tree-hash", "ic-crypto-utils-threshold-sig-der", "ic-error-types", + "ic-http-endpoints-async-utils", "ic-interfaces", "ic-interfaces-mocks", "ic-interfaces-registry", @@ -8548,7 +8509,7 @@ dependencies = [ "rand 0.8.5", "reqwest 0.12.9", "rstest", - "rustls 0.23.18", + "rustls 0.23.19", "serde", "serde_bytes", "serde_cbor", @@ -8574,10 +8535,10 @@ dependencies = [ "crossbeam-channel", "hyper 1.5.1", "hyper-util", - "ic-async-utils", "ic-config", "ic-crypto-tls-interfaces", "ic-crypto-tls-interfaces-mocks", + "ic-http-endpoints-async-utils", "ic-interfaces-certified-stream-store", "ic-interfaces-registry", "ic-interfaces-registry-mocks", @@ -8613,7 +8574,7 @@ dependencies = [ "bytes", "candid", "futures", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "ic-agent 0.37.1", @@ -8630,7 +8591,7 @@ dependencies = [ "assert_matches", "flate2", "hex", - "http 1.1.0", + "http 1.2.0", "ic-crypto-sha2", "ic-logger", "ic-test-utilities-in-memory-logger", @@ -8645,31 +8606,30 @@ dependencies = [ [[package]] name = "ic-https-outcalls-adapter" -version = "0.1.0" +version = "0.9.0" dependencies = [ "async-stream", "byte-unit", "bytes", "clap 4.5.20", "futures", - "http 1.1.0", + "http 1.2.0", "http-body-util", "hyper 1.5.1", "hyper-rustls 0.27.3", "hyper-socks2", "hyper-util", "ic-adapter-metrics-server", - "ic-async-utils", "ic-config", + "ic-http-endpoints-async-utils", "ic-https-outcalls-service", "ic-logger", "ic-metrics", "once_cell", - "parking_lot 0.12.3", "prometheus", "rand 0.8.5", "rstest", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pemfile 2.2.0", "serde", "serde_json", @@ -8686,15 +8646,15 @@ dependencies = [ [[package]] name = "ic-https-outcalls-adapter-client" -version = "0.1.0" +version = "0.9.0" dependencies = [ "candid", "futures", "hyper-util", "ic-adapter-metrics-client", - "ic-async-utils", "ic-config", "ic-error-types", + "ic-http-endpoints-async-utils", "ic-https-outcalls-service", "ic-interfaces", "ic-interfaces-adapter-client", @@ -8751,7 +8711,7 @@ dependencies = [ [[package]] name = "ic-https-outcalls-service" -version = "0.1.0" +version = "0.9.0" dependencies = [ "prost 0.13.3", "tonic", @@ -8989,161 +8949,73 @@ dependencies = [ ] [[package]] -name = "ic-icrc1-benchmark-generator" -version = "0.9.0" -dependencies = [ - "async-trait", - "candid", - "dfn_http_metrics", - "futures", - "getrandom", - "ic-base-types", - "ic-cdk 0.16.0", - "ic-cdk-macros 0.9.0", - "ic-icrc1-benchmark-worker", - "ic-icrc1-index", - "ic-ledger-core", - "ic-metrics-encoder", - "icrc-ledger-client-cdk", - "icrc-ledger-types", - "rand 0.8.5", - "rand_chacha 0.3.1", - "serde", - "serde_bytes", -] - -[[package]] -name = "ic-icrc1-benchmark-worker" -version = "0.1.0" -dependencies = [ - "async-trait", - "candid", - "ciborium", - "dfn_http_metrics", - "futures", - "getrandom", - "hex", - "ic-base-types", - "ic-cdk 0.16.0", - "ic-cdk-macros 0.9.0", - "ic-crypto-tree-hash", - "ic-icrc1", - "ic-ledger-canister-core", - "ic-ledger-core", - "ic-metrics-encoder", - "icrc-ledger-client", - "icrc-ledger-client-cdk", - "icrc-ledger-types", - "num-traits", - "rand 0.8.5", - "rand_chacha 0.3.1", - "serde", - "serde_bytes", -] - -[[package]] -name = "ic-icrc1-index" +name = "ic-icrc1-index-ng" version = "0.9.0" dependencies = [ - "assert_matches", - "async-trait", "candid", "candid_parser", "ciborium", + "ic-agent 0.37.1", "ic-base-types", + "ic-canister-log 0.2.0", "ic-canister-profiler", "ic-canisters-http-types", "ic-cdk 0.16.0", "ic-cdk-macros 0.9.0", "ic-cdk-timers", + "ic-crypto-sha2", "ic-icrc1", "ic-icrc1-ledger", + "ic-icrc1-test-utils", + "ic-icrc1-tokens-u256", "ic-icrc1-tokens-u64", "ic-ledger-canister-core", "ic-ledger-core", - "ic-ledger-hash-of", "ic-ledger-suite-state-machine-tests", "ic-metrics-encoder", + "ic-registry-subnet-type", "ic-rosetta-test-utils", + "ic-stable-structures", "ic-state-machine-tests", "ic-test-utilities-load-wasm", + "ic-types", "icrc-ledger-types", "num-traits", "proptest", "scopeguard", "serde", + "serde_bytes", "serde_json", ] [[package]] -name = "ic-icrc1-index-ng" +name = "ic-icrc1-ledger" version = "0.9.0" dependencies = [ + "assert_matches", + "async-trait", + "canbench-rs", "candid", "candid_parser", + "cddl", "ciborium", + "hex", "ic-agent 0.37.1", "ic-base-types", "ic-canister-log 0.2.0", - "ic-canister-profiler", "ic-canisters-http-types", "ic-cdk 0.16.0", "ic-cdk-macros 0.9.0", "ic-cdk-timers", - "ic-crypto-sha2", + "ic-certification 2.6.0", + "ic-crypto-tree-hash", "ic-icrc1", - "ic-icrc1-index", - "ic-icrc1-ledger", "ic-icrc1-test-utils", "ic-icrc1-tokens-u256", "ic-icrc1-tokens-u64", "ic-ledger-canister-core", "ic-ledger-core", - "ic-ledger-suite-state-machine-tests", - "ic-metrics-encoder", - "ic-registry-subnet-type", - "ic-rosetta-test-utils", - "ic-stable-structures", - "ic-state-machine-tests", - "ic-test-utilities-load-wasm", - "ic-types", - "icrc-ledger-types", - "num-traits", - "proptest", - "scopeguard", - "serde", - "serde_bytes", - "serde_json", -] - -[[package]] -name = "ic-icrc1-ledger" -version = "0.9.0" -dependencies = [ - "assert_matches", - "async-trait", - "canbench-rs", - "candid", - "candid_parser", - "cddl", - "ciborium", - "hex", - "ic-agent 0.37.1", - "ic-base-types", - "ic-canister-log 0.2.0", - "ic-canisters-http-types", - "ic-cdk 0.16.0", - "ic-cdk-macros 0.9.0", - "ic-cdk-timers", - "ic-certification 2.6.0", - "ic-crypto-tree-hash", - "ic-icrc1", - "ic-icrc1-test-utils", - "ic-icrc1-tokens-u256", - "ic-icrc1-tokens-u64", - "ic-ledger-canister-core", - "ic-ledger-core", - "ic-ledger-hash-of", + "ic-ledger-hash-of", "ic-ledger-suite-state-machine-tests", "ic-metrics-encoder", "ic-stable-structures", @@ -9184,7 +9056,7 @@ dependencies = [ [[package]] name = "ic-icrc1-tokens-u256" -version = "0.1.0" +version = "0.9.0" dependencies = [ "candid", "ciborium", @@ -9202,7 +9074,7 @@ dependencies = [ [[package]] name = "ic-icrc1-tokens-u64" -version = "0.1.0" +version = "0.9.0" dependencies = [ "candid", "ciborium", @@ -9449,7 +9321,7 @@ dependencies = [ [[package]] name = "ic-ledger-suite-orchestrator" -version = "0.1.0" +version = "0.9.0" dependencies = [ "askama", "assert_matches", @@ -9661,7 +9533,7 @@ dependencies = [ [[package]] name = "ic-memory-transport" -version = "0.1.0" +version = "0.9.0" dependencies = [ "anyhow", "async-trait", @@ -10092,6 +9964,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "ic-nervous-system-long-message" +version = "0.0.1" +dependencies = [ + "candid", + "canister-test", + "ic-cdk 0.16.0", + "ic-cdk-timers", + "ic-config", + "ic-nervous-system-temporary", + "ic-nns-test-utils", + "ic-registry-subnet-type", + "ic-state-machine-tests", + "ic-types", + "serde", +] + [[package]] name = "ic-nervous-system-proto" version = "0.9.0" @@ -10163,6 +10052,13 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "ic-nervous-system-timestamp" +version = "0.0.1" +dependencies = [ + "time", +] + [[package]] name = "ic-networking-subnet-update-workload" version = "0.9.0" @@ -10300,6 +10196,7 @@ dependencies = [ "ic-nervous-system-common-test-utils", "ic-nervous-system-governance", "ic-nervous-system-linear-map", + "ic-nervous-system-long-message", "ic-nervous-system-proto", "ic-nervous-system-root", "ic-nervous-system-runtime", @@ -10361,6 +10258,7 @@ dependencies = [ "ic-base-types", "ic-crypto-sha2", "ic-nervous-system-clients", + "ic-nervous-system-common", "ic-nervous-system-common-validation", "ic-nervous-system-proto", "ic-nns-common", @@ -10470,11 +10368,11 @@ dependencies = [ "candid_parser", "canister-test", "dfn_candid", - "dfn_core", - "dfn_macro", "hex", "ic-base-types", "ic-canisters-http-types", + "ic-cdk 0.16.0", + "ic-cdk-macros 0.9.0", "ic-crypto-sha2", "ic-management-canister-types", "ic-metrics-encoder", @@ -10518,6 +10416,7 @@ dependencies = [ "dfn_candid", "dfn_core", "ic-base-types", + "ic-cdk 0.16.0", "ic-nervous-system-clients", "ic-nns-constants", "serde", @@ -10565,6 +10464,7 @@ dependencies = [ "csv", "hex", "ic-base-types", + "ic-ledger-canister-core", "ic-nns-constants", "ic-nns-governance-api", "ic-nns-gtc", @@ -10650,6 +10550,7 @@ dependencies = [ "on_wire", "phantom_newtype", "pocket-ic", + "pretty_assertions", "prometheus-parse", "prost 0.13.3", "rand 0.8.5", @@ -10757,7 +10658,7 @@ dependencies = [ [[package]] name = "ic-p2p-test-utils" -version = "0.1.0" +version = "0.9.0" dependencies = [ "anyhow", "async-trait", @@ -10794,7 +10695,7 @@ dependencies = [ "quinn", "quinn-udp", "rcgen", - "rustls 0.23.18", + "rustls 0.23.19", "serde", "slog", "tempfile", @@ -10804,7 +10705,7 @@ dependencies = [ [[package]] name = "ic-peer-manager" -version = "0.1.0" +version = "0.9.0" dependencies = [ "ic-base-types", "ic-interfaces", @@ -10932,7 +10833,7 @@ dependencies = [ [[package]] name = "ic-quic-transport" -version = "0.1.0" +version = "0.9.0" dependencies = [ "anyhow", "assert_matches", @@ -10941,11 +10842,11 @@ dependencies = [ "bytes", "criterion", "futures", - "http 1.1.0", - "ic-async-utils", + "http 1.2.0", "ic-base-types", "ic-crypto-tls-interfaces", "ic-crypto-utils-tls", + "ic-http-endpoints-async-utils", "ic-interfaces-registry", "ic-logger", "ic-metrics", @@ -10958,9 +10859,10 @@ dependencies = [ "prost 0.13.3", "quinn", "rstest", - "rustls 0.23.18", + "rustls 0.23.19", "slog", "socket2 0.5.7", + "static_assertions", "thiserror 2.0.3", "tokio", "tokio-metrics", @@ -10986,7 +10888,7 @@ dependencies = [ [[package]] name = "ic-recovery" -version = "0.1.0" +version = "0.9.0" dependencies = [ "base64 0.13.1", "clap 4.5.20", @@ -11082,6 +10984,23 @@ dependencies = [ "ic-types", ] +[[package]] +name = "ic-registry-canister-data-provider" +version = "0.9.0" +dependencies = [ + "anyhow", + "candid", + "ic-cdk 0.16.0", + "ic-interfaces-registry", + "ic-nns-common", + "ic-nns-constants", + "ic-registry-canister-client", + "ic-registry-transport", + "ic-stable-structures", + "ic-types", + "itertools 0.12.1", +] + [[package]] name = "ic-registry-client" version = "0.9.0" @@ -11262,7 +11181,7 @@ dependencies = [ [[package]] name = "ic-registry-replicator" -version = "0.1.0" +version = "0.9.0" dependencies = [ "clap 4.5.20", "ic-config", @@ -11406,7 +11325,6 @@ dependencies = [ "criterion", "hex", "ic-artifact-pool", - "ic-async-utils", "ic-btc-adapter-client", "ic-btc-consensus", "ic-config", @@ -11415,6 +11333,7 @@ dependencies = [ "ic-crypto-sha2", "ic-cycles-account-manager", "ic-execution-environment", + "ic-http-endpoints-async-utils", "ic-http-endpoints-metrics", "ic-http-endpoints-public", "ic-http-endpoints-xnet", @@ -11504,7 +11423,6 @@ dependencies = [ "candid", "canister-test", "crossbeam-channel", - "ic-async-utils", "ic-base-types", "ic-btc-interface", "ic-btc-replica-types", @@ -11514,6 +11432,7 @@ dependencies = [ "ic-crypto-sha2", "ic-error-types", "ic-execution-environment", + "ic-http-endpoints-async-utils", "ic-interfaces", "ic-interfaces-registry", "ic-interfaces-state-manager", @@ -11562,7 +11481,6 @@ dependencies = [ "ic-base-types", "ic-btc-interface", "ic-btc-replica-types", - "ic-btc-test-utils", "ic-certification-version", "ic-config", "ic-crypto-ed25519", @@ -11649,7 +11567,7 @@ dependencies = [ [[package]] name = "ic-rosetta-api" -version = "2.1.0" +version = "2.1.1" dependencies = [ "actix-rt", "actix-web", @@ -11868,6 +11786,7 @@ dependencies = [ "base64 0.13.1", "build-info", "build-info-build", + "canbench-rs", "candid", "candid_parser", "clap 4.5.20", @@ -11901,6 +11820,7 @@ dependencies = [ "ic-nervous-system-proto", "ic-nervous-system-root", "ic-nervous-system-runtime", + "ic-nervous-system-timestamp", "ic-nns-constants", "ic-protobuf", "ic-sns-governance", @@ -11933,7 +11853,6 @@ dependencies = [ "strum", "strum_macros", "tempfile", - "time", "tokio", "tokio-test", ] @@ -12548,13 +12467,13 @@ dependencies = [ [[package]] name = "ic-state-sync-manager" -version = "0.1.0" +version = "0.9.0" dependencies = [ "axum", "bytes", "futures", - "ic-async-utils", "ic-base-types", + "ic-http-endpoints-async-utils", "ic-interfaces", "ic-logger", "ic-memory-transport", @@ -12605,7 +12524,7 @@ dependencies = [ [[package]] name = "ic-subnet-splitting" -version = "0.1.0" +version = "0.9.0" dependencies = [ "clap 4.5.20", "hex", @@ -12713,7 +12632,7 @@ dependencies = [ "ed25519-dalek", "futures", "hex", - "http 1.1.0", + "http 1.2.0", "humantime", "humantime-serde", "hyper 1.5.1", @@ -13151,11 +13070,10 @@ dependencies = [ "dfn_candid", "ic-agent 0.37.1", "ic-base-types", + "ic-btc-checker", "ic-btc-interface", - "ic-btc-kyt", "ic-canister-client", "ic-ckbtc-agent", - "ic-ckbtc-kyt", "ic-ckbtc-minter", "ic-config", "ic-icrc1-ledger", @@ -13185,6 +13103,43 @@ dependencies = [ "tokio", ] +[[package]] +name = "ic-tests-cross-chain" +version = "0.9.0" +dependencies = [ + "anyhow", + "candid", + "canister-test", + "dfn_candid", + "futures", + "hex-literal", + "ic-base-types", + "ic-canister-client", + "ic-cketh-minter", + "ic-ethereum-types", + "ic-icrc1-index-ng", + "ic-icrc1-ledger", + "ic-ledger-suite-orchestrator", + "ic-management-canister-types", + "ic-nervous-system-clients", + "ic-nervous-system-common-test-keys", + "ic-nervous-system-root", + "ic-nns-common", + "ic-nns-constants", + "ic-nns-governance-api", + "ic-nns-test-utils", + "ic-registry-subnet-type", + "ic-system-test-driver", + "ic-types", + "ic-wasm-types", + "ic_consensus_system_test_utils", + "ic_consensus_threshold_sig_system_test_utils", + "icrc-ledger-types", + "reqwest 0.12.9", + "serde_json", + "slog", +] + [[package]] name = "ic-tracing" version = "0.9.0" @@ -13253,29 +13208,6 @@ dependencies = [ "thiserror 1.0.68", ] -[[package]] -name = "ic-tvl-canister" -version = "0.9.0" -dependencies = [ - "assert_matches", - "candid", - "candid_parser", - "ic-base-types", - "ic-canisters-http-types", - "ic-cdk 0.16.0", - "ic-cdk-macros 0.9.0", - "ic-cdk-timers", - "ic-metrics-encoder", - "ic-nns-governance", - "ic-nns-test-utils", - "ic-stable-structures", - "ic-state-machine-tests", - "ic-test-utilities-load-wasm", - "rand 0.8.5", - "serde", - "xrc-mock", -] - [[package]] name = "ic-types" version = "0.9.0" @@ -13403,14 +13335,14 @@ version = "0.9.0" [[package]] name = "ic-validate-eq" -version = "0.0.0" +version = "0.9.0" dependencies = [ "ic-validate-eq-derive", ] [[package]] name = "ic-validate-eq-derive" -version = "0.0.0" +version = "0.9.0" dependencies = [ "proc-macro2", "quote", @@ -13712,7 +13644,7 @@ dependencies = [ name = "ic-xnet-uri" version = "0.9.0" dependencies = [ - "http 1.1.0", + "http 1.2.0", "ic-types", ] @@ -13971,7 +13903,7 @@ dependencies = [ [[package]] name = "icp-config" -version = "0.1.0" +version = "0.9.0" dependencies = [ "clap 4.5.20", "eyre", @@ -14009,6 +13941,7 @@ dependencies = [ "ic-ledger-test-utils", "ic-nns-constants", "ic-nns-test-utils-golden-nns-state", + "ic-stable-structures", "ic-state-machine-tests", "ic-test-utilities-compare-dirs", "icrc-ledger-types", @@ -14453,7 +14386,7 @@ dependencies = [ "crossbeam-channel", "crossbeam-utils", "dashmap 6.1.0", - "env_logger 0.11.5", + "env_logger", "indexmap 2.6.0", "itoa", "log", @@ -14514,7 +14447,7 @@ dependencies = [ "async-trait", "base64 0.22.1", "bytes", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -14553,6 +14486,9 @@ name = "ipnet" version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +dependencies = [ + "serde", +] [[package]] name = "ipnetwork" @@ -14787,7 +14723,7 @@ dependencies = [ "either", "futures", "home", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -14799,7 +14735,7 @@ dependencies = [ "k8s-openapi", "kube-core", "pem 3.0.4", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pemfile 2.2.0", "secrecy", "serde", @@ -14821,7 +14757,7 @@ checksum = "cce373a74d787d439063cdefab0f3672860bd7bac01a38e39019177e764a0fe6" dependencies = [ "chrono", "form_urlencoded", - "http 1.1.0", + "http 1.2.0", "k8s-openapi", "serde", "serde_json", @@ -14993,6 +14929,7 @@ dependencies = [ "ic-base-types", "ic-canister-log 0.2.0", "ic-cdk 0.16.0", + "ic-cdk-timers", "ic-error-types", "ic-icrc1", "ic-icrc1-test-utils", @@ -15009,8 +14946,10 @@ dependencies = [ "icrc-ledger-types", "intmap", "lazy_static", + "minicbor", "num-traits", "on_wire", + "proptest", "serde", "serde_bytes", "serde_cbor", @@ -15320,7 +15259,7 @@ checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "local_key" -version = "0.1.0" +version = "0.9.0" dependencies = [ "pin-project-lite", ] @@ -15764,7 +15703,7 @@ dependencies = [ "bytes", "colored", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -15872,7 +15811,6 @@ dependencies = [ "ic-types", "ic_consensus_system_test_utils", "slog", - "tests", ] [[package]] @@ -16054,7 +15992,6 @@ dependencies = [ "reqwest 0.12.9", "serde_cbor", "slog", - "tests", "tokio", "url", "wat", @@ -16098,6 +16035,7 @@ dependencies = [ "ic-registry-canister-api", "ic-registry-subnet-type", "ic-system-test-driver", + "ic_consensus_system_test_utils", "indoc", "k256", "registry-canister", @@ -16439,7 +16377,7 @@ checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" dependencies = [ "async-trait", "futures-core", - "http 1.1.0", + "http 1.2.0", "opentelemetry 0.27.0", "opentelemetry-proto", "opentelemetry_sdk 0.27.0", @@ -16582,7 +16520,6 @@ dependencies = [ "hyper 1.5.1", "hyper-rustls 0.27.3", "hyper-util", - "ic-async-utils", "ic-canister-client", "ic-canister-client-sender", "ic-config", @@ -16595,6 +16532,7 @@ dependencies = [ "ic-crypto-test-utils-tls", "ic-crypto-tls-interfaces", "ic-dashboard", + "ic-http-endpoints-async-utils", "ic-http-endpoints-metrics", "ic-http-utils", "ic-image-upgrader", @@ -17243,11 +17181,12 @@ dependencies = [ "fqdn 0.3.12", "futures", "hex", - "http 1.1.0", + "http 1.2.0", "http-body-util", "hyper 1.5.1", "hyper-util", "ic-agent 0.37.1", + "ic-bn-lib", "ic-boundary", "ic-btc-adapter", "ic-btc-interface", @@ -17846,9 +17785,9 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68c610ff29655a42eeef41a5b5346e714586971a7d927739477e552fe7e23e3" +checksum = "a3b8d81cf799e20564931e9867ca32de545188c6ee4c2e0f6e41d32f0c7dc6fb" dependencies = [ "cranelift-bitset", "log", @@ -17894,17 +17833,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "quickcheck" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" -dependencies = [ - "env_logger 0.8.4", - "log", - "rand 0.8.5", -] - [[package]] name = "quinn" version = "0.11.5" @@ -17916,7 +17844,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.0.0", - "rustls 0.23.18", + "rustls 0.23.19", "socket2 0.5.7", "thiserror 1.0.68", "tokio", @@ -17933,7 +17861,7 @@ dependencies = [ "rand 0.8.5", "ring 0.17.8", "rustc-hash 2.0.0", - "rustls 0.23.18", + "rustls 0.23.19", "slab", "thiserror 1.0.68", "tinyvec", @@ -18137,8 +18065,10 @@ name = "random-traffic-test" version = "0.9.0" dependencies = [ "candid", - "dfn_core", + "futures", "ic-base-types", + "ic-cdk 0.16.0", + "ic-cdk-macros 0.9.0", "ic-error-types", "ic-types", "rand 0.8.5", @@ -18171,15 +18101,40 @@ dependencies = [ "tokio", ] +[[package]] +name = "rate-limiting-canister-client" +version = "0.9.0" +dependencies = [ + "anyhow", + "candid", + "clap 4.5.20", + "ic-agent 0.37.1", + "k256", + "rate-limits-api", + "regex", + "serde", + "serde_yaml", + "tokio", + "tracing", + "tracing-subscriber", + "uuid", +] + [[package]] name = "rate-limits-api" version = "0.9.0" dependencies = [ "candid", + "humantime", + "ic-bn-lib", + "indoc", + "ipnet", "regex", "serde", "serde_bytes", "serde_json", + "serde_regex", + "serde_yaml", ] [[package]] @@ -18456,9 +18411,10 @@ dependencies = [ name = "rejoin-test-lib" version = "0.9.0" dependencies = [ + "candid", "canister-test", "chrono", - "dfn_json", + "dfn_candid", "futures", "ic-system-test-driver", "slog", @@ -18536,7 +18492,7 @@ dependencies = [ "futures-util", "h2 0.4.6", "hickory-resolver", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -18551,7 +18507,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-native-certs 0.8.0", "rustls-pemfile 2.2.0", "rustls-pki-types", @@ -18759,31 +18715,102 @@ dependencies = [ ] [[package]] -name = "rsa" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +name = "rosetta-system-tests" +version = "0.9.0" dependencies = [ - "const-oid", - "digest 0.10.7", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "sha2 0.10.8", - "signature", - "spki", - "subtle", - "zeroize", -] - -[[package]] -name = "rstest" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5316d2a1479eeef1ea21e7f9ddc67c191d497abc8fc3ba2467857abbb68330" + "anyhow", + "assert-json-diff", + "canister-test", + "dfn_protobuf", + "ic-agent 0.37.1", + "ic-canister-client", + "ic-ledger-canister-blocks-synchronizer-test-utils", + "ic-ledger-core", + "ic-nns-common", + "ic-nns-constants", + "ic-nns-governance-api", + "ic-nns-test-utils", + "ic-registry-subnet-type", + "ic-rosetta-api", + "ic-rosetta-test-utils", + "ic-system-test-driver", + "ic-test-identity", + "ic-types", + "icp-ledger", + "lazy_static", + "rand 0.8.5", + "rosetta_test_lib", + "serde_json", + "slog", + "url", +] + +[[package]] +name = "rosetta_test_lib" +version = "0.9.0" +dependencies = [ + "anyhow", + "assert-json-diff", + "candid", + "canister-test", + "dfn_protobuf", + "hex", + "ic-agent 0.37.1", + "ic-base-types", + "ic-canister-client", + "ic-canister-client-sender", + "ic-icrc1-test-utils", + "ic-ledger-canister-blocks-synchronizer-test-utils", + "ic-ledger-core", + "ic-nns-common", + "ic-nns-constants", + "ic-nns-governance-api", + "ic-nns-test-utils", + "ic-registry-subnet-type", + "ic-rosetta-api", + "ic-rosetta-test-utils", + "ic-system-test-driver", + "ic-types", + "icp-ledger", + "lazy_static", + "on_wire", + "prost 0.13.3", + "rand 0.8.5", + "reqwest 0.12.9", + "rosetta-core", + "serde", + "serde_json", + "slog", + "tokio", + "url", +] + +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "sha2 0.10.8", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rstest" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5316d2a1479eeef1ea21e7f9ddc67c191d497abc8fc3ba2467857abbb68330" dependencies = [ "futures", "futures-timer", @@ -18966,9 +18993,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.18" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "brotli 7.0.0", "brotli-decompressor", @@ -18983,9 +19010,9 @@ dependencies = [ [[package]] name = "rustls-acme" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d05fdb718e53ad511fa6477187f43f5dcd01b88f39e64ec16d6afc7363767d6" +checksum = "54f05935c0b1d7c5981c40b768c5d5ed96a43f5cb5166f8f5be09779c5825697" dependencies = [ "async-io", "async-trait", @@ -18995,14 +19022,14 @@ dependencies = [ "chrono", "futures", "futures-rustls", - "http 1.1.0", + "http 1.2.0", "log", "pem 3.0.4", "rcgen", "ring 0.17.8", "serde", "serde_json", - "thiserror 1.0.68", + "thiserror 2.0.3", "webpki-roots 0.26.6", "x509-parser", ] @@ -19068,7 +19095,7 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.18", + "rustls 0.23.19", "rustls-native-certs 0.7.3", "rustls-platform-verifier-android", "rustls-webpki 0.102.8", @@ -20026,7 +20053,6 @@ dependencies = [ "rust_decimal", "slog", "sns_system_test_lib", - "tests", ] [[package]] @@ -20153,10 +20179,12 @@ dependencies = [ name = "statesync-test" version = "0.9.0" dependencies = [ + "candid", "canister-test", - "dfn_core", - "dfn_json", - "dfn_macro", + "ic-cdk 0.16.0", + "ic-cdk-macros 0.9.0", + "ic-management-canister-types", + "ic-state-machine-tests", "ic-test-utilities", "ic-types", "lazy_static", @@ -20364,7 +20392,7 @@ dependencies = [ ] [[package]] -name = "sync-with-released-nevous-system-wasms" +name = "sync-with-released-nervous-system-wasms" version = "0.9.0" dependencies = [ "anyhow", @@ -20440,7 +20468,7 @@ dependencies = [ "async-trait", "axum", "clap 4.5.20", - "http 1.1.0", + "http 1.2.0", "itertools 0.12.1", "reqwest 0.12.9", "thiserror 2.0.3", @@ -20644,9 +20672,21 @@ name = "testing-verification-tests" version = "0.9.0" dependencies = [ "anyhow", + "candid", + "ic-agent 0.37.1", + "ic-prep", + "ic-regedit", + "ic-registry-local-store", + "ic-registry-local-store-artifacts", "ic-registry-subnet-type", "ic-system-test-driver", + "ic-types", + "ic-universal-canister", + "serde_json", "slog", + "ssh2", + "tempfile", + "tokio", ] [[package]] @@ -20668,175 +20708,10 @@ dependencies = [ "serde", "serde_json", "slog", - "tests", "url", "xrc-mock", ] -[[package]] -name = "tests" -version = "0.9.0" -dependencies = [ - "anyhow", - "assert-json-diff", - "assert_matches", - "async-recursion", - "async-trait", - "axum", - "backon", - "base64 0.13.1", - "bincode", - "candid", - "canister-test", - "chrono", - "crossbeam-channel", - "cycles-minting-canister", - "deterministic_ips", - "dfn_candid", - "dfn_json", - "dfn_protobuf", - "ed25519-dalek", - "flate2", - "futures", - "hex", - "humantime", - "ic-agent 0.37.1", - "ic-async-utils", - "ic-base-types", - "ic-btc-interface", - "ic-canister-client", - "ic-canister-client-sender", - "ic-cdk 0.16.0", - "ic-certification 0.9.0", - "ic-ckbtc-agent", - "ic-ckbtc-minter", - "ic-config", - "ic-crypto-sha2", - "ic-crypto-test-utils-reproducible-rng", - "ic-crypto-tree-hash", - "ic-crypto-utils-threshold-sig-der", - "ic-cycles-account-manager", - "ic-fstrim-tool", - "ic-http-utils", - "ic-icrc1", - "ic-icrc1-index-ng", - "ic-icrc1-ledger", - "ic-icrc1-test-utils", - "ic-interfaces", - "ic-interfaces-registry", - "ic-ledger-canister-blocks-synchronizer-test-utils", - "ic-ledger-core", - "ic-ledger-suite-orchestrator", - "ic-limits", - "ic-management-canister-types", - "ic-message", - "ic-nervous-system-clients", - "ic-nervous-system-common", - "ic-nervous-system-common-test-keys", - "ic-nervous-system-proto", - "ic-nervous-system-root", - "ic-nns-common", - "ic-nns-constants", - "ic-nns-governance-api", - "ic-nns-gtc", - "ic-nns-handler-root", - "ic-nns-init", - "ic-nns-test-utils", - "ic-prep", - "ic-protobuf", - "ic-regedit", - "ic-registry-canister-api", - "ic-registry-client", - "ic-registry-client-helpers", - "ic-registry-keys", - "ic-registry-local-registry", - "ic-registry-local-store", - "ic-registry-local-store-artifacts", - "ic-registry-nns-data-provider", - "ic-registry-provisional-whitelist", - "ic-registry-routing-table", - "ic-registry-subnet-features", - "ic-registry-subnet-type", - "ic-registry-transport", - "ic-rosetta-api", - "ic-rosetta-test-utils", - "ic-sns-governance", - "ic-sns-init", - "ic-sns-root", - "ic-sns-swap", - "ic-sns-wasm", - "ic-sys", - "ic-system-test-driver", - "ic-test-identity", - "ic-test-utilities", - "ic-test-utilities-time", - "ic-test-utilities-types", - "ic-types", - "ic-types-test-utils", - "ic-universal-canister", - "ic-utils 0.37.0", - "ic-wasm-types", - "ic_consensus_system_test_utils", - "ic_consensus_threshold_sig_system_test_utils", - "icp-ledger", - "icrc-ledger-agent", - "icrc-ledger-types", - "itertools 0.12.1", - "json5", - "k256", - "kube", - "lazy_static", - "leb128", - "libflate", - "lifeline", - "maplit", - "nix 0.24.3", - "num-traits", - "num_cpus", - "on_wire", - "once_cell", - "openssh-keys", - "pem 1.1.1", - "phantom_newtype", - "proptest", - "prost 0.13.3", - "quickcheck", - "rand 0.8.5", - "rand_chacha 0.3.1", - "rayon", - "rcgen", - "regex", - "registry-canister", - "reqwest 0.12.9", - "rosetta-core", - "rsa", - "rust_decimal", - "serde", - "serde_bytes", - "serde_cbor", - "serde_json", - "serde_yaml", - "sha2 0.10.8", - "slog", - "slog-async", - "slog-term", - "ssh2", - "strum", - "strum_macros", - "tempfile", - "thiserror 2.0.3", - "time", - "tokio", - "tokio-util", - "tracing", - "tracing-subscriber", - "tree-deserializer", - "url", - "walkdir", - "wat", - "xnet-test", -] - [[package]] name = "textplots" version = "0.8.6" @@ -21028,7 +20903,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tla_instrumentation" -version = "0.1.0" +version = "0.9.0" dependencies = [ "candid", "local_key", @@ -21040,7 +20915,7 @@ dependencies = [ [[package]] name = "tla_instrumentation_proc_macros" -version = "0.1.0" +version = "0.9.0" dependencies = [ "proc-macro2", "quote", @@ -21070,9 +20945,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.41.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -21109,9 +20984,9 @@ dependencies = [ [[package]] name = "tokio-metrics" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eace09241d62c98b7eeb1107d4c5c64ca3bd7da92e8c218c153ab3a78f9be112" +checksum = "cb2bb07a8451c4c6fa8b3497ad198510d8b8dffa5df5cfb97a64102a58b113c8" dependencies = [ "futures-util", "pin-project-lite", @@ -21146,7 +21021,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.18", + "rustls 0.23.19", "rustls-pki-types", "tokio", ] @@ -21217,9 +21092,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -21261,7 +21136,7 @@ dependencies = [ "base64 0.22.1", "bytes", "h2 0.4.6", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -21342,7 +21217,7 @@ dependencies = [ "base64 0.21.7", "bitflags 2.6.0", "bytes", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", @@ -21362,7 +21237,7 @@ dependencies = [ "bitflags 2.6.0", "bytes", "futures-core", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "pin-project-lite", @@ -21387,7 +21262,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357a1f99dd439c1aa9ebbaf9c6431b41c05a26bf137e9e92879941bdac5cb66d" dependencies = [ - "http 1.1.0", + "http 1.2.0", "tower-layer", "tower-service", "ulid", @@ -21422,7 +21297,7 @@ dependencies = [ "axum", "forwarded-header-value", "governor", - "http 1.1.0", + "http 1.2.0", "pin-project", "thiserror 1.0.68", "tower 0.5.1", @@ -21431,9 +21306,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -21455,9 +21330,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", @@ -21466,9 +21341,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -21537,6 +21412,16 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-slog" version = "0.2.0" @@ -21550,9 +21435,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -21567,7 +21452,7 @@ dependencies = [ "tracing", "tracing-core", "tracing-log", - "tracing-serde", + "tracing-serde 0.2.0", ] [[package]] @@ -21657,7 +21542,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.1.0", + "http 1.2.0", "httparse", "log", "rand 0.8.5", @@ -21912,9 +21797,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vrl" -version = "0.19.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c22ec61cbd43e563df185521f9a2fb2f42f6ab96604a574c82f6564049fb431" +checksum = "ea6f5f954461e21cacc090537e49f1023c34b6d10e12030b40ca1821a43aca68" dependencies = [ "bytes", "cfg-if 1.0.0", @@ -22156,15 +22041,6 @@ dependencies = [ "wasmparser 0.217.0", ] -[[package]] -name = "wasm-encoder" -version = "0.218.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22b896fa8ceb71091ace9bcb81e853f54043183a1c9667cf93422c40252ffa0a" -dependencies = [ - "leb128", -] - [[package]] name = "wasm-encoder" version = "0.219.1" @@ -22218,9 +22094,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.218.0" +version = "0.219.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc" +checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5" dependencies = [ "ahash 0.8.11", "bitflags 2.6.0", @@ -22230,16 +22106,6 @@ dependencies = [ "serde", ] -[[package]] -name = "wasmparser" -version = "0.219.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5" -dependencies = [ - "bitflags 2.6.0", - "indexmap 2.6.0", -] - [[package]] name = "wasmprinter" version = "0.217.0" @@ -22253,20 +22119,20 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.218.0" +version = "0.219.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ace089155491837b75f474bf47c99073246d1b737393fe722d6dee311595ddc" +checksum = "228cdc1f30c27816da225d239ce4231f28941147d34713dee8f1fff7cb330e54" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.218.0", + "wasmparser 0.219.1", ] [[package]] name = "wasmtime" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffa3230b9ba1ab6568d116df21bf4ca55ed2bfac87723d910471d30d9656ea1" +checksum = "5b79302e3e084713249cc5622e8608e7410afdeeea8c8026d04f491d1fab0b4b" dependencies = [ "anyhow", "bitflags 2.6.0", @@ -22293,7 +22159,7 @@ dependencies = [ "smallvec", "sptr", "target-lexicon", - "wasmparser 0.218.0", + "wasmparser 0.219.1", "wasmtime-asm-macros", "wasmtime-component-macro", "wasmtime-cranelift", @@ -22306,18 +22172,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef15fad08bbaa0e5c5539b76fa5965ca25e24f17a584f83a40b43ba9a2b36f44" +checksum = "fe53a24e7016a5222875d8ca3ad6024b464465985693c42098cd0bb710002c28" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "wasmtime-component-macro" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb4e179f424260d0739c09d3bc83d34347a55d291d10dcb5244686a75c7733" +checksum = "e118acbd2bc09b32ad8606bc7cef793bf5019c1b107772e64dc6c76b5055d40b" dependencies = [ "anyhow", "proc-macro2", @@ -22330,15 +22196,15 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe3c27d64af5f584014db9381c081223d27a57e1dce2f6280bbafea37575619" +checksum = "4a6db4f3ee18c699629eabb9c64e77efe5a93a5137f098db7cab295037ba41c2" [[package]] name = "wasmtime-cranelift" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb56d9ee4a093509624bd0861888cd111f6530e16969a68bb12dc7dd7a2be27f" +checksum = "8b87e6c78f562b50aff1afd87ff32a57e241424c846c1c8f3c5fd352d2d62906" dependencies = [ "anyhow", "cfg-if 1.0.0", @@ -22354,16 +22220,16 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror 1.0.68", - "wasmparser 0.218.0", + "wasmparser 0.219.1", "wasmtime-environ", "wasmtime-versioned-export-macros", ] [[package]] name = "wasmtime-environ" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3444c1759d5b906ff76a3cab073dd92135bdd06e5d1f46635ec40a58207d314" +checksum = "c25bfeaa16432d59a0706e2463d315ef4c9ebcfaf5605670b99d46373bdf9f27" dependencies = [ "anyhow", "cranelift-bitset", @@ -22377,16 +22243,16 @@ dependencies = [ "serde_derive", "smallvec", "target-lexicon", - "wasm-encoder 0.218.0", - "wasmparser 0.218.0", - "wasmprinter 0.218.0", + "wasm-encoder 0.219.1", + "wasmparser 0.219.1", + "wasmprinter 0.219.1", ] [[package]] name = "wasmtime-jit-icache-coherence" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e458e6a1a010a53f86ac8d75837c0c6b2ce3e54b7503b2f1dc5629a4a541f5a" +checksum = "91b218a92866f74f35162f5d03a4e0f62cd0e1cc624285b1014275e5d4575fad" dependencies = [ "anyhow", "cfg-if 1.0.0", @@ -22396,15 +22262,15 @@ dependencies = [ [[package]] name = "wasmtime-slab" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339c9a2a62b989a3184baff31be3a5b5256ad52629634eb432f9ccf0ab251f83" +checksum = "4d5f8acf677ee6b3b8ba400dd9753ea4769e56a95c4b30b045ac6d2d54b2f8ea" [[package]] name = "wasmtime-versioned-export-macros" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe01058e422966659e1af00af833147d54658b07c7e74606d73ca9af3f1690a" +checksum = "df09be00c38f49172ca9936998938476e3f2df782673a39ae2ef9fb0838341b6" dependencies = [ "proc-macro2", "quote", @@ -22413,9 +22279,9 @@ dependencies = [ [[package]] name = "wasmtime-wit-bindgen" -version = "26.0.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c9e85935a1199e96b73e7fcd27a127035d2082265720a67d59268a24892d567" +checksum = "bf3963c9c29df91564d8bd181eb00d0dbaeafa1b2a01e15952bb7391166b704e" dependencies = [ "anyhow", "heck 0.5.0", @@ -22795,9 +22661,9 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wit-parser" -version = "0.218.0" +version = "0.219.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d3d1066ab761b115f97fef2b191090faabcb0f37b555b758d3caf42d4ed9e55" +checksum = "4a86f669283257e8e424b9a4fc3518e3ade0b95deb9fbc0f93a1876be3eda598" dependencies = [ "anyhow", "id-arena", @@ -22808,7 +22674,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.218.0", + "wasmparser 0.219.1", ] [[package]] @@ -22923,6 +22789,7 @@ dependencies = [ "rand 0.8.5", "rand_pcg 0.3.1", "serde", + "serde_bytes", ] [[package]] From 95aee5a140976acc74d6757d3bcf013e60ffe179 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Fri, 27 Dec 2024 10:35:36 +0000 Subject: [PATCH 31/34] lock --- Cargo.lock | 969 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 556 insertions(+), 413 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 055bfd21060..72288f43343 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,7 +372,6 @@ dependencies = [ "candid", "ic-canister-client", "ic-types", - "prometheus", "rand 0.8.5", "rsa", "thiserror 2.0.3", @@ -696,6 +695,17 @@ dependencies = [ "futures-lite", ] +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "async-scoped" version = "0.9.0" @@ -1807,6 +1817,18 @@ dependencies = [ "wat", ] +[[package]] +name = "canister_client" +version = "0.9.0" +dependencies = [ + "candid", + "ic-agent 0.37.1", + "k256", + "rate-limits-api", + "regex", + "tokio", +] + [[package]] name = "canister_http" version = "0.9.0" @@ -2185,7 +2207,7 @@ dependencies = [ [[package]] name = "cloner-canister-types" -version = "0.9.0" +version = "0.1.0" dependencies = [ "candid", "futures", @@ -2387,6 +2409,7 @@ version = "0.9.0" dependencies = [ "anyhow", "canister-test", + "canister_http", "ic-agent 0.37.1", "ic-base-types", "ic-interfaces-registry", @@ -2643,18 +2666,18 @@ dependencies = [ [[package]] name = "cranelift-bforest" -version = "0.114.0" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba4f80548f22dc9c43911907b5e322c5555544ee85f785115701e6a28c9abe1" +checksum = "540b193ff98b825a1f250a75b3118911af918a734154c69d80bcfcf91e7e9522" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.114.0" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "005884e3649c3e5ff2dc79e8a94b138f11569cc08a91244a292714d2a86e9156" +checksum = "c7cb269598b9557ab942d687d3c1086d77c4b50dcf35813f3a65ba306fd42279" dependencies = [ "serde", "serde_derive", @@ -2662,9 +2685,9 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.114.0" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4036255ec33ce9a37495dfbcfc4e1118fd34e693eff9a1e106336b7cd16a9b" +checksum = "46566d7c83a8bff4150748d66020f4c7224091952aa4b4df1ec4959c39d937a1" dependencies = [ "bumpalo", "cranelift-bforest", @@ -2679,40 +2702,39 @@ dependencies = [ "log", "regalloc2", "rustc-hash 2.0.0", - "serde", "smallvec", "target-lexicon", ] [[package]] name = "cranelift-codegen-meta" -version = "0.114.0" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7ca74f4b68319da11d39e894437cb6e20ec7c2e11fbbda823c3bf207beedff7" +checksum = "2df8a86a34236cc75a8a6a271973da779c2aeb36c43b6e14da474cf931317082" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.114.0" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897e54f433a0269c4187871aa06d452214d5515d228d5bdc22219585e9eef895" +checksum = "cf75340b6a57b7c7c1b74f10d3d90883ee6d43a554be8131a4046c2ebcf5eb65" [[package]] name = "cranelift-control" -version = "0.114.0" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cb4018f5bf59fb53f515fa9d80e6f8c5ce19f198dc538984ebd23ecf8965ec" +checksum = "2e84495bc5d23d86aad8c86f8ade4af765b94882af60d60e271d3153942f1978" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.114.0" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305399fd781a2953ac78c1396f02ff53144f39c33eb7fc7789cf4e8936d13a96" +checksum = "963c17147b80df351965e57c04d20dbedc85bcaf44c3436780a59a3f1ff1b1c2" dependencies = [ "cranelift-bitset", "serde", @@ -2721,9 +2743,9 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.114.0" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9230b460a128d53653456137751d27baf567947a3ab8c0c4d6e31fd08036d81e" +checksum = "727f02acbc4b4cb2ba38a6637101d579db50190df1dd05168c68e762851a3dd5" dependencies = [ "cranelift-codegen", "log", @@ -2733,15 +2755,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.114.0" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b961e24ae3ec9813a24a15ae64bbd2a42e4de4d79a7f3225a412e3b94e78d1c8" +checksum = "32b00cc2e03c748f2531eea01c871f502b909d30295fdcad43aec7bf5c5b4667" [[package]] name = "cranelift-native" -version = "0.114.0" +version = "0.113.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5bd76df6c9151188dfa428c863b33da5b34561b67f43c0cf3f24a794f9fa1f" +checksum = "bbeaf978dc7c1a2de8bbb9162510ed218eb156697bc45590b8fbdd69bb08e8de" dependencies = [ "cranelift-codegen", "libc", @@ -3787,6 +3809,16 @@ dependencies = [ "log", ] +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "log", + "regex", +] + [[package]] name = "env_logger" version = "0.11.5" @@ -5229,7 +5261,7 @@ version = "0.9.0" dependencies = [ "hyper-util", "ic-adapter-metrics-service", - "ic-http-endpoints-async-utils", + "ic-async-utils", "prometheus", "protobuf", "slog", @@ -5240,7 +5272,7 @@ dependencies = [ [[package]] name = "ic-adapter-metrics-server" -version = "0.9.0" +version = "0.1.0" dependencies = [ "futures", "ic-adapter-metrics-service", @@ -5254,7 +5286,7 @@ dependencies = [ [[package]] name = "ic-adapter-metrics-service" -version = "0.9.0" +version = "0.1.0" dependencies = [ "prost 0.13.3", "prost-build 0.13.3", @@ -5433,7 +5465,7 @@ dependencies = [ [[package]] name = "ic-artifact-downloader" -version = "0.9.0" +version = "0.1.0" dependencies = [ "anyhow", "axum", @@ -5526,6 +5558,23 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ic-async-utils" +version = "0.9.0" +dependencies = [ + "anyhow", + "async-stream", + "byte-unit", + "bytes", + "futures", + "futures-util", + "hyper 1.5.1", + "rand 0.8.5", + "slog", + "tokio", + "tonic", +] + [[package]] name = "ic-backup" version = "0.9.0" @@ -5615,7 +5664,7 @@ dependencies = [ [[package]] name = "ic-bn-lib" version = "0.1.0" -source = "git+https://github.com/dfinity/ic-bn-lib?rev=d74a6527fbaf8a2c1a7076983cc84f5c5a727923#d74a6527fbaf8a2c1a7076983cc84f5c5a727923" +source = "git+https://github.com/dfinity/ic-bn-lib?rev=526d34d15cfbf369d8baf2dae9932aa18d570a1d#526d34d15cfbf369d8baf2dae9932aa18d570a1d" dependencies = [ "ahash 0.8.11", "anyhow", @@ -5642,6 +5691,7 @@ dependencies = [ "hyper 1.5.1", "hyper-util", "instant-acme", + "mockall", "moka", "parse-size", "prometheus", @@ -5660,8 +5710,9 @@ dependencies = [ "sha1", "strum", "strum_macros", + "sync_wrapper 1.0.1", "systemstat", - "thiserror 2.0.3", + "thiserror 1.0.68", "tokio", "tokio-io-timeout", "tokio-rustls 0.26.0", @@ -5729,7 +5780,6 @@ dependencies = [ "ic-registry-subnet-type", "ic-types", "indoc", - "ipnet", "lazy_static", "maxminddb", "mockall", @@ -5738,7 +5788,6 @@ dependencies = [ "nix 0.24.3", "prometheus", "rand 0.8.5", - "rate-limits-api", "ratelimit", "rcgen", "regex", @@ -5874,6 +5923,7 @@ dependencies = [ "http 1.2.0", "hyper-util", "ic-adapter-metrics-server", + "ic-async-utils", "ic-btc-adapter-client", "ic-btc-adapter-test-utils", "ic-btc-interface", @@ -5881,7 +5931,6 @@ dependencies = [ "ic-btc-service", "ic-btc-validation", "ic-config", - "ic-http-endpoints-async-utils", "ic-interfaces-adapter-client", "ic-logger", "ic-metrics", @@ -5908,10 +5957,10 @@ version = "0.9.0" dependencies = [ "hyper-util", "ic-adapter-metrics-client", + "ic-async-utils", "ic-btc-replica-types", "ic-btc-service", "ic-config", - "ic-http-endpoints-async-utils", "ic-interfaces-adapter-client", "ic-logger", "ic-metrics", @@ -5937,39 +5986,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "ic-btc-checker" -version = "0.9.0" -dependencies = [ - "askama", - "base64 0.13.1", - "bitcoin 0.32.3", - "candid", - "candid_parser", - "ciborium", - "futures", - "hex", - "ic-base-types", - "ic-btc-interface", - "ic-canister-log 0.2.0", - "ic-canisters-http-types", - "ic-cdk 0.16.0", - "ic-metrics-encoder", - "ic-stable-structures", - "ic-test-utilities-load-wasm", - "ic-types", - "ic-universal-canister", - "pocket-ic", - "proptest", - "regex", - "scraper", - "serde", - "serde_json", - "time", - "tokio", - "url", -] - [[package]] name = "ic-btc-consensus" version = "0.9.0" @@ -6015,6 +6031,38 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "ic-btc-kyt" +version = "0.9.0" +dependencies = [ + "askama", + "base64 0.13.1", + "bitcoin 0.32.3", + "candid", + "candid_parser", + "ciborium", + "futures", + "hex", + "ic-base-types", + "ic-btc-interface", + "ic-canister-log 0.2.0", + "ic-canisters-http-types", + "ic-cdk 0.16.0", + "ic-metrics-encoder", + "ic-stable-structures", + "ic-test-utilities-load-wasm", + "ic-types", + "ic-universal-canister", + "num-traits", + "pocket-ic", + "scraper", + "serde", + "serde_json", + "time", + "tokio", + "url", +] + [[package]] name = "ic-btc-replica-types" version = "0.9.0" @@ -6036,9 +6084,18 @@ dependencies = [ "tonic-build", ] +[[package]] +name = "ic-btc-test-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8e0a43145188ba239150f8460d314b0dd6e0ddf7d753c0ef99296103c622dd" +dependencies = [ + "bitcoin 0.28.2", +] + [[package]] name = "ic-btc-validation" -version = "0.9.0" +version = "0.1.0" dependencies = [ "bitcoin 0.28.2", "csv", @@ -6575,8 +6632,8 @@ dependencies = [ "ic-agent 0.37.1", "ic-base-types", "ic-bitcoin-canister-mock", - "ic-btc-checker", "ic-btc-interface", + "ic-btc-kyt", "ic-canister-log 0.2.0", "ic-canisters-http-types", "ic-cdk 0.16.0", @@ -6605,7 +6662,6 @@ dependencies = [ "mockall", "num-traits", "proptest", - "regex", "ripemd", "scopeguard", "serde", @@ -6617,7 +6673,7 @@ dependencies = [ [[package]] name = "ic-cketh-minter" -version = "0.9.0" +version = "0.1.0" dependencies = [ "askama", "assert_matches", @@ -6799,7 +6855,7 @@ dependencies = [ [[package]] name = "ic-consensus-manager" -version = "0.9.0" +version = "0.1.0" dependencies = [ "anyhow", "axum", @@ -6891,6 +6947,7 @@ dependencies = [ "criterion", "hex", "ic-adapter-metrics-server", + "ic-async-utils", "ic-base-types", "ic-certification-test-utils", "ic-config", @@ -6938,7 +6995,6 @@ dependencies = [ "ic-crypto-utils-basic-sig", "ic-crypto-utils-canister-threshold-sig", "ic-crypto-utils-tls", - "ic-http-endpoints-async-utils", "ic-interfaces", "ic-interfaces-registry", "ic-interfaces-registry-mocks", @@ -7040,7 +7096,7 @@ dependencies = [ [[package]] name = "ic-crypto-iccsa" -version = "0.9.0" +version = "0.1.0" dependencies = [ "ic-crypto-internal-basic-sig-iccsa", ] @@ -7054,7 +7110,7 @@ dependencies = [ [[package]] name = "ic-crypto-internal-basic-sig-cose" -version = "0.9.0" +version = "0.1.0" dependencies = [ "hex", "ic-crypto-internal-basic-sig-der-utils", @@ -7257,7 +7313,6 @@ dependencies = [ "ic-crypto-internal-basic-sig-ecdsa-secp256r1", "ic-crypto-internal-basic-sig-ed25519", "ic-crypto-internal-basic-sig-rsa-pkcs1", - "ic-crypto-internal-bls12-381-vetkd", "ic-crypto-internal-csp-proptest-utils", "ic-crypto-internal-csp-protobuf-generator", "ic-crypto-internal-csp-test-utils", @@ -7564,7 +7619,7 @@ dependencies = [ [[package]] name = "ic-crypto-node-key-generation" -version = "0.9.0" +version = "0.1.0" dependencies = [ "assert_matches", "hex", @@ -7620,7 +7675,7 @@ dependencies = [ [[package]] name = "ic-crypto-prng" -version = "0.9.0" +version = "0.1.0" dependencies = [ "ic-crypto-sha2", "ic-types", @@ -8034,7 +8089,7 @@ dependencies = [ [[package]] name = "ic-crypto-utils-ni-dkg" -version = "0.9.0" +version = "0.8.0" dependencies = [ "ic-base-types", "ic-config", @@ -8122,7 +8177,7 @@ dependencies = [ [[package]] name = "ic-dashboard" -version = "0.9.0" +version = "0.1.0" dependencies = [ "async-trait", "tokio", @@ -8299,6 +8354,7 @@ dependencies = [ "hex", "ic-base-types", "ic-btc-interface", + "ic-btc-test-utils", "ic-canister-sandbox-backend-lib", "ic-config", "ic-crypto-prng", @@ -8369,7 +8425,7 @@ dependencies = [ [[package]] name = "ic-exhaustive-derive" -version = "0.9.0" +version = "0.1.0" dependencies = [ "proc-macro2", "quote", @@ -8407,30 +8463,13 @@ dependencies = [ "urlencoding", ] -[[package]] -name = "ic-http-endpoints-async-utils" -version = "0.9.0" -dependencies = [ - "anyhow", - "async-stream", - "byte-unit", - "bytes", - "futures", - "futures-util", - "hyper 1.5.1", - "rand 0.8.5", - "slog", - "tokio", - "tonic", -] - [[package]] name = "ic-http-endpoints-metrics" version = "0.9.0" dependencies = [ "axum", + "ic-async-utils", "ic-config", - "ic-http-endpoints-async-utils", "ic-metrics", "ic-test-utilities-logger", "prometheus", @@ -8461,6 +8500,7 @@ dependencies = [ "http-body-util", "hyper 1.5.1", "hyper-util", + "ic-async-utils", "ic-canister-client", "ic-canister-client-sender", "ic-canonical-state", @@ -8474,7 +8514,6 @@ dependencies = [ "ic-crypto-tree-hash", "ic-crypto-utils-threshold-sig-der", "ic-error-types", - "ic-http-endpoints-async-utils", "ic-interfaces", "ic-interfaces-mocks", "ic-interfaces-registry", @@ -8535,10 +8574,10 @@ dependencies = [ "crossbeam-channel", "hyper 1.5.1", "hyper-util", + "ic-async-utils", "ic-config", "ic-crypto-tls-interfaces", "ic-crypto-tls-interfaces-mocks", - "ic-http-endpoints-async-utils", "ic-interfaces-certified-stream-store", "ic-interfaces-registry", "ic-interfaces-registry-mocks", @@ -8606,7 +8645,7 @@ dependencies = [ [[package]] name = "ic-https-outcalls-adapter" -version = "0.9.0" +version = "0.1.0" dependencies = [ "async-stream", "byte-unit", @@ -8620,12 +8659,13 @@ dependencies = [ "hyper-socks2", "hyper-util", "ic-adapter-metrics-server", + "ic-async-utils", "ic-config", - "ic-http-endpoints-async-utils", "ic-https-outcalls-service", "ic-logger", "ic-metrics", "once_cell", + "parking_lot 0.12.3", "prometheus", "rand 0.8.5", "rstest", @@ -8646,15 +8686,15 @@ dependencies = [ [[package]] name = "ic-https-outcalls-adapter-client" -version = "0.9.0" +version = "0.1.0" dependencies = [ "candid", "futures", "hyper-util", "ic-adapter-metrics-client", + "ic-async-utils", "ic-config", "ic-error-types", - "ic-http-endpoints-async-utils", "ic-https-outcalls-service", "ic-interfaces", "ic-interfaces-adapter-client", @@ -8711,7 +8751,7 @@ dependencies = [ [[package]] name = "ic-https-outcalls-service" -version = "0.9.0" +version = "0.1.0" dependencies = [ "prost 0.13.3", "tonic", @@ -8949,80 +8989,168 @@ dependencies = [ ] [[package]] -name = "ic-icrc1-index-ng" +name = "ic-icrc1-benchmark-generator" +version = "0.9.0" +dependencies = [ + "async-trait", + "candid", + "dfn_http_metrics", + "futures", + "getrandom", + "ic-base-types", + "ic-cdk 0.16.0", + "ic-cdk-macros 0.9.0", + "ic-icrc1-benchmark-worker", + "ic-icrc1-index", + "ic-ledger-core", + "ic-metrics-encoder", + "icrc-ledger-client-cdk", + "icrc-ledger-types", + "rand 0.8.5", + "rand_chacha 0.3.1", + "serde", + "serde_bytes", +] + +[[package]] +name = "ic-icrc1-benchmark-worker" +version = "0.1.0" +dependencies = [ + "async-trait", + "candid", + "ciborium", + "dfn_http_metrics", + "futures", + "getrandom", + "hex", + "ic-base-types", + "ic-cdk 0.16.0", + "ic-cdk-macros 0.9.0", + "ic-crypto-tree-hash", + "ic-icrc1", + "ic-ledger-canister-core", + "ic-ledger-core", + "ic-metrics-encoder", + "icrc-ledger-client", + "icrc-ledger-client-cdk", + "icrc-ledger-types", + "num-traits", + "rand 0.8.5", + "rand_chacha 0.3.1", + "serde", + "serde_bytes", +] + +[[package]] +name = "ic-icrc1-index" version = "0.9.0" dependencies = [ + "assert_matches", + "async-trait", "candid", "candid_parser", "ciborium", - "ic-agent 0.37.1", "ic-base-types", - "ic-canister-log 0.2.0", "ic-canister-profiler", "ic-canisters-http-types", "ic-cdk 0.16.0", "ic-cdk-macros 0.9.0", "ic-cdk-timers", - "ic-crypto-sha2", "ic-icrc1", "ic-icrc1-ledger", - "ic-icrc1-test-utils", - "ic-icrc1-tokens-u256", "ic-icrc1-tokens-u64", "ic-ledger-canister-core", "ic-ledger-core", + "ic-ledger-hash-of", "ic-ledger-suite-state-machine-tests", "ic-metrics-encoder", - "ic-registry-subnet-type", "ic-rosetta-test-utils", - "ic-stable-structures", "ic-state-machine-tests", "ic-test-utilities-load-wasm", - "ic-types", "icrc-ledger-types", "num-traits", "proptest", "scopeguard", "serde", - "serde_bytes", "serde_json", ] [[package]] -name = "ic-icrc1-ledger" +name = "ic-icrc1-index-ng" version = "0.9.0" dependencies = [ - "assert_matches", - "async-trait", - "canbench-rs", "candid", "candid_parser", - "cddl", "ciborium", - "hex", "ic-agent 0.37.1", "ic-base-types", "ic-canister-log 0.2.0", + "ic-canister-profiler", "ic-canisters-http-types", "ic-cdk 0.16.0", "ic-cdk-macros 0.9.0", "ic-cdk-timers", - "ic-certification 2.6.0", - "ic-crypto-tree-hash", + "ic-crypto-sha2", "ic-icrc1", + "ic-icrc1-index", + "ic-icrc1-ledger", "ic-icrc1-test-utils", "ic-icrc1-tokens-u256", "ic-icrc1-tokens-u64", "ic-ledger-canister-core", "ic-ledger-core", - "ic-ledger-hash-of", "ic-ledger-suite-state-machine-tests", "ic-metrics-encoder", + "ic-registry-subnet-type", + "ic-rosetta-test-utils", "ic-stable-structures", "ic-state-machine-tests", "ic-test-utilities-load-wasm", + "ic-types", "icrc-ledger-types", - "leb128", + "num-traits", + "proptest", + "scopeguard", + "serde", + "serde_bytes", + "serde_json", +] + +[[package]] +name = "ic-icrc1-ledger" +version = "0.9.0" +dependencies = [ + "assert_matches", + "async-trait", + "canbench-rs", + "candid", + "candid_parser", + "cddl", + "ciborium", + "hex", + "ic-agent 0.37.1", + "ic-base-types", + "ic-canister-log 0.2.0", + "ic-canisters-http-types", + "ic-cdk 0.16.0", + "ic-cdk-macros 0.9.0", + "ic-cdk-timers", + "ic-certification 2.6.0", + "ic-crypto-tree-hash", + "ic-icrc1", + "ic-icrc1-test-utils", + "ic-icrc1-tokens-u256", + "ic-icrc1-tokens-u64", + "ic-ledger-canister-core", + "ic-ledger-core", + "ic-ledger-hash-of", + "ic-ledger-suite-state-machine-tests", + "ic-metrics-encoder", + "ic-stable-structures", + "ic-state-machine-tests", + "ic-test-utilities-load-wasm", + "icrc-ledger-types", + "leb128", "minicbor", "num-bigint 0.4.6", "num-traits", @@ -9056,7 +9184,7 @@ dependencies = [ [[package]] name = "ic-icrc1-tokens-u256" -version = "0.9.0" +version = "0.1.0" dependencies = [ "candid", "ciborium", @@ -9074,7 +9202,7 @@ dependencies = [ [[package]] name = "ic-icrc1-tokens-u64" -version = "0.9.0" +version = "0.1.0" dependencies = [ "candid", "ciborium", @@ -9321,7 +9449,7 @@ dependencies = [ [[package]] name = "ic-ledger-suite-orchestrator" -version = "0.9.0" +version = "0.1.0" dependencies = [ "askama", "assert_matches", @@ -9533,7 +9661,7 @@ dependencies = [ [[package]] name = "ic-memory-transport" -version = "0.9.0" +version = "0.1.0" dependencies = [ "anyhow", "async-trait", @@ -9964,23 +10092,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "ic-nervous-system-long-message" -version = "0.0.1" -dependencies = [ - "candid", - "canister-test", - "ic-cdk 0.16.0", - "ic-cdk-timers", - "ic-config", - "ic-nervous-system-temporary", - "ic-nns-test-utils", - "ic-registry-subnet-type", - "ic-state-machine-tests", - "ic-types", - "serde", -] - [[package]] name = "ic-nervous-system-proto" version = "0.9.0" @@ -10052,13 +10163,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "ic-nervous-system-timestamp" -version = "0.0.1" -dependencies = [ - "time", -] - [[package]] name = "ic-networking-subnet-update-workload" version = "0.9.0" @@ -10196,7 +10300,6 @@ dependencies = [ "ic-nervous-system-common-test-utils", "ic-nervous-system-governance", "ic-nervous-system-linear-map", - "ic-nervous-system-long-message", "ic-nervous-system-proto", "ic-nervous-system-root", "ic-nervous-system-runtime", @@ -10258,7 +10361,6 @@ dependencies = [ "ic-base-types", "ic-crypto-sha2", "ic-nervous-system-clients", - "ic-nervous-system-common", "ic-nervous-system-common-validation", "ic-nervous-system-proto", "ic-nns-common", @@ -10368,11 +10470,11 @@ dependencies = [ "candid_parser", "canister-test", "dfn_candid", + "dfn_core", + "dfn_macro", "hex", "ic-base-types", "ic-canisters-http-types", - "ic-cdk 0.16.0", - "ic-cdk-macros 0.9.0", "ic-crypto-sha2", "ic-management-canister-types", "ic-metrics-encoder", @@ -10416,7 +10518,6 @@ dependencies = [ "dfn_candid", "dfn_core", "ic-base-types", - "ic-cdk 0.16.0", "ic-nervous-system-clients", "ic-nns-constants", "serde", @@ -10464,7 +10565,6 @@ dependencies = [ "csv", "hex", "ic-base-types", - "ic-ledger-canister-core", "ic-nns-constants", "ic-nns-governance-api", "ic-nns-gtc", @@ -10550,7 +10650,6 @@ dependencies = [ "on_wire", "phantom_newtype", "pocket-ic", - "pretty_assertions", "prometheus-parse", "prost 0.13.3", "rand 0.8.5", @@ -10658,7 +10757,7 @@ dependencies = [ [[package]] name = "ic-p2p-test-utils" -version = "0.9.0" +version = "0.1.0" dependencies = [ "anyhow", "async-trait", @@ -10705,7 +10804,7 @@ dependencies = [ [[package]] name = "ic-peer-manager" -version = "0.9.0" +version = "0.1.0" dependencies = [ "ic-base-types", "ic-interfaces", @@ -10833,7 +10932,7 @@ dependencies = [ [[package]] name = "ic-quic-transport" -version = "0.9.0" +version = "0.1.0" dependencies = [ "anyhow", "assert_matches", @@ -10843,10 +10942,10 @@ dependencies = [ "criterion", "futures", "http 1.2.0", + "ic-async-utils", "ic-base-types", "ic-crypto-tls-interfaces", "ic-crypto-utils-tls", - "ic-http-endpoints-async-utils", "ic-interfaces-registry", "ic-logger", "ic-metrics", @@ -10862,7 +10961,6 @@ dependencies = [ "rustls 0.23.19", "slog", "socket2 0.5.7", - "static_assertions", "thiserror 2.0.3", "tokio", "tokio-metrics", @@ -10888,7 +10986,7 @@ dependencies = [ [[package]] name = "ic-recovery" -version = "0.9.0" +version = "0.1.0" dependencies = [ "base64 0.13.1", "clap 4.5.20", @@ -10984,23 +11082,6 @@ dependencies = [ "ic-types", ] -[[package]] -name = "ic-registry-canister-data-provider" -version = "0.9.0" -dependencies = [ - "anyhow", - "candid", - "ic-cdk 0.16.0", - "ic-interfaces-registry", - "ic-nns-common", - "ic-nns-constants", - "ic-registry-canister-client", - "ic-registry-transport", - "ic-stable-structures", - "ic-types", - "itertools 0.12.1", -] - [[package]] name = "ic-registry-client" version = "0.9.0" @@ -11181,7 +11262,7 @@ dependencies = [ [[package]] name = "ic-registry-replicator" -version = "0.9.0" +version = "0.1.0" dependencies = [ "clap 4.5.20", "ic-config", @@ -11325,6 +11406,7 @@ dependencies = [ "criterion", "hex", "ic-artifact-pool", + "ic-async-utils", "ic-btc-adapter-client", "ic-btc-consensus", "ic-config", @@ -11333,7 +11415,6 @@ dependencies = [ "ic-crypto-sha2", "ic-cycles-account-manager", "ic-execution-environment", - "ic-http-endpoints-async-utils", "ic-http-endpoints-metrics", "ic-http-endpoints-public", "ic-http-endpoints-xnet", @@ -11423,6 +11504,7 @@ dependencies = [ "candid", "canister-test", "crossbeam-channel", + "ic-async-utils", "ic-base-types", "ic-btc-interface", "ic-btc-replica-types", @@ -11432,7 +11514,6 @@ dependencies = [ "ic-crypto-sha2", "ic-error-types", "ic-execution-environment", - "ic-http-endpoints-async-utils", "ic-interfaces", "ic-interfaces-registry", "ic-interfaces-state-manager", @@ -11481,6 +11562,7 @@ dependencies = [ "ic-base-types", "ic-btc-interface", "ic-btc-replica-types", + "ic-btc-test-utils", "ic-certification-version", "ic-config", "ic-crypto-ed25519", @@ -11567,7 +11649,7 @@ dependencies = [ [[package]] name = "ic-rosetta-api" -version = "2.1.1" +version = "2.1.0" dependencies = [ "actix-rt", "actix-web", @@ -11786,7 +11868,6 @@ dependencies = [ "base64 0.13.1", "build-info", "build-info-build", - "canbench-rs", "candid", "candid_parser", "clap 4.5.20", @@ -11820,7 +11901,6 @@ dependencies = [ "ic-nervous-system-proto", "ic-nervous-system-root", "ic-nervous-system-runtime", - "ic-nervous-system-timestamp", "ic-nns-constants", "ic-protobuf", "ic-sns-governance", @@ -11853,6 +11933,7 @@ dependencies = [ "strum", "strum_macros", "tempfile", + "time", "tokio", "tokio-test", ] @@ -12467,13 +12548,13 @@ dependencies = [ [[package]] name = "ic-state-sync-manager" -version = "0.9.0" +version = "0.1.0" dependencies = [ "axum", "bytes", "futures", + "ic-async-utils", "ic-base-types", - "ic-http-endpoints-async-utils", "ic-interfaces", "ic-logger", "ic-memory-transport", @@ -12524,7 +12605,7 @@ dependencies = [ [[package]] name = "ic-subnet-splitting" -version = "0.9.0" +version = "0.1.0" dependencies = [ "clap 4.5.20", "hex", @@ -13070,10 +13151,11 @@ dependencies = [ "dfn_candid", "ic-agent 0.37.1", "ic-base-types", - "ic-btc-checker", "ic-btc-interface", + "ic-btc-kyt", "ic-canister-client", "ic-ckbtc-agent", + "ic-ckbtc-kyt", "ic-ckbtc-minter", "ic-config", "ic-icrc1-ledger", @@ -13103,43 +13185,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "ic-tests-cross-chain" -version = "0.9.0" -dependencies = [ - "anyhow", - "candid", - "canister-test", - "dfn_candid", - "futures", - "hex-literal", - "ic-base-types", - "ic-canister-client", - "ic-cketh-minter", - "ic-ethereum-types", - "ic-icrc1-index-ng", - "ic-icrc1-ledger", - "ic-ledger-suite-orchestrator", - "ic-management-canister-types", - "ic-nervous-system-clients", - "ic-nervous-system-common-test-keys", - "ic-nervous-system-root", - "ic-nns-common", - "ic-nns-constants", - "ic-nns-governance-api", - "ic-nns-test-utils", - "ic-registry-subnet-type", - "ic-system-test-driver", - "ic-types", - "ic-wasm-types", - "ic_consensus_system_test_utils", - "ic_consensus_threshold_sig_system_test_utils", - "icrc-ledger-types", - "reqwest 0.12.9", - "serde_json", - "slog", -] - [[package]] name = "ic-tracing" version = "0.9.0" @@ -13208,6 +13253,29 @@ dependencies = [ "thiserror 1.0.68", ] +[[package]] +name = "ic-tvl-canister" +version = "0.9.0" +dependencies = [ + "assert_matches", + "candid", + "candid_parser", + "ic-base-types", + "ic-canisters-http-types", + "ic-cdk 0.16.0", + "ic-cdk-macros 0.9.0", + "ic-cdk-timers", + "ic-metrics-encoder", + "ic-nns-governance", + "ic-nns-test-utils", + "ic-stable-structures", + "ic-state-machine-tests", + "ic-test-utilities-load-wasm", + "rand 0.8.5", + "serde", + "xrc-mock", +] + [[package]] name = "ic-types" version = "0.9.0" @@ -13335,14 +13403,14 @@ version = "0.9.0" [[package]] name = "ic-validate-eq" -version = "0.9.0" +version = "0.0.0" dependencies = [ "ic-validate-eq-derive", ] [[package]] name = "ic-validate-eq-derive" -version = "0.9.0" +version = "0.0.0" dependencies = [ "proc-macro2", "quote", @@ -13903,7 +13971,7 @@ dependencies = [ [[package]] name = "icp-config" -version = "0.9.0" +version = "0.1.0" dependencies = [ "clap 4.5.20", "eyre", @@ -13941,7 +14009,6 @@ dependencies = [ "ic-ledger-test-utils", "ic-nns-constants", "ic-nns-test-utils-golden-nns-state", - "ic-stable-structures", "ic-state-machine-tests", "ic-test-utilities-compare-dirs", "icrc-ledger-types", @@ -14386,7 +14453,7 @@ dependencies = [ "crossbeam-channel", "crossbeam-utils", "dashmap 6.1.0", - "env_logger", + "env_logger 0.11.5", "indexmap 2.6.0", "itoa", "log", @@ -14486,9 +14553,6 @@ name = "ipnet" version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" -dependencies = [ - "serde", -] [[package]] name = "ipnetwork" @@ -14929,7 +14993,6 @@ dependencies = [ "ic-base-types", "ic-canister-log 0.2.0", "ic-cdk 0.16.0", - "ic-cdk-timers", "ic-error-types", "ic-icrc1", "ic-icrc1-test-utils", @@ -14946,10 +15009,8 @@ dependencies = [ "icrc-ledger-types", "intmap", "lazy_static", - "minicbor", "num-traits", "on_wire", - "proptest", "serde", "serde_bytes", "serde_cbor", @@ -15259,7 +15320,7 @@ checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "local_key" -version = "0.9.0" +version = "0.1.0" dependencies = [ "pin-project-lite", ] @@ -15811,6 +15872,7 @@ dependencies = [ "ic-types", "ic_consensus_system_test_utils", "slog", + "tests", ] [[package]] @@ -15992,6 +16054,7 @@ dependencies = [ "reqwest 0.12.9", "serde_cbor", "slog", + "tests", "tokio", "url", "wat", @@ -16035,7 +16098,6 @@ dependencies = [ "ic-registry-canister-api", "ic-registry-subnet-type", "ic-system-test-driver", - "ic_consensus_system_test_utils", "indoc", "k256", "registry-canister", @@ -16520,6 +16582,7 @@ dependencies = [ "hyper 1.5.1", "hyper-rustls 0.27.3", "hyper-util", + "ic-async-utils", "ic-canister-client", "ic-canister-client-sender", "ic-config", @@ -16532,7 +16595,6 @@ dependencies = [ "ic-crypto-test-utils-tls", "ic-crypto-tls-interfaces", "ic-dashboard", - "ic-http-endpoints-async-utils", "ic-http-endpoints-metrics", "ic-http-utils", "ic-image-upgrader", @@ -17186,7 +17248,6 @@ dependencies = [ "hyper 1.5.1", "hyper-util", "ic-agent 0.37.1", - "ic-bn-lib", "ic-boundary", "ic-btc-adapter", "ic-btc-interface", @@ -17785,9 +17846,9 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b8d81cf799e20564931e9867ca32de545188c6ee4c2e0f6e41d32f0c7dc6fb" +checksum = "df33e7f8a43ccc7f93b330fef4baf271764674926f3f4d40f4a196d54de8af26" dependencies = [ "cranelift-bitset", "log", @@ -17833,6 +17894,17 @@ dependencies = [ "memchr", ] +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "env_logger 0.8.4", + "log", + "rand 0.8.5", +] + [[package]] name = "quinn" version = "0.11.5" @@ -18065,10 +18137,8 @@ name = "random-traffic-test" version = "0.9.0" dependencies = [ "candid", - "futures", + "dfn_core", "ic-base-types", - "ic-cdk 0.16.0", - "ic-cdk-macros 0.9.0", "ic-error-types", "ic-types", "rand 0.8.5", @@ -18101,40 +18171,15 @@ dependencies = [ "tokio", ] -[[package]] -name = "rate-limiting-canister-client" -version = "0.9.0" -dependencies = [ - "anyhow", - "candid", - "clap 4.5.20", - "ic-agent 0.37.1", - "k256", - "rate-limits-api", - "regex", - "serde", - "serde_yaml", - "tokio", - "tracing", - "tracing-subscriber", - "uuid", -] - [[package]] name = "rate-limits-api" version = "0.9.0" dependencies = [ "candid", - "humantime", - "ic-bn-lib", - "indoc", - "ipnet", "regex", "serde", "serde_bytes", "serde_json", - "serde_regex", - "serde_yaml", ] [[package]] @@ -18411,10 +18456,9 @@ dependencies = [ name = "rejoin-test-lib" version = "0.9.0" dependencies = [ - "candid", "canister-test", "chrono", - "dfn_candid", + "dfn_json", "futures", "ic-system-test-driver", "slog", @@ -18715,81 +18759,10 @@ dependencies = [ ] [[package]] -name = "rosetta-system-tests" -version = "0.9.0" -dependencies = [ - "anyhow", - "assert-json-diff", - "canister-test", - "dfn_protobuf", - "ic-agent 0.37.1", - "ic-canister-client", - "ic-ledger-canister-blocks-synchronizer-test-utils", - "ic-ledger-core", - "ic-nns-common", - "ic-nns-constants", - "ic-nns-governance-api", - "ic-nns-test-utils", - "ic-registry-subnet-type", - "ic-rosetta-api", - "ic-rosetta-test-utils", - "ic-system-test-driver", - "ic-test-identity", - "ic-types", - "icp-ledger", - "lazy_static", - "rand 0.8.5", - "rosetta_test_lib", - "serde_json", - "slog", - "url", -] - -[[package]] -name = "rosetta_test_lib" -version = "0.9.0" -dependencies = [ - "anyhow", - "assert-json-diff", - "candid", - "canister-test", - "dfn_protobuf", - "hex", - "ic-agent 0.37.1", - "ic-base-types", - "ic-canister-client", - "ic-canister-client-sender", - "ic-icrc1-test-utils", - "ic-ledger-canister-blocks-synchronizer-test-utils", - "ic-ledger-core", - "ic-nns-common", - "ic-nns-constants", - "ic-nns-governance-api", - "ic-nns-test-utils", - "ic-registry-subnet-type", - "ic-rosetta-api", - "ic-rosetta-test-utils", - "ic-system-test-driver", - "ic-types", - "icp-ledger", - "lazy_static", - "on_wire", - "prost 0.13.3", - "rand 0.8.5", - "reqwest 0.12.9", - "rosetta-core", - "serde", - "serde_json", - "slog", - "tokio", - "url", -] - -[[package]] -name = "rsa" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ "const-oid", "digest 0.10.7", @@ -19010,9 +18983,9 @@ dependencies = [ [[package]] name = "rustls-acme" -version = "0.12.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f05935c0b1d7c5981c40b768c5d5ed96a43f5cb5166f8f5be09779c5825697" +checksum = "3d05fdb718e53ad511fa6477187f43f5dcd01b88f39e64ec16d6afc7363767d6" dependencies = [ "async-io", "async-trait", @@ -19029,7 +19002,7 @@ dependencies = [ "ring 0.17.8", "serde", "serde_json", - "thiserror 2.0.3", + "thiserror 1.0.68", "webpki-roots 0.26.6", "x509-parser", ] @@ -20053,6 +20026,7 @@ dependencies = [ "rust_decimal", "slog", "sns_system_test_lib", + "tests", ] [[package]] @@ -20179,12 +20153,10 @@ dependencies = [ name = "statesync-test" version = "0.9.0" dependencies = [ - "candid", "canister-test", - "ic-cdk 0.16.0", - "ic-cdk-macros 0.9.0", - "ic-management-canister-types", - "ic-state-machine-tests", + "dfn_core", + "dfn_json", + "dfn_macro", "ic-test-utilities", "ic-types", "lazy_static", @@ -20392,7 +20364,7 @@ dependencies = [ ] [[package]] -name = "sync-with-released-nervous-system-wasms" +name = "sync-with-released-nevous-system-wasms" version = "0.9.0" dependencies = [ "anyhow", @@ -20672,21 +20644,9 @@ name = "testing-verification-tests" version = "0.9.0" dependencies = [ "anyhow", - "candid", - "ic-agent 0.37.1", - "ic-prep", - "ic-regedit", - "ic-registry-local-store", - "ic-registry-local-store-artifacts", "ic-registry-subnet-type", "ic-system-test-driver", - "ic-types", - "ic-universal-canister", - "serde_json", "slog", - "ssh2", - "tempfile", - "tokio", ] [[package]] @@ -20708,10 +20668,175 @@ dependencies = [ "serde", "serde_json", "slog", + "tests", "url", "xrc-mock", ] +[[package]] +name = "tests" +version = "0.9.0" +dependencies = [ + "anyhow", + "assert-json-diff", + "assert_matches", + "async-recursion", + "async-trait", + "axum", + "backon", + "base64 0.13.1", + "bincode", + "candid", + "canister-test", + "chrono", + "crossbeam-channel", + "cycles-minting-canister", + "deterministic_ips", + "dfn_candid", + "dfn_json", + "dfn_protobuf", + "ed25519-dalek", + "flate2", + "futures", + "hex", + "humantime", + "ic-agent 0.37.1", + "ic-async-utils", + "ic-base-types", + "ic-btc-interface", + "ic-canister-client", + "ic-canister-client-sender", + "ic-cdk 0.16.0", + "ic-certification 0.9.0", + "ic-ckbtc-agent", + "ic-ckbtc-minter", + "ic-config", + "ic-crypto-sha2", + "ic-crypto-test-utils-reproducible-rng", + "ic-crypto-tree-hash", + "ic-crypto-utils-threshold-sig-der", + "ic-cycles-account-manager", + "ic-fstrim-tool", + "ic-http-utils", + "ic-icrc1", + "ic-icrc1-index-ng", + "ic-icrc1-ledger", + "ic-icrc1-test-utils", + "ic-interfaces", + "ic-interfaces-registry", + "ic-ledger-canister-blocks-synchronizer-test-utils", + "ic-ledger-core", + "ic-ledger-suite-orchestrator", + "ic-limits", + "ic-management-canister-types", + "ic-message", + "ic-nervous-system-clients", + "ic-nervous-system-common", + "ic-nervous-system-common-test-keys", + "ic-nervous-system-proto", + "ic-nervous-system-root", + "ic-nns-common", + "ic-nns-constants", + "ic-nns-governance-api", + "ic-nns-gtc", + "ic-nns-handler-root", + "ic-nns-init", + "ic-nns-test-utils", + "ic-prep", + "ic-protobuf", + "ic-regedit", + "ic-registry-canister-api", + "ic-registry-client", + "ic-registry-client-helpers", + "ic-registry-keys", + "ic-registry-local-registry", + "ic-registry-local-store", + "ic-registry-local-store-artifacts", + "ic-registry-nns-data-provider", + "ic-registry-provisional-whitelist", + "ic-registry-routing-table", + "ic-registry-subnet-features", + "ic-registry-subnet-type", + "ic-registry-transport", + "ic-rosetta-api", + "ic-rosetta-test-utils", + "ic-sns-governance", + "ic-sns-init", + "ic-sns-root", + "ic-sns-swap", + "ic-sns-wasm", + "ic-sys", + "ic-system-test-driver", + "ic-test-identity", + "ic-test-utilities", + "ic-test-utilities-time", + "ic-test-utilities-types", + "ic-types", + "ic-types-test-utils", + "ic-universal-canister", + "ic-utils 0.37.0", + "ic-wasm-types", + "ic_consensus_system_test_utils", + "ic_consensus_threshold_sig_system_test_utils", + "icp-ledger", + "icrc-ledger-agent", + "icrc-ledger-types", + "itertools 0.12.1", + "json5", + "k256", + "kube", + "lazy_static", + "leb128", + "libflate", + "lifeline", + "maplit", + "nix 0.24.3", + "num-traits", + "num_cpus", + "on_wire", + "once_cell", + "openssh-keys", + "pem 1.1.1", + "phantom_newtype", + "proptest", + "prost 0.13.3", + "quickcheck", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rayon", + "rcgen", + "regex", + "registry-canister", + "reqwest 0.12.9", + "rosetta-core", + "rsa", + "rust_decimal", + "serde", + "serde_bytes", + "serde_cbor", + "serde_json", + "serde_yaml", + "sha2 0.10.8", + "slog", + "slog-async", + "slog-term", + "ssh2", + "strum", + "strum_macros", + "tempfile", + "thiserror 2.0.3", + "time", + "tokio", + "tokio-util", + "tracing", + "tracing-subscriber", + "tree-deserializer", + "url", + "walkdir", + "wat", + "xnet-test", +] + [[package]] name = "textplots" version = "0.8.6" @@ -20903,7 +21028,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tla_instrumentation" -version = "0.9.0" +version = "0.1.0" dependencies = [ "candid", "local_key", @@ -20915,7 +21040,7 @@ dependencies = [ [[package]] name = "tla_instrumentation_proc_macros" -version = "0.9.0" +version = "0.1.0" dependencies = [ "proc-macro2", "quote", @@ -20984,9 +21109,9 @@ dependencies = [ [[package]] name = "tokio-metrics" -version = "0.4.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb2bb07a8451c4c6fa8b3497ad198510d8b8dffa5df5cfb97a64102a58b113c8" +checksum = "eace09241d62c98b7eeb1107d4c5c64ca3bd7da92e8c218c153ab3a78f9be112" dependencies = [ "futures-util", "pin-project-lite", @@ -21797,9 +21922,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vrl" -version = "0.20.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6f5f954461e21cacc090537e49f1023c34b6d10e12030b40ca1821a43aca68" +checksum = "5c22ec61cbd43e563df185521f9a2fb2f42f6ab96604a574c82f6564049fb431" dependencies = [ "bytes", "cfg-if 1.0.0", @@ -22041,6 +22166,15 @@ dependencies = [ "wasmparser 0.217.0", ] +[[package]] +name = "wasm-encoder" +version = "0.218.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22b896fa8ceb71091ace9bcb81e853f54043183a1c9667cf93422c40252ffa0a" +dependencies = [ + "leb128", +] + [[package]] name = "wasm-encoder" version = "0.219.1" @@ -22094,9 +22228,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.219.1" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5" +checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc" dependencies = [ "ahash 0.8.11", "bitflags 2.6.0", @@ -22106,6 +22240,16 @@ dependencies = [ "serde", ] +[[package]] +name = "wasmparser" +version = "0.219.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5" +dependencies = [ + "bitflags 2.6.0", + "indexmap 2.6.0", +] + [[package]] name = "wasmprinter" version = "0.217.0" @@ -22119,20 +22263,20 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.219.1" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228cdc1f30c27816da225d239ce4231f28941147d34713dee8f1fff7cb330e54" +checksum = "0ace089155491837b75f474bf47c99073246d1b737393fe722d6dee311595ddc" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.219.1", + "wasmparser 0.218.0", ] [[package]] name = "wasmtime" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b79302e3e084713249cc5622e8608e7410afdeeea8c8026d04f491d1fab0b4b" +checksum = "51e762e163fd305770c6c341df3290f0cabb3c264e7952943018e9a1ced8d917" dependencies = [ "anyhow", "bitflags 2.6.0", @@ -22159,7 +22303,7 @@ dependencies = [ "smallvec", "sptr", "target-lexicon", - "wasmparser 0.219.1", + "wasmparser 0.218.0", "wasmtime-asm-macros", "wasmtime-component-macro", "wasmtime-cranelift", @@ -22172,18 +22316,18 @@ dependencies = [ [[package]] name = "wasmtime-asm-macros" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe53a24e7016a5222875d8ca3ad6024b464465985693c42098cd0bb710002c28" +checksum = "63caa7aebb546374e26257a1900fb93579171e7c02514cde26805b9ece3ef812" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "wasmtime-component-macro" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e118acbd2bc09b32ad8606bc7cef793bf5019c1b107772e64dc6c76b5055d40b" +checksum = "d61a4b5ce2ad9c15655e830f0eac0c38b8def30c74ecac71f452d3901e491b68" dependencies = [ "anyhow", "proc-macro2", @@ -22196,15 +22340,15 @@ dependencies = [ [[package]] name = "wasmtime-component-util" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6db4f3ee18c699629eabb9c64e77efe5a93a5137f098db7cab295037ba41c2" +checksum = "35e87a1212270dbb84a49af13d82594e00a92769d6952b0ea7fc4366c949f6ad" [[package]] name = "wasmtime-cranelift" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b87e6c78f562b50aff1afd87ff32a57e241424c846c1c8f3c5fd352d2d62906" +checksum = "7cb40dddf38c6a5eefd5ce7c1baf43b00fe44eada11a319fab22e993a960262f" dependencies = [ "anyhow", "cfg-if 1.0.0", @@ -22220,16 +22364,16 @@ dependencies = [ "smallvec", "target-lexicon", "thiserror 1.0.68", - "wasmparser 0.219.1", + "wasmparser 0.218.0", "wasmtime-environ", "wasmtime-versioned-export-macros", ] [[package]] name = "wasmtime-environ" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c25bfeaa16432d59a0706e2463d315ef4c9ebcfaf5605670b99d46373bdf9f27" +checksum = "8613075e89e94a48c05862243c2b718eef1b9c337f51493ebf951e149a10fa19" dependencies = [ "anyhow", "cranelift-bitset", @@ -22243,16 +22387,16 @@ dependencies = [ "serde_derive", "smallvec", "target-lexicon", - "wasm-encoder 0.219.1", - "wasmparser 0.219.1", - "wasmprinter 0.219.1", + "wasm-encoder 0.218.0", + "wasmparser 0.218.0", + "wasmprinter 0.218.0", ] [[package]] name = "wasmtime-jit-icache-coherence" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91b218a92866f74f35162f5d03a4e0f62cd0e1cc624285b1014275e5d4575fad" +checksum = "da47fba49af72581bc0dc67c8faaf5ee550e6f106e285122a184a675193701a5" dependencies = [ "anyhow", "cfg-if 1.0.0", @@ -22262,15 +22406,15 @@ dependencies = [ [[package]] name = "wasmtime-slab" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5f8acf677ee6b3b8ba400dd9753ea4769e56a95c4b30b045ac6d2d54b2f8ea" +checksum = "770e10cdefb15f2b6304152978e115bd062753c1ebe7221c0b6b104fa0419ff6" [[package]] name = "wasmtime-versioned-export-macros" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df09be00c38f49172ca9936998938476e3f2df782673a39ae2ef9fb0838341b6" +checksum = "db8efb877c9e5e67239d4553bb44dd2a34ae5cfb728f3cf2c5e64439c6ca6ee7" dependencies = [ "proc-macro2", "quote", @@ -22279,9 +22423,9 @@ dependencies = [ [[package]] name = "wasmtime-wit-bindgen" -version = "27.0.0" +version = "26.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf3963c9c29df91564d8bd181eb00d0dbaeafa1b2a01e15952bb7391166b704e" +checksum = "4bef2a726fd8d1ee9b0144655e16c492dc32eb4c7c9f7e3309fcffe637870933" dependencies = [ "anyhow", "heck 0.5.0", @@ -22661,9 +22805,9 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wit-parser" -version = "0.219.1" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a86f669283257e8e424b9a4fc3518e3ade0b95deb9fbc0f93a1876be3eda598" +checksum = "0d3d1066ab761b115f97fef2b191090faabcb0f37b555b758d3caf42d4ed9e55" dependencies = [ "anyhow", "id-arena", @@ -22674,7 +22818,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.219.1", + "wasmparser 0.218.0", ] [[package]] @@ -22789,7 +22933,6 @@ dependencies = [ "rand 0.8.5", "rand_pcg 0.3.1", "serde", - "serde_bytes", ] [[package]] From 609fb0565c71d12adb3f8fff8f358e81af1a9235 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Tue, 14 Jan 2025 09:03:55 +0000 Subject: [PATCH 32/34] comments --- rs/https_outcalls/adapter/src/metrics.rs | 6 +++--- rs/https_outcalls/adapter/src/rpc_server.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rs/https_outcalls/adapter/src/metrics.rs b/rs/https_outcalls/adapter/src/metrics.rs index 5c89c4380c5..c25d53776f7 100644 --- a/rs/https_outcalls/adapter/src/metrics.rs +++ b/rs/https_outcalls/adapter/src/metrics.rs @@ -25,7 +25,7 @@ pub struct AdapterMetrics { /// The number of socks clients in the cache pub socks_cache_size: IntGauge, /// The number of cache misses for socks clients - pub socks_cache_miss: IntCounter, + pub socks_cache_misses: IntCounter, /// Network traffic generated by adapter. pub network_traffic: IntCounterVec, /// Request failure types. @@ -53,8 +53,8 @@ impl AdapterMetrics { "socks_cache_size", "The size of the cache for SOCKS clients", ), - socks_cache_miss: metrics_registry.int_counter( - "socks_cache_miss_total", + socks_cache_misses: metrics_registry.int_counter( + "socks_cache_misses_total", "Total number of times the adapter failed to find a SOCKS client in the cache", ), network_traffic: metrics_registry.int_counter_vec( diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 5c28e27b426..8cbd03a57f9 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -180,7 +180,7 @@ impl CanisterHttp { Some(client.clone()) } else { let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); - self.metrics.socks_cache_miss.inc(); + self.metrics.socks_cache_misses.inc(); self.maybe_add_socks_client_for_address(&mut cache_guard, address); match cache_guard.get(address) { Some(client) => Some(client.clone()), From fc831e0e9b0336186b34c0e50b1ba2321420860e Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 22 Jan 2025 14:45:37 +0000 Subject: [PATCH 33/34] comments --- rs/https_outcalls/adapter/src/rpc_server.rs | 58 ++++++++++++--------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index 8cbd03a57f9..d91edf0c0bc 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -116,28 +116,28 @@ impl CanisterHttp { } } - fn maybe_add_socks_client_for_address(&self, cache: &mut Cache, address: &str) { + //TODO(mihailjianu): add a name for this. + fn create_socks_proxy_client( + &self, + proxy_addr: Uri, + ) -> Client>, Full> { let mut http_connector = HttpConnector::new(); http_connector.enforce_http(false); http_connector .set_connect_timeout(Some(Duration::from_secs(self.http_connect_timeout_secs))); - if let Ok(proxy_addr) = address.parse() { - let client = Client::builder(TokioExecutor::new()).build::<_, Full>( - HttpsConnectorBuilder::new() - .with_native_roots() - .expect("Failed to set native roots") - .https_only() - .enable_all_versions() - .wrap_connector(SocksConnector { - proxy_addr, - auth: None, - connector: http_connector, - }), - ); - cache.insert(address.to_string(), client); - self.metrics.socks_cache_size.set(cache.len() as i64); - } + Client::builder(TokioExecutor::new()).build::<_, Full>( + HttpsConnectorBuilder::new() + .with_native_roots() + .expect("Failed to set native roots") + .https_only() + .enable_all_versions() + .wrap_connector(SocksConnector { + proxy_addr, + auth: None, + connector: http_connector, + }), + ) } fn compare_results( @@ -181,7 +181,18 @@ impl CanisterHttp { } else { let mut cache_guard = RwLockUpgradableReadGuard::upgrade(cache_guard); self.metrics.socks_cache_misses.inc(); - self.maybe_add_socks_client_for_address(&mut cache_guard, address); + + match address.parse() { + Ok(proxy_addr) => { + let client = self.create_socks_proxy_client(proxy_addr); + cache_guard.insert(address.to_string(), client); + self.metrics.socks_cache_size.set(cache_guard.len() as i64); + } + Err(e) => { + debug!(self.logger, "Failed to parse SOCKS proxy address: {}", e); + } + } + match cache_guard.get(address) { Some(client) => Some(client.clone()), None => { @@ -195,9 +206,9 @@ impl CanisterHttp { } } - async fn https_outcall_socks_proxy( + async fn do_https_outcall_socks_proxy( &self, - socks_proxy_addrs: &[String], + socks_proxy_addrs: Vec, request: http::Request>, ) -> Result, String> { let mut socks_proxy_addrs = socks_proxy_addrs.to_owned(); @@ -213,9 +224,8 @@ impl CanisterHttp { if tries > MAX_SOCKS_PROXY_RETRIES { break; } - let next_socks_proxy_addr = socks_proxy_addr.clone(); - let socks_client = self.get_socks_client(&next_socks_proxy_addr); + let socks_client = self.get_socks_client(socks_proxy_addr); if let Some(socks_client) = socks_client { match socks_client.request(request.clone()).await { @@ -234,7 +244,7 @@ impl CanisterHttp { debug!( self.logger, "Failed to connect through SOCKS with address {}: {}", - next_socks_proxy_addr, + socks_proxy_addr, socks_err ); last_error = Some(socks_err); @@ -352,7 +362,7 @@ impl HttpsOutcallsService for CanisterHttp { //TODO(SOCKS_PROXY_DL): Remove the compare_results once we are confident in the SOCKS proxy implementation. if !req.socks_proxy_addrs.is_empty() { - let dl_result = self.https_outcall_socks_proxy(&req.socks_proxy_addrs, http_req_clone).await; + let dl_result = self.do_https_outcall_socks_proxy(req.socks_proxy_addrs, http_req_clone).await; self.compare_results(&result, &dl_result); } From 8be6dd85b624689719e34dd3c9053ae9bcbacb64 Mon Sep 17 00:00:00 2001 From: Mihail Jianu Date: Wed, 22 Jan 2025 14:47:51 +0000 Subject: [PATCH 34/34] remove todo --- rs/https_outcalls/adapter/src/rpc_server.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rs/https_outcalls/adapter/src/rpc_server.rs b/rs/https_outcalls/adapter/src/rpc_server.rs index d91edf0c0bc..14dec70e052 100644 --- a/rs/https_outcalls/adapter/src/rpc_server.rs +++ b/rs/https_outcalls/adapter/src/rpc_server.rs @@ -116,7 +116,6 @@ impl CanisterHttp { } } - //TODO(mihailjianu): add a name for this. fn create_socks_proxy_client( &self, proxy_addr: Uri,