mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-04-22 20:47:58 +00:00
Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 255de530c3 | |||
| c960f02417 | |||
| 5e19269124 | |||
| 458a0901d3 | |||
| 77f389bc74 | |||
| 897104857c | |||
| 3837ab86d3 | |||
| 9ae432b86a | |||
| 230d6729f4 | |||
| 7e26e5ebcc | |||
| e5c7bf300b | |||
| b2290b3177 | |||
| df6d485471 | |||
| 30a656844f | |||
| 1c335e5709 | |||
| 95ea886ba7 | |||
| c94e97cfd0 | |||
| 036579fb32 | |||
| 0bc55cf400 | |||
| ea29bb86c4 | |||
| fe6a4f790a | |||
| f98c15121d | |||
| 7b5ffed288 | |||
| 2ca220da0f | |||
| 4c9c001ad7 | |||
| 88f31348eb | |||
| cfbb5eefff | |||
| 2d01045ad2 | |||
| bd966300a5 | |||
| e8fa992a3b |
Generated
+3
@@ -4093,6 +4093,7 @@ dependencies = [
|
|||||||
"moka",
|
"moka",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"semver 1.0.26",
|
"semver 1.0.26",
|
||||||
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4159,6 +4160,7 @@ dependencies = [
|
|||||||
"alloy-primitives",
|
"alloy-primitives",
|
||||||
"alloy-sol-types",
|
"alloy-sol-types",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"regex",
|
||||||
"revive-common",
|
"revive-common",
|
||||||
"revive-dt-common",
|
"revive-dt-common",
|
||||||
"semver 1.0.26",
|
"semver 1.0.26",
|
||||||
@@ -4201,6 +4203,7 @@ name = "revive-dt-report"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"revive-dt-common",
|
||||||
"revive-dt-compiler",
|
"revive-dt-compiler",
|
||||||
"revive-dt-config",
|
"revive-dt-config",
|
||||||
"revive-dt-format",
|
"revive-dt-format",
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ clap = { version = "4", features = ["derive"] }
|
|||||||
foundry-compilers-artifacts = { version = "0.18.0" }
|
foundry-compilers-artifacts = { version = "0.18.0" }
|
||||||
futures = { version = "0.3.31" }
|
futures = { version = "0.3.31" }
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
|
regex = "1"
|
||||||
moka = "0.12.10"
|
moka = "0.12.10"
|
||||||
reqwest = { version = "0.12.15", features = ["json"] }
|
reqwest = { version = "0.12.15", features = ["json"] }
|
||||||
once_cell = "1.21"
|
once_cell = "1.21"
|
||||||
@@ -44,6 +45,7 @@ sp-core = "36.1.0"
|
|||||||
sp-runtime = "41.1.0"
|
sp-runtime = "41.1.0"
|
||||||
temp-dir = { version = "0.1.16" }
|
temp-dir = { version = "0.1.16" }
|
||||||
tempfile = "3.3"
|
tempfile = "3.3"
|
||||||
|
thiserror = "2"
|
||||||
tokio = { version = "1.47.0", default-features = false, features = [
|
tokio = { version = "1.47.0", default-features = false, features = [
|
||||||
"rt-multi-thread",
|
"rt-multi-thread",
|
||||||
"process",
|
"process",
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
"modes": [
|
"modes": [
|
||||||
"Y >=0.8.9",
|
"Y >=0.8.9",
|
||||||
"E",
|
"E"
|
||||||
"I"
|
|
||||||
],
|
],
|
||||||
"cases": [
|
"cases": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ anyhow = { workspace = true }
|
|||||||
moka = { workspace = true, features = ["sync"] }
|
moka = { workspace = true, features = ["sync"] }
|
||||||
once_cell = { workspace = true }
|
once_cell = { workspace = true }
|
||||||
semver = { workspace = true }
|
semver = { workspace = true }
|
||||||
|
serde = { workspace = true }
|
||||||
tokio = { workspace = true, default-features = false, features = ["time"] }
|
tokio = { workspace = true, default-features = false, features = ["time"] }
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
mod mode;
|
||||||
mod version_or_requirement;
|
mod version_or_requirement;
|
||||||
|
|
||||||
|
pub use mode::*;
|
||||||
pub use version_or_requirement::*;
|
pub use version_or_requirement::*;
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
use crate::types::VersionOrRequirement;
|
||||||
|
use semver::Version;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
/// This represents a mode that a given test should be run with, if possible.
|
||||||
|
///
|
||||||
|
/// We obtain this by taking a [`ParsedMode`], which may be looser or more strict
|
||||||
|
/// in its requirements, and then expanding it out into a list of [`Mode`]s.
|
||||||
|
///
|
||||||
|
/// Use [`ParsedMode::to_test_modes()`] to do this.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
|
||||||
|
pub struct Mode {
|
||||||
|
pub pipeline: ModePipeline,
|
||||||
|
pub optimize_setting: ModeOptimizerSetting,
|
||||||
|
pub version: Option<semver::VersionReq>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Mode {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.pipeline.fmt(f)?;
|
||||||
|
f.write_str(" ")?;
|
||||||
|
self.optimize_setting.fmt(f)?;
|
||||||
|
|
||||||
|
if let Some(version) = &self.version {
|
||||||
|
f.write_str(" ")?;
|
||||||
|
version.fmt(f)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mode {
|
||||||
|
/// Return all of the available mode combinations.
|
||||||
|
pub fn all() -> impl Iterator<Item = Mode> {
|
||||||
|
ModePipeline::test_cases().flat_map(|pipeline| {
|
||||||
|
ModeOptimizerSetting::test_cases().map(move |optimize_setting| Mode {
|
||||||
|
pipeline,
|
||||||
|
optimize_setting,
|
||||||
|
version: None,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves the [`Mode`]'s solidity version requirement into a [`VersionOrRequirement`] if
|
||||||
|
/// the requirement is present on the object. Otherwise, the passed default version is used.
|
||||||
|
pub fn compiler_version_to_use(&self, default: Version) -> VersionOrRequirement {
|
||||||
|
match self.version {
|
||||||
|
Some(ref requirement) => requirement.clone().into(),
|
||||||
|
None => default.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// What do we want the compiler to do?
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||||
|
pub enum ModePipeline {
|
||||||
|
/// Compile Solidity code via Yul IR
|
||||||
|
ViaYulIR,
|
||||||
|
/// Compile Solidity direct to assembly
|
||||||
|
ViaEVMAssembly,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ModePipeline {
|
||||||
|
type Err = anyhow::Error;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
// via Yul IR
|
||||||
|
"Y" => Ok(ModePipeline::ViaYulIR),
|
||||||
|
// Don't go via Yul IR
|
||||||
|
"E" => Ok(ModePipeline::ViaEVMAssembly),
|
||||||
|
// Anything else that we see isn't a mode at all
|
||||||
|
_ => Err(anyhow::anyhow!(
|
||||||
|
"Unsupported pipeline '{s}': expected 'Y' or 'E'"
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ModePipeline {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ModePipeline::ViaYulIR => f.write_str("Y"),
|
||||||
|
ModePipeline::ViaEVMAssembly => f.write_str("E"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModePipeline {
|
||||||
|
/// Should we go via Yul IR?
|
||||||
|
pub fn via_yul_ir(&self) -> bool {
|
||||||
|
matches!(self, ModePipeline::ViaYulIR)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator over the available pipelines that we'd like to test,
|
||||||
|
/// when an explicit pipeline was not specified.
|
||||||
|
pub fn test_cases() -> impl Iterator<Item = ModePipeline> + Clone {
|
||||||
|
[ModePipeline::ViaYulIR, ModePipeline::ViaEVMAssembly].into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||||
|
pub enum ModeOptimizerSetting {
|
||||||
|
/// 0 / -: Don't apply any optimizations
|
||||||
|
M0,
|
||||||
|
/// 1: Apply less than default optimizations
|
||||||
|
M1,
|
||||||
|
/// 2: Apply the default optimizations
|
||||||
|
M2,
|
||||||
|
/// 3 / +: Apply aggressive optimizations
|
||||||
|
M3,
|
||||||
|
/// s: Optimize for size
|
||||||
|
Ms,
|
||||||
|
/// z: Aggressively optimize for size
|
||||||
|
Mz,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ModeOptimizerSetting {
|
||||||
|
type Err = anyhow::Error;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s {
|
||||||
|
"M0" => Ok(ModeOptimizerSetting::M0),
|
||||||
|
"M1" => Ok(ModeOptimizerSetting::M1),
|
||||||
|
"M2" => Ok(ModeOptimizerSetting::M2),
|
||||||
|
"M3" => Ok(ModeOptimizerSetting::M3),
|
||||||
|
"Ms" => Ok(ModeOptimizerSetting::Ms),
|
||||||
|
"Mz" => Ok(ModeOptimizerSetting::Mz),
|
||||||
|
_ => Err(anyhow::anyhow!(
|
||||||
|
"Unsupported optimizer setting '{s}': expected 'M0', 'M1', 'M2', 'M3', 'Ms' or 'Mz'"
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ModeOptimizerSetting {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ModeOptimizerSetting::M0 => f.write_str("M0"),
|
||||||
|
ModeOptimizerSetting::M1 => f.write_str("M1"),
|
||||||
|
ModeOptimizerSetting::M2 => f.write_str("M2"),
|
||||||
|
ModeOptimizerSetting::M3 => f.write_str("M3"),
|
||||||
|
ModeOptimizerSetting::Ms => f.write_str("Ms"),
|
||||||
|
ModeOptimizerSetting::Mz => f.write_str("Mz"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModeOptimizerSetting {
|
||||||
|
/// An iterator over the available optimizer settings that we'd like to test,
|
||||||
|
/// when an explicit optimizer setting was not specified.
|
||||||
|
pub fn test_cases() -> impl Iterator<Item = ModeOptimizerSetting> + Clone {
|
||||||
|
[
|
||||||
|
// No optimizations:
|
||||||
|
ModeOptimizerSetting::M0,
|
||||||
|
// Aggressive optimizations:
|
||||||
|
ModeOptimizerSetting::M3,
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Are any optimizations enabled?
|
||||||
|
pub fn optimizations_enabled(&self) -> bool {
|
||||||
|
!matches!(self, ModeOptimizerSetting::M0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
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);
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
//! - Polkadot revive resolc compiler
|
//! - Polkadot revive resolc compiler
|
||||||
//! - Polkadot revive Wasm compiler
|
//! - Polkadot revive Wasm compiler
|
||||||
|
|
||||||
|
mod constants;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
@@ -19,6 +21,9 @@ use revive_dt_common::cached_fs::read_to_string;
|
|||||||
use revive_dt_common::types::VersionOrRequirement;
|
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.
|
||||||
|
pub use revive_dt_common::types::{Mode, ModeOptimizerSetting, ModePipeline};
|
||||||
|
|
||||||
pub mod revive_js;
|
pub mod revive_js;
|
||||||
pub mod revive_resolc;
|
pub mod revive_resolc;
|
||||||
pub mod solc;
|
pub mod solc;
|
||||||
@@ -43,13 +48,20 @@ pub trait SolidityCompiler {
|
|||||||
) -> impl Future<Output = anyhow::Result<PathBuf>>;
|
) -> impl Future<Output = anyhow::Result<PathBuf>>;
|
||||||
|
|
||||||
fn version(&self) -> anyhow::Result<Version>;
|
fn version(&self) -> anyhow::Result<Version>;
|
||||||
|
|
||||||
|
/// Does the compiler support the provided mode and version settings?
|
||||||
|
fn supports_mode(
|
||||||
|
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, Deserialize)]
|
||||||
pub struct CompilerInput {
|
pub struct CompilerInput {
|
||||||
pub enable_optimization: Option<bool>,
|
pub pipeline: Option<ModePipeline>,
|
||||||
pub via_ir: Option<bool>,
|
pub optimization: Option<ModeOptimizerSetting>,
|
||||||
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>,
|
||||||
@@ -85,8 +97,8 @@ where
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
input: CompilerInput {
|
input: CompilerInput {
|
||||||
enable_optimization: Default::default(),
|
pipeline: Default::default(),
|
||||||
via_ir: Default::default(),
|
optimization: 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(),
|
||||||
@@ -98,13 +110,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_optimization(mut self, value: impl Into<Option<bool>>) -> Self {
|
pub fn with_optimization(mut self, value: impl Into<Option<ModeOptimizerSetting>>) -> Self {
|
||||||
self.input.enable_optimization = value.into();
|
self.input.optimization = value.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_via_ir(mut self, value: impl Into<Option<bool>>) -> Self {
|
pub fn with_pipeline(mut self, value: impl Into<Option<ModePipeline>>) -> Self {
|
||||||
self.input.via_ir = value.into();
|
self.input.pipeline = value.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ use revive_solc_json_interface::{
|
|||||||
SolcStandardJsonOutput,
|
SolcStandardJsonOutput,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{CompilerInput, CompilerOutput, SolidityCompiler};
|
use super::constants::SOLC_VERSION_SUPPORTING_VIA_YUL_IR;
|
||||||
|
use crate::{CompilerInput, CompilerOutput, ModeOptimizerSetting, ModePipeline, SolidityCompiler};
|
||||||
|
|
||||||
use alloy::json_abi::JsonAbi;
|
use alloy::json_abi::JsonAbi;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
@@ -39,9 +40,8 @@ impl SolidityCompiler for Resolc {
|
|||||||
async fn build(
|
async fn build(
|
||||||
&self,
|
&self,
|
||||||
CompilerInput {
|
CompilerInput {
|
||||||
enable_optimization,
|
pipeline,
|
||||||
// Ignored and not honored since this is required for the resolc compilation.
|
optimization,
|
||||||
via_ir: _via_ir,
|
|
||||||
evm_version,
|
evm_version,
|
||||||
allow_paths,
|
allow_paths,
|
||||||
base_path,
|
base_path,
|
||||||
@@ -53,6 +53,12 @@ impl SolidityCompiler for Resolc {
|
|||||||
}: CompilerInput,
|
}: CompilerInput,
|
||||||
additional_options: Self::Options,
|
additional_options: Self::Options,
|
||||||
) -> anyhow::Result<CompilerOutput> {
|
) -> anyhow::Result<CompilerOutput> {
|
||||||
|
if !matches!(pipeline, None | Some(ModePipeline::ViaYulIR)) {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Resolc only supports the Y (via Yul IR) pipeline, but the provided pipeline is {pipeline:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let input = SolcStandardJsonInput {
|
let input = SolcStandardJsonInput {
|
||||||
language: SolcStandardJsonInputLanguage::Solidity,
|
language: SolcStandardJsonInputLanguage::Solidity,
|
||||||
sources: sources
|
sources: sources
|
||||||
@@ -81,7 +87,9 @@ impl SolidityCompiler for Resolc {
|
|||||||
output_selection: Some(SolcStandardJsonInputSettingsSelection::new_required()),
|
output_selection: Some(SolcStandardJsonInputSettingsSelection::new_required()),
|
||||||
via_ir: Some(true),
|
via_ir: Some(true),
|
||||||
optimizer: SolcStandardJsonInputSettingsOptimizer::new(
|
optimizer: SolcStandardJsonInputSettingsOptimizer::new(
|
||||||
enable_optimization.unwrap_or(false),
|
optimization
|
||||||
|
.unwrap_or(ModeOptimizerSetting::M0)
|
||||||
|
.optimizations_enabled(),
|
||||||
None,
|
None,
|
||||||
&Version::new(0, 0, 0),
|
&Version::new(0, 0, 0),
|
||||||
false,
|
false,
|
||||||
@@ -232,6 +240,18 @@ impl SolidityCompiler for Resolc {
|
|||||||
|
|
||||||
Version::parse(version_string).map_err(Into::into)
|
Version::parse(version_string).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn supports_mode(
|
||||||
|
compiler_version: &Version,
|
||||||
|
_optimize_setting: ModeOptimizerSetting,
|
||||||
|
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
|
||||||
|
&& compiler_version >= &SOLC_VERSION_SUPPORTING_VIA_YUL_IR
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ use revive_dt_common::types::VersionOrRequirement;
|
|||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use revive_dt_solc_binaries::download_solc;
|
use revive_dt_solc_binaries::download_solc;
|
||||||
|
|
||||||
use crate::{CompilerInput, CompilerOutput, SolidityCompiler};
|
use super::constants::SOLC_VERSION_SUPPORTING_VIA_YUL_IR;
|
||||||
|
use crate::{CompilerInput, CompilerOutput, ModeOptimizerSetting, ModePipeline, SolidityCompiler};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use foundry_compilers_artifacts::{
|
use foundry_compilers_artifacts::{
|
||||||
@@ -35,8 +36,8 @@ impl SolidityCompiler for Solc {
|
|||||||
async fn build(
|
async fn build(
|
||||||
&self,
|
&self,
|
||||||
CompilerInput {
|
CompilerInput {
|
||||||
enable_optimization,
|
pipeline,
|
||||||
via_ir,
|
optimization,
|
||||||
evm_version,
|
evm_version,
|
||||||
allow_paths,
|
allow_paths,
|
||||||
base_path,
|
base_path,
|
||||||
@@ -46,6 +47,17 @@ impl SolidityCompiler for Solc {
|
|||||||
}: CompilerInput,
|
}: CompilerInput,
|
||||||
_: Self::Options,
|
_: Self::Options,
|
||||||
) -> anyhow::Result<CompilerOutput> {
|
) -> anyhow::Result<CompilerOutput> {
|
||||||
|
let compiler_supports_via_ir = self.version()? >= SOLC_VERSION_SUPPORTING_VIA_YUL_IR;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// `supports_mode` is called prior to instantiating a compiler, we should never
|
||||||
|
// ask for something which is invalid.
|
||||||
|
let via_ir = match (pipeline, compiler_supports_via_ir) {
|
||||||
|
(pipeline, true) => pipeline.map(|p| p.via_yul_ir()),
|
||||||
|
(_pipeline, false) => None,
|
||||||
|
};
|
||||||
|
|
||||||
let input = SolcInput {
|
let input = SolcInput {
|
||||||
language: SolcLanguage::Solidity,
|
language: SolcLanguage::Solidity,
|
||||||
sources: Sources(
|
sources: Sources(
|
||||||
@@ -56,7 +68,7 @@ impl SolidityCompiler for Solc {
|
|||||||
),
|
),
|
||||||
settings: Settings {
|
settings: Settings {
|
||||||
optimizer: Optimizer {
|
optimizer: Optimizer {
|
||||||
enabled: enable_optimization,
|
enabled: optimization.map(|o| o.optimizations_enabled()),
|
||||||
details: Some(Default::default()),
|
details: Some(Default::default()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
@@ -222,6 +234,18 @@ impl SolidityCompiler for Solc {
|
|||||||
|
|
||||||
Version::parse(version_string).map_err(Into::into)
|
Version::parse(version_string).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
// (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::ViaYulIR
|
||||||
|
&& compiler_version >= &SOLC_VERSION_SUPPORTING_VIA_YUL_IR)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -58,10 +58,6 @@ pub struct Arguments {
|
|||||||
#[arg(long = "geth-start-timeout", default_value = "5000")]
|
#[arg(long = "geth-start-timeout", default_value = "5000")]
|
||||||
pub geth_start_timeout: u64,
|
pub geth_start_timeout: u64,
|
||||||
|
|
||||||
/// The test network chain ID.
|
|
||||||
#[arg(short, long = "network-id", default_value = "420420420")]
|
|
||||||
pub network_id: u64,
|
|
||||||
|
|
||||||
/// Configure nodes according to this genesis.json file.
|
/// Configure nodes according to this genesis.json file.
|
||||||
#[arg(long = "genesis", default_value = "genesis.json")]
|
#[arg(long = "genesis", default_value = "genesis.json")]
|
||||||
pub genesis_file: PathBuf,
|
pub genesis_file: PathBuf,
|
||||||
|
|||||||
+70
-26
@@ -13,7 +13,8 @@ use alloy::{
|
|||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use futures::StreamExt;
|
use futures::stream::futures_unordered::FuturesUnordered;
|
||||||
|
use futures::{Stream, StreamExt};
|
||||||
use revive_dt_common::iterators::FilesWithExtensionIterator;
|
use revive_dt_common::iterators::FilesWithExtensionIterator;
|
||||||
use revive_dt_node_interaction::EthereumNode;
|
use revive_dt_node_interaction::EthereumNode;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
@@ -22,6 +23,7 @@ use tokio::sync::{Mutex, RwLock, mpsc};
|
|||||||
use tracing::{Instrument, Level};
|
use tracing::{Instrument, Level};
|
||||||
use tracing_subscriber::{EnvFilter, FmtSubscriber};
|
use tracing_subscriber::{EnvFilter, FmtSubscriber};
|
||||||
|
|
||||||
|
use revive_dt_common::types::Mode;
|
||||||
use revive_dt_compiler::SolidityCompiler;
|
use revive_dt_compiler::SolidityCompiler;
|
||||||
use revive_dt_compiler::{Compiler, CompilerOutput};
|
use revive_dt_compiler::{Compiler, CompilerOutput};
|
||||||
use revive_dt_config::*;
|
use revive_dt_config::*;
|
||||||
@@ -34,7 +36,6 @@ use revive_dt_format::{
|
|||||||
corpus::Corpus,
|
corpus::Corpus,
|
||||||
input::{Input, Step},
|
input::{Input, Step},
|
||||||
metadata::{ContractInstance, ContractPathAndIdent, Metadata, MetadataFile},
|
metadata::{ContractInstance, ContractPathAndIdent, Metadata, MetadataFile},
|
||||||
mode::SolcMode,
|
|
||||||
};
|
};
|
||||||
use revive_dt_node::pool::NodePool;
|
use revive_dt_node::pool::NodePool;
|
||||||
use revive_dt_report::reporter::{Report, Span};
|
use revive_dt_report::reporter::{Report, Span};
|
||||||
@@ -44,7 +45,7 @@ static TEMP_DIR: LazyLock<TempDir> = LazyLock::new(|| TempDir::new().unwrap());
|
|||||||
type CompilationCache = Arc<
|
type CompilationCache = Arc<
|
||||||
RwLock<
|
RwLock<
|
||||||
HashMap<
|
HashMap<
|
||||||
(PathBuf, SolcMode, TestingPlatform),
|
(PathBuf, Mode, TestingPlatform),
|
||||||
Arc<Mutex<Option<Arc<(Version, CompilerOutput)>>>>,
|
Arc<Mutex<Option<Arc<(Version, CompilerOutput)>>>>,
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
@@ -55,8 +56,8 @@ type CompilationCache = Arc<
|
|||||||
struct Test {
|
struct Test {
|
||||||
metadata: Metadata,
|
metadata: Metadata,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
mode: SolcMode,
|
mode: Mode,
|
||||||
case_idx: usize,
|
case_idx: CaseIdx,
|
||||||
case: Case,
|
case: Case,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +145,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>(metadata_files);
|
let tests = prepare_tests::<L, F>(args, metadata_files);
|
||||||
let driver_task = start_driver_task::<L, F>(args, tests, span, report_tx)?;
|
let driver_task = start_driver_task::<L, F>(args, tests, span, report_tx)?;
|
||||||
let status_reporter_task = start_reporter_task(report_rx);
|
let status_reporter_task = start_reporter_task(report_rx);
|
||||||
|
|
||||||
@@ -153,7 +154,10 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_tests<L, F>(metadata_files: &[MetadataFile]) -> impl Iterator<Item = Test>
|
fn prepare_tests<L, F>(
|
||||||
|
args: &Arguments,
|
||||||
|
metadata_files: &[MetadataFile],
|
||||||
|
) -> impl Stream<Item = Test>
|
||||||
where
|
where
|
||||||
L: Platform,
|
L: Platform,
|
||||||
F: Platform,
|
F: Platform,
|
||||||
@@ -231,15 +235,53 @@ where
|
|||||||
metadata: metadata.clone(),
|
metadata: metadata.clone(),
|
||||||
path: metadata_file_path.to_path_buf(),
|
path: metadata_file_path.to_path_buf(),
|
||||||
mode: solc_mode,
|
mode: solc_mode,
|
||||||
case_idx,
|
case_idx: case_idx.into(),
|
||||||
case: case.clone(),
|
case: case.clone(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.map(async |test| test)
|
||||||
|
.collect::<FuturesUnordered<_>>()
|
||||||
|
.filter_map(async move |test| {
|
||||||
|
// Check that both compilers support this test, else we skip it
|
||||||
|
let is_supported = does_compiler_support_mode::<L>(args, &test.mode).await.ok().unwrap_or(false) &&
|
||||||
|
does_compiler_support_mode::<F>(args, &test.mode).await.ok().unwrap_or(false);
|
||||||
|
|
||||||
|
tracing::warn!(
|
||||||
|
metadata_file_path = %test.path.display(),
|
||||||
|
case_idx = %test.case_idx,
|
||||||
|
case_name = ?test.case.name,
|
||||||
|
mode = %test.mode,
|
||||||
|
"Skipping test as one or both of the compilers don't support it"
|
||||||
|
);
|
||||||
|
|
||||||
|
// We filter_map to avoid needing to clone `test`, but return it as-is.
|
||||||
|
if is_supported {
|
||||||
|
Some(test)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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()?;
|
||||||
|
|
||||||
|
Ok(P::Compiler::supports_mode(
|
||||||
|
&compiler_version,
|
||||||
|
mode.optimize_setting,
|
||||||
|
mode.pipeline,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_driver_task<L, F>(
|
fn start_driver_task<L, F>(
|
||||||
args: &Arguments,
|
args: &Arguments,
|
||||||
tests: impl Iterator<Item = Test>,
|
tests: impl Stream<Item = Test>,
|
||||||
span: Span,
|
span: Span,
|
||||||
report_tx: mpsc::UnboundedSender<(Test, CaseResult)>,
|
report_tx: mpsc::UnboundedSender<(Test, CaseResult)>,
|
||||||
) -> anyhow::Result<impl Future<Output = ()>>
|
) -> anyhow::Result<impl Future<Output = ()>>
|
||||||
@@ -254,7 +296,7 @@ where
|
|||||||
let compilation_cache = Arc::new(RwLock::new(HashMap::new()));
|
let compilation_cache = Arc::new(RwLock::new(HashMap::new()));
|
||||||
let number_concurrent_tasks = args.number_of_concurrent_tasks();
|
let number_concurrent_tasks = args.number_of_concurrent_tasks();
|
||||||
|
|
||||||
Ok(futures::stream::iter(tests).for_each_concurrent(
|
Ok(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.
|
||||||
@@ -284,7 +326,7 @@ where
|
|||||||
let result = handle_case_driver::<L, F>(
|
let result = handle_case_driver::<L, F>(
|
||||||
&test.path,
|
&test.path,
|
||||||
&test.metadata,
|
&test.metadata,
|
||||||
test.case_idx.into(),
|
test.case_idx,
|
||||||
&test.case,
|
&test.case,
|
||||||
test.mode.clone(),
|
test.mode.clone(),
|
||||||
args,
|
args,
|
||||||
@@ -328,13 +370,13 @@ async fn start_reporter_task(mut report_rx: mpsc::UnboundedReceiver<(Test, CaseR
|
|||||||
Ok(_inputs) => {
|
Ok(_inputs) => {
|
||||||
number_of_successes += 1;
|
number_of_successes += 1;
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{GREEN}Case Succeeded:{COLOUR_RESET} {test_path} -> {case_name}:{case_idx} (mode: {test_mode:?})"
|
"{GREEN}Case Succeeded:{COLOUR_RESET} {test_path} -> {case_name}:{case_idx} (mode: {test_mode})"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
number_of_failures += 1;
|
number_of_failures += 1;
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{RED}Case Failed:{COLOUR_RESET} {test_path} -> {case_name}:{case_idx} (mode: {test_mode:?})"
|
"{RED}Case Failed:{COLOUR_RESET} {test_path} -> {case_name}:{case_idx} (mode: {test_mode})"
|
||||||
);
|
);
|
||||||
failures.push((test, err));
|
failures.push((test, err));
|
||||||
}
|
}
|
||||||
@@ -357,7 +399,7 @@ async fn start_reporter_task(mut report_rx: mpsc::UnboundedReceiver<(Test, CaseR
|
|||||||
let test_mode = test.mode.clone();
|
let test_mode = test.mode.clone();
|
||||||
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"---- {RED}Case Failed:{COLOUR_RESET} {test_path} -> {case_name}:{case_idx} (mode: {test_mode:?}) ----\n\n{err}\n"
|
"---- {RED}Case Failed:{COLOUR_RESET} {test_path} -> {case_name}:{case_idx} (mode: {test_mode}) ----\n\n{err}\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,7 +418,7 @@ async fn handle_case_driver<L, F>(
|
|||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
case_idx: CaseIdx,
|
case_idx: CaseIdx,
|
||||||
case: &Case,
|
case: &Case,
|
||||||
mode: SolcMode,
|
mode: Mode,
|
||||||
config: &Arguments,
|
config: &Arguments,
|
||||||
compilation_cache: CompilationCache,
|
compilation_cache: CompilationCache,
|
||||||
leader_node: &L::Blockchain,
|
leader_node: &L::Blockchain,
|
||||||
@@ -617,7 +659,7 @@ where
|
|||||||
async fn get_or_build_contracts<P: Platform>(
|
async fn get_or_build_contracts<P: Platform>(
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
metadata_file_path: &Path,
|
metadata_file_path: &Path,
|
||||||
mode: SolcMode,
|
mode: Mode,
|
||||||
config: &Arguments,
|
config: &Arguments,
|
||||||
compilation_cache: CompilationCache,
|
compilation_cache: CompilationCache,
|
||||||
deployed_libraries: &HashMap<ContractInstance, (Address, JsonAbi)>,
|
deployed_libraries: &HashMap<ContractInstance, (Address, JsonAbi)>,
|
||||||
@@ -636,16 +678,16 @@ async fn get_or_build_contracts<P: Platform>(
|
|||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
tracing::debug!(?key, "Compiled contracts cache miss");
|
tracing::debug!(?key, "Compiled contracts cache miss");
|
||||||
let compiled_contracts = Arc::new(
|
let compiled_contracts = compile_contracts::<P>(
|
||||||
compile_contracts::<P>(
|
|
||||||
metadata,
|
metadata,
|
||||||
metadata_file_path,
|
metadata_file_path,
|
||||||
&mode,
|
&mode,
|
||||||
config,
|
config,
|
||||||
deployed_libraries,
|
deployed_libraries,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?;
|
||||||
);
|
let compiled_contracts = Arc::new(compiled_contracts);
|
||||||
|
|
||||||
*compilation_artifact = Some(compiled_contracts.clone());
|
*compilation_artifact = Some(compiled_contracts.clone());
|
||||||
return Ok(compiled_contracts.clone());
|
return Ok(compiled_contracts.clone());
|
||||||
}
|
}
|
||||||
@@ -660,16 +702,17 @@ async fn get_or_build_contracts<P: Platform>(
|
|||||||
mutex
|
mutex
|
||||||
};
|
};
|
||||||
let mut compilation_artifact = mutex.lock().await;
|
let mut compilation_artifact = mutex.lock().await;
|
||||||
let compiled_contracts = Arc::new(
|
|
||||||
compile_contracts::<P>(
|
let compiled_contracts = compile_contracts::<P>(
|
||||||
metadata,
|
metadata,
|
||||||
metadata_file_path,
|
metadata_file_path,
|
||||||
&mode,
|
&mode,
|
||||||
config,
|
config,
|
||||||
deployed_libraries,
|
deployed_libraries,
|
||||||
)
|
)
|
||||||
.await?,
|
.await?;
|
||||||
);
|
let compiled_contracts = Arc::new(compiled_contracts);
|
||||||
|
|
||||||
*compilation_artifact = Some(compiled_contracts.clone());
|
*compilation_artifact = Some(compiled_contracts.clone());
|
||||||
Ok(compiled_contracts.clone())
|
Ok(compiled_contracts.clone())
|
||||||
}
|
}
|
||||||
@@ -677,7 +720,7 @@ async fn get_or_build_contracts<P: Platform>(
|
|||||||
async fn compile_contracts<P: Platform>(
|
async fn compile_contracts<P: Platform>(
|
||||||
metadata: &Metadata,
|
metadata: &Metadata,
|
||||||
metadata_file_path: &Path,
|
metadata_file_path: &Path,
|
||||||
mode: &SolcMode,
|
mode: &Mode,
|
||||||
config: &Arguments,
|
config: &Arguments,
|
||||||
deployed_libraries: &HashMap<ContractInstance, (Address, JsonAbi)>,
|
deployed_libraries: &HashMap<ContractInstance, (Address, JsonAbi)>,
|
||||||
) -> anyhow::Result<(Version, CompilerOutput)> {
|
) -> anyhow::Result<(Version, CompilerOutput)> {
|
||||||
@@ -695,7 +738,8 @@ async fn compile_contracts<P: Platform>(
|
|||||||
|
|
||||||
let compiler = Compiler::<P::Compiler>::new()
|
let compiler = Compiler::<P::Compiler>::new()
|
||||||
.with_allow_path(metadata.directory()?)
|
.with_allow_path(metadata.directory()?)
|
||||||
.with_optimization(mode.solc_optimize());
|
.with_optimization(mode.optimize_setting)
|
||||||
|
.with_pipeline(mode.pipeline);
|
||||||
let mut compiler = metadata
|
let mut compiler = metadata
|
||||||
.files_to_compile()?
|
.files_to_compile()?
|
||||||
.try_fold(compiler, |compiler, path| compiler.with_source(&path))?;
|
.try_fold(compiler, |compiler, path| compiler.with_source(&path))?;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ alloy = { workspace = true }
|
|||||||
alloy-primitives = { workspace = true }
|
alloy-primitives = { workspace = true }
|
||||||
alloy-sol-types = { workspace = true }
|
alloy-sol-types = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
regex = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
semver = { workspace = true }
|
semver = { workspace = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use revive_dt_common::macros::define_wrapper_type;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
input::{Expected, Step},
|
input::{Expected, Step},
|
||||||
mode::Mode,
|
mode::ParsedMode,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)]
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, Eq, PartialEq)]
|
||||||
@@ -16,7 +16,7 @@ pub struct Case {
|
|||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub modes: Option<Vec<Mode>>,
|
pub modes: Option<Vec<ParsedMode>>,
|
||||||
|
|
||||||
#[serde(rename = "inputs")]
|
#[serde(rename = "inputs")]
|
||||||
pub steps: Vec<Step>,
|
pub steps: Vec<Step>,
|
||||||
@@ -67,3 +67,9 @@ define_wrapper_type!(
|
|||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct CaseIdx(usize);
|
pub struct CaseIdx(usize);
|
||||||
);
|
);
|
||||||
|
|
||||||
|
impl std::fmt::Display for CaseIdx {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,12 +13,10 @@ use serde::{Deserialize, Serialize};
|
|||||||
use revive_common::EVMVersion;
|
use revive_common::EVMVersion;
|
||||||
use revive_dt_common::{
|
use revive_dt_common::{
|
||||||
cached_fs::read_to_string, iterators::FilesWithExtensionIterator, macros::define_wrapper_type,
|
cached_fs::read_to_string, iterators::FilesWithExtensionIterator, macros::define_wrapper_type,
|
||||||
|
types::Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{case::Case, mode::ParsedMode};
|
||||||
case::Case,
|
|
||||||
mode::{Mode, SolcMode},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const METADATA_FILE_EXTENSION: &str = "json";
|
pub const METADATA_FILE_EXTENSION: &str = "json";
|
||||||
pub const SOLIDITY_CASE_FILE_EXTENSION: &str = "sol";
|
pub const SOLIDITY_CASE_FILE_EXTENSION: &str = "sol";
|
||||||
@@ -68,7 +66,7 @@ pub struct Metadata {
|
|||||||
pub libraries: Option<BTreeMap<PathBuf, BTreeMap<ContractIdent, ContractInstance>>>,
|
pub libraries: Option<BTreeMap<PathBuf, BTreeMap<ContractIdent, ContractInstance>>>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub modes: Option<Vec<Mode>>,
|
pub modes: Option<Vec<ParsedMode>>,
|
||||||
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub file_path: Option<PathBuf>,
|
pub file_path: Option<PathBuf>,
|
||||||
@@ -86,21 +84,12 @@ pub struct Metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Metadata {
|
impl Metadata {
|
||||||
/// Returns the solc modes of this metadata, inserting a default mode if not present.
|
/// Returns the modes that we should test from this metadata.
|
||||||
pub fn solc_modes(&self) -> Vec<SolcMode> {
|
pub fn solc_modes(&self) -> Vec<Mode> {
|
||||||
self.modes
|
match &self.modes {
|
||||||
.to_owned()
|
Some(modes) => ParsedMode::many_to_modes(modes.iter()).collect(),
|
||||||
.unwrap_or_else(|| vec![Mode::Solidity(Default::default())])
|
None => Mode::all().collect(),
|
||||||
.iter()
|
|
||||||
.filter_map(|mode| match mode {
|
|
||||||
Mode::Solidity(solc_mode) => Some(solc_mode),
|
|
||||||
Mode::Unknown(mode) => {
|
|
||||||
tracing::debug!("compiler: ignoring unknown mode '{mode}'");
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the base directory of this metadata.
|
/// Returns the base directory of this metadata.
|
||||||
|
|||||||
+249
-110
@@ -1,123 +1,262 @@
|
|||||||
use revive_dt_common::types::VersionOrRequirement;
|
use regex::Regex;
|
||||||
use semver::Version;
|
use revive_dt_common::types::{Mode, ModeOptimizerSetting, ModePipeline};
|
||||||
use serde::de::Deserializer;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
/// Specifies the compilation mode of the test artifact.
|
/// This represents a mode that has been parsed from test metadata.
|
||||||
#[derive(Hash, Debug, Clone, Eq, PartialEq)]
|
///
|
||||||
pub enum Mode {
|
/// Mode strings can take the following form (in pseudo-regex):
|
||||||
Solidity(SolcMode),
|
///
|
||||||
Unknown(String),
|
/// ```text
|
||||||
|
/// [YEILV][+-]? (M[0123sz])? <semver>?
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// We can parse valid mode strings into [`ParsedMode`] using [`ParsedMode::from_str`].
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
|
#[serde(try_from = "String", into = "String")]
|
||||||
|
pub struct ParsedMode {
|
||||||
|
pub pipeline: Option<ModePipeline>,
|
||||||
|
pub optimize_flag: Option<bool>,
|
||||||
|
pub optimize_setting: Option<ModeOptimizerSetting>,
|
||||||
|
pub version: Option<semver::VersionReq>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify Solidity specific compiler options.
|
impl FromStr for ParsedMode {
|
||||||
#[derive(Hash, Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
type Err = anyhow::Error;
|
||||||
pub struct SolcMode {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
pub solc_version: Option<semver::VersionReq>,
|
static REGEX: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
solc_optimize: Option<bool>,
|
Regex::new(r"(?x)
|
||||||
pub llvm_optimizer_settings: Vec<String>,
|
^
|
||||||
mode_string: String,
|
(?:(?P<pipeline>[YEILV])(?P<optimize_flag>[+-])?)? # Pipeline to use eg Y, E+, E-
|
||||||
}
|
\s*
|
||||||
|
(?P<optimize_setting>M[a-zA-Z0-9])? # Optimize setting eg M0, Ms, Mz
|
||||||
|
\s*
|
||||||
|
(?P<version>[>=<]*\d+(?:\.\d+)*)? # Optional semver version eg >=0.8.0, 0.7, <0.8
|
||||||
|
$
|
||||||
|
").unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
impl SolcMode {
|
let Some(caps) = REGEX.captures(s) else {
|
||||||
/// Try to parse a mode string into a solc mode.
|
anyhow::bail!("Cannot parse mode '{s}' from string");
|
||||||
/// Returns `None` if the string wasn't a solc YUL mode string.
|
|
||||||
///
|
|
||||||
/// The mode string is expected to start with the `Y` ID (YUL ID),
|
|
||||||
/// optionally followed by `+` or `-` for the solc optimizer settings.
|
|
||||||
///
|
|
||||||
/// Options can be separated by a whitespace contain the following
|
|
||||||
/// - A solc `SemVer version requirement` string
|
|
||||||
/// - One or more `-OX` where X is a supposed to be an LLVM opt mode
|
|
||||||
pub fn parse_from_mode_string(mode_string: &str) -> Option<Self> {
|
|
||||||
let mut result = Self {
|
|
||||||
mode_string: mode_string.to_string(),
|
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut parts = mode_string.trim().split(" ");
|
let pipeline = match caps.name("pipeline") {
|
||||||
|
Some(m) => Some(ModePipeline::from_str(m.as_str())?),
|
||||||
match parts.next()? {
|
None => None,
|
||||||
"Y" => {}
|
|
||||||
"Y+" => result.solc_optimize = Some(true),
|
|
||||||
"Y-" => result.solc_optimize = Some(false),
|
|
||||||
_ => return None,
|
|
||||||
}
|
|
||||||
|
|
||||||
for part in parts {
|
|
||||||
if let Ok(solc_version) = semver::VersionReq::parse(part) {
|
|
||||||
result.solc_version = Some(solc_version);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Some(level) = part.strip_prefix("-O") {
|
|
||||||
result.llvm_optimizer_settings.push(level.to_string());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
panic!("the YUL mode string {mode_string} failed to parse, invalid part: {part}")
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether to enable the solc optimizer.
|
|
||||||
pub fn solc_optimize(&self) -> bool {
|
|
||||||
self.solc_optimize.unwrap_or(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the latest matching solc patch version. Returns:
|
|
||||||
/// - `latest_supported` if no version request was specified.
|
|
||||||
/// - A matching version with the same minor version as `latest_supported`, if any.
|
|
||||||
/// - `None` if no minor version of the `latest_supported` version matches.
|
|
||||||
pub fn last_patch_version(&self, latest_supported: &Version) -> Option<Version> {
|
|
||||||
let Some(version_req) = self.solc_version.as_ref() else {
|
|
||||||
return Some(latest_supported.to_owned());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// lgtm
|
let optimize_flag = caps.name("optimize_flag").map(|m| m.as_str() == "+");
|
||||||
for patch in (0..latest_supported.patch + 1).rev() {
|
|
||||||
let version = Version::new(0, latest_supported.minor, patch);
|
|
||||||
if version_req.matches(&version) {
|
|
||||||
return Some(version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
let optimize_setting = match caps.name("optimize_setting") {
|
||||||
}
|
Some(m) => Some(ModeOptimizerSetting::from_str(m.as_str())?),
|
||||||
|
None => None,
|
||||||
/// Resolves the [`SolcMode`]'s solidity version requirement into a [`VersionOrRequirement`] if
|
|
||||||
/// the requirement is present on the object. Otherwise, the passed default version is used.
|
|
||||||
pub fn compiler_version_to_use(&self, default: Version) -> VersionOrRequirement {
|
|
||||||
match self.solc_version {
|
|
||||||
Some(ref requirement) => requirement.clone().into(),
|
|
||||||
None => default.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Mode {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let mode_string = String::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
if let Some(solc_mode) = SolcMode::parse_from_mode_string(&mode_string) {
|
|
||||||
return Ok(Self::Solidity(solc_mode));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self::Unknown(mode_string))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for Mode {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
let string = match self {
|
|
||||||
Mode::Solidity(solc_mode) => &solc_mode.mode_string,
|
|
||||||
Mode::Unknown(string) => string,
|
|
||||||
};
|
};
|
||||||
string.serialize(serializer)
|
|
||||||
|
let version = match caps.name("version") {
|
||||||
|
Some(m) => Some(semver::VersionReq::parse(m.as_str()).map_err(|e| {
|
||||||
|
anyhow::anyhow!("Cannot parse the version requirement '{}': {e}", m.as_str())
|
||||||
|
})?),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ParsedMode {
|
||||||
|
pipeline,
|
||||||
|
optimize_flag,
|
||||||
|
optimize_setting,
|
||||||
|
version,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ParsedMode {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let mut has_written = false;
|
||||||
|
|
||||||
|
if let Some(pipeline) = self.pipeline {
|
||||||
|
pipeline.fmt(f)?;
|
||||||
|
if let Some(optimize_flag) = self.optimize_flag {
|
||||||
|
f.write_str(if optimize_flag { "+" } else { "-" })?;
|
||||||
|
}
|
||||||
|
has_written = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(optimize_setting) = self.optimize_setting {
|
||||||
|
if has_written {
|
||||||
|
f.write_str(" ")?;
|
||||||
|
}
|
||||||
|
optimize_setting.fmt(f)?;
|
||||||
|
has_written = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(version) = &self.version {
|
||||||
|
if has_written {
|
||||||
|
f.write_str(" ")?;
|
||||||
|
}
|
||||||
|
version.fmt(f)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParsedMode> for String {
|
||||||
|
fn from(parsed_mode: ParsedMode) -> Self {
|
||||||
|
parsed_mode.to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<String> for ParsedMode {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
ParsedMode::from_str(&value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParsedMode {
|
||||||
|
/// This takes a [`ParsedMode`] and expands it into a list of [`Mode`]s that we should try.
|
||||||
|
pub fn to_modes(&self) -> impl Iterator<Item = Mode> {
|
||||||
|
let pipeline_iter = self.pipeline.as_ref().map_or_else(
|
||||||
|
|| EitherIter::A(ModePipeline::test_cases()),
|
||||||
|
|p| EitherIter::B(std::iter::once(*p)),
|
||||||
|
);
|
||||||
|
|
||||||
|
let optimize_flag_setting = self.optimize_flag.map(|flag| {
|
||||||
|
if flag {
|
||||||
|
ModeOptimizerSetting::M3
|
||||||
|
} else {
|
||||||
|
ModeOptimizerSetting::M0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let optimize_flag_iter = match optimize_flag_setting {
|
||||||
|
Some(setting) => EitherIter::A(std::iter::once(setting)),
|
||||||
|
None => EitherIter::B(ModeOptimizerSetting::test_cases()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let optimize_settings_iter = self.optimize_setting.as_ref().map_or_else(
|
||||||
|
|| EitherIter::A(optimize_flag_iter),
|
||||||
|
|s| EitherIter::B(std::iter::once(*s)),
|
||||||
|
);
|
||||||
|
|
||||||
|
pipeline_iter.flat_map(move |pipeline| {
|
||||||
|
optimize_settings_iter
|
||||||
|
.clone()
|
||||||
|
.map(move |optimize_setting| Mode {
|
||||||
|
pipeline,
|
||||||
|
optimize_setting,
|
||||||
|
version: self.version.clone(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a set of [`Mode`]s that correspond to the given [`ParsedMode`]s.
|
||||||
|
/// This avoids any duplicate entries.
|
||||||
|
pub fn many_to_modes<'a>(
|
||||||
|
parsed: impl Iterator<Item = &'a ParsedMode>,
|
||||||
|
) -> impl Iterator<Item = Mode> {
|
||||||
|
let modes: HashSet<_> = parsed.flat_map(|p| p.to_modes()).collect();
|
||||||
|
modes.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An iterator that could be either of two iterators.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum EitherIter<A, B> {
|
||||||
|
A(A),
|
||||||
|
B(B),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A, B> Iterator for EitherIter<A, B>
|
||||||
|
where
|
||||||
|
A: Iterator,
|
||||||
|
B: Iterator<Item = A::Item>,
|
||||||
|
{
|
||||||
|
type Item = A::Item;
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self {
|
||||||
|
EitherIter::A(iter) => iter.next(),
|
||||||
|
EitherIter::B(iter) => iter.next(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parsed_mode_from_str() {
|
||||||
|
let strings = vec![
|
||||||
|
("Mz", "Mz"),
|
||||||
|
("Y", "Y"),
|
||||||
|
("Y+", "Y+"),
|
||||||
|
("Y-", "Y-"),
|
||||||
|
("E", "E"),
|
||||||
|
("E+", "E+"),
|
||||||
|
("E-", "E-"),
|
||||||
|
("Y M0", "Y M0"),
|
||||||
|
("Y M1", "Y M1"),
|
||||||
|
("Y M2", "Y M2"),
|
||||||
|
("Y M3", "Y M3"),
|
||||||
|
("Y Ms", "Y Ms"),
|
||||||
|
("Y Mz", "Y Mz"),
|
||||||
|
("E M0", "E M0"),
|
||||||
|
("E M1", "E M1"),
|
||||||
|
("E M2", "E M2"),
|
||||||
|
("E M3", "E M3"),
|
||||||
|
("E Ms", "E Ms"),
|
||||||
|
("E Mz", "E Mz"),
|
||||||
|
// When stringifying semver again, 0.8.0 becomes ^0.8.0 (same meaning)
|
||||||
|
("Y 0.8.0", "Y ^0.8.0"),
|
||||||
|
("E+ 0.8.0", "E+ ^0.8.0"),
|
||||||
|
("Y M3 >=0.8.0", "Y M3 >=0.8.0"),
|
||||||
|
("E Mz <0.7.0", "E Mz <0.7.0"),
|
||||||
|
// We can parse +- _and_ M1/M2 but the latter takes priority.
|
||||||
|
("Y+ M1 0.8.0", "Y+ M1 ^0.8.0"),
|
||||||
|
("E- M2 0.7.0", "E- M2 ^0.7.0"),
|
||||||
|
// We don't see this in the wild but it is parsed.
|
||||||
|
("<=0.8", "<=0.8"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (actual, expected) in strings {
|
||||||
|
let parsed = ParsedMode::from_str(actual)
|
||||||
|
.expect(format!("Failed to parse mode string '{actual}'").as_str());
|
||||||
|
assert_eq!(
|
||||||
|
expected,
|
||||||
|
parsed.to_string(),
|
||||||
|
"Mode string '{actual}' did not parse to '{expected}': got '{parsed}'"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parsed_mode_to_test_modes() {
|
||||||
|
let strings = vec![
|
||||||
|
("Mz", vec!["Y Mz", "E Mz"]),
|
||||||
|
("Y", vec!["Y M0", "Y M3"]),
|
||||||
|
("E", vec!["E M0", "E M3"]),
|
||||||
|
("Y+", vec!["Y M3"]),
|
||||||
|
("Y-", vec!["Y M0"]),
|
||||||
|
("Y <=0.8", vec!["Y M0 <=0.8", "Y M3 <=0.8"]),
|
||||||
|
(
|
||||||
|
"<=0.8",
|
||||||
|
vec!["Y M0 <=0.8", "Y M3 <=0.8", "E M0 <=0.8", "E M3 <=0.8"],
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (actual, expected) in strings {
|
||||||
|
let parsed = ParsedMode::from_str(actual)
|
||||||
|
.expect(format!("Failed to parse mode string '{actual}'").as_str());
|
||||||
|
let expected_set: HashSet<_> = expected.into_iter().map(|s| s.to_owned()).collect();
|
||||||
|
let actual_set: HashSet<_> = parsed.to_modes().map(|m| m.to_string()).collect();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
expected_set, actual_set,
|
||||||
|
"Mode string '{actual}' did not expand to '{expected_set:?}': got '{actual_set:?}'"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-6
@@ -60,7 +60,6 @@ pub struct GethNode {
|
|||||||
geth: PathBuf,
|
geth: PathBuf,
|
||||||
id: u32,
|
id: u32,
|
||||||
handle: Option<Child>,
|
handle: Option<Child>,
|
||||||
network_id: u64,
|
|
||||||
start_timeout: u64,
|
start_timeout: u64,
|
||||||
wallet: EthereumWallet,
|
wallet: EthereumWallet,
|
||||||
nonce_manager: CachedNonceManager,
|
nonce_manager: CachedNonceManager,
|
||||||
@@ -165,8 +164,6 @@ impl GethNode {
|
|||||||
.arg(&self.data_directory)
|
.arg(&self.data_directory)
|
||||||
.arg("--ipcpath")
|
.arg("--ipcpath")
|
||||||
.arg(&self.connection_string)
|
.arg(&self.connection_string)
|
||||||
.arg("--networkid")
|
|
||||||
.arg(self.network_id.to_string())
|
|
||||||
.arg("--nodiscover")
|
.arg("--nodiscover")
|
||||||
.arg("--maxpeers")
|
.arg("--maxpeers")
|
||||||
.arg("0")
|
.arg("0")
|
||||||
@@ -213,6 +210,7 @@ impl GethNode {
|
|||||||
|
|
||||||
let maximum_wait_time = Duration::from_millis(self.start_timeout);
|
let maximum_wait_time = Duration::from_millis(self.start_timeout);
|
||||||
let mut stderr = BufReader::new(logs_file).lines();
|
let mut stderr = BufReader::new(logs_file).lines();
|
||||||
|
let mut lines = vec![];
|
||||||
loop {
|
loop {
|
||||||
if let Some(Ok(line)) = stderr.next() {
|
if let Some(Ok(line)) = stderr.next() {
|
||||||
if line.contains(Self::ERROR_MARKER) {
|
if line.contains(Self::ERROR_MARKER) {
|
||||||
@@ -221,9 +219,14 @@ impl GethNode {
|
|||||||
if line.contains(Self::READY_MARKER) {
|
if line.contains(Self::READY_MARKER) {
|
||||||
return Ok(self);
|
return Ok(self);
|
||||||
}
|
}
|
||||||
|
lines.push(line);
|
||||||
}
|
}
|
||||||
if Instant::now().duration_since(start_time) > maximum_wait_time {
|
if Instant::now().duration_since(start_time) > maximum_wait_time {
|
||||||
anyhow::bail!("Timeout in starting geth");
|
anyhow::bail!(
|
||||||
|
"Timeout in starting geth: took longer than {}ms. stdout:\n\n{}\n",
|
||||||
|
self.start_timeout,
|
||||||
|
lines.join("\n")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,7 +260,11 @@ impl GethNode {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
ProviderBuilder::new()
|
ProviderBuilder::new()
|
||||||
.disable_recommended_fillers()
|
.disable_recommended_fillers()
|
||||||
.filler(FallbackGasFiller::new(500_000_000, 500_000_000, 1))
|
.filler(FallbackGasFiller::new(
|
||||||
|
25_000_000,
|
||||||
|
1_000_000_000,
|
||||||
|
1_000_000_000,
|
||||||
|
))
|
||||||
.filler(ChainIdFiller::default())
|
.filler(ChainIdFiller::default())
|
||||||
.filler(NonceFiller::new(nonce_manager))
|
.filler(NonceFiller::new(nonce_manager))
|
||||||
.wallet(wallet)
|
.wallet(wallet)
|
||||||
@@ -517,7 +524,6 @@ impl Node for GethNode {
|
|||||||
geth: config.geth.clone(),
|
geth: config.geth.clone(),
|
||||||
id,
|
id,
|
||||||
handle: None,
|
handle: None,
|
||||||
network_id: config.network_id,
|
|
||||||
start_timeout: config.geth_start_timeout,
|
start_timeout: config.geth_start_timeout,
|
||||||
wallet,
|
wallet,
|
||||||
// We know that we only need to be storing 2 files so we can specify that when creating
|
// We know that we only need to be storing 2 files so we can specify that when creating
|
||||||
|
|||||||
@@ -367,9 +367,9 @@ impl KitchensinkNode {
|
|||||||
.disable_recommended_fillers()
|
.disable_recommended_fillers()
|
||||||
.network::<KitchenSinkNetwork>()
|
.network::<KitchenSinkNetwork>()
|
||||||
.filler(FallbackGasFiller::new(
|
.filler(FallbackGasFiller::new(
|
||||||
30_000_000,
|
25_000_000,
|
||||||
200_000_000_000,
|
1_000_000_000,
|
||||||
3_000_000_000,
|
1_000_000_000,
|
||||||
))
|
))
|
||||||
.filler(ChainIdFiller::default())
|
.filler(ChainIdFiller::default())
|
||||||
.filler(NonceFiller::new(nonce_manager))
|
.filler(NonceFiller::new(nonce_manager))
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ repository.workspace = true
|
|||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
revive-dt-common = { workspace = true }
|
||||||
revive-dt-config = { workspace = true }
|
revive-dt-config = { workspace = true }
|
||||||
revive-dt-format = { workspace = true }
|
revive-dt-format = { workspace = true }
|
||||||
revive-dt-compiler = { workspace = true }
|
revive-dt-compiler = { workspace = true }
|
||||||
|
|||||||
@@ -12,18 +12,19 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use revive_dt_compiler::{CompilerInput, CompilerOutput};
|
use serde::Serialize;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
|
use revive_dt_common::types::Mode;
|
||||||
|
use revive_dt_compiler::{CompilerInput, CompilerOutput};
|
||||||
use revive_dt_config::{Arguments, TestingPlatform};
|
use revive_dt_config::{Arguments, TestingPlatform};
|
||||||
use revive_dt_format::{corpus::Corpus, mode::SolcMode};
|
use revive_dt_format::corpus::Corpus;
|
||||||
|
|
||||||
use crate::analyzer::CompilerStatistics;
|
use crate::analyzer::CompilerStatistics;
|
||||||
|
|
||||||
pub(crate) static REPORTER: OnceLock<Mutex<Report>> = OnceLock::new();
|
pub(crate) static REPORTER: OnceLock<Mutex<Report>> = OnceLock::new();
|
||||||
|
|
||||||
/// The `Report` datastructure stores all relevant inforamtion required for generating reports.
|
/// The `Report` datastructure stores all relevant inforamtion required for generating reports.
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Serialize)]
|
||||||
pub struct Report {
|
pub struct Report {
|
||||||
/// The configuration used during the test.
|
/// The configuration used during the test.
|
||||||
pub config: Arguments,
|
pub config: Arguments,
|
||||||
@@ -41,14 +42,14 @@ pub struct Report {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Contains a compiled contract.
|
/// Contains a compiled contract.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
pub struct CompilationTask {
|
pub struct CompilationTask {
|
||||||
/// The observed compiler input.
|
/// The observed compiler input.
|
||||||
pub json_input: CompilerInput,
|
pub json_input: CompilerInput,
|
||||||
/// The observed compiler output.
|
/// The observed compiler output.
|
||||||
pub json_output: Option<CompilerOutput>,
|
pub json_output: Option<CompilerOutput>,
|
||||||
/// The observed compiler mode.
|
/// The observed compiler mode.
|
||||||
pub mode: SolcMode,
|
pub mode: Mode,
|
||||||
/// The observed compiler version.
|
/// The observed compiler version.
|
||||||
pub compiler_version: String,
|
pub compiler_version: String,
|
||||||
/// The observed error, if any.
|
/// The observed error, if any.
|
||||||
@@ -56,7 +57,7 @@ pub struct CompilationTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a report about a compilation task.
|
/// Represents a report about a compilation task.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
pub struct CompilationResult {
|
pub struct CompilationResult {
|
||||||
/// The observed compilation task.
|
/// The observed compilation task.
|
||||||
pub compilation_task: CompilationTask,
|
pub compilation_task: CompilationTask,
|
||||||
@@ -65,7 +66,7 @@ pub struct CompilationResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The [Span] struct indicates the context of what is being reported.
|
/// The [Span] struct indicates the context of what is being reported.
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Serialize)]
|
||||||
pub struct Span {
|
pub struct Span {
|
||||||
/// The corpus index this belongs to.
|
/// The corpus index this belongs to.
|
||||||
corpus: usize,
|
corpus: usize,
|
||||||
|
|||||||
Reference in New Issue
Block a user