fix(solc): add `RuntimeOrHandle` & fix solc blocking installation (#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
This commit is contained in:
parent
eb94e53d1f
commit
f3699d08bf
|
@ -1401,6 +1401,7 @@ dependencies = [
|
||||||
name = "ethers-solc"
|
name = "ethers-solc"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
"colored",
|
"colored",
|
||||||
"criterion",
|
"criterion",
|
||||||
"dunce",
|
"dunce",
|
||||||
|
|
|
@ -19,7 +19,7 @@ serde_json = "1.0.68"
|
||||||
serde = { version = "1.0.130", features = ["derive"] }
|
serde = { version = "1.0.130", features = ["derive"] }
|
||||||
semver = { version = "1.0.9", features = ["serde"] }
|
semver = { version = "1.0.9", features = ["serde"] }
|
||||||
walkdir = "2.3.2"
|
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 }
|
futures-util = { version = "^0.3", optional = true }
|
||||||
once_cell = "1.10.0"
|
once_cell = "1.10.0"
|
||||||
regex = "1.5.5"
|
regex = "1.5.5"
|
||||||
|
@ -39,6 +39,7 @@ solang-parser = { default-features = false, version = "=0.1.13" }
|
||||||
rayon = "1.5.2"
|
rayon = "1.5.2"
|
||||||
rand = { version = "0.8.5", optional = true }
|
rand = { version = "0.8.5", optional = true }
|
||||||
path-slash = "0.1.4"
|
path-slash = "0.1.4"
|
||||||
|
cfg-if = "1.0.0"
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
home = "0.5.3"
|
home = "0.5.3"
|
||||||
|
@ -80,7 +81,7 @@ required-features = ["full", "project-util"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rustls"]
|
default = ["rustls"]
|
||||||
async = ["tokio", "futures-util"]
|
async = ["tokio/process", "tokio/io-util", "tokio/fs", "tokio/time", "futures-util"]
|
||||||
full = ["async", "svm-solc"]
|
full = ["async", "svm-solc"]
|
||||||
svm-solc = ["svm/blocking", "svm-builds", "sha2"]
|
svm-solc = ["svm/blocking", "svm-builds", "sha2"]
|
||||||
# Utilities for creating and testing project workspaces
|
# Utilities for creating and testing project workspaces
|
||||||
|
|
|
@ -371,9 +371,21 @@ impl Solc {
|
||||||
/// Blocking version of `Self::install`
|
/// Blocking version of `Self::install`
|
||||||
#[cfg(all(feature = "svm-solc"))]
|
#[cfg(all(feature = "svm-solc"))]
|
||||||
pub fn blocking_install(version: &Version) -> std::result::Result<Self, svm::SolcVmError> {
|
pub fn blocking_install(version: &Version) -> std::result::Result<Self, svm::SolcVmError> {
|
||||||
|
use crate::utils::RuntimeOrHandle;
|
||||||
|
|
||||||
tracing::trace!("blocking installing solc version \"{}\"", version);
|
tracing::trace!("blocking installing solc version \"{}\"", version);
|
||||||
crate::report::solc_installation_start(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) => {
|
Ok(path) => {
|
||||||
crate::report::solc_installation_success(version);
|
crate::report::solc_installation_success(version);
|
||||||
Ok(Solc::new(path))
|
Ok(Solc::new(path))
|
||||||
|
@ -723,6 +735,7 @@ mod tests {
|
||||||
let other = solc().async_compile(&serde_json::json!(input)).await.unwrap();
|
let other = solc().async_compile(&serde_json::json!(input)).await.unwrap();
|
||||||
assert_eq!(out, other);
|
assert_eq!(out, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn async_solc_compile_works2() {
|
async fn async_solc_compile_works2() {
|
||||||
|
@ -799,6 +812,15 @@ mod tests {
|
||||||
assert_eq!(res.solc, expected);
|
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]
|
#[test]
|
||||||
fn does_not_find_not_installed_version() {
|
fn does_not_find_not_installed_version() {
|
||||||
let ver = "1.1.1";
|
let ver = "1.1.1";
|
||||||
|
|
|
@ -330,6 +330,40 @@ pub(crate) fn find_fave_or_alt_path(root: impl AsRef<Path>, fave: &str, alt: &st
|
||||||
p
|
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
|
/// Creates a new named tempdir
|
||||||
#[cfg(any(test, feature = "project-util"))]
|
#[cfg(any(test, feature = "project-util"))]
|
||||||
pub(crate) fn tempdir(name: &str) -> Result<tempfile::TempDir, SolcIoError> {
|
pub(crate) fn tempdir(name: &str) -> Result<tempfile::TempDir, SolcIoError> {
|
||||||
|
|
|
@ -17,6 +17,7 @@ use ethers_solc::{
|
||||||
ProjectPathsConfig, Solc, TestFileFilter,
|
ProjectPathsConfig, Solc, TestFileFilter,
|
||||||
};
|
};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
use semver::Version;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn init_tracing() {
|
fn init_tracing() {
|
||||||
|
@ -1329,3 +1330,53 @@ fn can_compile_model_checker_sample() {
|
||||||
assert!(!compiled.has_compiler_errors());
|
assert!(!compiled.has_compiler_errors());
|
||||||
assert!(compiled.has_compiler_warnings());
|
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"));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue