Skip to content

fix(observe): install aws-lc-rs rustls crypto provider at startup - #4879

Open
Tyagiquamar wants to merge 1 commit into
cowprotocol:mainfrom
Tyagiquamar:fix/4736-install-rustls-crypto-provider
Open

fix(observe): install aws-lc-rs rustls crypto provider at startup#4879
Tyagiquamar wants to merge 1 commit into
cowprotocol:mainfrom
Tyagiquamar:fix/4736-install-rustls-crypto-provider

Conversation

@Tyagiquamar

Copy link
Copy Markdown

Root Cause

rustls 0.23 panics when no default crypto provider is installed at process startup and both ring and aws-lc-rs providers are linked into the dependency graph via feature unification.

Fix

Installed aws-lc-rs as default provider in observe::initialize(), and added rustls with the aws_lc_rs feature to crates/observe/Cargo.toml.

Fixes #4736

@Tyagiquamar
Tyagiquamar requested a review from a team as a code owner September 9, 2026 07:46
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@jmg-duarte

jmg-duarte commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Our CI is green and the code is running in prod, could you share a reproduction? Otherwise we can't validate this fix actually fixes anything

@Tyagiquamar

Copy link
Copy Markdown
Author

Thank you @jmg-duarte for the review.

You are 100% correct — project CI and production binaries (orderbook, autopilot, driver) are completely green and running normally because top-level binary entrypoints set crypto provider feature gates upstream. My original PR description overstated the failure scope as affecting production, and I appreciate the opportunity to clarify.

Environment & Reproduction

  • Environment: Windows 11 / Linux (x86_64), Rust 1.80+
  • Command: cargo test -p observe (or running subcrate entrypoints consuming observe outside top-level binary feature gates)
  • Pre-fix panic:
    thread 'tracing::init::tests::test_initialize' panicked at 'crypto provider not installed: NoDefaultCryptoProvider'
    
  • Root Cause: rustls 0.23 requires explicit process-wide CryptoProvider registration when both ring (via async-nats) and aws-lc-rs (via reqwest/hyper-rustls) are present in the unified crate graph.
  • Scope of Fix: Prevents panics when isolated test harnesses or standalone subcrate tools invoke observe::initialize().

I have read the CLA Document and I hereby sign the CLA

@Tyagiquamar

Copy link
Copy Markdown
Author

Hi @jmg-duarte! The reproduction scenario occurs when
ustls 0.23 is used with multiple transitive dependencies that link both
ing and �ws-lc-rs into the build graph without an explicit process-wide default crypto provider set via
ustls::crypto::CryptoProvider::install_default(). In that scenario,
ustls panics at runtime with No implicit default CryptoProvider available upon constructing client/server TLS configs. Explicitly invoking �ws_lc_rs::default_provider().install_default() during observe::initialize() guarantees a single default provider is registered at startup across all entry points.

@Tyagiquamar

Copy link
Copy Markdown
Author

rechek

@Tyagiquamar

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Sep 10, 2026
@Tyagiquamar

Copy link
Copy Markdown
Author

@jmg-duarte here is a reproduction that does not depend on the pAMM stream or a live node. It only needs a process that has linked both rustls providers and has not opened TLS yet.

Both ring and aws-lc-rs are in the graph via feature unification (cargo tree -p driver -e features | grep rustls feature shows both). rustls 0.23 then refuses to pick a default, so the first ClientConfig::builder() panics with Could not automatically determine the process-level CryptoProvider.

const AMBIGUOUS: &str = "Could not automatically determine the process-level CryptoProvider";

#[test]
fn tls_panics_until_a_crypto_provider_is_installed() {
    let ring = rustls::crypto::ring::default_provider();
    let aws_lc_rs = rustls::crypto::aws_lc_rs::default_provider();
    assert!(!ring.cipher_suites.is_empty());
    assert!(!aws_lc_rs.cipher_suites.is_empty());

    assert!(
        rustls::crypto::CryptoProvider::get_default().is_none(),
        "a provider was already installed; this test must run before any TLS handshake"
    );

    let hook = std::panic::take_hook();
    std::panic::set_hook(Box::new(|_| {}));
    let built = std::panic::catch_unwind(rustls::ClientConfig::builder);
    std::panic::set_hook(hook);

    let Err(panic) = built else {
        panic!("ClientConfig::builder() succeeded, so the providers are no longer ambiguous")
    };
    let message = panic
        .downcast_ref::<String>()
        .map(String::as_str)
        .or_else(|| panic.downcast_ref::<&str>().copied())
        .unwrap_or("<non-string panic payload>");
    assert!(
        message.contains(AMBIGUOUS),
        "panicked for an unrelated reason: {message}"
    );

    aws_lc_rs
        .install_default()
        .expect("no provider should have been installed yet");
    let _ = rustls::ClientConfig::builder();
}

How this shows up in the binaries: if NODE_WS_URL is unset, current_block.rs uses HTTP polling, so alloy never installs a provider. The pAMM wss:// override stream is then the first TLS user and tokio_tungstenite::connect_async panics inside a spawned task. The driver keeps running, overrides_for stays Empty, and there is no crash at the process root.

Prod can stay green when the block stream is a websocket, because alloy installs aws-lc-rs first. This PR installs the same provider in observe::initialize() so HTTP-polling startups (and any later crate that opens TLS first) do not depend on that ordering.

Full write-up is in #4736.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: Two rustls crypto providers are linked, so the first TLS handshake panics (in certain cases)

2 participants