Skip to content

Commit

Permalink
fix(solc): add RuntimeOrHandle & fix solc blocking installation (ga…
Browse files Browse the repository at this point in the history
…konst#1260)

* rt wrapper for solc install

* fix

* uncomment feat flag

* feature deps & comment

* async it tests

* use svm::block_install for wasm

* hide rt or handle for wasm

* hide import for wasm
  • Loading branch information
rkrasiuk authored May 14, 2022
1 parent eb94e53 commit f3699d0
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 3 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions ethers-solc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ["rt"] }
futures-util = { version = "^0.3", optional = true }
once_cell = "1.10.0"
regex = "1.5.5"
Expand All @@ -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"
Expand Down Expand Up @@ -80,7 +81,7 @@ required-features = ["full", "project-util"]

[features]
default = ["rustls"]
async = ["tokio", "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
Expand Down
24 changes: 23 additions & 1 deletion ethers-solc/src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,21 @@ impl Solc {
/// Blocking version of `Self::install`
#[cfg(all(feature = "svm-solc"))]
pub fn blocking_install(version: &Version) -> std::result::Result<Self, svm::SolcVmError> {
use crate::utils::RuntimeOrHandle;

tracing::trace!("blocking installing solc version \"{}\"", version);
crate::report::solc_installation_start(version);
match svm::blocking_install(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
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))
Expand Down Expand Up @@ -723,6 +735,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() {
Expand Down Expand Up @@ -799,6 +812,15 @@ mod tests {
assert_eq!(res.solc, expected);
}

#[test]
#[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();
let result = rt.block_on(async { Solc::blocking_install(&version) });
assert!(result.is_ok());
}

#[test]
fn does_not_find_not_installed_version() {
let ver = "1.1.1";
Expand Down
34 changes: 34 additions & 0 deletions ethers-solc/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,40 @@ pub(crate) fn find_fave_or_alt_path(root: impl AsRef<Path>, 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 {
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() {
Ok(handle) => RuntimeOrHandle::Handle(handle),
Err(_) => RuntimeOrHandle::Runtime(Runtime::new().expect("Failed to start runtime")),
}
}

pub fn block_on<F: std::future::Future>(&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<tempfile::TempDir, SolcIoError> {
Expand Down
51 changes: 51 additions & 0 deletions ethers-solc/tests/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use ethers_solc::{
ProjectPathsConfig, Solc, TestFileFilter,
};
use pretty_assertions::assert_eq;
use semver::Version;

#[allow(unused)]
fn init_tracing() {
Expand Down Expand Up @@ -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"));
}

0 comments on commit f3699d0

Please sign in to comment.