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"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"colored",
|
||||
"criterion",
|
||||
"dunce",
|
||||
|
|
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
@ -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() {
|
||||
|
@ -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";
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue