Skip to content

Commit

Permalink
feat: add compile sierra to casm util
Browse files Browse the repository at this point in the history
  • Loading branch information
ArniStarkware committed Jul 22, 2024
1 parent 77398c0 commit 7d36848
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 39 deletions.
13 changes: 2 additions & 11 deletions crates/gateway/src/compilation.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::panic;
use std::sync::OnceLock;

use blockifier::execution::contract_class::{ClassInfo, ContractClass, ContractClassV1};
Expand All @@ -8,7 +7,6 @@ use cairo_lang_starknet_classes::casm_contract_class::{
use starknet_api::core::CompiledClassHash;
use starknet_api::rpc_transaction::RPCDeclareTransaction;
use starknet_sierra_compile::compile::compile_sierra_to_casm;
use starknet_sierra_compile::errors::CompilationUtilError;
use starknet_sierra_compile::utils::into_contract_class_for_compilation;

use crate::config::GatewayCompilerConfig;
Expand Down Expand Up @@ -39,15 +37,8 @@ impl GatewayCompiler {
into_contract_class_for_compilation(starknet_api_contract_class);

// Compile Sierra to Casm.
let catch_unwind_result =
panic::catch_unwind(|| compile_sierra_to_casm(cairo_lang_contract_class));
let casm_contract_class = match catch_unwind_result {
Ok(compilation_result) => compilation_result?,
Err(_) => {
// TODO(Arni): Log the panic.
return Err(GatewayError::CompilationError(CompilationUtilError::CompilationPanic));
}
};
let casm_contract_class = compile_sierra_to_casm(cairo_lang_contract_class)?;

self.validate_casm_class(&casm_contract_class)?;

let hash_result = CompiledClassHash(casm_contract_class.compiled_class_hash());
Expand Down
6 changes: 3 additions & 3 deletions crates/gateway/src/compilation_test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use assert_matches::assert_matches;
use blockifier::execution::contract_class::ContractClass;
use cairo_lang_starknet_classes::allowed_libfuncs::AllowedLibfuncsError;
use mempool_test_utils::starknet_api_test_utils::declare_tx;
use rstest::{fixture, rstest};
use starknet_api::core::CompiledClassHash;
Expand Down Expand Up @@ -48,9 +47,10 @@ fn test_compile_contract_class_bad_sierra(gateway_compiler: GatewayCompiler) {
let result = gateway_compiler.compile_contract_class(&declare_tx);
assert_matches!(
result.unwrap_err(),
GatewayError::CompilationError(CompilationUtilError::AllowedLibfuncsError(
AllowedLibfuncsError::SierraProgramError
GatewayError::CompilationError(CompilationUtilError::CompilationError(
string
))
if string.contains("Error: Invalid Sierra program.")
)
}

Expand Down
23 changes: 23 additions & 0 deletions crates/starknet_sierra_compile/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use std::process::Command;

fn main() {
println!("cargo::rerun-if-changed=../../Cargo.lock");
println!("cargo::rerun-if-changed=build.rs");
install_starknet_sierra_compile();
}

fn install_starknet_sierra_compile() {
println!("Installing starknet-sierra-compile");
let mut command = Command::new("cargo");
command.arg("install");
command.arg("--root");
command.arg("tmp/cargo"); // TODO: Don't dup the path.
command.arg("starknet-sierra-compile");
let compile_output =
command.output().unwrap_or_else(|e| panic!("Failed to execute command: {}", e));

if !compile_output.status.success() {
let stderr_output = String::from_utf8(compile_output.stderr).unwrap(); // TODO:handle error
panic!("Failed to compile Sierra code: {}", stderr_output);
};
}
68 changes: 53 additions & 15 deletions crates/starknet_sierra_compile/src/compile.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,71 @@
use cairo_lang_starknet_classes::allowed_libfuncs::ListSelector;
use std::env;
use std::env::temp_dir;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;

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

use crate::errors::CompilationUtilError;

// Solve Code duplication.
pub fn get_absolute_path(relative_path: &str) -> PathBuf {
Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join("../..").join(relative_path)
}

#[cfg(test)]
#[path = "compile_test.rs"]
pub mod compile_test;
pub struct SierraToCasmCompilationArgs {
list_selector: ListSelector,

const STARKNET_SIERRA_COMPILE_EXE: &str =
"crates/starknet_sierra_compile/tmp/cargo/bin/starknet-sierra-compile";

struct SierraToCasmCompilationArgs {
add_pythonic_hints: bool,
max_bytecode_size: usize,
}

/// This function may panic.
// TODO(Arni, 1/05/2024): Add the configurable parameters to the function.
pub fn compile_sierra_to_casm(
contract_class: ContractClass,
) -> Result<CasmContractClass, CompilationUtilError> {
let compilation_args = SierraToCasmCompilationArgs {
list_selector: ListSelector::DefaultList,
add_pythonic_hints: true,
max_bytecode_size: 1000000,
};
env::set_current_dir(get_absolute_path("")).expect("Failed to set current dir.");

let serialized_contract_class = serde_json::to_string(&contract_class).expect("number 1");

// Create a temporary file path
let mut temp_path = temp_dir();
temp_path.push("temp_file.sierra.json");

contract_class.validate_version_compatible(compilation_args.list_selector)?;
// Create and open the file
let mut file = File::create(&temp_path).expect("number 2");

// Write the content to the file
file.write_all(serialized_contract_class.as_bytes()).expect("number 3");

let compilation_args =
SierraToCasmCompilationArgs { add_pythonic_hints: true, max_bytecode_size: 180000 };
let compiler_path = STARKNET_SIERRA_COMPILE_EXE;

let mut command = Command::new(compiler_path);
command.arg(temp_path.to_str().expect("number 4"));

// Add aditional arguments.
if compilation_args.add_pythonic_hints {
command.arg("--add-pythonic-hints");
}
// TODO(Arni): use max-bytecode-size.
let _max_bytecode_size = compilation_args.max_bytecode_size;

let compile_output =
command.output().unwrap_or_else(|e| panic!("Failed to execute command: {}", e));

if !compile_output.status.success() {
let stderr_output = String::from_utf8(compile_output.stderr).expect("number 5"); // TODO: handle error
return Err(CompilationUtilError::CompilationError(stderr_output));
};

Ok(CasmContractClass::from_contract_class(
contract_class,
compilation_args.add_pythonic_hints,
compilation_args.max_bytecode_size,
)?)
Ok(serde_json::from_slice::<CasmContractClass>(&compile_output.stdout).expect("number 6"))
}
4 changes: 2 additions & 2 deletions crates/starknet_sierra_compile/src/compile_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ 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 crate::compile::{compile_sierra_to_casm, CompilationUtilError};
Expand Down Expand Up @@ -34,6 +33,7 @@ fn test_negative_flow_compile_sierra_to_casm() {
let result = compile_sierra_to_casm(contract_class);
assert_matches!(
result,
Err(CompilationUtilError::AllowedLibfuncsError(AllowedLibfuncsError::SierraProgramError))
Err(CompilationUtilError::CompilationError(string))
if string.contains("Error: Invalid Sierra program.")
);
}
10 changes: 2 additions & 8 deletions crates/starknet_sierra_compile/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
use cairo_lang_starknet_classes::allowed_libfuncs::AllowedLibfuncsError;
use cairo_lang_starknet_classes::casm_contract_class::StarknetSierraCompilationError;
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),
}

0 comments on commit 7d36848

Please sign in to comment.