Emerge Yul recompiler (#1)

Provide a modified (and incomplete) version of ZKSync zksolc that can compile the most basic contracts
This commit is contained in:
Cyrill Leutwiler
2024-03-12 12:06:02 +01:00
committed by GitHub
parent d238d8f39e
commit cffa14a4d2
247 changed files with 35357 additions and 4905 deletions
+57
View File
@@ -0,0 +1,57 @@
//!
//! Process for compiling a single compilation unit.
//!
//! The input data.
//!
use serde::Deserialize;
use serde::Serialize;
use crate::project::contract::Contract;
use crate::project::Project;
///
/// The input data.
///
#[derive(Debug, Serialize, Deserialize)]
pub struct Input {
/// The contract representation.
pub contract: Contract,
/// The project representation.
pub project: Project,
/// The system mode flag.
pub is_system_mode: bool,
/// Whether to append the metadata hash.
pub include_metadata_hash: bool,
/// Enables the test bytecode encoding.
pub enable_test_encoding: bool,
/// The optimizer settings.
pub optimizer_settings: era_compiler_llvm_context::OptimizerSettings,
/// The debug output config.
pub debug_config: Option<era_compiler_llvm_context::DebugConfig>,
}
impl Input {
///
/// A shortcut constructor.
///
pub fn new(
contract: Contract,
project: Project,
is_system_mode: bool,
include_metadata_hash: bool,
enable_test_encoding: bool,
optimizer_settings: era_compiler_llvm_context::OptimizerSettings,
debug_config: Option<era_compiler_llvm_context::DebugConfig>,
) -> Self {
Self {
contract,
project,
is_system_mode,
include_metadata_hash,
enable_test_encoding,
optimizer_settings,
debug_config,
}
}
}
+108
View File
@@ -0,0 +1,108 @@
//!
//! Process for compiling a single compilation unit.
//!
pub mod input;
pub mod output;
use std::io::Read;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
use once_cell::sync::OnceCell;
use self::input::Input;
use self::output::Output;
/// The overriden executable name used when the compiler is run as a library.
pub static EXECUTABLE: OnceCell<PathBuf> = OnceCell::new();
///
/// Read input from `stdin`, compile a contract, and write the output to `stdout`.
///
pub fn run() -> anyhow::Result<()> {
let mut stdin = std::io::stdin();
let mut stdout = std::io::stdout();
let mut stderr = std::io::stderr();
let mut buffer = Vec::with_capacity(16384);
stdin.read_to_end(&mut buffer).expect("Stdin reading error");
let input: Input = era_compiler_common::deserialize_from_slice(buffer.as_slice())?;
if input.enable_test_encoding {
todo!()
}
let result = input.contract.compile(
input.project,
input.optimizer_settings,
input.is_system_mode,
input.include_metadata_hash,
input.debug_config,
);
match result {
Ok(build) => {
let output = Output::new(build);
let json = serde_json::to_vec(&output).expect("Always valid");
stdout
.write_all(json.as_slice())
.expect("Stdout writing error");
Ok(())
}
Err(error) => {
let message = error.to_string();
stderr
.write_all(message.as_bytes())
.expect("Stderr writing error");
Err(error)
}
}
}
///
/// Runs this process recursively to compile a single contract.
///
pub fn call(input: Input) -> anyhow::Result<Output> {
let input_json = serde_json::to_vec(&input).expect("Always valid");
let executable = match EXECUTABLE.get() {
Some(executable) => executable.to_owned(),
None => std::env::current_exe()?,
};
let mut command = Command::new(executable.as_path());
command.stdin(std::process::Stdio::piped());
command.stdout(std::process::Stdio::piped());
command.stderr(std::process::Stdio::piped());
command.arg("--recursive-process");
let process = command.spawn().map_err(|error| {
anyhow::anyhow!("{:?} subprocess spawning error: {:?}", executable, error)
})?;
process
.stdin
.as_ref()
.ok_or_else(|| anyhow::anyhow!("{:?} stdin getting error", executable))?
.write_all(input_json.as_slice())
.map_err(|error| anyhow::anyhow!("{:?} stdin writing error: {:?}", executable, error))?;
let output = process.wait_with_output().map_err(|error| {
anyhow::anyhow!("{:?} subprocess output error: {:?}", executable, error)
})?;
if !output.status.success() {
anyhow::bail!(
"{}",
String::from_utf8_lossy(output.stderr.as_slice()).to_string(),
);
}
let output: Output = era_compiler_common::deserialize_from_slice(output.stdout.as_slice())
.map_err(|error| {
anyhow::anyhow!(
"{:?} subprocess output parsing error: {}",
executable,
error,
)
})?;
Ok(output)
}
+28
View File
@@ -0,0 +1,28 @@
//!
//! Process for compiling a single compilation unit.
//!
//! The output data.
//!
use serde::Deserialize;
use serde::Serialize;
use crate::build::contract::Contract as ContractBuild;
///
/// The output data.
///
#[derive(Debug, Serialize, Deserialize)]
pub struct Output {
/// The contract build.
pub build: ContractBuild,
}
impl Output {
///
/// A shortcut constructor.
///
pub fn new(build: ContractBuild) -> Self {
Self { build }
}
}