From 5e827d67c7f7b15f0b2675e1f2d30b6a71032543 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sat, 14 May 2022 10:46:56 +0300 Subject: [PATCH 1/8] rt wrapper for solc install --- ethers-solc/Cargo.toml | 4 ++-- ethers-solc/src/compile/mod.rs | 17 +++++++++++++++-- ethers-solc/src/utils.rs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/ethers-solc/Cargo.toml b/ethers-solc/Cargo.toml index a184ea32e..1bc0841bc 100644 --- a/ethers-solc/Cargo.toml +++ b/ethers-solc/Cargo.toml @@ -19,7 +19,7 @@ serde_json = "1.0.68" serde = { version = "1.0.130", features = ["derive"] } semver = { version = "1.0.9", features = ["serde"] } walkdir = "2.3.2" -tokio = { version = "1.15.0", default-features = false, features = ["process", "io-util", "fs", "time"], optional = true } +tokio = { version = "1.15.0", default-features = false, features = ["process", "io-util", "fs", "time"] } futures-util = { version = "^0.3", optional = true } once_cell = "1.10.0" regex = "1.5.5" @@ -80,7 +80,7 @@ required-features = ["full", "project-util"] [features] default = ["rustls"] -async = ["tokio", "futures-util"] +async = ["futures-util"] full = ["async", "svm-solc"] svm-solc = ["svm/blocking", "svm-builds", "sha2"] # Utilities for creating and testing project workspaces diff --git a/ethers-solc/src/compile/mod.rs b/ethers-solc/src/compile/mod.rs index 384f9c75a..69b06dddf 100644 --- a/ethers-solc/src/compile/mod.rs +++ b/ethers-solc/src/compile/mod.rs @@ -369,11 +369,13 @@ impl Solc { } /// Blocking version of `Self::install` - #[cfg(all(feature = "svm-solc"))] + // #[cfg(all(feature = "svm-solc"))] pub fn blocking_install(version: &Version) -> std::result::Result { + use crate::utils::RuntimeOrHandle; + tracing::trace!("blocking installing solc version \"{}\"", version); crate::report::solc_installation_start(version); - match svm::blocking_install(version) { + match RuntimeOrHandle::new().block_on(svm::install(version)) { Ok(path) => { crate::report::solc_installation_success(version); Ok(Solc::new(path)) @@ -799,6 +801,17 @@ mod tests { assert_eq!(res.solc, expected); } + #[test] + #[cfg(feature = "svm-solc")] + fn can_install_solc_in_tokio_rt() { + let ver = "0.8.6"; + let version = Version::from_str(ver).unwrap(); + let result = tokio::runtime::Runtime::new() + .unwrap() + .block_on(async { Solc::blocking_install(&version) }); + assert!(result.is_err()); + } + #[test] fn does_not_find_not_installed_version() { let ver = "1.1.1"; diff --git a/ethers-solc/src/utils.rs b/ethers-solc/src/utils.rs index 825107ea5..56f200cda 100644 --- a/ethers-solc/src/utils.rs +++ b/ethers-solc/src/utils.rs @@ -12,6 +12,7 @@ use regex::{Match, Regex}; use semver::Version; use serde::de::DeserializeOwned; use tiny_keccak::{Hasher, Keccak}; +use tokio::runtime::{Handle, Runtime}; use walkdir::WalkDir; /// A regex that matches the import path and identifier of a solidity import @@ -330,6 +331,35 @@ pub(crate) fn find_fave_or_alt_path(root: impl AsRef, fave: &str, alt: &st p } +#[allow(clippy::large_enum_variant)] +#[derive(Debug)] +pub enum RuntimeOrHandle { + Runtime(Runtime), + Handle(Handle), +} + +impl Default for RuntimeOrHandle { + fn default() -> Self { + Self::new() + } +} + +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)), + } + } +} + /// Creates a new named tempdir #[cfg(any(test, feature = "project-util"))] pub(crate) fn tempdir(name: &str) -> Result { From f8ba2db7ac7bdd355b664073a1b4b29bcc7881c9 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sat, 14 May 2022 10:47:59 +0300 Subject: [PATCH 2/8] fix --- ethers-solc/src/compile/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethers-solc/src/compile/mod.rs b/ethers-solc/src/compile/mod.rs index 69b06dddf..93d616d0f 100644 --- a/ethers-solc/src/compile/mod.rs +++ b/ethers-solc/src/compile/mod.rs @@ -809,7 +809,7 @@ mod tests { let result = tokio::runtime::Runtime::new() .unwrap() .block_on(async { Solc::blocking_install(&version) }); - assert!(result.is_err()); + assert!(result.is_ok()); } #[test] From 1f9d2b8fb8041f2c36593b7ba06cb4d924b01469 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sat, 14 May 2022 11:00:50 +0300 Subject: [PATCH 3/8] uncomment feat flag --- ethers-solc/src/compile/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethers-solc/src/compile/mod.rs b/ethers-solc/src/compile/mod.rs index 93d616d0f..e3e3b3aa4 100644 --- a/ethers-solc/src/compile/mod.rs +++ b/ethers-solc/src/compile/mod.rs @@ -369,7 +369,7 @@ impl Solc { } /// Blocking version of `Self::install` - // #[cfg(all(feature = "svm-solc"))] + #[cfg(all(feature = "svm-solc"))] pub fn blocking_install(version: &Version) -> std::result::Result { use crate::utils::RuntimeOrHandle; From 866a351632681a1bc8dd761da6ef24c5d96c8ea4 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sat, 14 May 2022 15:54:48 +0300 Subject: [PATCH 4/8] feature deps & comment --- ethers-solc/Cargo.toml | 4 ++-- ethers-solc/src/compile/mod.rs | 12 +++++++----- ethers-solc/src/utils.rs | 1 - 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/ethers-solc/Cargo.toml b/ethers-solc/Cargo.toml index 1bc0841bc..b77974081 100644 --- a/ethers-solc/Cargo.toml +++ b/ethers-solc/Cargo.toml @@ -19,7 +19,7 @@ serde_json = "1.0.68" serde = { version = "1.0.130", features = ["derive"] } semver = { version = "1.0.9", features = ["serde"] } walkdir = "2.3.2" -tokio = { version = "1.15.0", default-features = false, features = ["process", "io-util", "fs", "time"] } +tokio = { version = "1.15.0", default-features = false, features = ["rt"] } futures-util = { version = "^0.3", optional = true } once_cell = "1.10.0" regex = "1.5.5" @@ -80,7 +80,7 @@ required-features = ["full", "project-util"] [features] default = ["rustls"] -async = ["futures-util"] +async = ["tokio/process", "tokio/io-util", "tokio/fs", "tokio/time", "futures-util"] full = ["async", "svm-solc"] svm-solc = ["svm/blocking", "svm-builds", "sha2"] # Utilities for creating and testing project workspaces diff --git a/ethers-solc/src/compile/mod.rs b/ethers-solc/src/compile/mod.rs index e3e3b3aa4..efdc31f07 100644 --- a/ethers-solc/src/compile/mod.rs +++ b/ethers-solc/src/compile/mod.rs @@ -375,6 +375,9 @@ impl Solc { tracing::trace!("blocking installing solc version \"{}\"", version); crate::report::solc_installation_start(version); + // 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 match RuntimeOrHandle::new().block_on(svm::install(version)) { Ok(path) => { crate::report::solc_installation_success(version); @@ -725,6 +728,7 @@ mod tests { let other = solc().async_compile(&serde_json::json!(input)).await.unwrap(); assert_eq!(out, other); } + #[cfg(feature = "async")] #[tokio::test] async fn async_solc_compile_works2() { @@ -804,11 +808,9 @@ mod tests { #[test] #[cfg(feature = "svm-solc")] fn can_install_solc_in_tokio_rt() { - let ver = "0.8.6"; - let version = Version::from_str(ver).unwrap(); - let result = tokio::runtime::Runtime::new() - .unwrap() - .block_on(async { Solc::blocking_install(&version) }); + let version = Version::from_str("0.8.6").unwrap(); + let rt = tokio::runtime::Runtime::new().unwrap(); + let result = rt.block_on(async { Solc::blocking_install(&version) }); assert!(result.is_ok()); } diff --git a/ethers-solc/src/utils.rs b/ethers-solc/src/utils.rs index 56f200cda..c594e1fd4 100644 --- a/ethers-solc/src/utils.rs +++ b/ethers-solc/src/utils.rs @@ -331,7 +331,6 @@ pub(crate) fn find_fave_or_alt_path(root: impl AsRef, fave: &str, alt: &st p } -#[allow(clippy::large_enum_variant)] #[derive(Debug)] pub enum RuntimeOrHandle { Runtime(Runtime), From 99caa27c634bb94b77869b663761628c467cf409 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sat, 14 May 2022 17:18:18 +0300 Subject: [PATCH 5/8] async it tests --- ethers-solc/tests/project.rs | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/ethers-solc/tests/project.rs b/ethers-solc/tests/project.rs index 5bc568e7b..21698fd7f 100644 --- a/ethers-solc/tests/project.rs +++ b/ethers-solc/tests/project.rs @@ -17,6 +17,7 @@ use ethers_solc::{ ProjectPathsConfig, Solc, TestFileFilter, }; use pretty_assertions::assert_eq; +use semver::Version; #[allow(unused)] fn init_tracing() { @@ -1329,3 +1330,53 @@ fn can_compile_model_checker_sample() { assert!(!compiled.has_compiler_errors()); assert!(compiled.has_compiler_warnings()); } + +fn remove_solc_if_exists(version: &Version) { + match Solc::find_svm_installed_version(version.to_string()).unwrap() { + Some(_) => svm::remove_version(&version).expect("failed to remove version"), + None => {} + }; +} + +#[tokio::test(flavor = "multi_thread")] +async fn can_install_solc_and_compile_version() { + let project = TempProject::dapptools().unwrap(); + let version = Version::new(0, 8, 10); + + project + .add_source( + "Contract", + format!( + r#" +pragma solidity {}; +contract Contract {{ }} +"#, + version.to_string() + ), + ) + .unwrap(); + + remove_solc_if_exists(&version); + + let compiled = project.compile().unwrap(); + assert!(!compiled.has_compiler_errors()); +} + +#[tokio::test(flavor = "multi_thread")] +async fn can_install_solc_and_compile_std_json_input_async() { + let tmp = TempProject::dapptools_init().unwrap(); + tmp.assert_no_errors(); + let source = tmp.list_source_files().into_iter().find(|p| p.ends_with("Dapp.t.sol")).unwrap(); + let input = tmp.project().standard_json_input(source).unwrap(); + let solc = &tmp.project().solc; + + assert!(input.settings.remappings.contains(&"ds-test/=lib/ds-test/src/".parse().unwrap())); + let input: CompilerInput = input.into(); + assert!(input.sources.contains_key(Path::new("lib/ds-test/src/test.sol"))); + + remove_solc_if_exists(&solc.version().expect("failed to get version")); + + let out = solc.async_compile(&input).await.unwrap(); + assert!(!out.has_error()); + assert!(out.sources.contains_key("lib/ds-test/src/test.sol")); +} From 8b37b219d9c340fc791e1be6c2d0817038d87ead Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sat, 14 May 2022 17:29:38 +0300 Subject: [PATCH 6/8] use svm::block_install for wasm --- Cargo.lock | 1 + ethers-solc/Cargo.toml | 1 + ethers-solc/src/compile/mod.rs | 9 ++++++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 8fdbc201e..458ac4c7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1401,6 +1401,7 @@ dependencies = [ name = "ethers-solc" version = "0.3.0" dependencies = [ + "cfg-if 1.0.0", "colored", "criterion", "dunce", diff --git a/ethers-solc/Cargo.toml b/ethers-solc/Cargo.toml index b77974081..c0acee2ae 100644 --- a/ethers-solc/Cargo.toml +++ b/ethers-solc/Cargo.toml @@ -39,6 +39,7 @@ solang-parser = { default-features = false, version = "=0.1.13" } rayon = "1.5.2" rand = { version = "0.8.5", optional = true } path-slash = "0.1.4" +cfg-if = "1.0.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] home = "0.5.3" diff --git a/ethers-solc/src/compile/mod.rs b/ethers-solc/src/compile/mod.rs index efdc31f07..92e3b9a96 100644 --- a/ethers-solc/src/compile/mod.rs +++ b/ethers-solc/src/compile/mod.rs @@ -378,7 +378,14 @@ impl Solc { // 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 - match RuntimeOrHandle::new().block_on(svm::install(version)) { + 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 { Ok(path) => { crate::report::solc_installation_success(version); Ok(Solc::new(path)) From 3fd78f75f189cba17fb98bab227f1bd7e76e520f Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sat, 14 May 2022 17:37:20 +0300 Subject: [PATCH 7/8] hide rt or handle for wasm --- ethers-solc/src/utils.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ethers-solc/src/utils.rs b/ethers-solc/src/utils.rs index c594e1fd4..f91141518 100644 --- a/ethers-solc/src/utils.rs +++ b/ethers-solc/src/utils.rs @@ -331,18 +331,21 @@ pub(crate) fn find_fave_or_alt_path(root: impl AsRef, fave: &str, alt: &st p } +#[cfg(not(target_arch = "wasm32"))] #[derive(Debug)] pub enum RuntimeOrHandle { Runtime(Runtime), Handle(Handle), } +#[cfg(not(target_arch = "wasm32"))] impl Default for RuntimeOrHandle { fn default() -> Self { Self::new() } } +#[cfg(not(target_arch = "wasm32"))] impl RuntimeOrHandle { pub fn new() -> RuntimeOrHandle { match Handle::try_current() { From e32c312723edd7090f3b8d2a4514055f8afd9bc9 Mon Sep 17 00:00:00 2001 From: Roman Krasiuk Date: Sat, 14 May 2022 17:43:40 +0300 Subject: [PATCH 8/8] hide import for wasm --- ethers-solc/src/utils.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ethers-solc/src/utils.rs b/ethers-solc/src/utils.rs index f91141518..a5bd3e115 100644 --- a/ethers-solc/src/utils.rs +++ b/ethers-solc/src/utils.rs @@ -12,7 +12,6 @@ use regex::{Match, Regex}; use semver::Version; use serde::de::DeserializeOwned; use tiny_keccak::{Hasher, Keccak}; -use tokio::runtime::{Handle, Runtime}; use walkdir::WalkDir; /// A regex that matches the import path and identifier of a solidity import @@ -331,6 +330,9 @@ pub(crate) fn find_fave_or_alt_path(root: impl AsRef, fave: &str, alt: &st p } +#[cfg(not(target_arch = "wasm32"))] +use tokio::runtime::{Handle, Runtime}; + #[cfg(not(target_arch = "wasm32"))] #[derive(Debug)] pub enum RuntimeOrHandle {