Skip to content

Commit c23b54a

Browse files
committed
all: Install rustls aws_lc_rs as default crypto provider
With alloy 2.0.0 pulling in rustls with aws_lc_rs and object_store (via reqwest) pulling in rustls with ring, rustls 0.23 refuses to auto-pick and panics on first TLS use. Install aws_lc_rs explicitly at each binary/test-harness entry point via a shared helper.
1 parent bfcce15 commit c23b54a

10 files changed

Lines changed: 73 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ license = "MIT OR Apache-2.0"
3737
[workspace.dependencies]
3838
alloy = { version = "2.0.0", features = ["dyn-abi", "json-abi", "full", "arbitrary", "json-rpc", "serde"] }
3939
alloy-rpc-types = "2.0.0"
40+
# rustls is pulled in transitively by alloy (aws_lc_rs) and object_store via
41+
# reqwest (ring). With both providers linked, rustls 0.23 requires an explicit
42+
# default provider to be installed before any TLS use. We install aws_lc_rs
43+
# explicitly in each binary/test entry point.
44+
rustls = { version = "0.23", default-features = false, features = ["aws_lc_rs"] }
4045
anyhow = "1.0"
4146
async-graphql = { version = "7.2.1", features = ["chrono"] }
4247
async-graphql-axum = "7.2.1"

gnd/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ fn generate_completions(completions_opt: CompletionsOpt) -> Result<()> {
155155

156156
#[tokio::main]
157157
async fn main() -> Result<()> {
158+
graph::tls::install_default_crypto_provider();
158159
std::env::set_var("ETHEREUM_REORG_THRESHOLD", "10");
159160
std::env::set_var("GRAPH_NODE_DISABLE_DEPLOYMENT_HASH_VALIDATION", "true");
160161
env_logger::init();

graph/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ chrono = "0.4.44"
2727
envconfig = { workspace = true }
2828
Inflector = "0.11.3"
2929
reqwest = { version = "0.12.23", features = ["json", "stream", "multipart", "gzip", "brotli", "deflate"] }
30+
rustls = { workspace = true }
3031
hex = "0.4.3"
3132
http0 = { version = "0", package = "http" }
3233
http = "1"

graph/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ pub mod env;
3333

3434
pub mod ipfs;
3535

36+
pub mod tls;
37+
3638
pub mod abi;
3739

3840
pub mod amp;

graph/src/tls.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//! Process-wide TLS crypto provider setup.
2+
//!
3+
//! # Background
4+
//!
5+
//! `rustls` 0.23 requires a "crypto provider" (the backend that implements
6+
//! AES, SHA, ECDSA, RNG, etc.) to be selected before any TLS connection is
7+
//! built. When exactly one provider feature is compiled in, `rustls` picks
8+
//! it automatically. When **multiple** providers are linked, `rustls`
9+
//! refuses to guess and panics on the first TLS use with:
10+
//!
11+
//! > no process-level CryptoProvider available --
12+
//! > call CryptoProvider::install_default() before this point
13+
//!
14+
//! # Why we hit this
15+
//!
16+
//! Our dependency graph pulls in two providers:
17+
//!
18+
//! - `alloy-transport-ws` (alloy 2.0+) enables `rustls`'s `aws_lc_rs` feature.
19+
//! - `object_store` (via `reqwest`'s `rustls-tls-native-roots`) enables
20+
//! `rustls`'s `ring` feature.
21+
//!
22+
//! Cargo features are additive, so `rustls` ends up compiled with **both**
23+
//! `aws_lc_rs` and `ring`. We can't disable either without forking an
24+
//! upstream crate, so we resolve the ambiguity by explicitly installing
25+
//! `aws_lc_rs` as the process-wide default at startup.
26+
//!
27+
//! # Where to call this
28+
//!
29+
//! This must be called **once per process**, as early as possible, before
30+
//! any code opens a TLS connection. In practice that means:
31+
//!
32+
//! - At the top of every binary's `main()` (`graph-node`, `graphman`, `gnd`).
33+
//! - From a function that every test harness touches before using TLS
34+
//! (we hook into `test-store`'s `build_store()` and `graph-tests`'
35+
//! `fixture::stores()`).
36+
//!
37+
//! Each Rust binary (including each `cargo test` binary) is a separate
38+
//! process, so every entry point needs its own call. There is no single
39+
//! "Rust process startup hook" short of pulling in the `ctor` crate.
40+
//!
41+
//! # Safety / idempotency
42+
//!
43+
//! `install_default` only succeeds on the first call per process. Subsequent
44+
//! calls return an error, which we deliberately ignore. This makes the
45+
//! helper safe to call from many places without coordination.
46+
47+
/// Install `aws_lc_rs` as the process-wide default `rustls` crypto provider.
48+
///
49+
/// Idempotent: safe to call multiple times per process. Only the first call
50+
/// actually installs; later calls are no-ops. Must be called before any
51+
/// TLS connection is built. See the module docs for why this exists.
52+
pub fn install_default_crypto_provider() {
53+
// If a provider is already installed (by an earlier call, or by another
54+
// crate), `install_default` returns Err. That's fine -- as long as some
55+
// provider is set, `rustls` will not panic. We deliberately do not
56+
// require that `aws_lc_rs` specifically wins, only that a default
57+
// exists.
58+
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
59+
}

node/src/bin/manager.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,7 @@ impl Context {
11321132

11331133
#[tokio::main]
11341134
async fn main() -> anyhow::Result<()> {
1135+
graph::tls::install_default_crypto_provider();
11351136
// Disable load management for graphman commands
11361137
env::set_var("GRAPH_LOAD_THRESHOLD", "0");
11371138

node/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ lazy_static! {
1515
}
1616

1717
fn main() {
18+
graph::tls::install_default_crypto_provider();
1819
tokio::runtime::Builder::new_multi_thread()
1920
.enable_all()
2021
.max_blocking_threads(*MAX_BLOCKING_THREADS)

store/test-store/src/store.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ pub fn all_shards() -> Vec<Shard> {
619619
}
620620

621621
fn build_store() -> (Arc<Store>, ConnectionPool, Config, Arc<SubscriptionManager>) {
622+
graph::tls::install_default_crypto_provider();
622623
let mut opt = Opt::default();
623624
let url = std::env::var_os("THEGRAPH_STORE_POSTGRES_DIESEL_URL").filter(|s| !s.is_empty());
624625
let file = std::env::var_os("GRAPH_NODE_TEST_CONFIG").filter(|s| !s.is_empty());

tests/src/fixture/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ fn test_logger(test_name: &str) -> Logger {
365365

366366
#[allow(clippy::await_holding_lock)]
367367
pub async fn stores(test_name: &str, store_config_path: &str) -> Stores {
368+
graph::tls::install_default_crypto_provider();
368369
let _mutex_guard = STORE_MUTEX.lock().unwrap();
369370

370371
let config = {

0 commit comments

Comments
 (0)