Have simple-request return an error upon failing to find the system's root certificates

This commit is contained in:
Luke Parker
2025-09-18 17:03:16 -04:00
parent 10c126ad92
commit 18a9cf2535
11 changed files with 34 additions and 28 deletions

View File

@@ -52,7 +52,7 @@ pub struct Client {
}
impl Client {
fn connector() -> Connector {
fn connector() -> Result<Connector, Error> {
let mut res = HttpConnector::new();
res.set_keepalive(Some(core::time::Duration::from_secs(60)));
res.set_nodelay(true);
@@ -62,27 +62,31 @@ impl Client {
#[cfg(feature = "tls")]
let res = HttpsConnectorBuilder::new()
.with_native_roots()
.expect("couldn't fetch system's SSL roots")
.map_err(|e| {
Error::ConnectionError(
format!("couldn't load system's SSL root certificates: {e:?}").into(),
)
})?
.https_or_http()
.enable_http1()
.wrap_connector(res);
res
Ok(res)
}
pub fn with_connection_pool() -> Client {
Client {
pub fn with_connection_pool() -> Result<Client, Error> {
Ok(Client {
connection: Connection::ConnectionPool(
HyperClient::builder(TokioExecutor::new())
.pool_idle_timeout(core::time::Duration::from_secs(60))
.build(Self::connector()),
.build(Self::connector()?),
),
}
})
}
pub fn without_connection_pool(host: &str) -> Result<Client, Error> {
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() {
@@ -149,7 +153,7 @@ impl Client {
*connection_lock = Some(requester);
}
let connection = connection_lock.as_mut().unwrap();
let connection = connection_lock.as_mut().expect("lock over the connection was poisoned");
let mut err = connection.ready().await.err();
if err.is_none() {
// Send the request
@@ -161,7 +165,7 @@ impl Client {
}
// Since this connection has been put into an error state, drop it
*connection_lock = None;
Err(Error::Hyper(err.unwrap()))?
Err(Error::Hyper(err.expect("only here if `err` is some yet no error")))?
}
};

View File

@@ -42,7 +42,8 @@ impl Request {
formatted.zeroize();
self.request.headers_mut().insert(
hyper::header::AUTHORIZATION,
HeaderValue::from_str(&format!("Basic {encoded}")).unwrap(),
HeaderValue::from_str(&format!("Basic {encoded}"))
.expect("couldn't form header from base64-encoded string"),
);
encoded.zeroize();
}

View File

@@ -62,7 +62,8 @@ impl Rpc {
/// provided to this library, if the RPC has an incompatible argument layout. That is not checked
/// at time of RPC creation.
pub async fn new(url: String) -> Result<Rpc, RpcError> {
let rpc = Rpc { client: Client::with_connection_pool(), url };
let rpc =
Rpc { client: Client::with_connection_pool().map_err(|_| RpcError::ConnectionError)?, url };
// Make an RPC request to verify the node is reachable and sane
let res: String = rpc.rpc_call("help", json!([])).await?;

View File

@@ -7,7 +7,7 @@ use std::io;
use alloy_json_rpc::{RequestPacket, ResponsePacket};
use alloy_transport::{TransportError, TransportErrorKind, TransportFut};
use simple_request::{hyper, Request, Client};
use simple_request::{hyper, Error, Request, Client};
use tower::Service;
@@ -18,8 +18,8 @@ pub struct SimpleRequest {
}
impl SimpleRequest {
pub fn new(url: String) -> Self {
Self { client: Client::with_connection_pool(), url }
pub fn new(url: String) -> Result<Self, Error> {
Ok(Self { client: Client::with_connection_pool()?, url })
}
}

View File

@@ -36,7 +36,7 @@ async fn setup_test() -> (AnvilInstance, Arc<RootProvider>, Address) {
let anvil = Anvil::new().spawn();
let provider = Arc::new(RootProvider::new(
ClientBuilder::default().transport(SimpleRequest::new(anvil.endpoint()), true),
ClientBuilder::default().transport(SimpleRequest::new(anvil.endpoint()).unwrap(), true),
));
let mut address = [0; 20];

View File

@@ -21,7 +21,7 @@ async fn test_deployer() {
let anvil = Anvil::new().arg("--hardfork").arg(network).spawn();
let provider = Arc::new(RootProvider::new(
ClientBuilder::default().transport(SimpleRequest::new(anvil.endpoint()), true),
ClientBuilder::default().transport(SimpleRequest::new(anvil.endpoint()).unwrap(), true),
));
// Deploy the Deployer

View File

@@ -129,7 +129,7 @@ impl Test {
.spawn();
let provider = Arc::new(RootProvider::new(
ClientBuilder::default().transport(SimpleRequest::new(anvil.endpoint()), true),
ClientBuilder::default().transport(SimpleRequest::new(anvil.endpoint()).unwrap(), true),
));
let chain_id = U256::from(provider.get_chain_id().await.unwrap());

View File

@@ -61,7 +61,7 @@ async fn main() {
let db = bin::init();
let provider = Arc::new(RootProvider::new(
ClientBuilder::default().transport(SimpleRequest::new(bin::url()), true),
ClientBuilder::default().transport(SimpleRequest::new(bin::url()).unwrap(), true),
));
let chain_id = {

View File

@@ -158,7 +158,7 @@ impl Serai {
}
pub async fn new(url: String) -> Result<Self, SeraiError> {
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())

View File

@@ -277,7 +277,7 @@ impl Coordinator {
};
let provider = Arc::new(RootProvider::<_, Ethereum>::new(
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()).unwrap(), true),
));
if handle
@@ -417,7 +417,7 @@ impl Coordinator {
};
let provider = RootProvider::<_, Ethereum>::new(
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()).unwrap(), true),
);
let start = provider
.get_block(BlockNumberOrTag::Latest.into(), BlockTransactionsKind::Hashes)
@@ -509,7 +509,7 @@ impl Coordinator {
let (expected_number, state) = {
let provider = RootProvider::<_, Ethereum>::new(
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()).unwrap(), true),
);
let expected_number = provider
@@ -528,7 +528,7 @@ impl Coordinator {
for coordinator in others {
let rpc_url = network_rpc(coordinator.network, ops, &coordinator.network_handle);
let provider = RootProvider::<_, Ethereum>::new(
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()).unwrap(), true),
);
assert!(provider
.raw_request::<_, bool>("anvil_loadState".into(), &[&state])
@@ -605,7 +605,7 @@ impl Coordinator {
};
let provider = RootProvider::<_, Ethereum>::new(
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()).unwrap(), true),
);
let _ = provider.send_raw_transaction(tx).await.unwrap();
}
@@ -662,7 +662,7 @@ impl Coordinator {
ExternalNetworkId::Ethereum => {
/*
let provider = RootProvider::<_, Ethereum>::new(
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()).unwrap(), true),
);
let mut hash = [0; 32];
hash.copy_from_slice(tx);

View File

@@ -165,7 +165,7 @@ impl Wallet {
ethereum_serai::crypto::address(&(<Secp256k1 as WrappedGroup>::generator() * key));
let provider = RootProvider::<_, Ethereum>::new(
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()).unwrap(), true),
);
provider
@@ -319,7 +319,7 @@ impl Wallet {
let one_eth = eighteen_decimals;
let provider = Arc::new(RootProvider::<_, Ethereum>::new(
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true),
ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()).unwrap(), true),
));
let to_as_key = PublicKey::new(