From f3ecaa2a7b1541eac96960ab2d1c963624f88ca4 Mon Sep 17 00:00:00 2001 From: Arni Hod Date: Mon, 26 Aug 2024 14:15:35 +0300 Subject: [PATCH] feat: use the starknet-sierra-compile binary to compile --- Cargo.lock | 1 + crates/starknet_sierra_compile/Cargo.toml | 1 + crates/starknet_sierra_compile/build.rs | 21 ++----- .../src/build_utils.rs | 28 +++++++++ .../src/command_line_compiler.rs | 61 +++++++++++++++++++ .../src/compile_test.rs | 22 +++++-- crates/starknet_sierra_compile/src/errors.rs | 12 ++++ crates/starknet_sierra_compile/src/lib.rs | 2 + 8 files changed, 127 insertions(+), 21 deletions(-) create mode 100644 crates/starknet_sierra_compile/src/build_utils.rs create mode 100644 crates/starknet_sierra_compile/src/command_line_compiler.rs diff --git a/Cargo.lock b/Cargo.lock index 0bfc1ed33e..65a3ce1160 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9107,6 +9107,7 @@ dependencies = [ "serde_json", "starknet-types-core", "starknet_api", + "tempfile", "thiserror", "validator", ] diff --git a/crates/starknet_sierra_compile/Cargo.toml b/crates/starknet_sierra_compile/Cargo.toml index 5d76a24570..97e211e96a 100644 --- a/crates/starknet_sierra_compile/Cargo.toml +++ b/crates/starknet_sierra_compile/Cargo.toml @@ -17,6 +17,7 @@ serde.workspace = true serde_json.workspace = true starknet-types-core.workspace = true starknet_api.workspace = true +tempfile.workspace = true thiserror.workspace = true validator.workspace = true diff --git a/crates/starknet_sierra_compile/build.rs b/crates/starknet_sierra_compile/build.rs index 25b9d88db4..ff1873ecf1 100644 --- a/crates/starknet_sierra_compile/build.rs +++ b/crates/starknet_sierra_compile/build.rs @@ -1,6 +1,7 @@ -use std::path::Path; use std::process::Command; +include!("src/build_utils.rs"); + fn main() { println!("cargo:rerun-if-changed=../../Cargo.lock"); println!("cargo:rerun-if-changed=build.rs"); @@ -8,7 +9,6 @@ fn main() { install_starknet_sierra_compile(); } -const BINARY_NAME: &str = "starknet-sierra-compile"; const REQUIRED_VERSION: &str = "2.7.1"; /// Downloads the Cairo crate from StarkWare's release page and extracts its contents into the @@ -16,18 +16,7 @@ const REQUIRED_VERSION: &str = "2.7.1"; /// compile Sierra to Casm. The binary is executed as a subprocess whenever Sierra compilation is /// required. fn install_starknet_sierra_compile() { - let out_dir = Path::new( - &std::env::var("OUT_DIR").expect("Failed to get the OUT_DIR environment variable"), - ) - .to_path_buf(); - // Get the crate's `OUT_DIR` and navigate up to reach the `target/BUILD_FLAVOR` directory. - // This directory is shared accross all crates in this project. - let shared_folder_dir = out_dir - .ancestors() - .nth(3) - .expect("Failed to navigate up three levels from OUT_DIR") - .join("shared_executables"); - let binary_path = shared_folder_dir.join(BINARY_NAME); + let binary_path = binary_path(); match Command::new(&binary_path).args(["--version"]).output() { Ok(binary_version) => { @@ -52,6 +41,7 @@ fn install_starknet_sierra_compile() { } } + let out_dir = out_dir(); let temp_cargo_path = out_dir.join("cargo"); let post_install_file_path = temp_cargo_path.join("bin").join(BINARY_NAME); @@ -74,7 +64,8 @@ fn install_starknet_sierra_compile() { } // Move the 'starknet-sierra-compile' executable to a shared location - std::fs::create_dir_all(shared_folder_dir).expect("Failed to create shared executables folder"); + std::fs::create_dir_all(shared_folder_dir()) + .expect("Failed to create shared executables folder"); let move_command_status = Command::new("mv") .args([post_install_file_path.as_os_str(), binary_path.as_os_str()]) .status() diff --git a/crates/starknet_sierra_compile/src/build_utils.rs b/crates/starknet_sierra_compile/src/build_utils.rs new file mode 100644 index 0000000000..af239682e5 --- /dev/null +++ b/crates/starknet_sierra_compile/src/build_utils.rs @@ -0,0 +1,28 @@ +use std::path::{Path, PathBuf}; + +const BINARY_NAME: &str = "starknet-sierra-compile"; + +fn out_dir() -> PathBuf { + Path::new(&std::env::var("OUT_DIR").expect("Failed to get the OUT_DIR environment variable")) + .to_path_buf() +} + +/// Get the crate's `OUT_DIR` and navigate up to reach the `target/BUILD_FLAVOR` directory. +/// This directory is shared accross all crates in this project. +fn target_dir() -> PathBuf { + let out_dir = out_dir(); + + out_dir + .ancestors() + .nth(3) + .expect("Failed to navigate up three levels from OUT_DIR") + .to_path_buf() +} + +fn shared_folder_dir() -> PathBuf { + target_dir().join("shared_executables") +} + +pub fn binary_path() -> PathBuf { + shared_folder_dir().join(BINARY_NAME) +} diff --git a/crates/starknet_sierra_compile/src/command_line_compiler.rs b/crates/starknet_sierra_compile/src/command_line_compiler.rs new file mode 100644 index 0000000000..2a59932ba3 --- /dev/null +++ b/crates/starknet_sierra_compile/src/command_line_compiler.rs @@ -0,0 +1,61 @@ +use std::io::Write; +use std::path::PathBuf; +use std::process::Command; + +use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass; +use cairo_lang_starknet_classes::contract_class::ContractClass; +use tempfile::NamedTempFile; + +use crate::build_utils::binary_path; +use crate::config::SierraToCasmCompilationConfig; +use crate::errors::CompilationUtilError; +use crate::SierraToCasmCompiler; + +#[derive(Clone)] +pub struct CommandLineCompiler { + pub config: SierraToCasmCompilationConfig, + path_to_starknet_sierra_compile_binary: PathBuf, +} + +impl CommandLineCompiler { + pub fn new(config: SierraToCasmCompilationConfig) -> Self { + Self { config, path_to_starknet_sierra_compile_binary: binary_path() } + } +} + +impl SierraToCasmCompiler for CommandLineCompiler { + fn compile( + &self, + contract_class: ContractClass, + ) -> Result { + // Create a temporary file to store the Sierra contract class. + let serialized_contract_class = serde_json::to_string(&contract_class)?; + + let mut temp_file = NamedTempFile::new()?; + temp_file.write_all(serialized_contract_class.as_bytes())?; + let temp_file_path = temp_file.path().to_str().ok_or( + CompilationUtilError::UnexpectedError("Failed to get temporary file path".to_owned()), + )?; + + // Set the parameters for the compile process. + // TODO(Arni): Setup the ulimit for the process. + let mut command = Command::new(self.path_to_starknet_sierra_compile_binary.as_os_str()); + command.args([ + temp_file_path, + "--add-pythonic-hints", + "--max-bytecode-size", + &self.config.max_bytecode_size.to_string(), + ]); + + // Run the compile process. + let compile_output = command.output()?; + + if !compile_output.status.success() { + let stderr_output = String::from_utf8(compile_output.stderr) + .unwrap_or("Failed to get stderr output".into()); + return Err(CompilationUtilError::CompilationError(stderr_output)); + }; + + Ok(serde_json::from_slice::(&compile_output.stdout)?) + } +} diff --git a/crates/starknet_sierra_compile/src/compile_test.rs b/crates/starknet_sierra_compile/src/compile_test.rs index 547b92c497..675f911343 100644 --- a/crates/starknet_sierra_compile/src/compile_test.rs +++ b/crates/starknet_sierra_compile/src/compile_test.rs @@ -3,22 +3,30 @@ use std::path::Path; use assert_matches::assert_matches; use mempool_test_utils::{get_absolute_path, FAULTY_ACCOUNT_CLASS_FILE, TEST_FILES_FOLDER}; -use rstest::{fixture, rstest}; +use rstest::rstest; use crate::cairo_lang_compiler::CairoLangSierraToCasmCompiler; +use crate::command_line_compiler::CommandLineCompiler; use crate::config::SierraToCasmCompilationConfig; use crate::errors::CompilationUtilError; use crate::test_utils::contract_class_from_file; use crate::SierraToCasmCompiler; -#[fixture] -fn compiler() -> impl SierraToCasmCompiler { - CairoLangSierraToCasmCompiler { config: SierraToCasmCompilationConfig::default() } +const SIERRA_TO_CASM_COMPILATION_CONFIG: SierraToCasmCompilationConfig = + SierraToCasmCompilationConfig { max_bytecode_size: 81920 }; + +fn cairo_lang_compiler() -> CairoLangSierraToCasmCompiler { + CairoLangSierraToCasmCompiler { config: SIERRA_TO_CASM_COMPILATION_CONFIG } +} +fn commnad_line_compiler() -> CommandLineCompiler { + CommandLineCompiler::new(SIERRA_TO_CASM_COMPILATION_CONFIG) } // TODO: use the other compiler as well. #[rstest] -fn test_compile_sierra_to_casm(compiler: impl SierraToCasmCompiler) { +#[case::cairo_lang_compiler(cairo_lang_compiler())] +#[case::command_line_compiler(commnad_line_compiler())] +fn test_compile_sierra_to_casm(#[case] compiler: impl SierraToCasmCompiler) { env::set_current_dir(get_absolute_path(TEST_FILES_FOLDER)).expect("Failed to set current dir."); let sierra_path = Path::new(FAULTY_ACCOUNT_CLASS_FILE); let expected_casm_contract_length = 72304; @@ -32,7 +40,9 @@ fn test_compile_sierra_to_casm(compiler: impl SierraToCasmCompiler) { // TODO(Arni, 1/5/2024): Add a test for panic result test. #[rstest] -fn test_negative_flow_compile_sierra_to_casm(compiler: impl SierraToCasmCompiler) { +#[case::cairo_lang_compiler(cairo_lang_compiler())] +#[case::command_line_compiler(commnad_line_compiler())] +fn test_negative_flow_compile_sierra_to_casm(#[case] compiler: impl SierraToCasmCompiler) { env::set_current_dir(get_absolute_path(TEST_FILES_FOLDER)).expect("Failed to set current dir."); let sierra_path = Path::new(FAULTY_ACCOUNT_CLASS_FILE); diff --git a/crates/starknet_sierra_compile/src/errors.rs b/crates/starknet_sierra_compile/src/errors.rs index c1f25719ec..85ca1823c2 100644 --- a/crates/starknet_sierra_compile/src/errors.rs +++ b/crates/starknet_sierra_compile/src/errors.rs @@ -21,3 +21,15 @@ impl From for CompilationUtilError { CompilationUtilError::CompilationError(error.to_string()) } } + +impl From for CompilationUtilError { + fn from(error: serde_json::Error) -> Self { + CompilationUtilError::UnexpectedError(error.to_string()) + } +} + +impl From for CompilationUtilError { + fn from(error: std::io::Error) -> Self { + CompilationUtilError::UnexpectedError(error.to_string()) + } +} diff --git a/crates/starknet_sierra_compile/src/lib.rs b/crates/starknet_sierra_compile/src/lib.rs index e68efcc505..8734f4d9c2 100644 --- a/crates/starknet_sierra_compile/src/lib.rs +++ b/crates/starknet_sierra_compile/src/lib.rs @@ -4,7 +4,9 @@ use cairo_lang_starknet_classes::contract_class::ContractClass; use crate::errors::CompilationUtilError; +pub mod build_utils; pub mod cairo_lang_compiler; +pub mod command_line_compiler; pub mod config; pub mod errors; pub mod utils;