mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-05-30 18:21:01 +00:00
Use the solc version required in tests rather than one on PATH
This commit is contained in:
Generated
+1
@@ -4526,6 +4526,7 @@ dependencies = [
|
|||||||
"revive-dt-node",
|
"revive-dt-node",
|
||||||
"revive-dt-node-interaction",
|
"revive-dt-node-interaction",
|
||||||
"revive-dt-report",
|
"revive-dt-report",
|
||||||
|
"revive-dt-solc-binaries",
|
||||||
"semver 1.0.26",
|
"semver 1.0.26",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|||||||
@@ -6,6 +6,42 @@ pub enum VersionOrRequirement {
|
|||||||
Requirement(VersionReq),
|
Requirement(VersionReq),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VersionOrRequirement {
|
||||||
|
/// A helper function to convert a [`semver::Version`] into a [`semver::VersionReq`].
|
||||||
|
pub fn version_to_requirement(version: &Version) -> VersionReq {
|
||||||
|
// Ignoring "build" metadata in the version, we can turn
|
||||||
|
// it into a requirement which is an exact match for the
|
||||||
|
// given version and nothing else:
|
||||||
|
VersionReq {
|
||||||
|
comparators: vec![semver::Comparator {
|
||||||
|
op: semver::Op::Exact,
|
||||||
|
major: version.major,
|
||||||
|
minor: Some(version.minor),
|
||||||
|
patch: Some(version.patch),
|
||||||
|
pre: version.pre.clone(),
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::Serialize for VersionOrRequirement {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
VersionOrRequirement::Version(v) => serializer.serialize_str(&v.to_string()),
|
||||||
|
VersionOrRequirement::Requirement(r) => serializer.serialize_str(&r.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VersionOrRequirement {
|
||||||
|
fn default() -> Self {
|
||||||
|
VersionOrRequirement::Requirement(VersionReq::STAR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Version> for VersionOrRequirement {
|
impl From<Version> for VersionOrRequirement {
|
||||||
fn from(value: Version) -> Self {
|
fn from(value: Version) -> Self {
|
||||||
Self::Version(value)
|
Self::Version(value)
|
||||||
@@ -18,24 +54,45 @@ impl From<VersionReq> for VersionOrRequirement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<VersionOrRequirement> for VersionReq {
|
||||||
|
fn from(value: VersionOrRequirement) -> Self {
|
||||||
|
match value {
|
||||||
|
VersionOrRequirement::Version(version) => {
|
||||||
|
VersionOrRequirement::version_to_requirement(&version)
|
||||||
|
}
|
||||||
|
VersionOrRequirement::Requirement(version_req) => version_req,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<VersionOrRequirement> for Version {
|
impl TryFrom<VersionOrRequirement> for Version {
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
fn try_from(value: VersionOrRequirement) -> Result<Self, Self::Error> {
|
fn try_from(value: VersionOrRequirement) -> Result<Self, Self::Error> {
|
||||||
let VersionOrRequirement::Version(version) = value else {
|
match value {
|
||||||
anyhow::bail!("Version or requirement was not a version");
|
VersionOrRequirement::Version(version) => Ok(version),
|
||||||
};
|
VersionOrRequirement::Requirement(mut version_req) => {
|
||||||
Ok(version)
|
if version_req.comparators.len() != 1 {
|
||||||
}
|
anyhow::bail!(
|
||||||
}
|
"The version requirement in VersionOrRequirement is not a single exact version"
|
||||||
|
);
|
||||||
impl TryFrom<VersionOrRequirement> for VersionReq {
|
}
|
||||||
type Error = anyhow::Error;
|
|
||||||
|
let c = version_req.comparators.pop().unwrap();
|
||||||
fn try_from(value: VersionOrRequirement) -> Result<Self, Self::Error> {
|
let (semver::Op::Exact, Some(minor), Some(patch)) = (c.op, c.minor, c.patch) else {
|
||||||
let VersionOrRequirement::Requirement(requirement) = value else {
|
anyhow::bail!(
|
||||||
anyhow::bail!("Version or requirement was not a requirement");
|
"The version requirement in VersionOrRequirement is not an exact version"
|
||||||
};
|
);
|
||||||
Ok(requirement)
|
};
|
||||||
|
|
||||||
|
Ok(Version {
|
||||||
|
major: c.major,
|
||||||
|
minor,
|
||||||
|
patch,
|
||||||
|
pre: c.pre,
|
||||||
|
build: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-27
@@ -4,6 +4,7 @@
|
|||||||
//! - Polkadot revive Wasm compiler
|
//! - Polkadot revive Wasm compiler
|
||||||
|
|
||||||
mod constants;
|
mod constants;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@@ -13,12 +14,11 @@ use std::{
|
|||||||
|
|
||||||
use alloy::json_abi::JsonAbi;
|
use alloy::json_abi::JsonAbi;
|
||||||
use alloy_primitives::Address;
|
use alloy_primitives::Address;
|
||||||
use semver::Version;
|
use semver::VersionReq;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use revive_common::EVMVersion;
|
use revive_common::EVMVersion;
|
||||||
use revive_dt_common::cached_fs::read_to_string;
|
use revive_dt_common::cached_fs::read_to_string;
|
||||||
use revive_dt_common::types::VersionOrRequirement;
|
|
||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
|
|
||||||
// Re-export this as it's a part of the compiler interface.
|
// Re-export this as it's a part of the compiler interface.
|
||||||
@@ -40,28 +40,20 @@ pub trait SolidityCompiler {
|
|||||||
additional_options: Self::Options,
|
additional_options: Self::Options,
|
||||||
) -> impl Future<Output = anyhow::Result<CompilerOutput>>;
|
) -> impl Future<Output = anyhow::Result<CompilerOutput>>;
|
||||||
|
|
||||||
fn new(solc_executable: PathBuf) -> Self;
|
/// Instantiate a new compiler.
|
||||||
|
fn new(config: &Arguments) -> Self;
|
||||||
fn get_compiler_executable(
|
|
||||||
config: &Arguments,
|
|
||||||
version: impl Into<VersionOrRequirement>,
|
|
||||||
) -> impl Future<Output = anyhow::Result<PathBuf>>;
|
|
||||||
|
|
||||||
fn version(&self) -> impl Future<Output = anyhow::Result<Version>>;
|
|
||||||
|
|
||||||
/// Does the compiler support the provided mode and version settings?
|
/// Does the compiler support the provided mode and version settings?
|
||||||
fn supports_mode(
|
fn supports_mode(optimize_setting: ModeOptimizerSetting, pipeline: ModePipeline) -> bool;
|
||||||
compiler_version: &Version,
|
|
||||||
optimize_setting: ModeOptimizerSetting,
|
|
||||||
pipeline: ModePipeline,
|
|
||||||
) -> bool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The generic compilation input configuration.
|
/// The generic compilation input configuration.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct CompilerInput {
|
pub struct CompilerInput {
|
||||||
|
pub wasm: bool,
|
||||||
pub pipeline: Option<ModePipeline>,
|
pub pipeline: Option<ModePipeline>,
|
||||||
pub optimization: Option<ModeOptimizerSetting>,
|
pub optimization: Option<ModeOptimizerSetting>,
|
||||||
|
pub solc_version: Option<VersionReq>,
|
||||||
pub evm_version: Option<EVMVersion>,
|
pub evm_version: Option<EVMVersion>,
|
||||||
pub allow_paths: Vec<PathBuf>,
|
pub allow_paths: Vec<PathBuf>,
|
||||||
pub base_path: Option<PathBuf>,
|
pub base_path: Option<PathBuf>,
|
||||||
@@ -84,12 +76,6 @@ pub struct Compiler<T: SolidityCompiler> {
|
|||||||
additional_options: T::Options,
|
additional_options: T::Options,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Compiler<solc::Solc> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Compiler<T>
|
impl<T> Compiler<T>
|
||||||
where
|
where
|
||||||
T: SolidityCompiler,
|
T: SolidityCompiler,
|
||||||
@@ -97,8 +83,10 @@ where
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
input: CompilerInput {
|
input: CompilerInput {
|
||||||
|
wasm: Default::default(),
|
||||||
pipeline: Default::default(),
|
pipeline: Default::default(),
|
||||||
optimization: Default::default(),
|
optimization: Default::default(),
|
||||||
|
solc_version: Default::default(),
|
||||||
evm_version: Default::default(),
|
evm_version: Default::default(),
|
||||||
allow_paths: Default::default(),
|
allow_paths: Default::default(),
|
||||||
base_path: Default::default(),
|
base_path: Default::default(),
|
||||||
@@ -110,6 +98,16 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_wasm(mut self, value: bool) -> Self {
|
||||||
|
self.input.wasm = value;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_solc_version_req(mut self, value: impl Into<Option<VersionReq>>) -> Self {
|
||||||
|
self.input.solc_version = value.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_optimization(mut self, value: impl Into<Option<ModeOptimizerSetting>>) -> Self {
|
pub fn with_optimization(mut self, value: impl Into<Option<ModeOptimizerSetting>>) -> Self {
|
||||||
self.input.optimization = value.into();
|
self.input.optimization = value.into();
|
||||||
self
|
self
|
||||||
@@ -177,11 +175,8 @@ where
|
|||||||
callback(self)
|
callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn try_build(
|
pub async fn try_build(self, config: &Arguments) -> anyhow::Result<CompilerOutput> {
|
||||||
self,
|
T::new(config)
|
||||||
compiler_path: impl AsRef<Path>,
|
|
||||||
) -> anyhow::Result<CompilerOutput> {
|
|
||||||
T::new(compiler_path.as_ref().to_path_buf())
|
|
||||||
.build(self.input, self.additional_options)
|
.build(self.input, self.additional_options)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@@ -191,6 +186,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Default for Compiler<T>
|
||||||
|
where
|
||||||
|
T: SolidityCompiler,
|
||||||
|
{
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Defines how the compiler should handle revert strings.
|
/// Defines how the compiler should handle revert strings.
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize,
|
Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize,
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
//! Implements the [SolidityCompiler] trait with `resolc` for
|
//! Implements the [SolidityCompiler] trait with `resolc` for
|
||||||
//! compiling contracts to PolkaVM (PVM) bytecode.
|
//! compiling contracts to PolkaVM (PVM) bytecode.
|
||||||
|
|
||||||
use std::{
|
use std::{path::PathBuf, process::Stdio};
|
||||||
path::PathBuf,
|
|
||||||
process::{Command, Stdio},
|
|
||||||
sync::LazyLock,
|
|
||||||
};
|
|
||||||
|
|
||||||
use dashmap::DashMap;
|
|
||||||
use revive_dt_common::types::VersionOrRequirement;
|
use revive_dt_common::types::VersionOrRequirement;
|
||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use revive_solc_json_interface::{
|
use revive_solc_json_interface::{
|
||||||
@@ -17,6 +12,7 @@ use revive_solc_json_interface::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::constants::SOLC_VERSION_SUPPORTING_VIA_YUL_IR;
|
use super::constants::SOLC_VERSION_SUPPORTING_VIA_YUL_IR;
|
||||||
|
use super::utils;
|
||||||
use crate::{CompilerInput, CompilerOutput, ModeOptimizerSetting, ModePipeline, SolidityCompiler};
|
use crate::{CompilerInput, CompilerOutput, ModeOptimizerSetting, ModePipeline, SolidityCompiler};
|
||||||
|
|
||||||
use alloy::json_abi::JsonAbi;
|
use alloy::json_abi::JsonAbi;
|
||||||
@@ -31,6 +27,11 @@ use tokio::{io::AsyncWriteExt, process::Command as AsyncCommand};
|
|||||||
/// A wrapper around the `resolc` binary, emitting PVM-compatible bytecode.
|
/// A wrapper around the `resolc` binary, emitting PVM-compatible bytecode.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Resolc {
|
pub struct Resolc {
|
||||||
|
// Where to cache artifacts.
|
||||||
|
cache_directory: PathBuf,
|
||||||
|
// We'll use this version when no explicit version
|
||||||
|
// requirement is given in the test mode.
|
||||||
|
solc_version: Version,
|
||||||
/// Path to the `resolc` executable
|
/// Path to the `resolc` executable
|
||||||
resolc_path: PathBuf,
|
resolc_path: PathBuf,
|
||||||
}
|
}
|
||||||
@@ -42,8 +43,10 @@ impl SolidityCompiler for Resolc {
|
|||||||
async fn build(
|
async fn build(
|
||||||
&self,
|
&self,
|
||||||
CompilerInput {
|
CompilerInput {
|
||||||
|
wasm,
|
||||||
pipeline,
|
pipeline,
|
||||||
optimization,
|
optimization,
|
||||||
|
solc_version,
|
||||||
evm_version,
|
evm_version,
|
||||||
allow_paths,
|
allow_paths,
|
||||||
base_path,
|
base_path,
|
||||||
@@ -61,6 +64,19 @@ impl SolidityCompiler for Resolc {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let solc_version_req = solc_version
|
||||||
|
.unwrap_or_else(|| VersionOrRequirement::version_to_requirement(&self.solc_version));
|
||||||
|
let solc_path =
|
||||||
|
revive_dt_solc_binaries::download_solc(&self.cache_directory, solc_version_req, wasm)
|
||||||
|
.await?;
|
||||||
|
let solc_version = utils::solc_version(&solc_path).await?;
|
||||||
|
|
||||||
|
if solc_version < SOLC_VERSION_SUPPORTING_VIA_YUL_IR {
|
||||||
|
anyhow::bail!(
|
||||||
|
"We are trying to run the test with solc version {solc_version}, but require {SOLC_VERSION_SUPPORTING_VIA_YUL_IR} or greater"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let input = SolcStandardJsonInput {
|
let input = SolcStandardJsonInput {
|
||||||
language: SolcStandardJsonInputLanguage::Solidity,
|
language: SolcStandardJsonInputLanguage::Solidity,
|
||||||
sources: sources
|
sources: sources
|
||||||
@@ -106,6 +122,8 @@ impl SolidityCompiler for Resolc {
|
|||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
|
.arg("--solc")
|
||||||
|
.arg(&solc_path)
|
||||||
.arg("--standard-json");
|
.arg("--standard-json");
|
||||||
|
|
||||||
if let Some(ref base_path) = base_path {
|
if let Some(ref base_path) = base_path {
|
||||||
@@ -206,86 +224,17 @@ impl SolidityCompiler for Resolc {
|
|||||||
Ok(compiler_output)
|
Ok(compiler_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(resolc_path: PathBuf) -> Self {
|
fn new(config: &Arguments) -> Self {
|
||||||
Resolc { resolc_path }
|
Resolc {
|
||||||
}
|
cache_directory: config.directory().to_path_buf(),
|
||||||
|
solc_version: config.solc.clone(),
|
||||||
async fn get_compiler_executable(
|
resolc_path: config.resolc.clone(),
|
||||||
config: &Arguments,
|
|
||||||
_version: impl Into<VersionOrRequirement>,
|
|
||||||
) -> anyhow::Result<PathBuf> {
|
|
||||||
if !config.resolc.as_os_str().is_empty() {
|
|
||||||
return Ok(config.resolc.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(PathBuf::from("resolc"))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn version(&self) -> anyhow::Result<semver::Version> {
|
|
||||||
/// This is a cache of the path of the compiler to the version number of the compiler. We
|
|
||||||
/// choose to cache the version in this way rather than through a field on the struct since
|
|
||||||
/// compiler objects are being created all the time from the path and the compiler object is
|
|
||||||
/// not reused over time.
|
|
||||||
static VERSION_CACHE: LazyLock<DashMap<PathBuf, Version>> = LazyLock::new(Default::default);
|
|
||||||
|
|
||||||
match VERSION_CACHE.entry(self.resolc_path.clone()) {
|
|
||||||
dashmap::Entry::Occupied(occupied_entry) => Ok(occupied_entry.get().clone()),
|
|
||||||
dashmap::Entry::Vacant(vacant_entry) => {
|
|
||||||
let output = Command::new(self.resolc_path.as_path())
|
|
||||||
.arg("--version")
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.spawn()?
|
|
||||||
.wait_with_output()?
|
|
||||||
.stdout;
|
|
||||||
|
|
||||||
let output = String::from_utf8_lossy(&output);
|
|
||||||
let version_string = output
|
|
||||||
.split("version ")
|
|
||||||
.nth(1)
|
|
||||||
.context("Version parsing failed")?
|
|
||||||
.split("+")
|
|
||||||
.next()
|
|
||||||
.context("Version parsing failed")?;
|
|
||||||
|
|
||||||
let version = Version::parse(version_string)?;
|
|
||||||
|
|
||||||
vacant_entry.insert(version.clone());
|
|
||||||
|
|
||||||
Ok(version)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_mode(
|
fn supports_mode(_optimize_setting: ModeOptimizerSetting, pipeline: ModePipeline) -> bool {
|
||||||
compiler_version: &Version,
|
// We only support the Y (IE compile via Yul IR) mode here. We must always compile
|
||||||
_optimize_setting: ModeOptimizerSetting,
|
// via Yul IR as resolc needs this to translate to LLVM IR and then RISCV.
|
||||||
pipeline: ModePipeline,
|
|
||||||
) -> bool {
|
|
||||||
// We only support the Y (IE compile via Yul IR) mode here, which also means that we can
|
|
||||||
// only use solc version 0.8.13 and above. We must always compile via Yul IR as resolc
|
|
||||||
// needs this to translate to LLVM IR and then RISCV.
|
|
||||||
pipeline == ModePipeline::ViaYulIR
|
pipeline == ModePipeline::ViaYulIR
|
||||||
&& compiler_version >= &SOLC_VERSION_SUPPORTING_VIA_YUL_IR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn compiler_version_can_be_obtained() {
|
|
||||||
// Arrange
|
|
||||||
let args = Arguments::default();
|
|
||||||
let path = Resolc::get_compiler_executable(&args, Version::new(0, 7, 6))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let compiler = Resolc::new(path);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
let version = compiler.version().await;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
let _ = version.expect("Failed to get version");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-110
@@ -1,18 +1,13 @@
|
|||||||
//! Implements the [SolidityCompiler] trait with solc for
|
//! Implements the [SolidityCompiler] trait with solc for
|
||||||
//! compiling contracts to EVM bytecode.
|
//! compiling contracts to EVM bytecode.
|
||||||
|
|
||||||
use std::{
|
use std::{path::PathBuf, process::Stdio};
|
||||||
path::PathBuf,
|
|
||||||
process::{Command, Stdio},
|
|
||||||
sync::LazyLock,
|
|
||||||
};
|
|
||||||
|
|
||||||
use dashmap::DashMap;
|
|
||||||
use revive_dt_common::types::VersionOrRequirement;
|
use revive_dt_common::types::VersionOrRequirement;
|
||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use revive_dt_solc_binaries::download_solc;
|
|
||||||
|
|
||||||
use super::constants::SOLC_VERSION_SUPPORTING_VIA_YUL_IR;
|
use super::constants::SOLC_VERSION_SUPPORTING_VIA_YUL_IR;
|
||||||
|
use super::utils;
|
||||||
use crate::{CompilerInput, CompilerOutput, ModeOptimizerSetting, ModePipeline, SolidityCompiler};
|
use crate::{CompilerInput, CompilerOutput, ModeOptimizerSetting, ModePipeline, SolidityCompiler};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
@@ -28,7 +23,11 @@ use tokio::{io::AsyncWriteExt, process::Command as AsyncCommand};
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Solc {
|
pub struct Solc {
|
||||||
solc_path: PathBuf,
|
// Where to cache artifacts.
|
||||||
|
cache_directory: PathBuf,
|
||||||
|
// We'll use this version when no explicit version requirement
|
||||||
|
// is given in the test mode.
|
||||||
|
solc_version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SolidityCompiler for Solc {
|
impl SolidityCompiler for Solc {
|
||||||
@@ -38,8 +37,10 @@ impl SolidityCompiler for Solc {
|
|||||||
async fn build(
|
async fn build(
|
||||||
&self,
|
&self,
|
||||||
CompilerInput {
|
CompilerInput {
|
||||||
|
wasm,
|
||||||
pipeline,
|
pipeline,
|
||||||
optimization,
|
optimization,
|
||||||
|
solc_version,
|
||||||
evm_version,
|
evm_version,
|
||||||
allow_paths,
|
allow_paths,
|
||||||
base_path,
|
base_path,
|
||||||
@@ -49,7 +50,13 @@ impl SolidityCompiler for Solc {
|
|||||||
}: CompilerInput,
|
}: CompilerInput,
|
||||||
_: Self::Options,
|
_: Self::Options,
|
||||||
) -> anyhow::Result<CompilerOutput> {
|
) -> anyhow::Result<CompilerOutput> {
|
||||||
let compiler_supports_via_ir = self.version().await? >= SOLC_VERSION_SUPPORTING_VIA_YUL_IR;
|
let solc_version = solc_version
|
||||||
|
.unwrap_or_else(|| VersionOrRequirement::version_to_requirement(&self.solc_version));
|
||||||
|
let solc_path =
|
||||||
|
revive_dt_solc_binaries::download_solc(&self.cache_directory, solc_version, wasm)
|
||||||
|
.await?;
|
||||||
|
let compiler_supports_via_ir =
|
||||||
|
utils::solc_version(&solc_path).await? >= SOLC_VERSION_SUPPORTING_VIA_YUL_IR;
|
||||||
|
|
||||||
// Be careful to entirely omit the viaIR field if the compiler does not support it,
|
// Be careful to entirely omit the viaIR field if the compiler does not support it,
|
||||||
// as it will error if you provide fields it does not know about. Because
|
// as it will error if you provide fields it does not know about. Because
|
||||||
@@ -115,7 +122,7 @@ impl SolidityCompiler for Solc {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut command = AsyncCommand::new(&self.solc_path);
|
let mut command = AsyncCommand::new(&solc_path);
|
||||||
command
|
command
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
@@ -199,110 +206,16 @@ impl SolidityCompiler for Solc {
|
|||||||
Ok(compiler_output)
|
Ok(compiler_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(solc_path: PathBuf) -> Self {
|
fn new(config: &Arguments) -> Self {
|
||||||
Self { solc_path }
|
Self {
|
||||||
}
|
cache_directory: config.directory().to_path_buf(),
|
||||||
|
solc_version: config.solc.clone(),
|
||||||
async fn get_compiler_executable(
|
|
||||||
config: &Arguments,
|
|
||||||
version: impl Into<VersionOrRequirement>,
|
|
||||||
) -> anyhow::Result<PathBuf> {
|
|
||||||
let path = download_solc(config.directory(), version, config.wasm).await?;
|
|
||||||
Ok(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn version(&self) -> anyhow::Result<semver::Version> {
|
|
||||||
/// This is a cache of the path of the compiler to the version number of the compiler. We
|
|
||||||
/// choose to cache the version in this way rather than through a field on the struct since
|
|
||||||
/// compiler objects are being created all the time from the path and the compiler object is
|
|
||||||
/// not reused over time.
|
|
||||||
static VERSION_CACHE: LazyLock<DashMap<PathBuf, Version>> = LazyLock::new(Default::default);
|
|
||||||
|
|
||||||
match VERSION_CACHE.entry(self.solc_path.clone()) {
|
|
||||||
dashmap::Entry::Occupied(occupied_entry) => Ok(occupied_entry.get().clone()),
|
|
||||||
dashmap::Entry::Vacant(vacant_entry) => {
|
|
||||||
// The following is the parsing code for the version from the solc version strings
|
|
||||||
// which look like the following:
|
|
||||||
// ```
|
|
||||||
// solc, the solidity compiler commandline interface
|
|
||||||
// Version: 0.8.30+commit.73712a01.Darwin.appleclang
|
|
||||||
// ```
|
|
||||||
let child = Command::new(self.solc_path.as_path())
|
|
||||||
.arg("--version")
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.spawn()?;
|
|
||||||
let output = child.wait_with_output()?;
|
|
||||||
let output = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let version_line = output
|
|
||||||
.split("Version: ")
|
|
||||||
.nth(1)
|
|
||||||
.context("Version parsing failed")?;
|
|
||||||
let version_string = version_line
|
|
||||||
.split("+")
|
|
||||||
.next()
|
|
||||||
.context("Version parsing failed")?;
|
|
||||||
|
|
||||||
let version = Version::parse(version_string)?;
|
|
||||||
|
|
||||||
vacant_entry.insert(version.clone());
|
|
||||||
|
|
||||||
Ok(version)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_mode(
|
fn supports_mode(_optimize_setting: ModeOptimizerSetting, pipeline: ModePipeline) -> bool {
|
||||||
compiler_version: &Version,
|
|
||||||
_optimize_setting: ModeOptimizerSetting,
|
|
||||||
pipeline: ModePipeline,
|
|
||||||
) -> bool {
|
|
||||||
// solc 0.8.13 and above supports --via-ir, and less than that does not. Thus, we support mode E
|
// solc 0.8.13 and above supports --via-ir, and less than that does not. Thus, we support mode E
|
||||||
// (ie no Yul IR) in either case, but only support Y (via Yul IR) if the compiler is new enough.
|
// (ie no Yul IR) in either case, but only support Y (via Yul IR) if the compiler is new enough.
|
||||||
pipeline == ModePipeline::ViaEVMAssembly
|
pipeline == ModePipeline::ViaEVMAssembly || pipeline == ModePipeline::ViaYulIR
|
||||||
|| (pipeline == ModePipeline::ViaYulIR
|
|
||||||
&& compiler_version >= &SOLC_VERSION_SUPPORTING_VIA_YUL_IR)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn compiler_version_can_be_obtained() {
|
|
||||||
// Arrange
|
|
||||||
let args = Arguments::default();
|
|
||||||
let path = Solc::get_compiler_executable(&args, Version::new(0, 7, 6))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let compiler = Solc::new(path);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
let version = compiler.version().await;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
assert_eq!(
|
|
||||||
version.expect("Failed to get version"),
|
|
||||||
Version::new(0, 7, 6)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn compiler_version_can_be_obtained1() {
|
|
||||||
// Arrange
|
|
||||||
let args = Arguments::default();
|
|
||||||
let path = Solc::get_compiler_executable(&args, Version::new(0, 4, 21))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
let compiler = Solc::new(path);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
let version = compiler.version().await;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
assert_eq!(
|
|
||||||
version.expect("Failed to get version"),
|
|
||||||
Version::new(0, 4, 21)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
process::{Command, Stdio},
|
||||||
|
sync::LazyLock,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use semver::Version;
|
||||||
|
|
||||||
|
/// Fetch the solc version given a path to the executable
|
||||||
|
pub async fn solc_version(solc_path: &Path) -> anyhow::Result<semver::Version> {
|
||||||
|
/// This is a cache of the path of the compiler to the version number of the compiler. We
|
||||||
|
/// choose to cache the version in this way rather than through a field on the struct since
|
||||||
|
/// compiler objects are being created all the time from the path and the compiler object is
|
||||||
|
/// not reused over time.
|
||||||
|
static VERSION_CACHE: LazyLock<DashMap<PathBuf, Version>> = LazyLock::new(Default::default);
|
||||||
|
|
||||||
|
match VERSION_CACHE.entry(solc_path.to_path_buf()) {
|
||||||
|
dashmap::Entry::Occupied(occupied_entry) => Ok(occupied_entry.get().clone()),
|
||||||
|
dashmap::Entry::Vacant(vacant_entry) => {
|
||||||
|
// The following is the parsing code for the version from the solc version strings
|
||||||
|
// which look like the following:
|
||||||
|
// ```
|
||||||
|
// solc, the solidity compiler commandline interface
|
||||||
|
// Version: 0.8.30+commit.73712a01.Darwin.appleclang
|
||||||
|
// ```
|
||||||
|
let child = Command::new(solc_path)
|
||||||
|
.arg("--version")
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()?;
|
||||||
|
let output = child.wait_with_output()?;
|
||||||
|
let output = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let version_line = output
|
||||||
|
.split("Version: ")
|
||||||
|
.nth(1)
|
||||||
|
.context("Version parsing failed")?;
|
||||||
|
let version_string = version_line
|
||||||
|
.split("+")
|
||||||
|
.next()
|
||||||
|
.context("Version parsing failed")?;
|
||||||
|
|
||||||
|
let version = Version::parse(version_string)?;
|
||||||
|
|
||||||
|
vacant_entry.insert(version.clone());
|
||||||
|
|
||||||
|
Ok(version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,12 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use revive_dt_compiler::{Compiler, SolidityCompiler, revive_resolc::Resolc, solc::Solc};
|
use revive_dt_compiler::{Compiler, revive_resolc::Resolc, solc::Solc};
|
||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use semver::Version;
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn contracts_can_be_compiled_with_solc() {
|
async fn contracts_can_be_compiled_with_solc() {
|
||||||
// Arrange
|
// Arrange
|
||||||
let args = Arguments::default();
|
let args = Arguments::default();
|
||||||
let compiler_path = Solc::get_compiler_executable(&args, Version::new(0, 8, 30))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let output = Compiler::<Solc>::new()
|
let output = Compiler::<Solc>::new()
|
||||||
@@ -18,7 +14,7 @@ async fn contracts_can_be_compiled_with_solc() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.with_source("./tests/assets/array_one_element/main.sol")
|
.with_source("./tests/assets/array_one_element/main.sol")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.try_build(compiler_path)
|
.try_build(&args)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
@@ -49,9 +45,6 @@ async fn contracts_can_be_compiled_with_solc() {
|
|||||||
async fn contracts_can_be_compiled_with_resolc() {
|
async fn contracts_can_be_compiled_with_resolc() {
|
||||||
// Arrange
|
// Arrange
|
||||||
let args = Arguments::default();
|
let args = Arguments::default();
|
||||||
let compiler_path = Resolc::get_compiler_executable(&args, Version::new(0, 8, 30))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let output = Compiler::<Resolc>::new()
|
let output = Compiler::<Resolc>::new()
|
||||||
@@ -59,7 +52,7 @@ async fn contracts_can_be_compiled_with_resolc() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.with_source("./tests/assets/array_one_element/main.sol")
|
.with_source("./tests/assets/array_one_element/main.sol")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.try_build(compiler_path)
|
.try_build(&args)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ revive-dt-format = { workspace = true }
|
|||||||
revive-dt-node = { workspace = true }
|
revive-dt-node = { workspace = true }
|
||||||
revive-dt-node-interaction = { workspace = true }
|
revive-dt-node-interaction = { workspace = true }
|
||||||
revive-dt-report = { workspace = true }
|
revive-dt-report = { workspace = true }
|
||||||
|
revive-dt-solc-binaries = { workspace = true }
|
||||||
|
|
||||||
alloy = { workspace = true }
|
alloy = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ use std::{
|
|||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use revive_dt_common::iterators::FilesWithExtensionIterator;
|
use revive_dt_common::iterators::FilesWithExtensionIterator;
|
||||||
use revive_dt_compiler::{Compiler, CompilerOutput, Mode, SolidityCompiler};
|
use revive_dt_compiler::{Compiler, CompilerOutput, Mode};
|
||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use revive_dt_format::metadata::{ContractIdent, ContractInstance, Metadata};
|
use revive_dt_format::metadata::{ContractIdent, ContractInstance, Metadata};
|
||||||
|
use revive_dt_solc_binaries::solc_version;
|
||||||
|
|
||||||
use alloy::{hex::ToHexExt, json_abi::JsonAbi, primitives::Address};
|
use alloy::{hex::ToHexExt, json_abi::JsonAbi, primitives::Address};
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
@@ -57,14 +58,7 @@ impl CachedCompiler {
|
|||||||
Lazy::new(Default::default);
|
Lazy::new(Default::default);
|
||||||
|
|
||||||
let compiler_version_or_requirement = mode.compiler_version_to_use(config.solc.clone());
|
let compiler_version_or_requirement = mode.compiler_version_to_use(config.solc.clone());
|
||||||
let compiler_path = <P::Compiler as SolidityCompiler>::get_compiler_executable(
|
let compiler_version = solc_version(compiler_version_or_requirement, config.wasm).await?;
|
||||||
config,
|
|
||||||
compiler_version_or_requirement,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
let compiler_version = <P::Compiler as SolidityCompiler>::new(compiler_path.clone())
|
|
||||||
.version()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let cache_key = CacheKey {
|
let cache_key = CacheKey {
|
||||||
platform_key: P::config_id().to_string(),
|
platform_key: P::config_id().to_string(),
|
||||||
@@ -77,8 +71,8 @@ impl CachedCompiler {
|
|||||||
async move {
|
async move {
|
||||||
compile_contracts::<P>(
|
compile_contracts::<P>(
|
||||||
metadata.directory()?,
|
metadata.directory()?,
|
||||||
compiler_path,
|
|
||||||
metadata.files_to_compile()?,
|
metadata.files_to_compile()?,
|
||||||
|
config,
|
||||||
mode,
|
mode,
|
||||||
deployed_libraries,
|
deployed_libraries,
|
||||||
)
|
)
|
||||||
@@ -138,8 +132,8 @@ impl CachedCompiler {
|
|||||||
|
|
||||||
async fn compile_contracts<P: Platform>(
|
async fn compile_contracts<P: Platform>(
|
||||||
metadata_directory: impl AsRef<Path>,
|
metadata_directory: impl AsRef<Path>,
|
||||||
compiler_path: impl AsRef<Path>,
|
|
||||||
mut files_to_compile: impl Iterator<Item = PathBuf>,
|
mut files_to_compile: impl Iterator<Item = PathBuf>,
|
||||||
|
config: &Arguments,
|
||||||
mode: &Mode,
|
mode: &Mode,
|
||||||
deployed_libraries: Option<&HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>>,
|
deployed_libraries: Option<&HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>>,
|
||||||
) -> Result<CompilerOutput> {
|
) -> Result<CompilerOutput> {
|
||||||
@@ -149,6 +143,7 @@ async fn compile_contracts<P: Platform>(
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
Compiler::<P::Compiler>::new()
|
Compiler::<P::Compiler>::new()
|
||||||
|
.with_solc_version_req(mode.version.clone())
|
||||||
.with_allow_path(metadata_directory)
|
.with_allow_path(metadata_directory)
|
||||||
// Handling the modes
|
// Handling the modes
|
||||||
.with_optimization(mode.optimize_setting)
|
.with_optimization(mode.optimize_setting)
|
||||||
@@ -172,7 +167,7 @@ async fn compile_contracts<P: Platform>(
|
|||||||
compiler.with_library(path, ident.as_str(), *address)
|
compiler.with_library(path, ident.as_str(), *address)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.try_build(compiler_path)
|
.try_build(config)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-38
@@ -14,8 +14,8 @@ use alloy::{
|
|||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use futures::StreamExt;
|
||||||
use futures::stream;
|
use futures::stream;
|
||||||
use futures::{Stream, StreamExt};
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use revive_dt_node_interaction::EthereumNode;
|
use revive_dt_node_interaction::EthereumNode;
|
||||||
use temp_dir::TempDir;
|
use temp_dir::TempDir;
|
||||||
@@ -163,7 +163,7 @@ where
|
|||||||
{
|
{
|
||||||
let (report_tx, report_rx) = mpsc::unbounded_channel::<(Test<'_>, CaseResult)>();
|
let (report_tx, report_rx) = mpsc::unbounded_channel::<(Test<'_>, CaseResult)>();
|
||||||
|
|
||||||
let tests = prepare_tests::<L, F>(args, metadata_files);
|
let tests = prepare_tests::<L, F>(metadata_files);
|
||||||
let driver_task = start_driver_task::<L, F>(args, tests, span, report_tx).await?;
|
let driver_task = start_driver_task::<L, F>(args, tests, span, report_tx).await?;
|
||||||
let status_reporter_task = start_reporter_task(report_rx);
|
let status_reporter_task = start_reporter_task(report_rx);
|
||||||
|
|
||||||
@@ -172,17 +172,14 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_tests<'a, L, F>(
|
fn prepare_tests<'a, L, F>(metadata_files: &'a [MetadataFile]) -> impl Iterator<Item = Test<'a>>
|
||||||
args: &Arguments,
|
|
||||||
metadata_files: &'a [MetadataFile],
|
|
||||||
) -> impl Stream<Item = Test<'a>>
|
|
||||||
where
|
where
|
||||||
L: Platform,
|
L: Platform,
|
||||||
F: Platform,
|
F: Platform,
|
||||||
L::Blockchain: revive_dt_node::Node + Send + Sync + 'static,
|
L::Blockchain: revive_dt_node::Node + Send + Sync + 'static,
|
||||||
F::Blockchain: revive_dt_node::Node + Send + Sync + 'static,
|
F::Blockchain: revive_dt_node::Node + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let filtered_tests = metadata_files
|
metadata_files
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|metadata_file| {
|
.flat_map(|metadata_file| {
|
||||||
metadata_file
|
metadata_file
|
||||||
@@ -289,19 +286,12 @@ where
|
|||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.filter_map(move |test| {
|
||||||
stream::iter(filtered_tests)
|
let leader_support =
|
||||||
// Filter based on the compiler compatibility
|
L::Compiler::supports_mode(test.mode.optimize_setting, test.mode.pipeline);
|
||||||
.filter_map(move |test| async move {
|
let follower_support =
|
||||||
let leader_support = does_compiler_support_mode::<L>(args, &test.mode)
|
F::Compiler::supports_mode(test.mode.optimize_setting, test.mode.pipeline);
|
||||||
.await
|
|
||||||
.ok()
|
|
||||||
.unwrap_or(false);
|
|
||||||
let follower_support = does_compiler_support_mode::<F>(args, &test.mode)
|
|
||||||
.await
|
|
||||||
.ok()
|
|
||||||
.unwrap_or(false);
|
|
||||||
let is_allowed = leader_support && follower_support;
|
let is_allowed = leader_support && follower_support;
|
||||||
|
|
||||||
if !is_allowed {
|
if !is_allowed {
|
||||||
@@ -317,25 +307,9 @@ where
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn does_compiler_support_mode<P: Platform>(
|
|
||||||
args: &Arguments,
|
|
||||||
mode: &Mode,
|
|
||||||
) -> anyhow::Result<bool> {
|
|
||||||
let compiler_version_or_requirement = mode.compiler_version_to_use(args.solc.clone());
|
|
||||||
let compiler_path =
|
|
||||||
P::Compiler::get_compiler_executable(args, compiler_version_or_requirement).await?;
|
|
||||||
let compiler_version = P::Compiler::new(compiler_path.clone()).version().await?;
|
|
||||||
|
|
||||||
Ok(P::Compiler::supports_mode(
|
|
||||||
&compiler_version,
|
|
||||||
mode.optimize_setting,
|
|
||||||
mode.pipeline,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn start_driver_task<'a, L, F>(
|
async fn start_driver_task<'a, L, F>(
|
||||||
args: &Arguments,
|
args: &Arguments,
|
||||||
tests: impl Stream<Item = Test<'a>>,
|
tests: impl Iterator<Item = Test<'a>>,
|
||||||
span: Span,
|
span: Span,
|
||||||
report_tx: mpsc::UnboundedSender<(Test<'a>, CaseResult)>,
|
report_tx: mpsc::UnboundedSender<(Test<'a>, CaseResult)>,
|
||||||
) -> anyhow::Result<impl Future<Output = ()>>
|
) -> anyhow::Result<impl Future<Output = ()>>
|
||||||
@@ -356,7 +330,7 @@ where
|
|||||||
.await?,
|
.await?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(tests.for_each_concurrent(
|
Ok(stream::iter(tests).for_each_concurrent(
|
||||||
// We want to limit the concurrent tasks here because:
|
// We want to limit the concurrent tasks here because:
|
||||||
//
|
//
|
||||||
// 1. We don't want to overwhelm the nodes with too many requests, leading to responses timing out.
|
// 1. We don't want to overwhelm the nodes with too many requests, leading to responses timing out.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use cache::get_or_download;
|
use cache::get_or_download;
|
||||||
use download::SolcDownloader;
|
use download::SolcDownloader;
|
||||||
|
use semver::Version;
|
||||||
|
|
||||||
use revive_dt_common::types::VersionOrRequirement;
|
use revive_dt_common::types::VersionOrRequirement;
|
||||||
|
|
||||||
@@ -14,6 +15,25 @@ pub mod cache;
|
|||||||
pub mod download;
|
pub mod download;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
|
|
||||||
|
/// Return a [`SolcDownloader`] which can be used to download a `solc`
|
||||||
|
/// binary or return the resolved version it will download.
|
||||||
|
async fn downloader(
|
||||||
|
version: impl Into<VersionOrRequirement>,
|
||||||
|
wasm: bool,
|
||||||
|
) -> anyhow::Result<SolcDownloader> {
|
||||||
|
if wasm {
|
||||||
|
SolcDownloader::wasm(version).await
|
||||||
|
} else if cfg!(target_os = "linux") {
|
||||||
|
SolcDownloader::linux(version).await
|
||||||
|
} else if cfg!(target_os = "macos") {
|
||||||
|
SolcDownloader::macosx(version).await
|
||||||
|
} else if cfg!(target_os = "windows") {
|
||||||
|
SolcDownloader::windows(version).await
|
||||||
|
} else {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Downloads the solc binary for Wasm is `wasm` is set, otherwise for
|
/// Downloads the solc binary for Wasm is `wasm` is set, otherwise for
|
||||||
/// the target platform.
|
/// the target platform.
|
||||||
///
|
///
|
||||||
@@ -24,17 +44,16 @@ pub async fn download_solc(
|
|||||||
version: impl Into<VersionOrRequirement>,
|
version: impl Into<VersionOrRequirement>,
|
||||||
wasm: bool,
|
wasm: bool,
|
||||||
) -> anyhow::Result<PathBuf> {
|
) -> anyhow::Result<PathBuf> {
|
||||||
let downloader = if wasm {
|
let downloader = downloader(version, wasm).await?;
|
||||||
SolcDownloader::wasm(version).await
|
|
||||||
} else if cfg!(target_os = "linux") {
|
|
||||||
SolcDownloader::linux(version).await
|
|
||||||
} else if cfg!(target_os = "macos") {
|
|
||||||
SolcDownloader::macosx(version).await
|
|
||||||
} else if cfg!(target_os = "windows") {
|
|
||||||
SolcDownloader::windows(version).await
|
|
||||||
} else {
|
|
||||||
unimplemented!()
|
|
||||||
}?;
|
|
||||||
|
|
||||||
get_or_download(cache_directory, &downloader).await
|
get_or_download(cache_directory, &downloader).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the version of solc that will be downloaded via [`download_solc`]
|
||||||
|
/// given the version requirements and wasm flag.
|
||||||
|
pub async fn solc_version(
|
||||||
|
version: impl Into<VersionOrRequirement>,
|
||||||
|
wasm: bool,
|
||||||
|
) -> anyhow::Result<Version> {
|
||||||
|
let downloader = downloader(version, wasm).await?;
|
||||||
|
Ok(downloader.version.clone())
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user