Skip to content

Commit

Permalink
feat: use the constant starknet-sierra-compile binary to compile
Browse files Browse the repository at this point in the history
  • Loading branch information
ArniStarkware committed Aug 15, 2024
1 parent e783edf commit e311773
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 37 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions crates/gateway/src/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ impl GatewayCompiler {
) -> GatewayResult<CasmContractClass> {
match self.sierra_to_casm_compiler.compile(cairo_lang_contract_class) {
Ok(casm_contract_class) => Ok(casm_contract_class),
Err(starknet_sierra_compile::errors::CompilationUtilError::CompilationPanic) => {
// TODO(Arni): Log the panic.
error!("Compilation panicked.");
Err(starknet_sierra_compile::errors::CompilationUtilError::UnexpectedError(error)) => {
// TODO(Arni): Log the panic.UnexpectedPanic
error!("Compilation panicked. Error: {:?}", error);
Err(GatewaySpecError::UnexpectedError { data: "Internal server error.".to_owned() })
}
Err(e) => {
Expand Down
12 changes: 3 additions & 9 deletions crates/gateway/src/compilation_test.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use assert_matches::assert_matches;
use blockifier::execution::contract_class::ContractClass;
use cairo_lang_sierra_to_casm::compiler::CompilationError;
use cairo_lang_starknet_classes::allowed_libfuncs::AllowedLibfuncsError;
use cairo_lang_starknet_classes::casm_contract_class::StarknetSierraCompilationError;
use mempool_test_utils::starknet_api_test_utils::declare_tx as rpc_declare_tx;
use rstest::{fixture, rstest};
use starknet_api::core::CompiledClassHash;
Expand Down Expand Up @@ -65,11 +62,8 @@ fn test_compile_contract_class_bytecode_size_validation(declare_tx_v3: RpcDeclar

let result = gateway_compiler.process_declare_tx(&RpcDeclareTransaction::V3(declare_tx_v3));
assert_matches!(result.unwrap_err(), GatewaySpecError::CompilationFailed);
let expected_compilation_error = CompilationUtilError::StarknetSierraCompilationError(
StarknetSierraCompilationError::CompilationError(Box::new(
CompilationError::CodeSizeLimitExceeded,
)),
);
let expected_compilation_error =
CompilationUtilError::CompilationError("Code size limit exceeded.".to_owned());
assert!(logs_contain(format!("Compilation failed: {:?}", expected_compilation_error).as_str()));
}

Expand All @@ -88,7 +82,7 @@ fn test_compile_contract_class_bad_sierra(
assert_eq!(err, GatewaySpecError::CompilationFailed);

let expected_compilation_error =
CompilationUtilError::AllowedLibfuncsError(AllowedLibfuncsError::SierraProgramError);
CompilationUtilError::CompilationError("Invalid Sierra program.".to_owned());
assert!(logs_contain(format!("Compilation failed: {:?}", expected_compilation_error).as_str()));
}

Expand Down
1 change: 1 addition & 0 deletions crates/starknet_sierra_compile/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Binary file not shown.
12 changes: 6 additions & 6 deletions crates/starknet_sierra_compile/src/cairo_lang_compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ use crate::config::SierraToCasmCompilationConfig;
use crate::errors::CompilationUtilError;
use crate::SierraToCasmCompiler;

#[cfg(test)]
#[path = "compile_test.rs"]
pub mod compile_test;

/// A compiler that compiles Sierra programs to Casm. Uses the code from the
/// `cairo_lang_starknet_classes` crate.
#[derive(Clone)]
Expand All @@ -25,8 +21,12 @@ impl SierraToCasmCompiler for CairoLangSierraToCasmCompiler {
contract_class: ContractClass,
) -> Result<CasmContractClass, CompilationUtilError> {
let catch_unwind_result = panic::catch_unwind(|| self.compile_inner(contract_class));
let casm_contract_class =
catch_unwind_result.map_err(|_| CompilationUtilError::CompilationPanic)??;
let casm_contract_class = catch_unwind_result.map_err(|error| {
CompilationUtilError::UnexpectedError(format!(
"Compilation Paniced: Error: {:?}",
error
))
})??;

Ok(casm_contract_class)
}
Expand Down
74 changes: 74 additions & 0 deletions crates/starknet_sierra_compile/src/command_line_compiler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use std::io::Write;
use std::process::Command;
use std::sync::OnceLock;

use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use cairo_lang_starknet_classes::contract_class::ContractClass;
use tempfile::NamedTempFile;

use crate::config::SierraToCasmCompilationConfig;
use crate::errors::CompilationUtilError;
use crate::SierraToCasmCompiler;

#[derive(Clone)]
pub struct CommandLineCompiler {
pub config: SierraToCasmCompilationConfig,
}

impl SierraToCasmCompiler for CommandLineCompiler {
fn compile(
&self,
contract_class: ContractClass,
) -> Result<CasmContractClass, CompilationUtilError> {
// 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::CompilationError("Failed to get temporary file path".to_owned()),
)?;

// Set the parameters for the compile process.
let mut command = Command::new(excutable_file_location());
command.arg(temp_file_path);

command.arg("--add-pythonic-hints");
command.args(["--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::<CasmContractClass>(&compile_output.stdout)?)
}
}

/// Returns the absolute path from the project root.
pub fn get_absolute_path(relative_path: &str) -> std::path::PathBuf {
std::path::Path::new(&std::env::var("CARGO_MANIFEST_DIR").unwrap())
.join("../..")
.join(relative_path)
}

// TODO(Arni): Get the binary in a cleaner way.
/// Returns the location of the "starknet-sierra-compile" executable.
/// This executable compiles Sierra contracts into Casm.
fn excutable_file_location() -> &'static str {
static COMPILER_PATH: OnceLock<&str> = OnceLock::new();
COMPILER_PATH.get_or_init(|| {
const COMPILER_RELATIVE_PATH: &str =
"crates/starknet_sierra_compile/executable/starknet-sierra-compile";
Box::leak(
get_absolute_path(COMPILER_RELATIVE_PATH)
.to_str()
.expect("Error getting compiler path")
.into(),
)
})
}
32 changes: 19 additions & 13 deletions crates/starknet_sierra_compile/src/compile_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,29 @@ use std::env;
use std::path::Path;

use assert_matches::assert_matches;
use cairo_lang_starknet_classes::allowed_libfuncs::AllowedLibfuncsError;
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, CompilationUtilError};
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 };

const CAIRO_LANG_COMPILER: CairoLangSierraToCasmCompiler =
CairoLangSierraToCasmCompiler { config: SIERRA_TO_CASM_COMPILATION_CONFIG };
const COMMAND_LINE_COMPILER: CommandLineCompiler =
CommandLineCompiler { config: 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(&COMMAND_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;
Expand All @@ -31,7 +38,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(&COMMAND_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);

Expand All @@ -40,8 +49,5 @@ fn test_negative_flow_compile_sierra_to_casm(compiler: impl SierraToCasmCompiler
contract_class.sierra_program = contract_class.sierra_program[..100].to_vec();

let result = compiler.compile(contract_class);
assert_matches!(
result,
Err(CompilationUtilError::AllowedLibfuncsError(AllowedLibfuncsError::SierraProgramError))
);
assert_matches!(result, Err(CompilationUtilError::CompilationError(..)));
}
34 changes: 28 additions & 6 deletions crates/starknet_sierra_compile/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,32 @@ use thiserror::Error;

#[derive(Debug, Error)]
pub enum CompilationUtilError {
#[error(transparent)]
AllowedLibfuncsError(#[from] AllowedLibfuncsError),
#[error(transparent)]
StarknetSierraCompilationError(#[from] StarknetSierraCompilationError),
#[error("Compilation panicked")]
CompilationPanic,
#[error("Starknet Sierra compilation error: {0}")]
CompilationError(String),
#[error("Unexpected compilation error: {0}")]
UnexpectedError(String),
}

impl From<AllowedLibfuncsError> for CompilationUtilError {
fn from(error: AllowedLibfuncsError) -> Self {
CompilationUtilError::CompilationError(error.to_string())
}
}

impl From<StarknetSierraCompilationError> for CompilationUtilError {
fn from(error: StarknetSierraCompilationError) -> Self {
CompilationUtilError::CompilationError(error.to_string())
}
}

impl From<serde_json::Error> for CompilationUtilError {
fn from(error: serde_json::Error) -> Self {
CompilationUtilError::UnexpectedError(error.to_string())
}
}

impl From<std::io::Error> for CompilationUtilError {
fn from(error: std::io::Error) -> Self {
CompilationUtilError::UnexpectedError(error.to_string())
}
}
5 changes: 5 additions & 0 deletions crates/starknet_sierra_compile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ use cairo_lang_starknet_classes::contract_class::ContractClass;
use crate::errors::CompilationUtilError;

pub mod cairo_lang_compiler;
pub mod command_line_compiler;
pub mod config;
pub mod errors;
pub mod utils;

#[cfg(test)]
pub mod test_utils;

#[cfg(test)]
#[path = "compile_test.rs"]
pub mod compile_test;

pub trait SierraToCasmCompiler: Send + Sync {
fn compile(
&self,
Expand Down

0 comments on commit e311773

Please sign in to comment.