diff --git a/Cargo.toml b/Cargo.toml index 6c5197e0..9148b01c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,12 +21,8 @@ rustdoc-args = ["--cfg", "docsrs"] all-features = true [dependencies] -alloy-primitives = { version = "0.6", default-features = false, features = [ - "std", - "serde", - "rand", -] } -alloy-json-abi = { version = "0.6", default-features = false, features = ["std", "serde_json"] } +alloy-primitives = { version = "0.6", features = ["serde", "rand"] } +alloy-json-abi = { version = "0.6", features = ["serde_json"] } solang-parser = { version = "=0.3.3", default-features = false } @@ -38,7 +34,6 @@ serde_json = "1.0" tracing = "0.1.37" tiny-keccak = { version = "2.0.2", default-features = false } -sha2 = { version = "0.10.7", default-features = false, optional = true } md-5 = "0.10.5" semver = { version = "1.0", features = ["serde"] } @@ -56,20 +51,22 @@ dunce = "1.0" rayon = "1.7" path-slash = "0.2.1" cfg-if = "1.0.0" +memmap2 = "0.9.0" +# async +futures-util = { version = "0.3", optional = true } +tokio = { version = "1.32", features = ["rt-multi-thread"], optional = true } + +# project-util tempfile = { version = "3.8.0", optional = true } fs_extra = { version = "1.3.0", optional = true } rand = { version = "0.8", optional = true } -futures-util = { version = "0.3.28", optional = true } -memmap2 = "0.9.0" -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +# svm home = "0.5.5" -svm = { package = "svm-rs", version = "0.3", default-features = false, features = [ - "blocking", -], optional = true } -svm-builds = { package = "svm-rs-builds", version = "0.3", optional = true } -tokio = { version = "1.32", features = ["rt-multi-thread"] } +svm = { package = "svm-rs", version = "0.3", default-features = false, optional = true } +svm-builds = { package = "svm-rs-builds", version = "0.3", default-features = false, optional = true } +sha2 = { version = "0.10.7", default-features = false, optional = true } [dev-dependencies] criterion = { version = "0.5", features = ["async_tokio"] } @@ -107,12 +104,13 @@ default = ["rustls"] full = ["async", "svm-solc"] -async = ["tokio/process", "tokio/io-util", "tokio/fs", "tokio/time", "futures-util"] -svm-solc = ["svm", "svm-builds", "sha2"] +async = ["dep:futures-util", "dep:tokio", "tokio/fs", "tokio/process"] +svm-solc = ["dep:svm", "dep:svm-builds", "dep:sha2"] -# Utilities for creating and testing project workspaces -project-util = ["tempfile", "fs_extra", "rand"] +# Utilities for creating and testing project workspaces. +project-util = ["dep:tempfile", "dep:fs_extra", "dep:rand"] -tests = [] rustls = ["svm?/rustls"] openssl = ["svm?/openssl"] + +tests = [] diff --git a/src/compile/mod.rs b/src/compile/mod.rs index 97a67024..26526c31 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -84,7 +84,7 @@ pub(crate) fn take_solc_installer_lock() -> std::sync::MutexGuard<'static, ()> { /// A list of upstream Solc releases, used to check which version /// we should download. /// The boolean value marks whether there was an error accessing the release list -#[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] +#[cfg(feature = "svm-solc")] pub static RELEASES: Lazy<(svm::Releases, Vec, bool)> = Lazy::new(|| match serde_json::from_str::(svm_builds::RELEASE_LIST_JSON) { Ok(releases) => { @@ -159,14 +159,12 @@ impl Default for Solc { if let Ok(solc) = std::env::var("SOLC_PATH") { return Solc::new(solc); } - #[cfg(not(target_arch = "wasm32"))] + + if let Some(solc) = Solc::svm_global_version() + .and_then(|vers| Solc::find_svm_installed_version(vers.to_string()).ok()) + .flatten() { - if let Some(solc) = Solc::svm_global_version() - .and_then(|vers| Solc::find_svm_installed_version(vers.to_string()).ok()) - .flatten() - { - return solc; - } + return solc; } Solc::new(SOLC) @@ -220,9 +218,8 @@ impl Solc { /// Returns the directory in which [svm](https://github.com/roynalnaruto/svm-rs) stores all versions /// /// This will be: - /// `~/.svm` on unix, if it exists + /// - `~/.svm` on unix, if it exists /// - $XDG_DATA_HOME (~/.local/share/svm) if the svm folder does not exist. - #[cfg(not(target_arch = "wasm32"))] pub fn svm_home() -> Option { match home::home_dir().map(|dir| dir.join(".svm")) { Some(dir) => { @@ -241,7 +238,6 @@ impl Solc { /// /// This will read the version string (eg: "0.8.9") that the `~/.svm/.global_version` file /// contains - #[cfg(not(target_arch = "wasm32"))] pub fn svm_global_version() -> Option { let home = Self::svm_home()?; let version = std::fs::read_to_string(home.join(".global_version")).ok()?; @@ -249,7 +245,6 @@ impl Solc { } /// Returns the list of all solc instances installed at `SVM_HOME` - #[cfg(not(target_arch = "wasm32"))] pub fn installed_versions() -> Vec { Self::svm_home() .map(|home| { @@ -264,7 +259,7 @@ impl Solc { /// Returns the list of all versions that are available to download and marking those which are /// already installed. - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub fn all_versions() -> Vec { let mut all_versions = Self::installed_versions(); let mut uniques = all_versions @@ -297,7 +292,6 @@ impl Solc { /// # Ok(()) /// # } /// ``` - #[cfg(not(target_arch = "wasm32"))] pub fn find_svm_installed_version(version: impl AsRef) -> Result> { let version = version.as_ref(); let solc = Self::svm_home() @@ -324,7 +318,7 @@ impl Solc { /// # Ok(()) /// # } /// ``` - #[cfg(all(not(target_arch = "wasm32"), feature = "svm-solc"))] + #[cfg(feature = "svm-solc")] pub fn find_or_install_svm_version(version: impl AsRef) -> Result { let version = version.as_ref(); if let Some(solc) = Solc::find_svm_installed_version(version)? { @@ -348,7 +342,7 @@ impl Solc { /// to build it, and returns it. /// /// If the required compiler version is not installed, it also proceeds to install it. - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub fn detect_version(source: &Source) -> Result { // detects the required solc version let sol_version = Self::source_version_req(source)?; @@ -359,7 +353,7 @@ impl Solc { /// used to build it, and returns it. /// /// If the required compiler version is not installed, it also proceeds to install it. - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub fn ensure_installed(sol_version: &VersionReq) -> Result { #[cfg(any(test, feature = "tests"))] let _lock = take_solc_installer_lock(); @@ -427,33 +421,33 @@ impl Solc { /// # Ok(()) /// # } /// ``` - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub async fn install(version: &Version) -> std::result::Result { trace!("installing solc version \"{}\"", version); crate::report::solc_installation_start(version); - let result = svm::install(version).await; - crate::report::solc_installation_success(version); - result.map(Solc::new) + match svm::install(version).await { + Ok(path) => { + crate::report::solc_installation_success(version); + Ok(Solc::new(path)) + } + Err(err) => { + crate::report::solc_installation_error(version, &err.to_string()); + Err(err) + } + } } /// Blocking version of `Self::install` - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub fn blocking_install(version: &Version) -> std::result::Result { use crate::utils::RuntimeOrHandle; trace!("blocking installing solc version \"{}\"", version); crate::report::solc_installation_start(version); - // the async version `svm::install` is used instead of `svm::blocking_intsall` + // The async version `svm::install` is used instead of `svm::blocking_intsall` // because the underlying `reqwest::blocking::Client` does not behave well - // in tokio rt. see https://github.com/seanmonstar/reqwest/issues/1017 - cfg_if::cfg_if! { - if #[cfg(target_arch = "wasm32")] { - let installation = svm::blocking_install(version); - } else { - let installation = RuntimeOrHandle::new().block_on(svm::install(version)); - } - }; - match installation { + // inside of a Tokio runtime. See: https://github.com/seanmonstar/reqwest/issues/1017 + match RuntimeOrHandle::new().block_on(svm::install(version)) { Ok(path) => { crate::report::solc_installation_success(version); Ok(Solc::new(path)) @@ -467,7 +461,7 @@ impl Solc { /// Verify that the checksum for this version of solc is correct. We check against the SHA256 /// checksum from the build information published by [binaries.soliditylang.org](https://binaries.soliditylang.org/) - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub fn verify_checksum(&self) -> Result<()> { let version = self.version_short()?; let mut version_path = svm::version_path(version.to_string().as_str()); @@ -874,8 +868,7 @@ mod tests { } #[test] - // This test might be a bit hard to maintain - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] fn test_detect_version() { for (pragma, expected) in [ // pinned @@ -916,7 +909,7 @@ mod tests { } #[test] - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] fn can_install_solc_in_tokio_rt() { let version = Version::from_str("0.8.6").unwrap(); let rt = tokio::runtime::Runtime::new().unwrap(); diff --git a/src/compile/project.rs b/src/compile/project.rs index fe84bcd3..a6682ecb 100644 --- a/src/compile/project.rs +++ b/src/compile/project.rs @@ -139,7 +139,7 @@ impl<'a, T: ArtifactOutput> ProjectCompiler<'a, T> { /// let project = Project::builder().build().unwrap(); /// let output = project.compile().unwrap(); /// ``` - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub fn new(project: &'a Project) -> Result { Self::with_sources(project, project.paths.read_input_files()?) } @@ -150,7 +150,7 @@ impl<'a, T: ArtifactOutput> ProjectCompiler<'a, T> { /// /// Multiple (`Solc` -> `Sources`) pairs can be compiled in parallel if the `Project` allows /// multiple `jobs`, see [`crate::Project::set_solc_jobs()`]. - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub fn with_sources(project: &'a Project, sources: Sources) -> Result { let graph = Graph::resolve_sources(&project.paths, sources)?; let (versions, edges) = graph.into_sources_by_version(project.offline)?; diff --git a/src/error.rs b/src/error.rs index 611bca31..14f397d1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -56,7 +56,7 @@ pub enum SolcError { {2:?}"# )] FailedResolveImport(Box, PathBuf, PathBuf), - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] #[error(transparent)] SvmError(#[from] svm::SolcVmError), #[error("no contracts found at \"{0}\"")] diff --git a/src/lib.rs b/src/lib.rs index 8afb7eb4..491e4f56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,15 @@ #![doc = include_str!("../README.md")] -#![deny(rustdoc::broken_intra_doc_links)] -#![cfg_attr(docsrs, feature(doc_cfg))] +// #![warn( +// missing_copy_implementations, +// missing_debug_implementations, +// missing_docs, +// unreachable_pub, +// clippy::missing_const_for_fn, +// rustdoc::all +// )] +// #![cfg_attr(not(test), warn(unused_crate_dependencies))] +// #![deny(unused_must_use, rust_2018_idioms)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #[macro_use] extern crate tracing; @@ -274,7 +283,7 @@ impl Project { let sources = self.paths.read_input_files()?; trace!("found {} sources to compile: {:?}", sources.len(), sources.keys()); - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] if self.auto_detect { trace!("using solc auto detection to compile sources"); return self.svm_compile(sources); @@ -306,7 +315,7 @@ impl Project { /// let output = project.svm_compile(sources).unwrap(); /// # } /// ``` - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub fn svm_compile(&self, sources: Sources) -> Result> { project::ProjectCompiler::with_sources(self, sources)?.compile() } @@ -323,7 +332,7 @@ impl Project { /// let output = project.compile_file("example/Greeter.sol").unwrap(); /// # } /// ``` - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub fn compile_file(&self, file: impl Into) -> Result> { let file = file.into(); let source = Source::read(&file)?; @@ -349,7 +358,7 @@ impl Project { { let sources = Source::read_all(files)?; - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] if self.auto_detect { return project::ProjectCompiler::with_sources(self, sources)?.compile(); } @@ -386,7 +395,7 @@ impl Project { let sources = Source::read_all(self.paths.input_files().into_iter().filter(|p| filter.is_match(p)))?; - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] if self.auto_detect { return project::ProjectCompiler::with_sources(self, sources)? .with_sparse_output(filter) @@ -1004,7 +1013,7 @@ fn rebase_path(base: impl AsRef, path: impl AsRef) -> PathBuf { } #[cfg(test)] -#[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] +#[cfg(feature = "svm-solc")] mod tests { use super::*; use crate::remappings::Remapping; diff --git a/src/project_util/mod.rs b/src/project_util/mod.rs index b0f44d81..82fbc200 100644 --- a/src/project_util/mod.rs +++ b/src/project_util/mod.rs @@ -70,7 +70,7 @@ impl TempProject { } /// Explicitly sets the solc version for the project - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] pub fn set_solc(&mut self, solc: impl AsRef) -> &mut Self { self.inner.solc = crate::Solc::find_or_install_svm_version(solc).unwrap(); self.inner.auto_detect = false; diff --git a/src/resolver/mod.rs b/src/resolver/mod.rs index 569d339a..97bf6a40 100644 --- a/src/resolver/mod.rs +++ b/src/resolver/mod.rs @@ -458,7 +458,7 @@ impl Graph { } } -#[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] +#[cfg(feature = "svm-solc")] impl Graph { /// Consumes the nodes of the graph and returns all input files together with their appropriate /// version and the edges of the graph @@ -782,7 +782,7 @@ impl<'a> Iterator for NodesIter<'a> { } /// Container type for solc versions and their compatible sources -#[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] +#[cfg(feature = "svm-solc")] #[derive(Debug)] pub struct VersionedSources { resolved_solc_include_paths: IncludePaths, @@ -790,7 +790,7 @@ pub struct VersionedSources { offline: bool, } -#[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] +#[cfg(feature = "svm-solc")] impl VersionedSources { /// Resolves or installs the corresponding `Solc` installation. /// @@ -913,7 +913,7 @@ impl Node { /// /// This returns an error if the file's version is invalid semver, or is not available such as /// 0.8.20, if the highest available version is `0.8.19` - #[cfg(all(feature = "svm-solc", not(target_arch = "wasm32")))] + #[cfg(feature = "svm-solc")] fn check_available_version( &self, all_versions: &[crate::SolcVersion], diff --git a/src/utils.rs b/src/utils.rs index 7d15a49c..33bc5694 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -483,36 +483,36 @@ pub(crate) fn find_case_sensitive_existing_file(non_existing: &Path) -> Option

