mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-06-15 03:11:03 +00:00
Remove the old traits
This commit is contained in:
@@ -18,8 +18,6 @@ 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::{ResolcConfiguration, SolcConfiguration, WorkingDirectoryConfiguration};
|
|
||||||
|
|
||||||
// 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};
|
||||||
@@ -29,7 +27,7 @@ pub mod revive_resolc;
|
|||||||
pub mod solc;
|
pub mod solc;
|
||||||
|
|
||||||
/// A common interface for all supported Solidity compilers.
|
/// A common interface for all supported Solidity compilers.
|
||||||
pub trait DynSolidityCompiler {
|
pub trait SolidityCompiler {
|
||||||
/// Returns the version of the compiler.
|
/// Returns the version of the compiler.
|
||||||
fn version(&self) -> &Version;
|
fn version(&self) -> &Version;
|
||||||
|
|
||||||
@@ -50,38 +48,6 @@ pub trait DynSolidityCompiler {
|
|||||||
) -> bool;
|
) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove
|
|
||||||
/// A common interface for all supported Solidity compilers.
|
|
||||||
pub trait SolidityCompiler: Sized {
|
|
||||||
/// Instantiates a new compiler object.
|
|
||||||
///
|
|
||||||
/// Based on the given context and [`VersionOrRequirement`] this function instantiates a
|
|
||||||
/// new compiler object. Certain implementations of this trait might choose to cache the
|
|
||||||
/// compiler objects and return the same compiler objects if given the same set of arguments.
|
|
||||||
fn new(
|
|
||||||
context: impl AsRef<SolcConfiguration>
|
|
||||||
+ AsRef<ResolcConfiguration>
|
|
||||||
+ AsRef<WorkingDirectoryConfiguration>,
|
|
||||||
version: impl Into<Option<VersionOrRequirement>>,
|
|
||||||
) -> impl Future<Output = Result<Self>>;
|
|
||||||
|
|
||||||
/// Returns the version of the compiler.
|
|
||||||
fn version(&self) -> &Version;
|
|
||||||
|
|
||||||
/// Returns the path of the compiler executable.
|
|
||||||
fn path(&self) -> &Path;
|
|
||||||
|
|
||||||
/// The low-level compiler interface.
|
|
||||||
fn build(&self, input: CompilerInput) -> impl Future<Output = Result<CompilerOutput>>;
|
|
||||||
|
|
||||||
/// Does the compiler support the provided mode and version settings.
|
|
||||||
fn supports_mode(
|
|
||||||
&self,
|
|
||||||
optimizer_setting: ModeOptimizerSetting,
|
|
||||||
pipeline: ModePipeline,
|
|
||||||
) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The generic compilation input configuration.
|
/// The generic compilation input configuration.
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct CompilerInput {
|
pub struct CompilerInput {
|
||||||
@@ -188,11 +154,7 @@ impl Compiler {
|
|||||||
callback(self)
|
callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn try_build(self, compiler: &impl SolidityCompiler) -> Result<CompilerOutput> {
|
pub async fn try_build(self, compiler: &dyn SolidityCompiler) -> Result<CompilerOutput> {
|
||||||
compiler.build(self.input).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn dyn_try_build(self, compiler: &dyn DynSolidityCompiler) -> Result<CompilerOutput> {
|
|
||||||
compiler.build(self.input).await
|
compiler.build(self.input).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
pin::Pin,
|
||||||
process::Stdio,
|
process::Stdio,
|
||||||
sync::{Arc, LazyLock},
|
sync::{Arc, LazyLock},
|
||||||
};
|
};
|
||||||
@@ -17,8 +18,7 @@ use revive_solc_json_interface::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CompilerInput, CompilerOutput, DynSolidityCompiler, ModeOptimizerSetting, ModePipeline,
|
CompilerInput, CompilerOutput, ModeOptimizerSetting, ModePipeline, SolidityCompiler, solc::Solc,
|
||||||
SolidityCompiler, solc::Solc,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use alloy::json_abi::JsonAbi;
|
use alloy::json_abi::JsonAbi;
|
||||||
@@ -38,34 +38,8 @@ struct ResolcInner {
|
|||||||
resolc_path: PathBuf,
|
resolc_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynSolidityCompiler for Resolc {
|
impl Resolc {
|
||||||
fn version(&self) -> &Version {
|
pub async fn new(
|
||||||
SolidityCompiler::version(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path(&self) -> &std::path::Path {
|
|
||||||
SolidityCompiler::path(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build(
|
|
||||||
&self,
|
|
||||||
input: CompilerInput,
|
|
||||||
) -> std::pin::Pin<Box<dyn Future<Output = Result<CompilerOutput>> + '_>> {
|
|
||||||
Box::pin(SolidityCompiler::build(self, input))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_mode(
|
|
||||||
&self,
|
|
||||||
optimizer_setting: ModeOptimizerSetting,
|
|
||||||
pipeline: ModePipeline,
|
|
||||||
) -> bool {
|
|
||||||
SolidityCompiler::supports_mode(self, optimizer_setting, pipeline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove
|
|
||||||
impl SolidityCompiler for Resolc {
|
|
||||||
async fn new(
|
|
||||||
context: impl AsRef<SolcConfiguration>
|
context: impl AsRef<SolcConfiguration>
|
||||||
+ AsRef<ResolcConfiguration>
|
+ AsRef<ResolcConfiguration>
|
||||||
+ AsRef<WorkingDirectoryConfiguration>,
|
+ AsRef<WorkingDirectoryConfiguration>,
|
||||||
@@ -92,11 +66,13 @@ impl SolidityCompiler for Resolc {
|
|||||||
})
|
})
|
||||||
.clone())
|
.clone())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SolidityCompiler for Resolc {
|
||||||
fn version(&self) -> &Version {
|
fn version(&self) -> &Version {
|
||||||
// We currently return the solc compiler version since we do not support multiple resolc
|
// We currently return the solc compiler version since we do not support multiple resolc
|
||||||
// compiler versions.
|
// compiler versions.
|
||||||
DynSolidityCompiler::version(&self.0.solc)
|
SolidityCompiler::version(&self.0.solc)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path(&self) -> &std::path::Path {
|
fn path(&self) -> &std::path::Path {
|
||||||
@@ -104,7 +80,7 @@ impl SolidityCompiler for Resolc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", ret)]
|
#[tracing::instrument(level = "debug", ret)]
|
||||||
async fn build(
|
fn build(
|
||||||
&self,
|
&self,
|
||||||
CompilerInput {
|
CompilerInput {
|
||||||
pipeline,
|
pipeline,
|
||||||
@@ -118,190 +94,196 @@ impl SolidityCompiler for Resolc {
|
|||||||
// resolc. So, we need to go back to this later once it's supported.
|
// resolc. So, we need to go back to this later once it's supported.
|
||||||
revert_string_handling: _,
|
revert_string_handling: _,
|
||||||
}: CompilerInput,
|
}: CompilerInput,
|
||||||
) -> Result<CompilerOutput> {
|
) -> Pin<Box<dyn Future<Output = Result<CompilerOutput>> + '_>> {
|
||||||
if !matches!(pipeline, None | Some(ModePipeline::ViaYulIR)) {
|
Box::pin(async move {
|
||||||
anyhow::bail!(
|
if !matches!(pipeline, None | Some(ModePipeline::ViaYulIR)) {
|
||||||
"Resolc only supports the Y (via Yul IR) pipeline, but the provided pipeline is {pipeline:?}"
|
anyhow::bail!(
|
||||||
);
|
"Resolc only supports the Y (via Yul IR) pipeline, but the provided pipeline is {pipeline:?}"
|
||||||
}
|
|
||||||
|
|
||||||
let input = SolcStandardJsonInput {
|
|
||||||
language: SolcStandardJsonInputLanguage::Solidity,
|
|
||||||
sources: sources
|
|
||||||
.into_iter()
|
|
||||||
.map(|(path, source)| (path.display().to_string(), source.into()))
|
|
||||||
.collect(),
|
|
||||||
settings: SolcStandardJsonInputSettings {
|
|
||||||
evm_version,
|
|
||||||
libraries: Some(
|
|
||||||
libraries
|
|
||||||
.into_iter()
|
|
||||||
.map(|(source_code, libraries_map)| {
|
|
||||||
(
|
|
||||||
source_code.display().to_string(),
|
|
||||||
libraries_map
|
|
||||||
.into_iter()
|
|
||||||
.map(|(library_ident, library_address)| {
|
|
||||||
(library_ident, library_address.to_string())
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
),
|
|
||||||
remappings: None,
|
|
||||||
output_selection: Some(SolcStandardJsonInputSettingsSelection::new_required()),
|
|
||||||
via_ir: Some(true),
|
|
||||||
optimizer: SolcStandardJsonInputSettingsOptimizer::new(
|
|
||||||
optimization
|
|
||||||
.unwrap_or(ModeOptimizerSetting::M0)
|
|
||||||
.optimizations_enabled(),
|
|
||||||
None,
|
|
||||||
&Version::new(0, 0, 0),
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
metadata: None,
|
|
||||||
polkavm: None,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let path = &self.0.resolc_path;
|
|
||||||
let mut command = AsyncCommand::new(path);
|
|
||||||
command
|
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.stderr(Stdio::piped())
|
|
||||||
.arg("--standard-json");
|
|
||||||
|
|
||||||
if let Some(ref base_path) = base_path {
|
|
||||||
command.arg("--base-path").arg(base_path);
|
|
||||||
}
|
|
||||||
if !allow_paths.is_empty() {
|
|
||||||
command.arg("--allow-paths").arg(
|
|
||||||
allow_paths
|
|
||||||
.iter()
|
|
||||||
.map(|path| path.display().to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(","),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut child = command
|
|
||||||
.spawn()
|
|
||||||
.with_context(|| format!("Failed to spawn resolc at {}", path.display()))?;
|
|
||||||
|
|
||||||
let stdin_pipe = child.stdin.as_mut().expect("stdin must be piped");
|
|
||||||
let serialized_input = serde_json::to_vec(&input)
|
|
||||||
.context("Failed to serialize Standard JSON input for resolc")?;
|
|
||||||
stdin_pipe
|
|
||||||
.write_all(&serialized_input)
|
|
||||||
.await
|
|
||||||
.context("Failed to write Standard JSON to resolc stdin")?;
|
|
||||||
|
|
||||||
let output = child
|
|
||||||
.wait_with_output()
|
|
||||||
.await
|
|
||||||
.context("Failed while waiting for resolc process to finish")?;
|
|
||||||
let stdout = output.stdout;
|
|
||||||
let stderr = output.stderr;
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
let json_in = serde_json::to_string_pretty(&input)
|
|
||||||
.context("Failed to pretty-print Standard JSON input for logging")?;
|
|
||||||
let message = String::from_utf8_lossy(&stderr);
|
|
||||||
tracing::error!(
|
|
||||||
status = %output.status,
|
|
||||||
message = %message,
|
|
||||||
json_input = json_in,
|
|
||||||
"Compilation using resolc failed"
|
|
||||||
);
|
|
||||||
anyhow::bail!("Compilation failed with an error: {message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let parsed = serde_json::from_slice::<SolcStandardJsonOutput>(&stdout)
|
|
||||||
.map_err(|e| {
|
|
||||||
anyhow::anyhow!(
|
|
||||||
"failed to parse resolc JSON output: {e}\nstderr: {}",
|
|
||||||
String::from_utf8_lossy(&stderr)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.context("Failed to parse resolc standard JSON output")?;
|
|
||||||
|
|
||||||
tracing::debug!(
|
|
||||||
output = %serde_json::to_string(&parsed).unwrap(),
|
|
||||||
"Compiled successfully"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Detecting if the compiler output contained errors and reporting them through logs and
|
|
||||||
// errors instead of returning the compiler output that might contain errors.
|
|
||||||
for error in parsed.errors.iter().flatten() {
|
|
||||||
if error.severity == "error" {
|
|
||||||
tracing::error!(
|
|
||||||
?error,
|
|
||||||
?input,
|
|
||||||
output = %serde_json::to_string(&parsed).unwrap(),
|
|
||||||
"Encountered an error in the compilation"
|
|
||||||
);
|
);
|
||||||
anyhow::bail!("Encountered an error in the compilation: {error}")
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let Some(contracts) = parsed.contracts else {
|
let input = SolcStandardJsonInput {
|
||||||
anyhow::bail!("Unexpected error - resolc output doesn't have a contracts section");
|
language: SolcStandardJsonInputLanguage::Solidity,
|
||||||
};
|
sources: sources
|
||||||
|
.into_iter()
|
||||||
|
.map(|(path, source)| (path.display().to_string(), source.into()))
|
||||||
|
.collect(),
|
||||||
|
settings: SolcStandardJsonInputSettings {
|
||||||
|
evm_version,
|
||||||
|
libraries: Some(
|
||||||
|
libraries
|
||||||
|
.into_iter()
|
||||||
|
.map(|(source_code, libraries_map)| {
|
||||||
|
(
|
||||||
|
source_code.display().to_string(),
|
||||||
|
libraries_map
|
||||||
|
.into_iter()
|
||||||
|
.map(|(library_ident, library_address)| {
|
||||||
|
(library_ident, library_address.to_string())
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
remappings: None,
|
||||||
|
output_selection: Some(SolcStandardJsonInputSettingsSelection::new_required()),
|
||||||
|
via_ir: Some(true),
|
||||||
|
optimizer: SolcStandardJsonInputSettingsOptimizer::new(
|
||||||
|
optimization
|
||||||
|
.unwrap_or(ModeOptimizerSetting::M0)
|
||||||
|
.optimizations_enabled(),
|
||||||
|
None,
|
||||||
|
&Version::new(0, 0, 0),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
metadata: None,
|
||||||
|
polkavm: None,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let mut compiler_output = CompilerOutput::default();
|
let path = &self.0.resolc_path;
|
||||||
for (source_path, contracts) in contracts.into_iter() {
|
let mut command = AsyncCommand::new(path);
|
||||||
let src_for_msg = source_path.clone();
|
command
|
||||||
let source_path = PathBuf::from(source_path)
|
.stdin(Stdio::piped())
|
||||||
.canonicalize()
|
.stdout(Stdio::piped())
|
||||||
.with_context(|| format!("Failed to canonicalize path {src_for_msg}"))?;
|
.stderr(Stdio::piped())
|
||||||
|
.arg("--standard-json");
|
||||||
|
|
||||||
let map = compiler_output.contracts.entry(source_path).or_default();
|
if let Some(ref base_path) = base_path {
|
||||||
for (contract_name, contract_information) in contracts.into_iter() {
|
command.arg("--base-path").arg(base_path);
|
||||||
let bytecode = contract_information
|
}
|
||||||
.evm
|
if !allow_paths.is_empty() {
|
||||||
.and_then(|evm| evm.bytecode.clone())
|
command.arg("--allow-paths").arg(
|
||||||
.context("Unexpected - Contract compiled with resolc has no bytecode")?;
|
allow_paths
|
||||||
let abi = {
|
.iter()
|
||||||
let metadata = contract_information
|
.map(|path| path.display().to_string())
|
||||||
.metadata
|
.collect::<Vec<_>>()
|
||||||
.as_ref()
|
.join(","),
|
||||||
.context("No metadata found for the contract")?;
|
);
|
||||||
let solc_metadata_str = match metadata {
|
}
|
||||||
serde_json::Value::String(solc_metadata_str) => solc_metadata_str.as_str(),
|
let mut child = command
|
||||||
serde_json::Value::Object(metadata_object) => {
|
.spawn()
|
||||||
let solc_metadata_value = metadata_object
|
.with_context(|| format!("Failed to spawn resolc at {}", path.display()))?;
|
||||||
.get("solc_metadata")
|
|
||||||
.context("Contract doesn't have a 'solc_metadata' field")?;
|
let stdin_pipe = child.stdin.as_mut().expect("stdin must be piped");
|
||||||
solc_metadata_value
|
let serialized_input = serde_json::to_vec(&input)
|
||||||
.as_str()
|
.context("Failed to serialize Standard JSON input for resolc")?;
|
||||||
.context("The 'solc_metadata' field is not a string")?
|
stdin_pipe
|
||||||
}
|
.write_all(&serialized_input)
|
||||||
serde_json::Value::Null
|
.await
|
||||||
| serde_json::Value::Bool(_)
|
.context("Failed to write Standard JSON to resolc stdin")?;
|
||||||
| serde_json::Value::Number(_)
|
|
||||||
| serde_json::Value::Array(_) => {
|
let output = child
|
||||||
anyhow::bail!("Unsupported type of metadata {metadata:?}")
|
.wait_with_output()
|
||||||
}
|
.await
|
||||||
};
|
.context("Failed while waiting for resolc process to finish")?;
|
||||||
let solc_metadata =
|
let stdout = output.stdout;
|
||||||
serde_json::from_str::<serde_json::Value>(solc_metadata_str).context(
|
let stderr = output.stderr;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
let json_in = serde_json::to_string_pretty(&input)
|
||||||
|
.context("Failed to pretty-print Standard JSON input for logging")?;
|
||||||
|
let message = String::from_utf8_lossy(&stderr);
|
||||||
|
tracing::error!(
|
||||||
|
status = %output.status,
|
||||||
|
message = %message,
|
||||||
|
json_input = json_in,
|
||||||
|
"Compilation using resolc failed"
|
||||||
|
);
|
||||||
|
anyhow::bail!("Compilation failed with an error: {message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
let parsed = serde_json::from_slice::<SolcStandardJsonOutput>(&stdout)
|
||||||
|
.map_err(|e| {
|
||||||
|
anyhow::anyhow!(
|
||||||
|
"failed to parse resolc JSON output: {e}\nstderr: {}",
|
||||||
|
String::from_utf8_lossy(&stderr)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.context("Failed to parse resolc standard JSON output")?;
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
output = %serde_json::to_string(&parsed).unwrap(),
|
||||||
|
"Compiled successfully"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Detecting if the compiler output contained errors and reporting them through logs and
|
||||||
|
// errors instead of returning the compiler output that might contain errors.
|
||||||
|
for error in parsed.errors.iter().flatten() {
|
||||||
|
if error.severity == "error" {
|
||||||
|
tracing::error!(
|
||||||
|
?error,
|
||||||
|
?input,
|
||||||
|
output = %serde_json::to_string(&parsed).unwrap(),
|
||||||
|
"Encountered an error in the compilation"
|
||||||
|
);
|
||||||
|
anyhow::bail!("Encountered an error in the compilation: {error}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(contracts) = parsed.contracts else {
|
||||||
|
anyhow::bail!("Unexpected error - resolc output doesn't have a contracts section");
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut compiler_output = CompilerOutput::default();
|
||||||
|
for (source_path, contracts) in contracts.into_iter() {
|
||||||
|
let src_for_msg = source_path.clone();
|
||||||
|
let source_path = PathBuf::from(source_path)
|
||||||
|
.canonicalize()
|
||||||
|
.with_context(|| format!("Failed to canonicalize path {src_for_msg}"))?;
|
||||||
|
|
||||||
|
let map = compiler_output.contracts.entry(source_path).or_default();
|
||||||
|
for (contract_name, contract_information) in contracts.into_iter() {
|
||||||
|
let bytecode = contract_information
|
||||||
|
.evm
|
||||||
|
.and_then(|evm| evm.bytecode.clone())
|
||||||
|
.context("Unexpected - Contract compiled with resolc has no bytecode")?;
|
||||||
|
let abi = {
|
||||||
|
let metadata = contract_information
|
||||||
|
.metadata
|
||||||
|
.as_ref()
|
||||||
|
.context("No metadata found for the contract")?;
|
||||||
|
let solc_metadata_str = match metadata {
|
||||||
|
serde_json::Value::String(solc_metadata_str) => {
|
||||||
|
solc_metadata_str.as_str()
|
||||||
|
}
|
||||||
|
serde_json::Value::Object(metadata_object) => {
|
||||||
|
let solc_metadata_value = metadata_object
|
||||||
|
.get("solc_metadata")
|
||||||
|
.context("Contract doesn't have a 'solc_metadata' field")?;
|
||||||
|
solc_metadata_value
|
||||||
|
.as_str()
|
||||||
|
.context("The 'solc_metadata' field is not a string")?
|
||||||
|
}
|
||||||
|
serde_json::Value::Null
|
||||||
|
| serde_json::Value::Bool(_)
|
||||||
|
| serde_json::Value::Number(_)
|
||||||
|
| serde_json::Value::Array(_) => {
|
||||||
|
anyhow::bail!("Unsupported type of metadata {metadata:?}")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let solc_metadata = serde_json::from_str::<serde_json::Value>(
|
||||||
|
solc_metadata_str,
|
||||||
|
)
|
||||||
|
.context(
|
||||||
"Failed to deserialize the solc_metadata as a serde_json generic value",
|
"Failed to deserialize the solc_metadata as a serde_json generic value",
|
||||||
)?;
|
)?;
|
||||||
let output_value = solc_metadata
|
let output_value = solc_metadata
|
||||||
.get("output")
|
.get("output")
|
||||||
.context("solc_metadata doesn't have an output field")?;
|
.context("solc_metadata doesn't have an output field")?;
|
||||||
let abi_value = output_value
|
let abi_value = output_value
|
||||||
.get("abi")
|
.get("abi")
|
||||||
.context("solc_metadata output doesn't contain an abi field")?;
|
.context("solc_metadata output doesn't contain an abi field")?;
|
||||||
serde_json::from_value::<JsonAbi>(abi_value.clone())
|
serde_json::from_value::<JsonAbi>(abi_value.clone())
|
||||||
.context("ABI found in solc_metadata output is not valid ABI")?
|
.context("ABI found in solc_metadata output is not valid ABI")?
|
||||||
};
|
};
|
||||||
map.insert(contract_name, (bytecode.object, abi));
|
map.insert(contract_name, (bytecode.object, abi));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(compiler_output)
|
Ok(compiler_output)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_mode(
|
fn supports_mode(
|
||||||
@@ -310,6 +292,6 @@ impl SolidityCompiler for Resolc {
|
|||||||
pipeline: ModePipeline,
|
pipeline: ModePipeline,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
pipeline == ModePipeline::ViaYulIR
|
pipeline == ModePipeline::ViaYulIR
|
||||||
&& DynSolidityCompiler::supports_mode(&self.0.solc, optimize_setting, pipeline)
|
&& SolidityCompiler::supports_mode(&self.0.solc, optimize_setting, pipeline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+165
-189
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
pin::Pin,
|
||||||
process::Stdio,
|
process::Stdio,
|
||||||
sync::{Arc, LazyLock},
|
sync::{Arc, LazyLock},
|
||||||
};
|
};
|
||||||
@@ -12,10 +13,7 @@ use revive_dt_common::types::VersionOrRequirement;
|
|||||||
use revive_dt_config::{ResolcConfiguration, SolcConfiguration, WorkingDirectoryConfiguration};
|
use revive_dt_config::{ResolcConfiguration, SolcConfiguration, WorkingDirectoryConfiguration};
|
||||||
use revive_dt_solc_binaries::download_solc;
|
use revive_dt_solc_binaries::download_solc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{CompilerInput, CompilerOutput, ModeOptimizerSetting, ModePipeline, SolidityCompiler};
|
||||||
CompilerInput, CompilerOutput, DynSolidityCompiler, ModeOptimizerSetting, ModePipeline,
|
|
||||||
SolidityCompiler,
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{Context as _, Result};
|
use anyhow::{Context as _, Result};
|
||||||
use foundry_compilers_artifacts::{
|
use foundry_compilers_artifacts::{
|
||||||
@@ -39,34 +37,8 @@ struct SolcInner {
|
|||||||
solc_version: Version,
|
solc_version: Version,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynSolidityCompiler for Solc {
|
impl Solc {
|
||||||
fn version(&self) -> &Version {
|
pub async fn new(
|
||||||
SolidityCompiler::version(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn path(&self) -> &std::path::Path {
|
|
||||||
SolidityCompiler::path(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build(
|
|
||||||
&self,
|
|
||||||
input: CompilerInput,
|
|
||||||
) -> std::pin::Pin<Box<dyn Future<Output = Result<CompilerOutput>> + '_>> {
|
|
||||||
Box::pin(SolidityCompiler::build(self, input))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn supports_mode(
|
|
||||||
&self,
|
|
||||||
optimizer_setting: ModeOptimizerSetting,
|
|
||||||
pipeline: ModePipeline,
|
|
||||||
) -> bool {
|
|
||||||
SolidityCompiler::supports_mode(self, optimizer_setting, pipeline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove
|
|
||||||
impl SolidityCompiler for Solc {
|
|
||||||
async fn new(
|
|
||||||
context: impl AsRef<SolcConfiguration>
|
context: impl AsRef<SolcConfiguration>
|
||||||
+ AsRef<ResolcConfiguration>
|
+ AsRef<ResolcConfiguration>
|
||||||
+ AsRef<WorkingDirectoryConfiguration>,
|
+ AsRef<WorkingDirectoryConfiguration>,
|
||||||
@@ -104,7 +76,9 @@ impl SolidityCompiler for Solc {
|
|||||||
})
|
})
|
||||||
.clone())
|
.clone())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SolidityCompiler for Solc {
|
||||||
fn version(&self) -> &Version {
|
fn version(&self) -> &Version {
|
||||||
&self.0.solc_version
|
&self.0.solc_version
|
||||||
}
|
}
|
||||||
@@ -114,7 +88,7 @@ impl SolidityCompiler for Solc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", ret)]
|
#[tracing::instrument(level = "debug", ret)]
|
||||||
async fn build(
|
fn build(
|
||||||
&self,
|
&self,
|
||||||
CompilerInput {
|
CompilerInput {
|
||||||
pipeline,
|
pipeline,
|
||||||
@@ -126,171 +100,173 @@ impl SolidityCompiler for Solc {
|
|||||||
libraries,
|
libraries,
|
||||||
revert_string_handling,
|
revert_string_handling,
|
||||||
}: CompilerInput,
|
}: CompilerInput,
|
||||||
) -> Result<CompilerOutput> {
|
) -> Pin<Box<dyn Future<Output = Result<CompilerOutput>> + '_>> {
|
||||||
// Be careful to entirely omit the viaIR field if the compiler does not support it,
|
Box::pin(async move {
|
||||||
// as it will error if you provide fields it does not know about. Because
|
// Be careful to entirely omit the viaIR field if the compiler does not support it,
|
||||||
// `supports_mode` is called prior to instantiating a compiler, we should never
|
// as it will error if you provide fields it does not know about. Because
|
||||||
// ask for something which is invalid.
|
// `supports_mode` is called prior to instantiating a compiler, we should never
|
||||||
let via_ir = match (pipeline, self.compiler_supports_yul()) {
|
// ask for something which is invalid.
|
||||||
(pipeline, true) => pipeline.map(|p| p.via_yul_ir()),
|
let via_ir = match (pipeline, self.compiler_supports_yul()) {
|
||||||
(_pipeline, false) => None,
|
(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(
|
||||||
sources
|
sources
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(source_path, source_code)| (source_path, Source::new(source_code)))
|
.map(|(source_path, source_code)| (source_path, Source::new(source_code)))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
settings: Settings {
|
settings: Settings {
|
||||||
optimizer: Optimizer {
|
optimizer: Optimizer {
|
||||||
enabled: optimization.map(|o| o.optimizations_enabled()),
|
enabled: optimization.map(|o| o.optimizations_enabled()),
|
||||||
details: Some(Default::default()),
|
details: Some(Default::default()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
output_selection: OutputSelection::common_output_selection(
|
||||||
|
[
|
||||||
|
ContractOutputSelection::Abi,
|
||||||
|
ContractOutputSelection::Evm(EvmOutputSelection::ByteCode(
|
||||||
|
BytecodeOutputSelection::Object,
|
||||||
|
)),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|item| item.to_string()),
|
||||||
|
),
|
||||||
|
evm_version: evm_version.map(|version| version.to_string().parse().unwrap()),
|
||||||
|
via_ir,
|
||||||
|
libraries: Libraries {
|
||||||
|
libs: libraries
|
||||||
|
.into_iter()
|
||||||
|
.map(|(file_path, libraries)| {
|
||||||
|
(
|
||||||
|
file_path,
|
||||||
|
libraries
|
||||||
|
.into_iter()
|
||||||
|
.map(|(library_name, library_address)| {
|
||||||
|
(library_name, library_address.to_string())
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
debug: revert_string_handling.map(|revert_string_handling| DebuggingSettings {
|
||||||
|
revert_strings: match revert_string_handling {
|
||||||
|
crate::RevertString::Default => Some(RevertStrings::Default),
|
||||||
|
crate::RevertString::Debug => Some(RevertStrings::Debug),
|
||||||
|
crate::RevertString::Strip => Some(RevertStrings::Strip),
|
||||||
|
crate::RevertString::VerboseDebug => Some(RevertStrings::VerboseDebug),
|
||||||
|
},
|
||||||
|
debug_info: Default::default(),
|
||||||
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
output_selection: OutputSelection::common_output_selection(
|
};
|
||||||
[
|
|
||||||
ContractOutputSelection::Abi,
|
|
||||||
ContractOutputSelection::Evm(EvmOutputSelection::ByteCode(
|
|
||||||
BytecodeOutputSelection::Object,
|
|
||||||
)),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.map(|item| item.to_string()),
|
|
||||||
),
|
|
||||||
evm_version: evm_version.map(|version| version.to_string().parse().unwrap()),
|
|
||||||
via_ir,
|
|
||||||
libraries: Libraries {
|
|
||||||
libs: libraries
|
|
||||||
.into_iter()
|
|
||||||
.map(|(file_path, libraries)| {
|
|
||||||
(
|
|
||||||
file_path,
|
|
||||||
libraries
|
|
||||||
.into_iter()
|
|
||||||
.map(|(library_name, library_address)| {
|
|
||||||
(library_name, library_address.to_string())
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
},
|
|
||||||
debug: revert_string_handling.map(|revert_string_handling| DebuggingSettings {
|
|
||||||
revert_strings: match revert_string_handling {
|
|
||||||
crate::RevertString::Default => Some(RevertStrings::Default),
|
|
||||||
crate::RevertString::Debug => Some(RevertStrings::Debug),
|
|
||||||
crate::RevertString::Strip => Some(RevertStrings::Strip),
|
|
||||||
crate::RevertString::VerboseDebug => Some(RevertStrings::VerboseDebug),
|
|
||||||
},
|
|
||||||
debug_info: Default::default(),
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let path = &self.0.solc_path;
|
let path = &self.0.solc_path;
|
||||||
let mut command = AsyncCommand::new(path);
|
let mut command = AsyncCommand::new(path);
|
||||||
command
|
command
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.arg("--standard-json");
|
.arg("--standard-json");
|
||||||
|
|
||||||
if let Some(ref base_path) = base_path {
|
if let Some(ref base_path) = base_path {
|
||||||
command.arg("--base-path").arg(base_path);
|
command.arg("--base-path").arg(base_path);
|
||||||
}
|
|
||||||
if !allow_paths.is_empty() {
|
|
||||||
command.arg("--allow-paths").arg(
|
|
||||||
allow_paths
|
|
||||||
.iter()
|
|
||||||
.map(|path| path.display().to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(","),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let mut child = command
|
|
||||||
.spawn()
|
|
||||||
.with_context(|| format!("Failed to spawn solc at {}", path.display()))?;
|
|
||||||
|
|
||||||
let stdin = child.stdin.as_mut().expect("should be piped");
|
|
||||||
let serialized_input = serde_json::to_vec(&input)
|
|
||||||
.context("Failed to serialize Standard JSON input for solc")?;
|
|
||||||
stdin
|
|
||||||
.write_all(&serialized_input)
|
|
||||||
.await
|
|
||||||
.context("Failed to write Standard JSON to solc stdin")?;
|
|
||||||
let output = child
|
|
||||||
.wait_with_output()
|
|
||||||
.await
|
|
||||||
.context("Failed while waiting for solc process to finish")?;
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
let json_in = serde_json::to_string_pretty(&input)
|
|
||||||
.context("Failed to pretty-print Standard JSON input for logging")?;
|
|
||||||
let message = String::from_utf8_lossy(&output.stderr);
|
|
||||||
tracing::error!(
|
|
||||||
status = %output.status,
|
|
||||||
message = %message,
|
|
||||||
json_input = json_in,
|
|
||||||
"Compilation using solc failed"
|
|
||||||
);
|
|
||||||
anyhow::bail!("Compilation failed with an error: {message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let parsed = serde_json::from_slice::<SolcOutput>(&output.stdout)
|
|
||||||
.map_err(|e| {
|
|
||||||
anyhow::anyhow!(
|
|
||||||
"failed to parse resolc JSON output: {e}\nstderr: {}",
|
|
||||||
String::from_utf8_lossy(&output.stdout)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.context("Failed to parse solc standard JSON output")?;
|
|
||||||
|
|
||||||
// Detecting if the compiler output contained errors and reporting them through logs and
|
|
||||||
// errors instead of returning the compiler output that might contain errors.
|
|
||||||
for error in parsed.errors.iter() {
|
|
||||||
if error.severity == Severity::Error {
|
|
||||||
tracing::error!(?error, ?input, "Encountered an error in the compilation");
|
|
||||||
anyhow::bail!("Encountered an error in the compilation: {error}")
|
|
||||||
}
|
}
|
||||||
}
|
if !allow_paths.is_empty() {
|
||||||
|
command.arg("--allow-paths").arg(
|
||||||
|
allow_paths
|
||||||
|
.iter()
|
||||||
|
.map(|path| path.display().to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(","),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut child = command
|
||||||
|
.spawn()
|
||||||
|
.with_context(|| format!("Failed to spawn solc at {}", path.display()))?;
|
||||||
|
|
||||||
tracing::debug!(
|
let stdin = child.stdin.as_mut().expect("should be piped");
|
||||||
output = %String::from_utf8_lossy(&output.stdout).to_string(),
|
let serialized_input = serde_json::to_vec(&input)
|
||||||
"Compiled successfully"
|
.context("Failed to serialize Standard JSON input for solc")?;
|
||||||
);
|
stdin
|
||||||
|
.write_all(&serialized_input)
|
||||||
|
.await
|
||||||
|
.context("Failed to write Standard JSON to solc stdin")?;
|
||||||
|
let output = child
|
||||||
|
.wait_with_output()
|
||||||
|
.await
|
||||||
|
.context("Failed while waiting for solc process to finish")?;
|
||||||
|
|
||||||
let mut compiler_output = CompilerOutput::default();
|
if !output.status.success() {
|
||||||
for (contract_path, contracts) in parsed.contracts {
|
let json_in = serde_json::to_string_pretty(&input)
|
||||||
let map = compiler_output
|
.context("Failed to pretty-print Standard JSON input for logging")?;
|
||||||
.contracts
|
let message = String::from_utf8_lossy(&output.stderr);
|
||||||
.entry(contract_path.canonicalize().with_context(|| {
|
tracing::error!(
|
||||||
format!(
|
status = %output.status,
|
||||||
"Failed to canonicalize contract path {}",
|
message = %message,
|
||||||
contract_path.display()
|
json_input = json_in,
|
||||||
|
"Compilation using solc failed"
|
||||||
|
);
|
||||||
|
anyhow::bail!("Compilation failed with an error: {message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
let parsed = serde_json::from_slice::<SolcOutput>(&output.stdout)
|
||||||
|
.map_err(|e| {
|
||||||
|
anyhow::anyhow!(
|
||||||
|
"failed to parse resolc JSON output: {e}\nstderr: {}",
|
||||||
|
String::from_utf8_lossy(&output.stdout)
|
||||||
)
|
)
|
||||||
})?)
|
})
|
||||||
.or_default();
|
.context("Failed to parse solc standard JSON output")?;
|
||||||
for (contract_name, contract_info) in contracts.into_iter() {
|
|
||||||
let source_code = contract_info
|
|
||||||
.evm
|
|
||||||
.and_then(|evm| evm.bytecode)
|
|
||||||
.map(|bytecode| match bytecode.object {
|
|
||||||
BytecodeObject::Bytecode(bytecode) => bytecode.to_string(),
|
|
||||||
BytecodeObject::Unlinked(unlinked) => unlinked,
|
|
||||||
})
|
|
||||||
.context("Unexpected - contract compiled with solc has no source code")?;
|
|
||||||
let abi = contract_info
|
|
||||||
.abi
|
|
||||||
.context("Unexpected - contract compiled with solc as no ABI")?;
|
|
||||||
map.insert(contract_name, (source_code, abi));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(compiler_output)
|
// Detecting if the compiler output contained errors and reporting them through logs and
|
||||||
|
// errors instead of returning the compiler output that might contain errors.
|
||||||
|
for error in parsed.errors.iter() {
|
||||||
|
if error.severity == Severity::Error {
|
||||||
|
tracing::error!(?error, ?input, "Encountered an error in the compilation");
|
||||||
|
anyhow::bail!("Encountered an error in the compilation: {error}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
output = %String::from_utf8_lossy(&output.stdout).to_string(),
|
||||||
|
"Compiled successfully"
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut compiler_output = CompilerOutput::default();
|
||||||
|
for (contract_path, contracts) in parsed.contracts {
|
||||||
|
let map = compiler_output
|
||||||
|
.contracts
|
||||||
|
.entry(contract_path.canonicalize().with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to canonicalize contract path {}",
|
||||||
|
contract_path.display()
|
||||||
|
)
|
||||||
|
})?)
|
||||||
|
.or_default();
|
||||||
|
for (contract_name, contract_info) in contracts.into_iter() {
|
||||||
|
let source_code = contract_info
|
||||||
|
.evm
|
||||||
|
.and_then(|evm| evm.bytecode)
|
||||||
|
.map(|bytecode| match bytecode.object {
|
||||||
|
BytecodeObject::Bytecode(bytecode) => bytecode.to_string(),
|
||||||
|
BytecodeObject::Unlinked(unlinked) => unlinked,
|
||||||
|
})
|
||||||
|
.context("Unexpected - contract compiled with solc has no source code")?;
|
||||||
|
let abi = contract_info
|
||||||
|
.abi
|
||||||
|
.context("Unexpected - contract compiled with solc as no ABI")?;
|
||||||
|
map.insert(contract_name, (source_code, abi));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(compiler_output)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn supports_mode(
|
fn supports_mode(
|
||||||
@@ -308,6 +284,6 @@ impl SolidityCompiler for Solc {
|
|||||||
impl Solc {
|
impl Solc {
|
||||||
fn compiler_supports_yul(&self) -> bool {
|
fn compiler_supports_yul(&self) -> bool {
|
||||||
const SOLC_VERSION_SUPPORTING_VIA_YUL_IR: Version = Version::new(0, 8, 13);
|
const SOLC_VERSION_SUPPORTING_VIA_YUL_IR: Version = Version::new(0, 8, 13);
|
||||||
DynSolidityCompiler::version(self) >= &SOLC_VERSION_SUPPORTING_VIA_YUL_IR
|
SolidityCompiler::version(self) >= &SOLC_VERSION_SUPPORTING_VIA_YUL_IR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ use std::{
|
|||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use revive_dt_common::{iterators::FilesWithExtensionIterator, types::CompilerIdentifier};
|
use revive_dt_common::{iterators::FilesWithExtensionIterator, types::CompilerIdentifier};
|
||||||
use revive_dt_compiler::{Compiler, CompilerOutput, DynSolidityCompiler, Mode};
|
use revive_dt_compiler::{Compiler, CompilerOutput, Mode, SolidityCompiler};
|
||||||
use revive_dt_core::DynPlatform;
|
use revive_dt_core::Platform;
|
||||||
use revive_dt_format::metadata::{ContractIdent, ContractInstance, Metadata};
|
use revive_dt_format::metadata::{ContractIdent, ContractInstance, Metadata};
|
||||||
|
|
||||||
use alloy::{hex::ToHexExt, json_abi::JsonAbi, primitives::Address};
|
use alloy::{hex::ToHexExt, json_abi::JsonAbi, primitives::Address};
|
||||||
@@ -65,8 +65,8 @@ impl<'a> CachedCompiler<'a> {
|
|||||||
metadata_file_path: &'a Path,
|
metadata_file_path: &'a Path,
|
||||||
mode: Cow<'a, Mode>,
|
mode: Cow<'a, Mode>,
|
||||||
deployed_libraries: Option<&HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>>,
|
deployed_libraries: Option<&HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>>,
|
||||||
compiler: &dyn DynSolidityCompiler,
|
compiler: &dyn SolidityCompiler,
|
||||||
platform: &dyn DynPlatform,
|
platform: &dyn Platform,
|
||||||
reporter: &ExecutionSpecificReporter,
|
reporter: &ExecutionSpecificReporter,
|
||||||
) -> Result<CompilerOutput> {
|
) -> Result<CompilerOutput> {
|
||||||
let cache_key = CacheKey {
|
let cache_key = CacheKey {
|
||||||
@@ -183,7 +183,7 @@ async fn compile_contracts(
|
|||||||
mut files_to_compile: impl Iterator<Item = PathBuf>,
|
mut files_to_compile: impl Iterator<Item = PathBuf>,
|
||||||
mode: &Mode,
|
mode: &Mode,
|
||||||
deployed_libraries: Option<&HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>>,
|
deployed_libraries: Option<&HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>>,
|
||||||
compiler: &dyn DynSolidityCompiler,
|
compiler: &dyn SolidityCompiler,
|
||||||
reporter: &ExecutionSpecificReporter,
|
reporter: &ExecutionSpecificReporter,
|
||||||
) -> 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())
|
||||||
@@ -217,7 +217,7 @@ async fn compile_contracts(
|
|||||||
});
|
});
|
||||||
|
|
||||||
let input = compilation.input().clone();
|
let input = compilation.input().clone();
|
||||||
let output = compilation.dyn_try_build(compiler).await;
|
let output = compilation.try_build(compiler).await;
|
||||||
|
|
||||||
match (output.as_ref(), deployed_libraries.is_some()) {
|
match (output.as_ref(), deployed_libraries.is_some()) {
|
||||||
(Ok(output), true) => {
|
(Ok(output), true) => {
|
||||||
|
|||||||
+26
-70
@@ -11,61 +11,17 @@ use std::{
|
|||||||
use alloy::genesis::Genesis;
|
use alloy::genesis::Genesis;
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use revive_dt_common::types::*;
|
use revive_dt_common::types::*;
|
||||||
use revive_dt_compiler::{
|
use revive_dt_compiler::{SolidityCompiler, revive_resolc::Resolc, solc::Solc};
|
||||||
DynSolidityCompiler, SolidityCompiler,
|
|
||||||
revive_resolc::{self, Resolc},
|
|
||||||
solc::{self, Solc},
|
|
||||||
};
|
|
||||||
use revive_dt_config::*;
|
use revive_dt_config::*;
|
||||||
use revive_dt_format::traits::ResolverApi;
|
use revive_dt_node::{Node, geth::GethNode, substrate::SubstrateNode};
|
||||||
use revive_dt_node::{
|
|
||||||
Node,
|
|
||||||
geth::{self, GethNode},
|
|
||||||
substrate::SubstrateNode,
|
|
||||||
};
|
|
||||||
use revive_dt_node_interaction::EthereumNode;
|
use revive_dt_node_interaction::EthereumNode;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
pub mod driver;
|
pub mod driver;
|
||||||
|
|
||||||
/// One platform can be tested differentially against another.
|
|
||||||
///
|
|
||||||
/// For this we need a blockchain node implementation and a compiler.
|
|
||||||
pub trait Platform {
|
|
||||||
type Blockchain: EthereumNode + Node + ResolverApi;
|
|
||||||
type Compiler: SolidityCompiler;
|
|
||||||
|
|
||||||
/// Returns the matching [TestingPlatform] of the [revive_dt_config::Arguments].
|
|
||||||
fn config_id() -> &'static TestingPlatform;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Geth;
|
|
||||||
|
|
||||||
impl Platform for Geth {
|
|
||||||
type Blockchain = geth::GethNode;
|
|
||||||
type Compiler = solc::Solc;
|
|
||||||
|
|
||||||
fn config_id() -> &'static TestingPlatform {
|
|
||||||
&TestingPlatform::Geth
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Kitchensink;
|
|
||||||
|
|
||||||
impl Platform for Kitchensink {
|
|
||||||
type Blockchain = SubstrateNode;
|
|
||||||
type Compiler = revive_resolc::Resolc;
|
|
||||||
|
|
||||||
fn config_id() -> &'static TestingPlatform {
|
|
||||||
&TestingPlatform::Kitchensink
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A trait that describes the interface for the platforms that are supported by the tool.
|
/// A trait that describes the interface for the platforms that are supported by the tool.
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
pub trait DynPlatform {
|
pub trait Platform {
|
||||||
/// Returns the identifier of this platform. This is a combination of the node and the compiler
|
/// Returns the identifier of this platform. This is a combination of the node and the compiler
|
||||||
/// used.
|
/// used.
|
||||||
fn platform_identifier(&self) -> PlatformIdentifier;
|
fn platform_identifier(&self) -> PlatformIdentifier;
|
||||||
@@ -100,13 +56,13 @@ pub trait DynPlatform {
|
|||||||
&self,
|
&self,
|
||||||
context: Context,
|
context: Context,
|
||||||
version: Option<VersionOrRequirement>,
|
version: Option<VersionOrRequirement>,
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn DynSolidityCompiler>>>>>;
|
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn SolidityCompiler>>>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
||||||
pub struct GethEvmSolcPlatform;
|
pub struct GethEvmSolcPlatform;
|
||||||
|
|
||||||
impl DynPlatform for GethEvmSolcPlatform {
|
impl Platform for GethEvmSolcPlatform {
|
||||||
fn platform_identifier(&self) -> PlatformIdentifier {
|
fn platform_identifier(&self) -> PlatformIdentifier {
|
||||||
PlatformIdentifier::GethEvmSolc
|
PlatformIdentifier::GethEvmSolc
|
||||||
}
|
}
|
||||||
@@ -140,10 +96,10 @@ impl DynPlatform for GethEvmSolcPlatform {
|
|||||||
&self,
|
&self,
|
||||||
context: Context,
|
context: Context,
|
||||||
version: Option<VersionOrRequirement>,
|
version: Option<VersionOrRequirement>,
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn DynSolidityCompiler>>>>> {
|
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn SolidityCompiler>>>>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let compiler = Solc::new(context, version).await;
|
let compiler = Solc::new(context, version).await;
|
||||||
compiler.map(|compiler| Box::new(compiler) as Box<dyn DynSolidityCompiler>)
|
compiler.map(|compiler| Box::new(compiler) as Box<dyn SolidityCompiler>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,7 +107,7 @@ impl DynPlatform for GethEvmSolcPlatform {
|
|||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
||||||
pub struct KitchensinkPolkavmResolcPlatform;
|
pub struct KitchensinkPolkavmResolcPlatform;
|
||||||
|
|
||||||
impl DynPlatform for KitchensinkPolkavmResolcPlatform {
|
impl Platform for KitchensinkPolkavmResolcPlatform {
|
||||||
fn platform_identifier(&self) -> PlatformIdentifier {
|
fn platform_identifier(&self) -> PlatformIdentifier {
|
||||||
PlatformIdentifier::KitchensinkPolkavmResolc
|
PlatformIdentifier::KitchensinkPolkavmResolc
|
||||||
}
|
}
|
||||||
@@ -192,10 +148,10 @@ impl DynPlatform for KitchensinkPolkavmResolcPlatform {
|
|||||||
&self,
|
&self,
|
||||||
context: Context,
|
context: Context,
|
||||||
version: Option<VersionOrRequirement>,
|
version: Option<VersionOrRequirement>,
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn DynSolidityCompiler>>>>> {
|
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn SolidityCompiler>>>>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let compiler = Resolc::new(context, version).await;
|
let compiler = Resolc::new(context, version).await;
|
||||||
compiler.map(|compiler| Box::new(compiler) as Box<dyn DynSolidityCompiler>)
|
compiler.map(|compiler| Box::new(compiler) as Box<dyn SolidityCompiler>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,7 +159,7 @@ impl DynPlatform for KitchensinkPolkavmResolcPlatform {
|
|||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
||||||
pub struct KitchensinkRevmSolcPlatform;
|
pub struct KitchensinkRevmSolcPlatform;
|
||||||
|
|
||||||
impl DynPlatform for KitchensinkRevmSolcPlatform {
|
impl Platform for KitchensinkRevmSolcPlatform {
|
||||||
fn platform_identifier(&self) -> PlatformIdentifier {
|
fn platform_identifier(&self) -> PlatformIdentifier {
|
||||||
PlatformIdentifier::KitchensinkRevmSolc
|
PlatformIdentifier::KitchensinkRevmSolc
|
||||||
}
|
}
|
||||||
@@ -244,10 +200,10 @@ impl DynPlatform for KitchensinkRevmSolcPlatform {
|
|||||||
&self,
|
&self,
|
||||||
context: Context,
|
context: Context,
|
||||||
version: Option<VersionOrRequirement>,
|
version: Option<VersionOrRequirement>,
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn DynSolidityCompiler>>>>> {
|
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn SolidityCompiler>>>>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let compiler = Solc::new(context, version).await;
|
let compiler = Solc::new(context, version).await;
|
||||||
compiler.map(|compiler| Box::new(compiler) as Box<dyn DynSolidityCompiler>)
|
compiler.map(|compiler| Box::new(compiler) as Box<dyn SolidityCompiler>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,7 +211,7 @@ impl DynPlatform for KitchensinkRevmSolcPlatform {
|
|||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
||||||
pub struct ReviveDevNodePolkavmResolcPlatform;
|
pub struct ReviveDevNodePolkavmResolcPlatform;
|
||||||
|
|
||||||
impl DynPlatform for ReviveDevNodePolkavmResolcPlatform {
|
impl Platform for ReviveDevNodePolkavmResolcPlatform {
|
||||||
fn platform_identifier(&self) -> PlatformIdentifier {
|
fn platform_identifier(&self) -> PlatformIdentifier {
|
||||||
PlatformIdentifier::ReviveDevNodePolkavmResolc
|
PlatformIdentifier::ReviveDevNodePolkavmResolc
|
||||||
}
|
}
|
||||||
@@ -296,10 +252,10 @@ impl DynPlatform for ReviveDevNodePolkavmResolcPlatform {
|
|||||||
&self,
|
&self,
|
||||||
context: Context,
|
context: Context,
|
||||||
version: Option<VersionOrRequirement>,
|
version: Option<VersionOrRequirement>,
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn DynSolidityCompiler>>>>> {
|
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn SolidityCompiler>>>>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let compiler = Resolc::new(context, version).await;
|
let compiler = Resolc::new(context, version).await;
|
||||||
compiler.map(|compiler| Box::new(compiler) as Box<dyn DynSolidityCompiler>)
|
compiler.map(|compiler| Box::new(compiler) as Box<dyn SolidityCompiler>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,7 +263,7 @@ impl DynPlatform for ReviveDevNodePolkavmResolcPlatform {
|
|||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
||||||
pub struct ReviveDevNodeRevmSolcPlatform;
|
pub struct ReviveDevNodeRevmSolcPlatform;
|
||||||
|
|
||||||
impl DynPlatform for ReviveDevNodeRevmSolcPlatform {
|
impl Platform for ReviveDevNodeRevmSolcPlatform {
|
||||||
fn platform_identifier(&self) -> PlatformIdentifier {
|
fn platform_identifier(&self) -> PlatformIdentifier {
|
||||||
PlatformIdentifier::ReviveDevNodeRevmSolc
|
PlatformIdentifier::ReviveDevNodeRevmSolc
|
||||||
}
|
}
|
||||||
@@ -348,15 +304,15 @@ impl DynPlatform for ReviveDevNodeRevmSolcPlatform {
|
|||||||
&self,
|
&self,
|
||||||
context: Context,
|
context: Context,
|
||||||
version: Option<VersionOrRequirement>,
|
version: Option<VersionOrRequirement>,
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn DynSolidityCompiler>>>>> {
|
) -> Pin<Box<dyn Future<Output = anyhow::Result<Box<dyn SolidityCompiler>>>>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let compiler = Solc::new(context, version).await;
|
let compiler = Solc::new(context, version).await;
|
||||||
compiler.map(|compiler| Box::new(compiler) as Box<dyn DynSolidityCompiler>)
|
compiler.map(|compiler| Box::new(compiler) as Box<dyn SolidityCompiler>)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PlatformIdentifier> for Box<dyn DynPlatform> {
|
impl From<PlatformIdentifier> for Box<dyn Platform> {
|
||||||
fn from(value: PlatformIdentifier) -> Self {
|
fn from(value: PlatformIdentifier) -> Self {
|
||||||
match value {
|
match value {
|
||||||
PlatformIdentifier::GethEvmSolc => Box::new(GethEvmSolcPlatform) as Box<_>,
|
PlatformIdentifier::GethEvmSolc => Box::new(GethEvmSolcPlatform) as Box<_>,
|
||||||
@@ -376,21 +332,21 @@ impl From<PlatformIdentifier> for Box<dyn DynPlatform> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PlatformIdentifier> for &dyn DynPlatform {
|
impl From<PlatformIdentifier> for &dyn Platform {
|
||||||
fn from(value: PlatformIdentifier) -> Self {
|
fn from(value: PlatformIdentifier) -> Self {
|
||||||
match value {
|
match value {
|
||||||
PlatformIdentifier::GethEvmSolc => &GethEvmSolcPlatform as &dyn DynPlatform,
|
PlatformIdentifier::GethEvmSolc => &GethEvmSolcPlatform as &dyn Platform,
|
||||||
PlatformIdentifier::KitchensinkPolkavmResolc => {
|
PlatformIdentifier::KitchensinkPolkavmResolc => {
|
||||||
&KitchensinkPolkavmResolcPlatform as &dyn DynPlatform
|
&KitchensinkPolkavmResolcPlatform as &dyn Platform
|
||||||
}
|
}
|
||||||
PlatformIdentifier::KitchensinkRevmSolc => {
|
PlatformIdentifier::KitchensinkRevmSolc => {
|
||||||
&KitchensinkRevmSolcPlatform as &dyn DynPlatform
|
&KitchensinkRevmSolcPlatform as &dyn Platform
|
||||||
}
|
}
|
||||||
PlatformIdentifier::ReviveDevNodePolkavmResolc => {
|
PlatformIdentifier::ReviveDevNodePolkavmResolc => {
|
||||||
&ReviveDevNodePolkavmResolcPlatform as &dyn DynPlatform
|
&ReviveDevNodePolkavmResolcPlatform as &dyn Platform
|
||||||
}
|
}
|
||||||
PlatformIdentifier::ReviveDevNodeRevmSolc => {
|
PlatformIdentifier::ReviveDevNodeRevmSolc => {
|
||||||
&ReviveDevNodeRevmSolcPlatform as &dyn DynPlatform
|
&ReviveDevNodeRevmSolcPlatform as &dyn Platform
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ use tracing::{debug, error, info, info_span, instrument};
|
|||||||
use tracing_subscriber::{EnvFilter, FmtSubscriber};
|
use tracing_subscriber::{EnvFilter, FmtSubscriber};
|
||||||
|
|
||||||
use revive_dt_common::{iterators::EitherIter, types::Mode};
|
use revive_dt_common::{iterators::EitherIter, types::Mode};
|
||||||
use revive_dt_compiler::DynSolidityCompiler;
|
use revive_dt_compiler::SolidityCompiler;
|
||||||
use revive_dt_config::{Context, *};
|
use revive_dt_config::{Context, *};
|
||||||
use revive_dt_core::{
|
use revive_dt_core::{
|
||||||
DynPlatform,
|
Platform,
|
||||||
driver::{CaseDriver, CaseState},
|
driver::{CaseDriver, CaseState},
|
||||||
};
|
};
|
||||||
use revive_dt_format::{
|
use revive_dt_format::{
|
||||||
@@ -138,9 +138,9 @@ async fn run_driver(
|
|||||||
metadata_files: &[MetadataFile],
|
metadata_files: &[MetadataFile],
|
||||||
reporter: Reporter,
|
reporter: Reporter,
|
||||||
report_aggregator_task: impl Future<Output = anyhow::Result<()>>,
|
report_aggregator_task: impl Future<Output = anyhow::Result<()>>,
|
||||||
platforms: Vec<&dyn DynPlatform>,
|
platforms: Vec<&dyn Platform>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut nodes = Vec::<(&dyn DynPlatform, NodePool)>::new();
|
let mut nodes = Vec::<(&dyn Platform, NodePool)>::new();
|
||||||
for platform in platforms.into_iter() {
|
for platform in platforms.into_iter() {
|
||||||
let pool = NodePool::new(Context::ExecuteTests(Box::new(context.clone())), platform)
|
let pool = NodePool::new(Context::ExecuteTests(Box::new(context.clone())), platform)
|
||||||
.inspect_err(|err| {
|
.inspect_err(|err| {
|
||||||
@@ -175,7 +175,7 @@ async fn run_driver(
|
|||||||
async fn tests_stream<'a>(
|
async fn tests_stream<'a>(
|
||||||
args: &TestExecutionContext,
|
args: &TestExecutionContext,
|
||||||
metadata_files: impl IntoIterator<Item = &'a MetadataFile> + Clone,
|
metadata_files: impl IntoIterator<Item = &'a MetadataFile> + Clone,
|
||||||
nodes: &'a [(&dyn DynPlatform, NodePool)],
|
nodes: &'a [(&dyn Platform, NodePool)],
|
||||||
reporter: Reporter,
|
reporter: Reporter,
|
||||||
) -> impl Stream<Item = Test<'a>> {
|
) -> impl Stream<Item = Test<'a>> {
|
||||||
let tests = metadata_files
|
let tests = metadata_files
|
||||||
@@ -619,7 +619,7 @@ async fn execute_corpus(
|
|||||||
.copied()
|
.copied()
|
||||||
.collect::<BTreeSet<_>>()
|
.collect::<BTreeSet<_>>()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Into::<&dyn DynPlatform>::into)
|
.map(Into::<&dyn Platform>::into)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
run_driver(context, tests, reporter, report_aggregator_task, platforms).await?;
|
run_driver(context, tests, reporter, report_aggregator_task, platforms).await?;
|
||||||
@@ -636,9 +636,9 @@ struct Test<'a> {
|
|||||||
case_idx: CaseIdx,
|
case_idx: CaseIdx,
|
||||||
case: &'a Case,
|
case: &'a Case,
|
||||||
platforms: Vec<(
|
platforms: Vec<(
|
||||||
&'a dyn DynPlatform,
|
&'a dyn Platform,
|
||||||
&'a dyn EthereumNode,
|
&'a dyn EthereumNode,
|
||||||
Box<dyn DynSolidityCompiler>,
|
Box<dyn SolidityCompiler>,
|
||||||
ExecutionSpecificReporter,
|
ExecutionSpecificReporter,
|
||||||
)>,
|
)>,
|
||||||
reporter: TestSpecificReporter,
|
reporter: TestSpecificReporter,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
|||||||
|
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use revive_dt_config::*;
|
use revive_dt_config::*;
|
||||||
use revive_dt_core::DynPlatform;
|
use revive_dt_core::Platform;
|
||||||
use revive_dt_node_interaction::EthereumNode;
|
use revive_dt_node_interaction::EthereumNode;
|
||||||
|
|
||||||
/// The node pool starts one or more [Node] which then can be accessed
|
/// The node pool starts one or more [Node] which then can be accessed
|
||||||
@@ -16,7 +16,7 @@ pub struct NodePool {
|
|||||||
|
|
||||||
impl NodePool {
|
impl NodePool {
|
||||||
/// Create a new Pool. This will start as many nodes as there are workers in `config`.
|
/// Create a new Pool. This will start as many nodes as there are workers in `config`.
|
||||||
pub fn new(context: Context, platform: &dyn DynPlatform) -> anyhow::Result<Self> {
|
pub fn new(context: Context, platform: &dyn Platform) -> anyhow::Result<Self> {
|
||||||
let concurrency_configuration = AsRef::<ConcurrencyConfiguration>::as_ref(&context);
|
let concurrency_configuration = AsRef::<ConcurrencyConfiguration>::as_ref(&context);
|
||||||
let nodes = concurrency_configuration.number_of_nodes;
|
let nodes = concurrency_configuration.number_of_nodes;
|
||||||
|
|
||||||
|
|||||||
+32
-159
@@ -647,158 +647,6 @@ impl<F: TxFiller<Ethereum>, P: Provider<Ethereum>> ResolverApi for GethNodeResol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove
|
|
||||||
impl ResolverApi for GethNode {
|
|
||||||
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
|
||||||
fn chain_id(
|
|
||||||
&self,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<alloy::primitives::ChainId>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Geth provider")?
|
|
||||||
.get_chain_id()
|
|
||||||
.await
|
|
||||||
.map_err(Into::into)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
|
||||||
fn transaction_gas_price(
|
|
||||||
&self,
|
|
||||||
tx_hash: TxHash,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<u128>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Geth provider")?
|
|
||||||
.get_transaction_receipt(tx_hash)
|
|
||||||
.await?
|
|
||||||
.context("Failed to get the transaction receipt")
|
|
||||||
.map(|receipt| receipt.effective_gas_price)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
|
||||||
fn block_gas_limit(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<u128>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Geth provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the geth block")?
|
|
||||||
.context("Failed to get the Geth block, perhaps there are no blocks?")
|
|
||||||
.map(|block| block.header.gas_limit as _)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
|
||||||
fn block_coinbase(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<Address>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Geth provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the geth block")?
|
|
||||||
.context("Failed to get the Geth block, perhaps there are no blocks?")
|
|
||||||
.map(|block| block.header.beneficiary)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
|
||||||
fn block_difficulty(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<U256>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Geth provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the geth block")?
|
|
||||||
.context("Failed to get the Geth block, perhaps there are no blocks?")
|
|
||||||
.map(|block| U256::from_be_bytes(block.header.mix_hash.0))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
|
||||||
fn block_base_fee(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<u64>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Geth provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the geth block")?
|
|
||||||
.context("Failed to get the Geth block, perhaps there are no blocks?")
|
|
||||||
.and_then(|block| {
|
|
||||||
block
|
|
||||||
.header
|
|
||||||
.base_fee_per_gas
|
|
||||||
.context("Failed to get the base fee per gas")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
|
||||||
fn block_hash(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<BlockHash>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Geth provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the geth block")?
|
|
||||||
.context("Failed to get the Geth block, perhaps there are no blocks?")
|
|
||||||
.map(|block| block.header.hash)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
|
||||||
fn block_timestamp(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<BlockTimestamp>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Geth provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the geth block")?
|
|
||||||
.context("Failed to get the Geth block, perhaps there are no blocks?")
|
|
||||||
.map(|block| block.header.timestamp)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
|
||||||
fn last_block_number(&self) -> Pin<Box<dyn Future<Output = anyhow::Result<BlockNumber>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Geth provider")?
|
|
||||||
.get_block_number()
|
|
||||||
.await
|
|
||||||
.map_err(Into::into)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node for GethNode {
|
impl Node for GethNode {
|
||||||
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
#[instrument(level = "info", skip_all, fields(geth_node_id = self.id))]
|
||||||
fn shutdown(&mut self) -> anyhow::Result<()> {
|
fn shutdown(&mut self) -> anyhow::Result<()> {
|
||||||
@@ -884,7 +732,7 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let chain_id = node.chain_id().await;
|
let chain_id = node.resolver().await.unwrap().chain_id().await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let chain_id = chain_id.expect("Failed to get the chain id");
|
let chain_id = chain_id.expect("Failed to get the chain id");
|
||||||
@@ -897,7 +745,12 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let gas_limit = node.block_gas_limit(BlockNumberOrTag::Latest).await;
|
let gas_limit = node
|
||||||
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_gas_limit(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let gas_limit = gas_limit.expect("Failed to get the gas limit");
|
let gas_limit = gas_limit.expect("Failed to get the gas limit");
|
||||||
@@ -910,7 +763,12 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let coinbase = node.block_coinbase(BlockNumberOrTag::Latest).await;
|
let coinbase = node
|
||||||
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_coinbase(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let coinbase = coinbase.expect("Failed to get the coinbase");
|
let coinbase = coinbase.expect("Failed to get the coinbase");
|
||||||
@@ -923,7 +781,12 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_difficulty = node.block_difficulty(BlockNumberOrTag::Latest).await;
|
let block_difficulty = node
|
||||||
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_difficulty(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let block_difficulty = block_difficulty.expect("Failed to get the block difficulty");
|
let block_difficulty = block_difficulty.expect("Failed to get the block difficulty");
|
||||||
@@ -936,7 +799,12 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_hash = node.block_hash(BlockNumberOrTag::Latest).await;
|
let block_hash = node
|
||||||
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_hash(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_hash.expect("Failed to get the block hash");
|
let _ = block_hash.expect("Failed to get the block hash");
|
||||||
@@ -948,7 +816,12 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_timestamp = node.block_timestamp(BlockNumberOrTag::Latest).await;
|
let block_timestamp = node
|
||||||
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_timestamp(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
||||||
@@ -960,7 +833,7 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_number = node.last_block_number().await;
|
let block_number = node.resolver().await.unwrap().last_block_number().await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let block_number = block_number.expect("Failed to get the block number");
|
let block_number = block_number.expect("Failed to get the block number");
|
||||||
|
|||||||
+32
-150
@@ -671,149 +671,6 @@ impl<F: TxFiller<ReviveNetwork>, P: Provider<ReviveNetwork>> ResolverApi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove
|
|
||||||
impl ResolverApi for SubstrateNode {
|
|
||||||
fn chain_id(
|
|
||||||
&self,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<alloy::primitives::ChainId>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Kitchensink provider")?
|
|
||||||
.get_chain_id()
|
|
||||||
.await
|
|
||||||
.map_err(Into::into)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transaction_gas_price(
|
|
||||||
&self,
|
|
||||||
tx_hash: TxHash,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<u128>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Kitchensink provider")?
|
|
||||||
.get_transaction_receipt(tx_hash)
|
|
||||||
.await?
|
|
||||||
.context("Failed to get the transaction receipt")
|
|
||||||
.map(|receipt| receipt.effective_gas_price)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_gas_limit(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<u128>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Kitchensink provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the kitchensink block")?
|
|
||||||
.context("Failed to get the Kitchensink block, perhaps the chain has no blocks?")
|
|
||||||
.map(|block| block.header.gas_limit as _)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_coinbase(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<Address>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Kitchensink provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the kitchensink block")?
|
|
||||||
.context("Failed to get the Kitchensink block, perhaps the chain has no blocks?")
|
|
||||||
.map(|block| block.header.beneficiary)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_difficulty(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<U256>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Kitchensink provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the kitchensink block")?
|
|
||||||
.context("Failed to get the Kitchensink block, perhaps the chain has no blocks?")
|
|
||||||
.map(|block| U256::from_be_bytes(block.header.mix_hash.0))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_base_fee(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<u64>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Kitchensink provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the kitchensink block")?
|
|
||||||
.context("Failed to get the Kitchensink block, perhaps the chain has no blocks?")
|
|
||||||
.and_then(|block| {
|
|
||||||
block
|
|
||||||
.header
|
|
||||||
.base_fee_per_gas
|
|
||||||
.context("Failed to get the base fee per gas")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_hash(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<BlockHash>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Kitchensink provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the kitchensink block")?
|
|
||||||
.context("Failed to get the Kitchensink block, perhaps the chain has no blocks?")
|
|
||||||
.map(|block| block.header.hash)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_timestamp(
|
|
||||||
&self,
|
|
||||||
number: BlockNumberOrTag,
|
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<BlockTimestamp>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Kitchensink provider")?
|
|
||||||
.get_block_by_number(number)
|
|
||||||
.await
|
|
||||||
.context("Failed to get the kitchensink block")?
|
|
||||||
.context("Failed to get the Kitchensink block, perhaps the chain has no blocks?")
|
|
||||||
.map(|block| block.header.timestamp)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn last_block_number(&self) -> Pin<Box<dyn Future<Output = anyhow::Result<BlockNumber>> + '_>> {
|
|
||||||
Box::pin(async move {
|
|
||||||
self.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to get the Kitchensink provider")?
|
|
||||||
.get_block_number()
|
|
||||||
.await
|
|
||||||
.map_err(Into::into)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node for SubstrateNode {
|
impl Node for SubstrateNode {
|
||||||
fn shutdown(&mut self) -> anyhow::Result<()> {
|
fn shutdown(&mut self) -> anyhow::Result<()> {
|
||||||
// Terminate the processes in a graceful manner to allow for the output to be flushed.
|
// Terminate the processes in a graceful manner to allow for the output to be flushed.
|
||||||
@@ -1544,7 +1401,7 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let chain_id = node.chain_id().await;
|
let chain_id = node.resolver().await.unwrap().chain_id().await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let chain_id = chain_id.expect("Failed to get the chain id");
|
let chain_id = chain_id.expect("Failed to get the chain id");
|
||||||
@@ -1557,7 +1414,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let gas_limit = node.block_gas_limit(BlockNumberOrTag::Latest).await;
|
let gas_limit = node
|
||||||
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_gas_limit(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = gas_limit.expect("Failed to get the gas limit");
|
let _ = gas_limit.expect("Failed to get the gas limit");
|
||||||
@@ -1569,7 +1431,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let coinbase = node.block_coinbase(BlockNumberOrTag::Latest).await;
|
let coinbase = node
|
||||||
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_coinbase(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = coinbase.expect("Failed to get the coinbase");
|
let _ = coinbase.expect("Failed to get the coinbase");
|
||||||
@@ -1581,7 +1448,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_difficulty = node.block_difficulty(BlockNumberOrTag::Latest).await;
|
let block_difficulty = node
|
||||||
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_difficulty(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_difficulty.expect("Failed to get the block difficulty");
|
let _ = block_difficulty.expect("Failed to get the block difficulty");
|
||||||
@@ -1593,7 +1465,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_hash = node.block_hash(BlockNumberOrTag::Latest).await;
|
let block_hash = node
|
||||||
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_hash(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_hash.expect("Failed to get the block hash");
|
let _ = block_hash.expect("Failed to get the block hash");
|
||||||
@@ -1605,7 +1482,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_timestamp = node.block_timestamp(BlockNumberOrTag::Latest).await;
|
let block_timestamp = node
|
||||||
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_timestamp(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
||||||
@@ -1617,7 +1499,7 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_number = node.last_block_number().await;
|
let block_number = node.resolver().await.unwrap().last_block_number().await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_number.expect("Failed to get the block number");
|
let _ = block_number.expect("Failed to get the block number");
|
||||||
|
|||||||
Reference in New Issue
Block a user