From 53d4902005bb7777cb783fbeeede3613b4219df1 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sun, 26 Nov 2023 10:27:30 -0500 Subject: [PATCH] Replace rustls with boring-ssl This removes all re-attempts present in monero-serai's RPC and is an attempt to narrow down the sporadic failures. Inspired by https://github.com/hyperium/hyper/issues/3427 --- Cargo.toml | 2 ++ coins/bitcoin/src/rpc.rs | 6 +++--- coins/monero/src/rpc/http.rs | 15 ++++++++++++--- coins/monero/src/rpc/mod.rs | 6 +----- common/request/Cargo.toml | 4 ++-- common/request/src/lib.rs | 26 +++++++++++++++----------- substrate/client/src/serai/mod.rs | 2 +- 7 files changed, 36 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 14add4b98..906368b4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,3 +93,5 @@ lazy_static = { git = "https://github.com/rust-lang-nursery/lazy-static.rs", rev # subxt *can* pull these off crates.io yet there's no benefit to this sp-core-hashing = { git = "https://github.com/serai-dex/substrate" } sp-std = { git = "https://github.com/serai-dex/substrate" } + +hyper-boring = { git = "https://github.com/cloudflare/boring", rev = "423c260d87b69a926594ded0dd693b5cf1220452" } diff --git a/coins/bitcoin/src/rpc.rs b/coins/bitcoin/src/rpc.rs index 73a215e04..62248a1f5 100644 --- a/coins/bitcoin/src/rpc.rs +++ b/coins/bitcoin/src/rpc.rs @@ -6,7 +6,7 @@ use thiserror::Error; use serde::{Deserialize, de::DeserializeOwned}; use serde_json::json; -use simple_request::{hyper, Request, Client}; +use simple_request::{hyper, Full, Request, Client}; use bitcoin::{ hashes::{Hash, hex::FromHex}, @@ -110,11 +110,11 @@ impl Rpc { let mut request = Request::from( hyper::Request::post(&self.url) .header("Content-Type", "application/json") - .body( + .body(Full::new( serde_json::to_vec(&json!({ "jsonrpc": "2.0", "method": method, "params": params })) .unwrap() .into(), - ) + )) .unwrap(), ); request.with_basic_auth(); diff --git a/coins/monero/src/rpc/http.rs b/coins/monero/src/rpc/http.rs index 270886380..a0af75b6b 100644 --- a/coins/monero/src/rpc/http.rs +++ b/coins/monero/src/rpc/http.rs @@ -6,7 +6,7 @@ use tokio::sync::Mutex; use digest_auth::{WwwAuthenticateHeader, AuthContext}; use simple_request::{ - hyper::{StatusCode, header::HeaderValue, Request}, + hyper::{header::HeaderValue, Request}, Response, Client, }; @@ -102,7 +102,9 @@ impl HttpRpc { connection: Arc::new(Mutex::new((challenge, client))), } } else { - Authentication::Unauthenticated(Client::with_connection_pool()) + Authentication::Unauthenticated( + Client::with_connection_pool().map_err(|e| RpcError::ConnectionError(format!("{e:?}")))?, + ) }; Ok(Rpc(HttpRpc { authentication, url })) @@ -258,7 +260,14 @@ impl HttpRpc { }); } - unreachable!() + let mut res = Vec::with_capacity(128); + response + .body() + .await + .map_err(|e| RpcError::ConnectionError(format!("{e:?}")))? + .read_to_end(&mut res) + .unwrap(); + Ok(res) } } diff --git a/coins/monero/src/rpc/mod.rs b/coins/monero/src/rpc/mod.rs index a5bf8c81e..0480d5757 100644 --- a/coins/monero/src/rpc/mod.rs +++ b/coins/monero/src/rpc/mod.rs @@ -135,11 +135,7 @@ impl Rpc { .0 .post( route, - if let Some(params) = params { - serde_json::to_string(¶ms).unwrap().into_bytes() - } else { - vec![] - }, + if let Some(params) = params { serde_json::to_vec(¶ms).unwrap() } else { vec![] }, ) .await?; let res_str = std_shims::str::from_utf8(&res) diff --git a/common/request/Cargo.toml b/common/request/Cargo.toml index 7fd694253..f4baab988 100644 --- a/common/request/Cargo.toml +++ b/common/request/Cargo.toml @@ -18,12 +18,12 @@ rustdoc-args = ["--cfg", "docsrs"] hyper = { version = "0.14", default-features = false, features = ["http1", "tcp", "client", "runtime", "backports", "deprecated"] } tokio = { version = "1", default-features = false } -hyper-rustls = { version = "0.24", default-features = false, features = ["http1", "native-tokio"], optional = true } +hyper-boring = { version = "4", default-features = false, features = ["runtime"], optional = true } zeroize = { version = "1", optional = true } base64ct = { version = "1", features = ["alloc"], optional = true } [features] -tls = ["hyper-rustls"] +tls = ["hyper-boring"] basic-auth = ["zeroize", "base64ct"] default = ["tls"] diff --git a/common/request/src/lib.rs b/common/request/src/lib.rs index 4c738e2ef..788b509e4 100644 --- a/common/request/src/lib.rs +++ b/common/request/src/lib.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use tokio::sync::Mutex; #[cfg(feature = "tls")] -use hyper_rustls::{HttpsConnectorBuilder, HttpsConnector}; +use hyper_boring::HttpsConnector; use hyper::{ Uri, header::HeaderValue, @@ -36,11 +36,16 @@ type Connector = HttpConnector; #[cfg(feature = "tls")] type Connector = HttpsConnector; -#[derive(Clone, Debug)] +#[derive(Clone)] enum Connection { ConnectionPool(hyper::Client), Connection { connector: Connector, host: Uri, connection: Arc>>> }, } +impl core::fmt::Debug for Connection { + fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + fmt.debug_struct("Connection").finish_non_exhaustive() + } +} #[derive(Clone, Debug)] pub struct Client { @@ -48,25 +53,24 @@ pub struct Client { } impl Client { - fn connector() -> Connector { + fn connector() -> Result { #[cfg(feature = "tls")] - let res = - HttpsConnectorBuilder::new().with_native_roots().https_or_http().enable_http1().build(); + let res = HttpsConnector::new().map_err(|e| Error::ConnectionError(format!("{e:?}").into()))?; #[cfg(not(feature = "tls"))] let res = HttpConnector::new(); - res + Ok(res) } - pub fn with_connection_pool() -> Client { - Client { - connection: Connection::ConnectionPool(hyper::Client::builder().build(Self::connector())), - } + pub fn with_connection_pool() -> Result { + Ok(Client { + connection: Connection::ConnectionPool(hyper::Client::builder().build(Self::connector()?)), + }) } pub fn without_connection_pool(host: String) -> Result { Ok(Client { connection: Connection::Connection { - connector: Self::connector(), + connector: Self::connector()?, host: { let uri: Uri = host.parse().map_err(|_| Error::InvalidUri)?; if uri.host().is_none() { diff --git a/substrate/client/src/serai/mod.rs b/substrate/client/src/serai/mod.rs index b725c02a1..91f2969b0 100644 --- a/substrate/client/src/serai/mod.rs +++ b/substrate/client/src/serai/mod.rs @@ -150,7 +150,7 @@ impl Serai { } pub async fn new(url: String) -> Result { - let client = Client::with_connection_pool(); + let client = Client::with_connection_pool().map_err(|_| SeraiError::ConnectionError)?; let mut res = Serai { url, client, genesis: [0xfe; 32] }; res.genesis = res.block_hash(0).await?.ok_or_else(|| { SeraiError::InvalidNode("node didn't have the first block's hash".to_string())