Self { - Self::new() - } -} +cfg_if! { + if #[cfg(any(feature = "async", feature = "svm-solc"))] { + use tokio::runtime::{Handle, Runtime}; + + #[derive(Debug)] + pub enum RuntimeOrHandle { + Runtime(Runtime), + Handle(Handle), + } -#[cfg(not(target_arch = "wasm32"))] -impl RuntimeOrHandle { - pub fn new() -> RuntimeOrHandle { - match Handle::try_current() { - Ok(handle) => RuntimeOrHandle::Handle(handle), - Err(_) => RuntimeOrHandle::Runtime(Runtime::new().expect("Failed to start runtime")), + impl Default for RuntimeOrHandle { + fn default() -> Self { + Self::new() + } } - } - pub fn block_on(&self, f: F) -> F::Output { - match &self { - RuntimeOrHandle::Runtime(runtime) => runtime.block_on(f), - RuntimeOrHandle::Handle(handle) => tokio::task::block_in_place(|| handle.block_on(f)), + impl RuntimeOrHandle { + pub fn new() -> RuntimeOrHandle { + match Handle::try_current() { + Ok(handle) => RuntimeOrHandle::Handle(handle), + Err(_) => RuntimeOrHandle::Runtime(Runtime::new().expect("Failed to start runtime")), + } + } + + pub fn block_on(&self, f: F) -> F::Output { + match &self { + RuntimeOrHandle::Runtime(runtime) => runtime.block_on(f), + RuntimeOrHandle::Handle(handle) => tokio::task::block_in_place(|| handle.block_on(f)), + } + } } } } diff --git a/tests/project.rs b/tests/project.rs index 40f9d1ee..6fe7dcb5 100644 --- a/tests/project.rs +++ b/tests/project.rs @@ -2182,8 +2182,8 @@ fn remove_solc_if_exists(version: &Version) { } } -#[tokio::test(flavor = "multi_thread")] -async fn can_install_solc_and_compile_version() { +#[test] +fn can_install_solc_and_compile_version() { let project = TempProject::dapptools().unwrap(); let version = Version::new(0, 8, 10);