diff --git a/ethers-solc/src/compile.rs b/ethers-solc/src/compile.rs index ddf031ae..153274dc 100644 --- a/ethers-solc/src/compile.rs +++ b/ethers-solc/src/compile.rs @@ -47,6 +47,19 @@ use std::sync::Mutex; #[allow(unused)] static LOCK: Lazy> = Lazy::new(|| Mutex::new(())); +/// take the lock in tests, we use this to enforce that +/// a test does not run while a compiler version is being installed +/// +/// This ensures that only one thread installs a missing `solc` exe. +/// Instead of taking this lock in `Solc::blocking_install`, the lock should be taken before +/// installation is detected. +#[cfg(any(test, feature = "tests"))] +#[allow(unused)] +pub(crate) fn take_solc_installer_lock() -> std::sync::LockResult> +{ + LOCK.lock() +} + #[cfg(all(feature = "svm", feature = "async"))] /// A list of upstream Solc releases, used to check which version /// we should download. @@ -289,9 +302,7 @@ impl Solc { #[cfg(all(feature = "svm", feature = "async"))] pub fn ensure_installed(sol_version: &VersionReq) -> Result { #[cfg(any(test, feature = "tests"))] - // take the lock in tests, we use this to enforce that - // a test does not run while a compiler version is being installed - let _lock = LOCK.lock(); + let _lock = take_solc_installer_lock(); // load the local / remote versions let versions = utils::installed_versions(svm::SVM_HOME.as_path()).unwrap_or_default(); diff --git a/ethers-solc/src/resolver.rs b/ethers-solc/src/resolver.rs index 22f1677d..e2c8403d 100644 --- a/ethers-solc/src/resolver.rs +++ b/ethers-solc/src/resolver.rs @@ -385,6 +385,10 @@ impl VersionedSources { ) -> Result> { use crate::SolcError; + // we take the installer lock here to ensure installation checking is done in sync + #[cfg(any(test, feature = "tests"))] + let _lock = crate::compile::take_solc_installer_lock(); + let mut sources_by_version = std::collections::BTreeMap::new(); for (version, sources) in self.inner { if !version.is_installed() {