mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-04-22 21:57:58 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b6e0701ec9 | |||
| f99b3dbc3c | |||
| 0e79594bb2 | |||
| 5c75228496 | |||
| 8229675ba8 | |||
| dd94b12b34 | |||
| 4af9f6695d | |||
| 4d8adb553c | |||
| bdd2eab194 | |||
| eb754bc9e8 | |||
| 0e5e57e703 | |||
| 491a9a32b2 |
Generated
+3
-10
@@ -4492,6 +4492,7 @@ dependencies = [
|
|||||||
"semver 1.0.26",
|
"semver 1.0.26",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -4504,7 +4505,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"semver 1.0.26",
|
"semver 1.0.26",
|
||||||
"serde",
|
"serde",
|
||||||
"temp-dir",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4529,7 +4530,6 @@ dependencies = [
|
|||||||
"semver 1.0.26",
|
"semver 1.0.26",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"temp-dir",
|
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -4571,7 +4571,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"sp-core",
|
"sp-core",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
"temp-dir",
|
"tempfile",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -4596,7 +4596,6 @@ dependencies = [
|
|||||||
"revive-dt-compiler",
|
"revive-dt-compiler",
|
||||||
"revive-dt-config",
|
"revive-dt-config",
|
||||||
"revive-dt-format",
|
"revive-dt-format",
|
||||||
"semver 1.0.26",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
@@ -5818,12 +5817,6 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "temp-dir"
|
|
||||||
version = "0.1.16"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "83176759e9416cf81ee66cb6508dbfe9c96f20b8b56265a39917551c23c70964"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.20.0"
|
version = "3.20.0"
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ serde_with = { version = "3.14.0" }
|
|||||||
sha2 = { version = "0.10.9" }
|
sha2 = { version = "0.10.9" }
|
||||||
sp-core = "36.1.0"
|
sp-core = "36.1.0"
|
||||||
sp-runtime = "41.1.0"
|
sp-runtime = "41.1.0"
|
||||||
temp-dir = { version = "0.1.16" }
|
|
||||||
tempfile = "3.3"
|
tempfile = "3.3"
|
||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
tokio = { version = "1.47.0", default-features = false, features = [
|
tokio = { version = "1.47.0", default-features = false, features = [
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,5 +26,8 @@ serde_json = { workspace = true }
|
|||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile = { workspace = true }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
use semver::Version;
|
|
||||||
|
|
||||||
/// This is the first version of solc that supports the `--via-ir` flag / "viaIR" input JSON.
|
|
||||||
pub const SOLC_VERSION_SUPPORTING_VIA_YUL_IR: Version = Version::new(0, 8, 13);
|
|
||||||
+17
-22
@@ -3,7 +3,7 @@
|
|||||||
//! - Polkadot revive resolc compiler
|
//! - Polkadot revive resolc compiler
|
||||||
//! - Polkadot revive Wasm compiler
|
//! - Polkadot revive Wasm compiler
|
||||||
|
|
||||||
mod constants;
|
mod utils;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@@ -14,17 +14,18 @@ use std::{
|
|||||||
use alloy::json_abi::JsonAbi;
|
use alloy::json_abi::JsonAbi;
|
||||||
use alloy_primitives::Address;
|
use alloy_primitives::Address;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use semver::Version;
|
|
||||||
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.
|
||||||
pub use revive_dt_common::types::{Mode, ModeOptimizerSetting, ModePipeline};
|
pub use revive_dt_common::types::{Mode, ModeOptimizerSetting, ModePipeline};
|
||||||
|
|
||||||
|
// Expose functionality for instantiating a SolcCompiler.
|
||||||
|
pub use utils::{SolcCompiler, solc_compiler};
|
||||||
|
|
||||||
pub mod revive_js;
|
pub mod revive_js;
|
||||||
pub mod revive_resolc;
|
pub mod revive_resolc;
|
||||||
pub mod solc;
|
pub mod solc;
|
||||||
@@ -41,28 +42,19 @@ 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 pipeline: Option<ModePipeline>,
|
pub pipeline: Option<ModePipeline>,
|
||||||
pub optimization: Option<ModeOptimizerSetting>,
|
pub optimization: Option<ModeOptimizerSetting>,
|
||||||
|
pub solc: Option<SolcCompiler>,
|
||||||
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>,
|
||||||
@@ -100,6 +92,7 @@ where
|
|||||||
input: CompilerInput {
|
input: CompilerInput {
|
||||||
pipeline: Default::default(),
|
pipeline: Default::default(),
|
||||||
optimization: Default::default(),
|
optimization: Default::default(),
|
||||||
|
solc: 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(),
|
||||||
@@ -111,6 +104,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_solc(mut self, value: impl Into<Option<SolcCompiler>>) -> Self {
|
||||||
|
self.input.solc = 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
|
||||||
@@ -179,11 +177,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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +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_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use revive_solc_json_interface::{
|
use revive_solc_json_interface::{
|
||||||
SolcStandardJsonInput, SolcStandardJsonInputLanguage, SolcStandardJsonInputSettings,
|
SolcStandardJsonInput, SolcStandardJsonInputLanguage, SolcStandardJsonInputSettings,
|
||||||
@@ -23,10 +17,6 @@ use anyhow::Context;
|
|||||||
use semver::Version;
|
use semver::Version;
|
||||||
use tokio::{io::AsyncWriteExt, process::Command as AsyncCommand};
|
use tokio::{io::AsyncWriteExt, process::Command as AsyncCommand};
|
||||||
|
|
||||||
// TODO: I believe that we need to also pass the solc compiler to resolc so that resolc uses the
|
|
||||||
// specified solc compiler. I believe that currently we completely ignore the specified solc binary
|
|
||||||
// when invoking resolc which doesn't seem right if we're using solc as a compiler frontend.
|
|
||||||
|
|
||||||
/// 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 {
|
||||||
@@ -43,6 +33,7 @@ impl SolidityCompiler for Resolc {
|
|||||||
CompilerInput {
|
CompilerInput {
|
||||||
pipeline,
|
pipeline,
|
||||||
optimization,
|
optimization,
|
||||||
|
solc,
|
||||||
evm_version,
|
evm_version,
|
||||||
allow_paths,
|
allow_paths,
|
||||||
base_path,
|
base_path,
|
||||||
@@ -60,6 +51,7 @@ impl SolidityCompiler for Resolc {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let solc = solc.ok_or_else(|| anyhow::anyhow!("solc compiler not provided to resolc."))?;
|
||||||
let input = SolcStandardJsonInput {
|
let input = SolcStandardJsonInput {
|
||||||
language: SolcStandardJsonInputLanguage::Solidity,
|
language: SolcStandardJsonInputLanguage::Solidity,
|
||||||
sources: sources
|
sources: sources
|
||||||
@@ -105,6 +97,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 {
|
||||||
@@ -238,108 +232,15 @@ 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 {
|
||||||
}
|
resolc_path: config.resolc.clone(),
|
||||||
|
|
||||||
async fn get_compiler_executable(
|
|
||||||
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()
|
|
||||||
.with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Failed to spawn resolc at {} to get version",
|
|
||||||
self.resolc_path.display()
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.wait_with_output()
|
|
||||||
.with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Failed waiting for resolc at {} to finish --version",
|
|
||||||
self.resolc_path.display()
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.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).with_context(|| {
|
|
||||||
format!("Failed to parse resolc semver from '{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.
|
|
||||||
|
|
||||||
// Note: the original implementation of this function looked like the following:
|
|
||||||
// ```
|
|
||||||
// pipeline == ModePipeline::ViaYulIR && compiler_version >= &SOLC_VERSION_SUPPORTING_VIA_YUL_IR
|
|
||||||
// ```
|
|
||||||
// However, that implementation is sadly incorrect since the version that's passed into this
|
|
||||||
// function is not the version of solc but the version of resolc. This is despite the fact
|
|
||||||
// that resolc depends on Solc for the initial Yul codegen. Therefore, we have skipped the
|
|
||||||
// version check until we do a better integrations between resolc and solc.
|
|
||||||
pipeline == ModePipeline::ViaYulIR
|
pipeline == ModePipeline::ViaYulIR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+14
-140
@@ -1,20 +1,8 @@
|
|||||||
//! 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 super::utils;
|
||||||
path::PathBuf,
|
|
||||||
process::{Command, Stdio},
|
|
||||||
sync::LazyLock,
|
|
||||||
};
|
|
||||||
|
|
||||||
use dashmap::DashMap;
|
|
||||||
use revive_dt_common::types::VersionOrRequirement;
|
|
||||||
use revive_dt_config::Arguments;
|
|
||||||
use revive_dt_solc_binaries::download_solc;
|
|
||||||
|
|
||||||
use super::constants::SOLC_VERSION_SUPPORTING_VIA_YUL_IR;
|
|
||||||
use crate::{CompilerInput, CompilerOutput, ModeOptimizerSetting, ModePipeline, SolidityCompiler};
|
use crate::{CompilerInput, CompilerOutput, ModeOptimizerSetting, ModePipeline, SolidityCompiler};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use foundry_compilers_artifacts::{
|
use foundry_compilers_artifacts::{
|
||||||
output_selection::{
|
output_selection::{
|
||||||
@@ -23,13 +11,12 @@ use foundry_compilers_artifacts::{
|
|||||||
solc::CompilerOutput as SolcOutput,
|
solc::CompilerOutput as SolcOutput,
|
||||||
solc::*,
|
solc::*,
|
||||||
};
|
};
|
||||||
use semver::Version;
|
use revive_dt_config::Arguments;
|
||||||
|
use std::process::Stdio;
|
||||||
use tokio::{io::AsyncWriteExt, process::Command as AsyncCommand};
|
use tokio::{io::AsyncWriteExt, process::Command as AsyncCommand};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Solc {
|
pub struct Solc {}
|
||||||
solc_path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SolidityCompiler for Solc {
|
impl SolidityCompiler for Solc {
|
||||||
type Options = ();
|
type Options = ();
|
||||||
@@ -40,6 +27,7 @@ impl SolidityCompiler for Solc {
|
|||||||
CompilerInput {
|
CompilerInput {
|
||||||
pipeline,
|
pipeline,
|
||||||
optimization,
|
optimization,
|
||||||
|
solc,
|
||||||
evm_version,
|
evm_version,
|
||||||
allow_paths,
|
allow_paths,
|
||||||
base_path,
|
base_path,
|
||||||
@@ -49,11 +37,9 @@ impl SolidityCompiler for Solc {
|
|||||||
}: CompilerInput,
|
}: CompilerInput,
|
||||||
_: Self::Options,
|
_: Self::Options,
|
||||||
) -> anyhow::Result<CompilerOutput> {
|
) -> anyhow::Result<CompilerOutput> {
|
||||||
let compiler_supports_via_ir = self
|
let solc = solc.ok_or_else(|| anyhow::anyhow!("solc compiler not provided to resolc."))?;
|
||||||
.version()
|
let compiler_supports_via_ir =
|
||||||
.await
|
utils::solc_versions_supporting_yul_ir().matches(&solc.version);
|
||||||
.context("Failed to query solc version to determine via-ir support")?
|
|
||||||
>= 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
|
||||||
@@ -119,7 +105,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())
|
||||||
@@ -140,7 +126,7 @@ impl SolidityCompiler for Solc {
|
|||||||
}
|
}
|
||||||
let mut child = command
|
let mut child = command
|
||||||
.spawn()
|
.spawn()
|
||||||
.with_context(|| format!("Failed to spawn solc at {}", self.solc_path.display()))?;
|
.with_context(|| format!("Failed to spawn solc at {}", solc.path.display()))?;
|
||||||
|
|
||||||
let stdin = child.stdin.as_mut().expect("should be piped");
|
let stdin = child.stdin.as_mut().expect("should be piped");
|
||||||
let serialized_input = serde_json::to_vec(&input)
|
let serialized_input = serde_json::to_vec(&input)
|
||||||
@@ -220,125 +206,13 @@ 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 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_compiler_executable(
|
fn supports_mode(_optimize_setting: ModeOptimizerSetting, pipeline: ModePipeline) -> bool {
|
||||||
config: &Arguments,
|
|
||||||
version: impl Into<VersionOrRequirement>,
|
|
||||||
) -> anyhow::Result<PathBuf> {
|
|
||||||
let path = download_solc(config.directory(), version, config.wasm)
|
|
||||||
.await
|
|
||||||
.context("Failed to download/get path to solc binary")?;
|
|
||||||
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()
|
|
||||||
.with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Failed to spawn solc at {} to get version",
|
|
||||||
self.solc_path.display()
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let output = child.wait_with_output().with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Failed waiting for solc at {} to finish --version",
|
|
||||||
self.solc_path.display()
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
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).with_context(|| {
|
|
||||||
format!("Failed to parse solc semver from '{version_string}'")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
vacant_entry.insert(version.clone());
|
|
||||||
|
|
||||||
Ok(version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_mode(
|
|
||||||
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,159 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
process::{Command, Stdio},
|
||||||
|
sync::LazyLock,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use revive_dt_common::types::{ModePipeline, VersionOrRequirement};
|
||||||
|
use semver::{Version, VersionReq};
|
||||||
|
|
||||||
|
/// Return the path and version of a suitable `solc` compiler given the requirements provided.
|
||||||
|
///
|
||||||
|
/// This caches any compiler binaries/paths that are downloaded as a result of calling this.
|
||||||
|
pub async fn solc_compiler(
|
||||||
|
cache_directory: &Path,
|
||||||
|
fallback_version: &Version,
|
||||||
|
required_version: Option<&VersionReq>,
|
||||||
|
pipeline: ModePipeline,
|
||||||
|
) -> anyhow::Result<SolcCompiler> {
|
||||||
|
// Require Yul compatible solc, or any if we don't care about compiling via Yul.
|
||||||
|
let mut version_req = if pipeline == ModePipeline::ViaYulIR {
|
||||||
|
solc_versions_supporting_yul_ir()
|
||||||
|
} else {
|
||||||
|
VersionReq::STAR
|
||||||
|
};
|
||||||
|
|
||||||
|
// Take into account the version requirements passed in, too.
|
||||||
|
if let Some(other_version_req) = required_version {
|
||||||
|
version_req
|
||||||
|
.comparators
|
||||||
|
.extend(other_version_req.comparators.iter().cloned());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no requirements yet then fall back to the fallback version.
|
||||||
|
let version_req = if version_req == VersionReq::STAR {
|
||||||
|
VersionOrRequirement::version_to_requirement(fallback_version)
|
||||||
|
} else {
|
||||||
|
version_req
|
||||||
|
};
|
||||||
|
|
||||||
|
// Download (or pull from cache) a suitable solc compiler given this.
|
||||||
|
let solc_path =
|
||||||
|
revive_dt_solc_binaries::download_solc(cache_directory, version_req, false).await?;
|
||||||
|
let solc_version = solc_version(&solc_path).await?;
|
||||||
|
|
||||||
|
Ok(SolcCompiler {
|
||||||
|
version: solc_version,
|
||||||
|
path: solc_path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `solc` compiler, returned from [`solc_compiler`].
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct SolcCompiler {
|
||||||
|
/// Version of the compiler.
|
||||||
|
pub version: Version,
|
||||||
|
/// Path to the compiler executable.
|
||||||
|
pub path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch the solc version given a path to the executable
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This returns the solc versions which support Yul IR.
|
||||||
|
pub fn solc_versions_supporting_yul_ir() -> VersionReq {
|
||||||
|
use semver::{Comparator, Op, Prerelease, VersionReq};
|
||||||
|
VersionReq {
|
||||||
|
comparators: vec![Comparator {
|
||||||
|
op: Op::GreaterEq,
|
||||||
|
major: 0,
|
||||||
|
minor: Some(8),
|
||||||
|
patch: Some(13),
|
||||||
|
pre: Prerelease::EMPTY,
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn compiler_version_can_be_obtained() {
|
||||||
|
// Arrange
|
||||||
|
let temp_dir = tempfile::tempdir().expect("can create tempdir");
|
||||||
|
let solc_path =
|
||||||
|
revive_dt_solc_binaries::download_solc(temp_dir.path(), Version::new(0, 7, 6), false)
|
||||||
|
.await
|
||||||
|
.expect("can download solc");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
let version = solc_version(&solc_path).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 temp_dir = tempfile::tempdir().expect("can create tempdir");
|
||||||
|
let solc_path =
|
||||||
|
revive_dt_solc_binaries::download_solc(temp_dir.path(), Version::new(0, 4, 21), false)
|
||||||
|
.await
|
||||||
|
.expect("can download solc");
|
||||||
|
|
||||||
|
// Act
|
||||||
|
let version = solc_version(&solc_path).await;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assert_eq!(
|
||||||
|
version.expect("Failed to get version"),
|
||||||
|
Version::new(0, 4, 21)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ rust-version.workspace = true
|
|||||||
alloy = { workspace = true }
|
alloy = { workspace = true }
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
semver = { workspace = true }
|
semver = { workspace = true }
|
||||||
temp-dir = { workspace = true }
|
tempfile = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use alloy::{network::EthereumWallet, signers::local::PrivateKeySigner};
|
|||||||
use clap::{Parser, ValueEnum};
|
use clap::{Parser, ValueEnum};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use temp_dir::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
#[derive(Debug, Parser, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Parser, Clone, Serialize, Deserialize)]
|
||||||
#[command(name = "retester")]
|
#[command(name = "retester")]
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ tracing-subscriber = { workspace = true }
|
|||||||
semver = { workspace = true }
|
semver = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
temp-dir = { workspace = true }
|
|
||||||
tempfile = { workspace = true }
|
tempfile = { workspace = true }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ 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, CompilerInput, CompilerOutput, Mode, SolidityCompiler};
|
use revive_dt_compiler::{Compiler, CompilerInput, CompilerOutput, Mode, SolcCompiler};
|
||||||
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};
|
||||||
|
|
||||||
@@ -53,70 +53,38 @@ impl CachedCompiler {
|
|||||||
&self,
|
&self,
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
metadata_file_path: impl AsRef<Path>,
|
metadata_file_path: impl AsRef<Path>,
|
||||||
|
solc: SolcCompiler,
|
||||||
mode: &Mode,
|
mode: &Mode,
|
||||||
config: &Arguments,
|
config: &Arguments,
|
||||||
deployed_libraries: Option<&HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>>,
|
deployed_libraries: Option<&HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>>,
|
||||||
compilation_success_report_callback: impl Fn(
|
compilation_success_report_callback: impl Fn(bool, Option<CompilerInput>, CompilerOutput)
|
||||||
Version,
|
+ Clone,
|
||||||
PathBuf,
|
compilation_failure_report_callback: impl Fn(Option<CompilerInput>, String),
|
||||||
bool,
|
) -> Result<CompilerOutput> {
|
||||||
Option<CompilerInput>,
|
|
||||||
CompilerOutput,
|
|
||||||
) + Clone,
|
|
||||||
compilation_failure_report_callback: impl Fn(
|
|
||||||
Option<Version>,
|
|
||||||
Option<PathBuf>,
|
|
||||||
Option<CompilerInput>,
|
|
||||||
String,
|
|
||||||
),
|
|
||||||
) -> Result<(CompilerOutput, Version)> {
|
|
||||||
static CACHE_KEY_LOCK: Lazy<RwLock<HashMap<CacheKey, Arc<Mutex<()>>>>> =
|
static CACHE_KEY_LOCK: Lazy<RwLock<HashMap<CacheKey, Arc<Mutex<()>>>>> =
|
||||||
Lazy::new(Default::default);
|
Lazy::new(Default::default);
|
||||||
|
|
||||||
let compiler_version_or_requirement = mode.compiler_version_to_use(config.solc.clone());
|
|
||||||
let compiler_path = <P::Compiler as SolidityCompiler>::get_compiler_executable(
|
|
||||||
config,
|
|
||||||
compiler_version_or_requirement,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.inspect_err(|err| {
|
|
||||||
compilation_failure_report_callback(None, None, None, format!("{err:#}"))
|
|
||||||
})
|
|
||||||
.context("Failed to obtain compiler executable path")?;
|
|
||||||
let compiler_version = <P::Compiler as SolidityCompiler>::new(compiler_path.clone())
|
|
||||||
.version()
|
|
||||||
.await
|
|
||||||
.inspect_err(|err| {
|
|
||||||
compilation_failure_report_callback(
|
|
||||||
None,
|
|
||||||
Some(compiler_path.clone()),
|
|
||||||
None,
|
|
||||||
format!("{err:#}"),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.context("Failed to query compiler version")?;
|
|
||||||
|
|
||||||
let cache_key = CacheKey {
|
let cache_key = CacheKey {
|
||||||
platform_key: P::config_id().to_string(),
|
platform_key: P::config_id().to_string(),
|
||||||
compiler_version: compiler_version.clone(),
|
compiler_version: solc.version.clone(),
|
||||||
metadata_file_path: metadata_file_path.as_ref().to_path_buf(),
|
metadata_file_path: metadata_file_path.as_ref().to_path_buf(),
|
||||||
solc_mode: mode.clone(),
|
solc_mode: mode.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let compilation_callback = || {
|
let compilation_callback = || {
|
||||||
let compiler_path = compiler_path.clone();
|
// let compiler_path = compiler_path.clone();
|
||||||
let compiler_version = compiler_version.clone();
|
// let compiler_version = compiler_version.clone();
|
||||||
let compilation_success_report_callback = compilation_success_report_callback.clone();
|
let compilation_success_report_callback = compilation_success_report_callback.clone();
|
||||||
async move {
|
async move {
|
||||||
compile_contracts::<P>(
|
compile_contracts::<P>(
|
||||||
metadata
|
metadata
|
||||||
.directory()
|
.directory()
|
||||||
.context("Failed to get metadata directory while preparing compilation")?,
|
.context("Failed to get metadata directory while preparing compilation")?,
|
||||||
compiler_path,
|
|
||||||
compiler_version,
|
|
||||||
metadata
|
metadata
|
||||||
.files_to_compile()
|
.files_to_compile()
|
||||||
.context("Failed to enumerate files to compile from metadata")?,
|
.context("Failed to enumerate files to compile from metadata")?,
|
||||||
|
config,
|
||||||
|
solc,
|
||||||
mode,
|
mode,
|
||||||
deployed_libraries,
|
deployed_libraries,
|
||||||
compilation_success_report_callback,
|
compilation_success_report_callback,
|
||||||
@@ -171,8 +139,6 @@ impl CachedCompiler {
|
|||||||
match self.0.get(&cache_key).await {
|
match self.0.get(&cache_key).await {
|
||||||
Some(cache_value) => {
|
Some(cache_value) => {
|
||||||
compilation_success_report_callback(
|
compilation_success_report_callback(
|
||||||
compiler_version.clone(),
|
|
||||||
compiler_path,
|
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
cache_value.compiler_output.clone(),
|
cache_value.compiler_output.clone(),
|
||||||
@@ -189,31 +155,20 @@ impl CachedCompiler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((compiled_contracts, compiler_version))
|
Ok(compiled_contracts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
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>,
|
|
||||||
compiler_version: Version,
|
|
||||||
mut files_to_compile: impl Iterator<Item = PathBuf>,
|
mut files_to_compile: impl Iterator<Item = PathBuf>,
|
||||||
|
config: &Arguments,
|
||||||
|
solc: SolcCompiler,
|
||||||
mode: &Mode,
|
mode: &Mode,
|
||||||
deployed_libraries: Option<&HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>>,
|
deployed_libraries: Option<&HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>>,
|
||||||
compilation_success_report_callback: impl Fn(
|
compilation_success_report_callback: impl Fn(bool, Option<CompilerInput>, CompilerOutput),
|
||||||
Version,
|
compilation_failure_report_callback: impl Fn(Option<CompilerInput>, String),
|
||||||
PathBuf,
|
|
||||||
bool,
|
|
||||||
Option<CompilerInput>,
|
|
||||||
CompilerOutput,
|
|
||||||
),
|
|
||||||
compilation_failure_report_callback: impl Fn(
|
|
||||||
Option<Version>,
|
|
||||||
Option<PathBuf>,
|
|
||||||
Option<CompilerInput>,
|
|
||||||
String,
|
|
||||||
),
|
|
||||||
) -> Result<CompilerOutput> {
|
) -> Result<CompilerOutput> {
|
||||||
let all_sources_in_dir = FilesWithExtensionIterator::new(metadata_directory.as_ref())
|
let all_sources_in_dir = FilesWithExtensionIterator::new(metadata_directory.as_ref())
|
||||||
.with_allowed_extension("sol")
|
.with_allowed_extension("sol")
|
||||||
@@ -221,6 +176,7 @@ async fn compile_contracts<P: Platform>(
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let compiler = Compiler::<P::Compiler>::new()
|
let compiler = Compiler::<P::Compiler>::new()
|
||||||
|
.with_solc(solc)
|
||||||
.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)
|
||||||
@@ -229,14 +185,7 @@ async fn compile_contracts<P: Platform>(
|
|||||||
.try_then(|compiler| {
|
.try_then(|compiler| {
|
||||||
files_to_compile.try_fold(compiler, |compiler, path| compiler.with_source(path))
|
files_to_compile.try_fold(compiler, |compiler, path| compiler.with_source(path))
|
||||||
})
|
})
|
||||||
.inspect_err(|err| {
|
.inspect_err(|err| compilation_failure_report_callback(None, format!("{err:#}")))?
|
||||||
compilation_failure_report_callback(
|
|
||||||
Some(compiler_version.clone()),
|
|
||||||
Some(compiler_path.as_ref().to_path_buf()),
|
|
||||||
None,
|
|
||||||
format!("{err:#}"),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
// Adding the deployed libraries to the compiler.
|
// Adding the deployed libraries to the compiler.
|
||||||
.then(|compiler| {
|
.then(|compiler| {
|
||||||
deployed_libraries
|
deployed_libraries
|
||||||
@@ -255,24 +204,14 @@ async fn compile_contracts<P: Platform>(
|
|||||||
|
|
||||||
let compiler_input = compiler.input();
|
let compiler_input = compiler.input();
|
||||||
let compiler_output = compiler
|
let compiler_output = compiler
|
||||||
.try_build(compiler_path.as_ref())
|
.try_build(config)
|
||||||
.await
|
.await
|
||||||
.inspect_err(|err| {
|
.inspect_err(|err| {
|
||||||
compilation_failure_report_callback(
|
compilation_failure_report_callback(Some(compiler_input.clone()), format!("{err:#}"))
|
||||||
Some(compiler_version.clone()),
|
|
||||||
Some(compiler_path.as_ref().to_path_buf()),
|
|
||||||
Some(compiler_input.clone()),
|
|
||||||
format!("{err:#}"),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.context("Failed to configure compiler with sources and options")?;
|
.context("Failed to configure compiler with sources and options")?;
|
||||||
compilation_success_report_callback(
|
|
||||||
compiler_version,
|
compilation_success_report_callback(false, Some(compiler_input), compiler_output.clone());
|
||||||
compiler_path.as_ref().to_path_buf(),
|
|
||||||
false,
|
|
||||||
Some(compiler_input),
|
|
||||||
compiler_output.clone(),
|
|
||||||
);
|
|
||||||
Ok(compiler_output)
|
Ok(compiler_output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+84
-96
@@ -14,15 +14,15 @@ 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 revive_dt_report::{
|
use revive_dt_report::{
|
||||||
NodeDesignation, ReportAggregator, Reporter, ReporterEvent, TestCaseStatus,
|
NodeDesignation, ReportAggregator, Reporter, ReporterEvent, TestCaseStatus,
|
||||||
TestSpecificReporter, TestSpecifier,
|
TestSpecificReporter, TestSpecifier,
|
||||||
};
|
};
|
||||||
use temp_dir::TempDir;
|
use tempfile::TempDir;
|
||||||
use tokio::{join, try_join};
|
use tokio::{join, try_join};
|
||||||
use tracing::{debug, info, info_span, instrument};
|
use tracing::{debug, info, info_span, instrument};
|
||||||
use tracing_appender::non_blocking::WorkerGuard;
|
use tracing_appender::non_blocking::WorkerGuard;
|
||||||
@@ -185,7 +185,7 @@ where
|
|||||||
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 tests = prepare_tests::<L, F>(args, metadata_files, reporter.clone());
|
let tests = prepare_tests::<L, F>(metadata_files, reporter.clone());
|
||||||
let driver_task = start_driver_task::<L, F>(args, tests)
|
let driver_task = start_driver_task::<L, F>(args, tests)
|
||||||
.await
|
.await
|
||||||
.context("Failed to start driver task")?;
|
.context("Failed to start driver task")?;
|
||||||
@@ -198,17 +198,16 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_tests<'a, L, F>(
|
fn prepare_tests<'a, L, F>(
|
||||||
args: &Arguments,
|
|
||||||
metadata_files: &'a [MetadataFile],
|
metadata_files: &'a [MetadataFile],
|
||||||
reporter: Reporter,
|
reporter: Reporter,
|
||||||
) -> impl Stream<Item = Test<'a>>
|
) -> impl Iterator<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
|
||||||
@@ -373,19 +372,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 {
|
||||||
@@ -419,29 +411,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
|
|
||||||
.context("Failed to obtain compiler executable path")?;
|
|
||||||
let compiler_version = P::Compiler::new(compiler_path.clone())
|
|
||||||
.version()
|
|
||||||
.await
|
|
||||||
.context("Failed to query compiler version")?;
|
|
||||||
|
|
||||||
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>>,
|
||||||
) -> anyhow::Result<impl Future<Output = ()>>
|
) -> anyhow::Result<impl Future<Output = ()>>
|
||||||
where
|
where
|
||||||
L: Platform,
|
L: Platform,
|
||||||
@@ -467,7 +439,7 @@ where
|
|||||||
.context("Failed to initialize cached compiler")?,
|
.context("Failed to initialize cached compiler")?,
|
||||||
);
|
);
|
||||||
|
|
||||||
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.
|
||||||
@@ -632,6 +604,14 @@ where
|
|||||||
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 solc = revive_dt_compiler::solc_compiler(
|
||||||
|
config.directory(),
|
||||||
|
&config.solc,
|
||||||
|
test.mode.version.as_ref(),
|
||||||
|
test.mode.pipeline,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let leader_reporter = test
|
let leader_reporter = test
|
||||||
.reporter
|
.reporter
|
||||||
.execution_specific_reporter(leader_node.id(), NodeDesignation::Leader);
|
.execution_specific_reporter(leader_node.id(), NodeDesignation::Leader);
|
||||||
@@ -640,41 +620,34 @@ where
|
|||||||
.execution_specific_reporter(follower_node.id(), NodeDesignation::Follower);
|
.execution_specific_reporter(follower_node.id(), NodeDesignation::Follower);
|
||||||
|
|
||||||
let (
|
let (
|
||||||
(
|
CompilerOutput {
|
||||||
CompilerOutput {
|
contracts: leader_pre_link_contracts,
|
||||||
contracts: leader_pre_link_contracts,
|
},
|
||||||
},
|
CompilerOutput {
|
||||||
_,
|
contracts: follower_pre_link_contracts,
|
||||||
),
|
},
|
||||||
(
|
|
||||||
CompilerOutput {
|
|
||||||
contracts: follower_pre_link_contracts,
|
|
||||||
},
|
|
||||||
_,
|
|
||||||
),
|
|
||||||
) = try_join!(
|
) = try_join!(
|
||||||
cached_compiler.compile_contracts::<L>(
|
cached_compiler.compile_contracts::<L>(
|
||||||
test.metadata,
|
test.metadata,
|
||||||
test.metadata_file_path,
|
test.metadata_file_path,
|
||||||
|
solc.clone(),
|
||||||
&test.mode,
|
&test.mode,
|
||||||
config,
|
config,
|
||||||
None,
|
None,
|
||||||
|compiler_version, compiler_path, is_cached, compiler_input, compiler_output| {
|
|is_cached, compiler_input, compiler_output| {
|
||||||
leader_reporter
|
leader_reporter
|
||||||
.report_pre_link_contracts_compilation_succeeded_event(
|
.report_pre_link_contracts_compilation_succeeded_event(
|
||||||
compiler_version,
|
|
||||||
compiler_path,
|
|
||||||
is_cached,
|
is_cached,
|
||||||
|
solc.clone(),
|
||||||
compiler_input,
|
compiler_input,
|
||||||
compiler_output,
|
compiler_output,
|
||||||
)
|
)
|
||||||
.expect("Can't fail")
|
.expect("Can't fail")
|
||||||
},
|
},
|
||||||
|compiler_version, compiler_path, compiler_input, failure_reason| {
|
|compiler_input, failure_reason| {
|
||||||
leader_reporter
|
leader_reporter
|
||||||
.report_pre_link_contracts_compilation_failed_event(
|
.report_pre_link_contracts_compilation_failed_event(
|
||||||
compiler_version,
|
solc.clone(),
|
||||||
compiler_path,
|
|
||||||
compiler_input,
|
compiler_input,
|
||||||
failure_reason,
|
failure_reason,
|
||||||
)
|
)
|
||||||
@@ -684,25 +657,24 @@ where
|
|||||||
cached_compiler.compile_contracts::<F>(
|
cached_compiler.compile_contracts::<F>(
|
||||||
test.metadata,
|
test.metadata,
|
||||||
test.metadata_file_path,
|
test.metadata_file_path,
|
||||||
|
solc.clone(),
|
||||||
&test.mode,
|
&test.mode,
|
||||||
config,
|
config,
|
||||||
None,
|
None,
|
||||||
|compiler_version, compiler_path, is_cached, compiler_input, compiler_output| {
|
|is_cached, compiler_input, compiler_output| {
|
||||||
follower_reporter
|
follower_reporter
|
||||||
.report_pre_link_contracts_compilation_succeeded_event(
|
.report_pre_link_contracts_compilation_succeeded_event(
|
||||||
compiler_version,
|
|
||||||
compiler_path,
|
|
||||||
is_cached,
|
is_cached,
|
||||||
|
solc.clone(),
|
||||||
compiler_input,
|
compiler_input,
|
||||||
compiler_output,
|
compiler_output,
|
||||||
)
|
)
|
||||||
.expect("Can't fail")
|
.expect("Can't fail")
|
||||||
},
|
},
|
||||||
|compiler_version, compiler_path, compiler_input, failure_reason| {
|
|compiler_input, failure_reason| {
|
||||||
follower_reporter
|
follower_reporter
|
||||||
.report_pre_link_contracts_compilation_failed_event(
|
.report_pre_link_contracts_compilation_failed_event(
|
||||||
compiler_version,
|
solc.clone(),
|
||||||
compiler_path,
|
|
||||||
compiler_input,
|
compiler_input,
|
||||||
failure_reason,
|
failure_reason,
|
||||||
)
|
)
|
||||||
@@ -839,41 +811,34 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (
|
let (
|
||||||
(
|
CompilerOutput {
|
||||||
CompilerOutput {
|
contracts: leader_post_link_contracts,
|
||||||
contracts: leader_post_link_contracts,
|
},
|
||||||
},
|
CompilerOutput {
|
||||||
leader_compiler_version,
|
contracts: follower_post_link_contracts,
|
||||||
),
|
},
|
||||||
(
|
|
||||||
CompilerOutput {
|
|
||||||
contracts: follower_post_link_contracts,
|
|
||||||
},
|
|
||||||
follower_compiler_version,
|
|
||||||
),
|
|
||||||
) = try_join!(
|
) = try_join!(
|
||||||
cached_compiler.compile_contracts::<L>(
|
cached_compiler.compile_contracts::<L>(
|
||||||
test.metadata,
|
test.metadata,
|
||||||
test.metadata_file_path,
|
test.metadata_file_path,
|
||||||
|
solc.clone(),
|
||||||
&test.mode,
|
&test.mode,
|
||||||
config,
|
config,
|
||||||
leader_deployed_libraries.as_ref(),
|
leader_deployed_libraries.as_ref(),
|
||||||
|compiler_version, compiler_path, is_cached, compiler_input, compiler_output| {
|
|is_cached, compiler_input, compiler_output| {
|
||||||
leader_reporter
|
leader_reporter
|
||||||
.report_post_link_contracts_compilation_succeeded_event(
|
.report_post_link_contracts_compilation_succeeded_event(
|
||||||
compiler_version,
|
|
||||||
compiler_path,
|
|
||||||
is_cached,
|
is_cached,
|
||||||
|
solc.clone(),
|
||||||
compiler_input,
|
compiler_input,
|
||||||
compiler_output,
|
compiler_output,
|
||||||
)
|
)
|
||||||
.expect("Can't fail")
|
.expect("Can't fail")
|
||||||
},
|
},
|
||||||
|compiler_version, compiler_path, compiler_input, failure_reason| {
|
|compiler_input, failure_reason| {
|
||||||
leader_reporter
|
leader_reporter
|
||||||
.report_post_link_contracts_compilation_failed_event(
|
.report_post_link_contracts_compilation_failed_event(
|
||||||
compiler_version,
|
solc.clone(),
|
||||||
compiler_path,
|
|
||||||
compiler_input,
|
compiler_input,
|
||||||
failure_reason,
|
failure_reason,
|
||||||
)
|
)
|
||||||
@@ -883,25 +848,24 @@ where
|
|||||||
cached_compiler.compile_contracts::<F>(
|
cached_compiler.compile_contracts::<F>(
|
||||||
test.metadata,
|
test.metadata,
|
||||||
test.metadata_file_path,
|
test.metadata_file_path,
|
||||||
|
solc.clone(),
|
||||||
&test.mode,
|
&test.mode,
|
||||||
config,
|
config,
|
||||||
follower_deployed_libraries.as_ref(),
|
follower_deployed_libraries.as_ref(),
|
||||||
|compiler_version, compiler_path, is_cached, compiler_input, compiler_output| {
|
|is_cached, compiler_input, compiler_output| {
|
||||||
follower_reporter
|
follower_reporter
|
||||||
.report_post_link_contracts_compilation_succeeded_event(
|
.report_post_link_contracts_compilation_succeeded_event(
|
||||||
compiler_version,
|
|
||||||
compiler_path,
|
|
||||||
is_cached,
|
is_cached,
|
||||||
|
solc.clone(),
|
||||||
compiler_input,
|
compiler_input,
|
||||||
compiler_output,
|
compiler_output,
|
||||||
)
|
)
|
||||||
.expect("Can't fail")
|
.expect("Can't fail")
|
||||||
},
|
},
|
||||||
|compiler_version, compiler_path, compiler_input, failure_reason| {
|
|compiler_input, failure_reason| {
|
||||||
follower_reporter
|
follower_reporter
|
||||||
.report_post_link_contracts_compilation_failed_event(
|
.report_post_link_contracts_compilation_failed_event(
|
||||||
compiler_version,
|
solc.clone(),
|
||||||
compiler_path,
|
|
||||||
compiler_input,
|
compiler_input,
|
||||||
failure_reason,
|
failure_reason,
|
||||||
)
|
)
|
||||||
@@ -912,13 +876,13 @@ where
|
|||||||
.context("Failed to compile post-link contracts for leader/follower in parallel")?;
|
.context("Failed to compile post-link contracts for leader/follower in parallel")?;
|
||||||
|
|
||||||
let leader_state = CaseState::<L>::new(
|
let leader_state = CaseState::<L>::new(
|
||||||
leader_compiler_version,
|
solc.version.clone(),
|
||||||
leader_post_link_contracts,
|
leader_post_link_contracts,
|
||||||
leader_deployed_libraries.unwrap_or_default(),
|
leader_deployed_libraries.unwrap_or_default(),
|
||||||
leader_reporter,
|
leader_reporter,
|
||||||
);
|
);
|
||||||
let follower_state = CaseState::<F>::new(
|
let follower_state = CaseState::<F>::new(
|
||||||
follower_compiler_version,
|
solc.version.clone(),
|
||||||
follower_post_link_contracts,
|
follower_post_link_contracts,
|
||||||
follower_deployed_libraries.unwrap_or_default(),
|
follower_deployed_libraries.unwrap_or_default(),
|
||||||
follower_reporter,
|
follower_reporter,
|
||||||
@@ -961,7 +925,7 @@ async fn compile_corpus(
|
|||||||
config: &Arguments,
|
config: &Arguments,
|
||||||
tests: &[MetadataFile],
|
tests: &[MetadataFile],
|
||||||
platform: &TestingPlatform,
|
platform: &TestingPlatform,
|
||||||
_: Reporter,
|
reporter: Reporter,
|
||||||
report_aggregator_task: impl Future<Output = anyhow::Result<()>>,
|
report_aggregator_task: impl Future<Output = anyhow::Result<()>>,
|
||||||
) {
|
) {
|
||||||
let tests = tests.iter().flat_map(|metadata| {
|
let tests = tests.iter().flat_map(|metadata| {
|
||||||
@@ -980,19 +944,42 @@ async fn compile_corpus(
|
|||||||
let compilation_task =
|
let compilation_task =
|
||||||
futures::stream::iter(tests).for_each_concurrent(None, |(metadata, mode)| {
|
futures::stream::iter(tests).for_each_concurrent(None, |(metadata, mode)| {
|
||||||
let cached_compiler = cached_compiler.clone();
|
let cached_compiler = cached_compiler.clone();
|
||||||
|
let reporter = reporter.clone();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
|
let solc = revive_dt_compiler::solc_compiler(
|
||||||
|
config.directory(),
|
||||||
|
&config.solc,
|
||||||
|
mode.version.as_ref(),
|
||||||
|
mode.pipeline,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let solc = match solc {
|
||||||
|
Ok(solc) => solc,
|
||||||
|
Err(err) => {
|
||||||
|
let test_specifier = TestSpecifier {
|
||||||
|
solc_mode: mode,
|
||||||
|
metadata_file_path: metadata.metadata_file_path.clone(),
|
||||||
|
case_idx: 0.into(),
|
||||||
|
};
|
||||||
|
let _ = reporter.report_test_failed_event(test_specifier, err.to_string());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match platform {
|
match platform {
|
||||||
TestingPlatform::Geth => {
|
TestingPlatform::Geth => {
|
||||||
let _ = cached_compiler
|
let _ = cached_compiler
|
||||||
.compile_contracts::<Geth>(
|
.compile_contracts::<Geth>(
|
||||||
metadata,
|
metadata,
|
||||||
metadata.metadata_file_path.as_path(),
|
metadata.metadata_file_path.as_path(),
|
||||||
|
solc,
|
||||||
&mode,
|
&mode,
|
||||||
config,
|
config,
|
||||||
None,
|
None,
|
||||||
|_, _, _, _, _| {},
|
|_, _, _| {},
|
||||||
|_, _, _, _| {},
|
|_, _| {},
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@@ -1001,11 +988,12 @@ async fn compile_corpus(
|
|||||||
.compile_contracts::<Kitchensink>(
|
.compile_contracts::<Kitchensink>(
|
||||||
metadata,
|
metadata,
|
||||||
metadata.metadata_file_path.as_path(),
|
metadata.metadata_file_path.as_path(),
|
||||||
|
solc,
|
||||||
&mode,
|
&mode,
|
||||||
config,
|
config,
|
||||||
None,
|
None,
|
||||||
|_, _, _, _, _| {},
|
|_, _, _| {},
|
||||||
|_, _, _, _| {},
|
|_, _| {},
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ sp-core = { workspace = true }
|
|||||||
sp-runtime = { workspace = true }
|
sp-runtime = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
temp-dir = { workspace = true }
|
tempfile = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
|
|||||||
@@ -664,7 +664,7 @@ impl Drop for GethNode {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
|
|
||||||
use temp_dir::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
use crate::{GENESIS_JSON, Node};
|
use crate::{GENESIS_JSON, Node};
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ alloy-primitives = { workspace = true }
|
|||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
paste = { workspace = true }
|
paste = { workspace = true }
|
||||||
indexmap = { workspace = true, features = ["serde"] }
|
indexmap = { workspace = true, features = ["serde"] }
|
||||||
semver = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
serde_with = { workspace = true }
|
serde_with = { workspace = true }
|
||||||
|
|||||||
@@ -4,17 +4,15 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
||||||
fs::OpenOptions,
|
fs::OpenOptions,
|
||||||
path::PathBuf,
|
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
use alloy_primitives::Address;
|
use alloy_primitives::Address;
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use revive_dt_compiler::{CompilerInput, CompilerOutput, Mode};
|
use revive_dt_compiler::{CompilerInput, CompilerOutput, Mode, SolcCompiler};
|
||||||
use revive_dt_config::{Arguments, TestingPlatform};
|
use revive_dt_config::{Arguments, TestingPlatform};
|
||||||
use revive_dt_format::{case::CaseIdx, corpus::Corpus, metadata::ContractInstance};
|
use revive_dt_format::{case::CaseIdx, corpus::Corpus, metadata::ContractInstance};
|
||||||
use semver::Version;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_with::{DisplayFromStr, serde_as};
|
use serde_with::{DisplayFromStr, serde_as};
|
||||||
use tokio::sync::{
|
use tokio::sync::{
|
||||||
@@ -300,8 +298,7 @@ impl ReportAggregator {
|
|||||||
|
|
||||||
execution_information.pre_link_compilation_status = Some(CompilationStatus::Success {
|
execution_information.pre_link_compilation_status = Some(CompilationStatus::Success {
|
||||||
is_cached: event.is_cached,
|
is_cached: event.is_cached,
|
||||||
compiler_version: event.compiler_version,
|
solc_info: event.solc_info,
|
||||||
compiler_path: event.compiler_path,
|
|
||||||
compiler_input,
|
compiler_input,
|
||||||
compiler_output,
|
compiler_output,
|
||||||
});
|
});
|
||||||
@@ -329,8 +326,7 @@ impl ReportAggregator {
|
|||||||
|
|
||||||
execution_information.post_link_compilation_status = Some(CompilationStatus::Success {
|
execution_information.post_link_compilation_status = Some(CompilationStatus::Success {
|
||||||
is_cached: event.is_cached,
|
is_cached: event.is_cached,
|
||||||
compiler_version: event.compiler_version,
|
solc_info: event.solc_info,
|
||||||
compiler_path: event.compiler_path,
|
|
||||||
compiler_input,
|
compiler_input,
|
||||||
compiler_output,
|
compiler_output,
|
||||||
});
|
});
|
||||||
@@ -352,8 +348,7 @@ impl ReportAggregator {
|
|||||||
|
|
||||||
execution_information.pre_link_compilation_status = Some(CompilationStatus::Failure {
|
execution_information.pre_link_compilation_status = Some(CompilationStatus::Failure {
|
||||||
reason: event.reason,
|
reason: event.reason,
|
||||||
compiler_version: event.compiler_version,
|
solc_info: event.solc_info,
|
||||||
compiler_path: event.compiler_path,
|
|
||||||
compiler_input,
|
compiler_input,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -374,8 +369,7 @@ impl ReportAggregator {
|
|||||||
|
|
||||||
execution_information.post_link_compilation_status = Some(CompilationStatus::Failure {
|
execution_information.post_link_compilation_status = Some(CompilationStatus::Failure {
|
||||||
reason: event.reason,
|
reason: event.reason,
|
||||||
compiler_version: event.compiler_version,
|
solc_info: event.solc_info,
|
||||||
compiler_path: event.compiler_path,
|
|
||||||
compiler_input,
|
compiler_input,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -528,10 +522,8 @@ pub enum CompilationStatus {
|
|||||||
Success {
|
Success {
|
||||||
/// A flag with information on whether the compilation artifacts were cached or not.
|
/// A flag with information on whether the compilation artifacts were cached or not.
|
||||||
is_cached: bool,
|
is_cached: bool,
|
||||||
/// The version of the compiler used to compile the contracts.
|
/// The version and path of the solc compiler used to compile the contracts.
|
||||||
compiler_version: Version,
|
solc_info: SolcCompiler,
|
||||||
/// The path of the compiler used to compile the contracts.
|
|
||||||
compiler_path: PathBuf,
|
|
||||||
/// The input provided to the compiler to compile the contracts. This is only included if
|
/// The input provided to the compiler to compile the contracts. This is only included if
|
||||||
/// the appropriate flag is set in the CLI configuration and if the contracts were not
|
/// the appropriate flag is set in the CLI configuration and if the contracts were not
|
||||||
/// cached and the compiler was invoked.
|
/// cached and the compiler was invoked.
|
||||||
@@ -546,12 +538,8 @@ pub enum CompilationStatus {
|
|||||||
Failure {
|
Failure {
|
||||||
/// The failure reason.
|
/// The failure reason.
|
||||||
reason: String,
|
reason: String,
|
||||||
/// The version of the compiler used to compile the contracts.
|
/// The version and path of the solc compiler used to compile the contracts.
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
solc_info: SolcCompiler,
|
||||||
compiler_version: Option<Version>,
|
|
||||||
/// The path of the compiler used to compile the contracts.
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
compiler_path: Option<PathBuf>,
|
|
||||||
/// The input provided to the compiler to compile the contracts. This is only included if
|
/// The input provided to the compiler to compile the contracts. This is only included if
|
||||||
/// the appropriate flag is set in the CLI configuration and if the contracts were not
|
/// the appropriate flag is set in the CLI configuration and if the contracts were not
|
||||||
/// cached and the compiler was invoked.
|
/// cached and the compiler was invoked.
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
//! The types associated with the events sent by the runner to the reporter.
|
//! The types associated with the events sent by the runner to the reporter.
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::{collections::BTreeMap, path::PathBuf, sync::Arc};
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
|
|
||||||
use alloy_primitives::Address;
|
use alloy_primitives::Address;
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use revive_dt_compiler::{CompilerInput, CompilerOutput};
|
use revive_dt_compiler::{CompilerInput, CompilerOutput, SolcCompiler};
|
||||||
use revive_dt_config::TestingPlatform;
|
use revive_dt_config::TestingPlatform;
|
||||||
use revive_dt_format::metadata::Metadata;
|
use revive_dt_format::metadata::Metadata;
|
||||||
use revive_dt_format::{corpus::Corpus, metadata::ContractInstance};
|
use revive_dt_format::{corpus::Corpus, metadata::ContractInstance};
|
||||||
use semver::Version;
|
|
||||||
use tokio::sync::{broadcast, oneshot};
|
use tokio::sync::{broadcast, oneshot};
|
||||||
|
|
||||||
use crate::{ExecutionSpecifier, ReporterEvent, TestSpecifier, common::MetadataFilePath};
|
use crate::{ExecutionSpecifier, ReporterEvent, TestSpecifier, common::MetadataFilePath};
|
||||||
@@ -547,13 +546,11 @@ define_event! {
|
|||||||
PreLinkContractsCompilationSucceeded {
|
PreLinkContractsCompilationSucceeded {
|
||||||
/// A specifier for the execution that's taking place.
|
/// A specifier for the execution that's taking place.
|
||||||
execution_specifier: Arc<ExecutionSpecifier>,
|
execution_specifier: Arc<ExecutionSpecifier>,
|
||||||
/// The version of the compiler used to compile the contracts.
|
|
||||||
compiler_version: Version,
|
|
||||||
/// The path of the compiler used to compile the contracts.
|
|
||||||
compiler_path: PathBuf,
|
|
||||||
/// A flag of whether the contract bytecode and ABI were cached or if they were compiled
|
/// A flag of whether the contract bytecode and ABI were cached or if they were compiled
|
||||||
/// anew.
|
/// anew.
|
||||||
is_cached: bool,
|
is_cached: bool,
|
||||||
|
/// The version and path of the solc compiler used to compile the contracts.
|
||||||
|
solc_info: SolcCompiler,
|
||||||
/// The input provided to the compiler - this is optional and not provided if the
|
/// The input provided to the compiler - this is optional and not provided if the
|
||||||
/// contracts were obtained from the cache.
|
/// contracts were obtained from the cache.
|
||||||
compiler_input: Option<CompilerInput>,
|
compiler_input: Option<CompilerInput>,
|
||||||
@@ -565,13 +562,11 @@ define_event! {
|
|||||||
PostLinkContractsCompilationSucceeded {
|
PostLinkContractsCompilationSucceeded {
|
||||||
/// A specifier for the execution that's taking place.
|
/// A specifier for the execution that's taking place.
|
||||||
execution_specifier: Arc<ExecutionSpecifier>,
|
execution_specifier: Arc<ExecutionSpecifier>,
|
||||||
/// The version of the compiler used to compile the contracts.
|
|
||||||
compiler_version: Version,
|
|
||||||
/// The path of the compiler used to compile the contracts.
|
|
||||||
compiler_path: PathBuf,
|
|
||||||
/// A flag of whether the contract bytecode and ABI were cached or if they were compiled
|
/// A flag of whether the contract bytecode and ABI were cached or if they were compiled
|
||||||
/// anew.
|
/// anew.
|
||||||
is_cached: bool,
|
is_cached: bool,
|
||||||
|
/// The version and path of the solc compiler used to compile the contracts.
|
||||||
|
solc_info: SolcCompiler,
|
||||||
/// The input provided to the compiler - this is optional and not provided if the
|
/// The input provided to the compiler - this is optional and not provided if the
|
||||||
/// contracts were obtained from the cache.
|
/// contracts were obtained from the cache.
|
||||||
compiler_input: Option<CompilerInput>,
|
compiler_input: Option<CompilerInput>,
|
||||||
@@ -583,10 +578,8 @@ define_event! {
|
|||||||
PreLinkContractsCompilationFailed {
|
PreLinkContractsCompilationFailed {
|
||||||
/// A specifier for the execution that's taking place.
|
/// A specifier for the execution that's taking place.
|
||||||
execution_specifier: Arc<ExecutionSpecifier>,
|
execution_specifier: Arc<ExecutionSpecifier>,
|
||||||
/// The version of the compiler used to compile the contracts.
|
/// The version and path of the solc compiler used to compile the contracts.
|
||||||
compiler_version: Option<Version>,
|
solc_info: SolcCompiler,
|
||||||
/// The path of the compiler used to compile the contracts.
|
|
||||||
compiler_path: Option<PathBuf>,
|
|
||||||
/// The input provided to the compiler - this is optional and not provided if the
|
/// The input provided to the compiler - this is optional and not provided if the
|
||||||
/// contracts were obtained from the cache.
|
/// contracts were obtained from the cache.
|
||||||
compiler_input: Option<CompilerInput>,
|
compiler_input: Option<CompilerInput>,
|
||||||
@@ -598,10 +591,8 @@ define_event! {
|
|||||||
PostLinkContractsCompilationFailed {
|
PostLinkContractsCompilationFailed {
|
||||||
/// A specifier for the execution that's taking place.
|
/// A specifier for the execution that's taking place.
|
||||||
execution_specifier: Arc<ExecutionSpecifier>,
|
execution_specifier: Arc<ExecutionSpecifier>,
|
||||||
/// The version of the compiler used to compile the contracts.
|
/// The version and path of the solc compiler used to compile the contracts.
|
||||||
compiler_version: Option<Version>,
|
solc_info: SolcCompiler,
|
||||||
/// The path of the compiler used to compile the contracts.
|
|
||||||
compiler_path: Option<PathBuf>,
|
|
||||||
/// The input provided to the compiler - this is optional and not provided if the
|
/// The input provided to the compiler - this is optional and not provided if the
|
||||||
/// contracts were obtained from the cache.
|
/// contracts were obtained from the cache.
|
||||||
compiler_input: Option<CompilerInput>,
|
compiler_input: Option<CompilerInput>,
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ impl SolcDownloader {
|
|||||||
.filter(|version| requirement.matches(version))
|
.filter(|version| requirement.matches(version))
|
||||||
.max()
|
.max()
|
||||||
else {
|
else {
|
||||||
anyhow::bail!("Failed to find a version that satisfies {requirement:?}");
|
anyhow::bail!("Failed to find a version that satisfies {requirement}");
|
||||||
};
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
version,
|
version,
|
||||||
|
|||||||
@@ -3,11 +3,9 @@
|
|||||||
//!
|
//!
|
||||||
//! [0]: https://binaries.soliditylang.org
|
//! [0]: https://binaries.soliditylang.org
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
use anyhow::Context;
|
|
||||||
use cache::get_or_download;
|
use cache::get_or_download;
|
||||||
use download::SolcDownloader;
|
use download::SolcDownloader;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use revive_dt_common::types::VersionOrRequirement;
|
use revive_dt_common::types::VersionOrRequirement;
|
||||||
|
|
||||||
@@ -15,6 +13,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.
|
||||||
///
|
///
|
||||||
@@ -25,18 +42,6 @@ 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!()
|
|
||||||
}
|
|
||||||
.context("Failed to initialize the Solc Downloader")?;
|
|
||||||
|
|
||||||
get_or_download(cache_directory, &downloader).await
|
get_or_download(cache_directory, &downloader).await
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user