diff --git a/Cargo.lock b/Cargo.lock index cfc2f21..0014281 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2998,7 +2998,10 @@ name = "revive-dt-compiler" version = "0.1.0" dependencies = [ "anyhow", + "log", "revive-common", + "revive-dt-config", + "revive-dt-solc-binaries", "revive-solc-json-interface", "semver 1.0.26", "serde_json", diff --git a/crates/compiler/Cargo.toml b/crates/compiler/Cargo.toml index 7c5af19..d86f8aa 100644 --- a/crates/compiler/Cargo.toml +++ b/crates/compiler/Cargo.toml @@ -11,6 +11,9 @@ rust-version.workspace = true [dependencies] anyhow = { workspace = true } revive-solc-json-interface = { workspace = true } +revive-dt-config = { workspace = true } +revive-dt-solc-binaries = { workspace = true } revive-common = { workspace = true } semver = { workspace = true } serde_json = { workspace = true } +log = { workspace = true } diff --git a/crates/compiler/src/lib.rs b/crates/compiler/src/lib.rs index 3651eb3..6820c27 100644 --- a/crates/compiler/src/lib.rs +++ b/crates/compiler/src/lib.rs @@ -9,6 +9,8 @@ use std::{ path::{Path, PathBuf}, }; +use revive_dt_config::Arguments; + use revive_common::EVMVersion; use revive_solc_json_interface::{ SolcStandardJsonInput, SolcStandardJsonInputLanguage, SolcStandardJsonInputSettings, @@ -33,6 +35,8 @@ pub trait SolidityCompiler { ) -> anyhow::Result>; fn new(solc_executable: PathBuf) -> Self; + + fn get_compiler_executable(config: &Arguments, version: Version) -> anyhow::Result; } /// The generic compilation input configuration. diff --git a/crates/compiler/src/revive_resolc.rs b/crates/compiler/src/revive_resolc.rs index ff76bc6..cae774b 100644 --- a/crates/compiler/src/revive_resolc.rs +++ b/crates/compiler/src/revive_resolc.rs @@ -1,2 +1,79 @@ -//! Implements the [crate::SolidityCompiler] trait with resolc for -//! compiling contracts to PVM bytecode. +//! Implements the [SolidityCompiler] trait with `resolc` for +//! compiling contracts to PolkaVM (PVM) bytecode. + +use std::{ + path::PathBuf, + process::{Command, Stdio}, +}; + +use crate::{CompilerInput, CompilerOutput, SolidityCompiler}; +use revive_dt_config::Arguments; +use revive_solc_json_interface::SolcStandardJsonOutput; + +/// A wrapper around the `resolc` binary, emitting PVM-compatible bytecode. +pub struct Resolc { + /// Path to the `resolc` executable + resolc_path: PathBuf, +} + +impl SolidityCompiler for Resolc { + type Options = Vec; + + fn build( + &self, + input: CompilerInput, + ) -> anyhow::Result> { + let mut child = Command::new(&self.resolc_path) + .arg("--standard-json") + .args(&input.extra_options) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + let stdin_pipe = child.stdin.as_mut().expect("stdin must be piped"); + serde_json::to_writer(stdin_pipe, &input.input)?; + + let json_in = serde_json::to_string_pretty(&input.input)?; + + let output = child.wait_with_output()?; + let stdout = output.stdout; + let stderr = output.stderr; + + if !output.status.success() { + log::error!( + "resolc failed exit={} stderr={} JSON-in={} ", + output.status, + String::from_utf8_lossy(&stderr), + json_in, + ); + } + + let parsed: SolcStandardJsonOutput = serde_json::from_slice(&stdout).map_err(|e| { + anyhow::anyhow!( + "failed to parse resolc JSON output: {e}\nstderr: {}", + String::from_utf8_lossy(&stderr) + ) + })?; + + Ok(CompilerOutput { + input, + output: parsed, + }) + } + + fn new(resolc_path: PathBuf) -> Self { + Resolc { resolc_path } + } + + fn get_compiler_executable( + config: &Arguments, + _version: semver::Version, + ) -> anyhow::Result { + if !config.resolc.as_os_str().is_empty() { + return Ok(config.resolc.clone()); + } + + Ok(PathBuf::from("resolc")) + } +} diff --git a/crates/compiler/src/solc.rs b/crates/compiler/src/solc.rs index aa21d51..c33e244 100644 --- a/crates/compiler/src/solc.rs +++ b/crates/compiler/src/solc.rs @@ -7,6 +7,8 @@ use std::{ }; use crate::{CompilerInput, CompilerOutput, SolidityCompiler}; +use revive_dt_config::Arguments; +use revive_dt_solc_binaries::download_solc; pub struct Solc { solc_path: PathBuf, @@ -39,4 +41,12 @@ impl SolidityCompiler for Solc { fn new(solc_path: PathBuf) -> Self { Self { solc_path } } + + fn get_compiler_executable( + config: &Arguments, + version: semver::Version, + ) -> anyhow::Result { + let path = download_solc(config.directory(), version, config.wasm)?; + Ok(path) + } } diff --git a/crates/core/src/driver/mod.rs b/crates/core/src/driver/mod.rs index 8c8d256..6865a48 100644 --- a/crates/core/src/driver/mod.rs +++ b/crates/core/src/driver/mod.rs @@ -8,7 +8,6 @@ use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler}; use revive_dt_config::Arguments; use revive_dt_format::{input::Input, metadata::Metadata, mode::SolcMode}; use revive_dt_node_interaction::EthereumNode; -use revive_dt_solc_binaries::download_solc; use revive_solc_json_interface::SolcStandardJsonOutput; use crate::Platform; @@ -43,16 +42,18 @@ where let sources = metadata.contract_sources()?; let base_path = metadata.directory()?.display().to_string(); + let mut compiler = Compiler::::new().base_path(base_path.clone()); for (file, _contract) in sources.values() { log::debug!("contract source {}", file.display()); compiler = compiler.with_source(file)?; } - let solc_path = download_solc(self.config.directory(), version, self.config.wasm)?; + let compiler_path = T::Compiler::get_compiler_executable(self.config, version)?; + let output = compiler .solc_optimizer(mode.solc_optimize()) - .try_build(solc_path)?; + .try_build(compiler_path)?; self.contracts.insert(output.input, output.output); diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 9ae8f3a..0eda722 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -3,7 +3,7 @@ //! This crate defines the testing configuration and //! provides a helper utilty to execute tests. -use revive_dt_compiler::{SolidityCompiler, solc}; +use revive_dt_compiler::{SolidityCompiler, revive_resolc, solc}; use revive_dt_node::geth; use revive_dt_node_interaction::EthereumNode; @@ -30,5 +30,5 @@ pub struct Kitchensink; impl Platform for Kitchensink { type Blockchain = geth::Instance; - type Compiler = solc::Solc; + type Compiler = revive_resolc::Resolc; } diff --git a/crates/core/src/main.rs b/crates/core/src/main.rs index 21ab8b0..c66bfe4 100644 --- a/crates/core/src/main.rs +++ b/crates/core/src/main.rs @@ -5,7 +5,7 @@ use rayon::{ThreadPoolBuilder, prelude::*}; use revive_dt_config::*; use revive_dt_core::{ - Geth, + Geth, Kitchensink, driver::{Driver, State}, }; use revive_dt_format::{corpus::Corpus, metadata::Metadata}; @@ -109,11 +109,16 @@ fn main_compile_only( ) -> anyhow::Result<()> { tests.par_iter().for_each(|metadata| { for mode in &metadata.solc_modes() { - let mut state = match platform { - TestingPlatform::Geth => State::::new(config), - _ => todo!(), + match platform { + TestingPlatform::Geth => { + let mut state = State::::new(config); + let _ = state.build_contracts(mode, metadata); + } + TestingPlatform::Kitchensink => { + let mut state = State::::new(config); + let _ = state.build_contracts(mode, metadata); + } }; - let _ = state.build_contracts(mode, metadata); } });