Skip to content

fix: handle concurrent rustls cryptoprovider initialization#217

Open
reez wants to merge 2 commits into
bitcoindevkit:masterfrom
reez:provider
Open

fix: handle concurrent rustls cryptoprovider initialization#217
reez wants to merge 2 commits into
bitcoindevkit:masterfrom
reez:provider

Conversation

@reez

@reez reez commented Jun 30, 2026

Copy link
Copy Markdown

Fixes #216
References bitcoindevkit/bdk-dart#103

When multiple SSL clients are created concurrently more than one caller can observe that no process-default rustls CryptoProvider is installed. This keeps the existing install path, but if install_default() fails, it re-checks whether a default provider is now present and treats that as success.

I tried to look for broader context/discussion in things like #171 (comment) and #171 (comment). This keeps the existing get_default() guard behavior, but also handles the concurrent "first use" case where another caller installs the provider after the initial check.

@oleonardolima oleonardolima added the bug Something isn't working label Jul 1, 2026
@oleonardolima oleonardolima moved this to In Progress in BDK Chain Jul 1, 2026
@oleonardolima

Copy link
Copy Markdown
Collaborator

@reez I pushed 1ca8828 to fix the CI.

@luisschwab luisschwab left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 3ea825a

@reez

reez commented Jul 1, 2026

Copy link
Copy Markdown
Author

@reez I pushed 1ca8828 to fix the CI.

cool appreciated 👍

@caarloshenriq caarloshenriq left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 3ea825a

Tried to reproduce #216 manually via concurrent Client::from_config calls, but couldn't trigger it reliably over a real network connection, timing is too noisy. I think we should add a regression test for this case.

Suggestion: extract the install logic into its own function, then hit it directly with many threads via a Barrier, no network or TLS involved. Something like:

fn install_crypto_provider() -> Result<(), Error> {
    if rustls::crypto::CryptoProvider::get_default().is_none() {
        #[cfg(all(feature = "rustls", not(feature = "rustls-ring")))]
        rustls::crypto::CryptoProvider::install_default(
            rustls::crypto::aws_lc_rs::default_provider(),
        )
        .or_else(|_| {
            rustls::crypto::CryptoProvider::get_default()
                .map(|_| ())
                .ok_or_else(|| {
                    Error::CouldNotCreateConnection(rustls::Error::General(
                        "Failed to install CryptoProvider".to_string(),
                    ))
                })
        })?;

        #[cfg(feature = "rustls-ring")]
        rustls::crypto::CryptoProvider::install_default(
            rustls::crypto::ring::default_provider(),
        )
        .or_else(|_| {
            rustls::crypto::CryptoProvider::get_default()
                .map(|_| ())
                .ok_or_else(|| {
                    Error::CouldNotCreateConnection(rustls::Error::General(
                        "Failed to install CryptoProvider".to_string(),
                    ))
                })
        })?;
    }
    Ok(())
}

#[test]
fn test_concurrent_crypto_provider_install() {
    use std::sync::{Arc, Barrier};
    use std::thread;

    let n = 64;
    let barrier = Arc::new(Barrier::new(n));
    let handles: Vec<_> = (0..n)
        .map(|_| {
            let barrier = Arc::clone(&barrier);
            thread::spawn(move || {
                barrier.wait();
                install_crypto_provider()
            })
        })
        .collect();

    for h in handles {
        assert!(h.join().unwrap().is_ok());
    }
}

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

Labels

bug Something isn't working

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

Concurrent SSL client creation can fail during rustls CryptoProvider initialization

4 participants