Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
feat: cairo1 recompilation support
Browse files Browse the repository at this point in the history
Signed-off-by: Dori Medini <[email protected]>
  • Loading branch information
dorimedini-starkware committed May 7, 2024
1 parent 51a949c commit 2770631
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 7 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.

1 change: 1 addition & 0 deletions crates/blockifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ starknet-crypto.workspace = true
starknet_api = { workspace = true, features = ["testing"] }
strum.workspace = true
strum_macros.workspace = true
tempfile.workspace = true
thiserror.workspace = true
toml.workspace = true

Expand Down
68 changes: 65 additions & 3 deletions crates/blockifier/src/test_utils/cairo_compile.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use std::process::Command;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use std::{env, fs};

use cached::proc_macro::cached;
use serde::{Deserialize, Serialize};
use tempfile::NamedTempFile;

const CAIRO0_PIP_REQUIREMENTS_FILE: &str = "tests/requirements.txt";
const LOCAL_CAIRO1_REPO_RELATIVE_PATH: &str = "../../../cairo";

/// Objects for simple deserialization of Cargo.toml to fetch the Cairo1 compiler version.
/// The compiler itself isn't actually a dependency, so we compile by using the version of the
Expand Down Expand Up @@ -52,6 +56,25 @@ pub fn cairo1_compiler_version() -> String {
}
}

/// Returns the path to the local Cairo1 compiler repository.
fn local_cairo1_compiler_repo_path() -> PathBuf {
// Location of blockifier's Cargo.toml.
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

// Returns <blockifier_crate_root>/<RELATIVE_PATH_TO_CAIRO_REPO>.
Path::new(&manifest_dir).join(LOCAL_CAIRO1_REPO_RELATIVE_PATH)
}

/// Run a command, assert exit code is zero (otherwise panic with stderr output).
fn run_and_verify_output(command: &mut Command) -> Output {
let output = command.output().unwrap();
if !output.status.success() {
let stderr_output = String::from_utf8(output.stderr).unwrap();
panic!("{stderr_output}");
}
output
}

/// Compiles a Cairo0 program using the deprecated compiler.
pub fn cairo0_compile(path: String, extra_arg: Option<String>, debug_info: bool) -> Vec<u8> {
verify_cairo0_compiler_deps();
Expand All @@ -69,8 +92,34 @@ pub fn cairo0_compile(path: String, extra_arg: Option<String>, debug_info: bool)
}

/// Compiles a Cairo1 program using the compiler version set in the Cargo.toml.
pub fn cairo1_compile(_path: String) -> Vec<u8> {
todo!();
pub fn cairo1_compile(path: String, git_tag_override: Option<String>) -> Vec<u8> {
verify_cairo1_compiler_deps(git_tag_override);
let cairo1_compiler_path = local_cairo1_compiler_repo_path();
let mut cargo_command = Command::new("cargo");
let sierra_output = run_and_verify_output(cargo_command.args([
"run",
&format!("--manifest-path={}/Cargo.toml", cairo1_compiler_path.to_string_lossy()),
"--bin",
"starknet-compile",
"--",
"--single-file",
&path,
]));
let mut temp_file = NamedTempFile::new().unwrap();

temp_file.write_all(&sierra_output.stdout).unwrap();
let temp_path_str = temp_file.into_temp_path();

let mut cargo_command = Command::new("cargo");
let casm_output = run_and_verify_output(cargo_command.args([
"run",
&format!("--manifest-path={}/Cargo.toml", cairo1_compiler_path.to_string_lossy()),
"--bin",
"starknet-sierra-compile",
temp_path_str.to_str().unwrap(),
]));

casm_output.stdout
}

/// Verifies that the required dependencies are available before compiling.
Expand All @@ -97,3 +146,16 @@ fn verify_cairo0_compiler_deps() {
CAIRO0_PIP_REQUIREMENTS_FILE
);
}

fn verify_cairo1_compiler_deps(git_tag_override: Option<String>) {
// TODO(Dori, 1/6/2024): Check repo exists.
let tag = git_tag_override.unwrap_or(format!("v{}", cairo1_compiler_version()));
// Checkout the required version in the compiler repo.
run_and_verify_output(Command::new("git").args([
"-C",
// TODO(Dori, 1/6/2024): Handle CI case (repo path will be different).
&local_cairo1_compiler_repo_path().to_str().unwrap(),
"checkout",
&tag,
]));
}
11 changes: 10 additions & 1 deletion crates/blockifier/src/test_utils/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ const ERC20_CONTRACT_PATH: &str =
"./ERC20_without_some_syscalls/ERC20/erc20_contract_without_some_syscalls_compiled.json";
const ERC20_CONTRACT_SOURCE_PATH: &str = "./ERC20_without_some_syscalls/ERC20/ERC20.cairo";

// Legacy contract is compiled with a fixed version of the compiler.
const LEGACY_CONTRACT_COMPILER_TAG: &str = "v2.1.0";

/// Enum representing all feature contracts.
/// The contracts that are implemented in both Cairo versions include a version field.
#[derive(Clone, Copy, Debug, EnumIter)]
Expand Down Expand Up @@ -187,7 +190,13 @@ impl FeatureContract {
};
cairo0_compile(self.get_source_path(), extra_arg, false)
}
CairoVersion::Cairo1 => cairo1_compile(self.get_source_path()),
CairoVersion::Cairo1 => {
let tag_override = match self {
Self::LegacyTestContract => Some(LEGACY_CONTRACT_COMPILER_TAG.into()),
_ => None,
};
cairo1_compile(self.get_source_path(), tag_override)
}
}
}

Expand Down
13 changes: 10 additions & 3 deletions crates/blockifier/tests/feature_contracts_compatibility_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::fs;
use blockifier::test_utils::contracts::FeatureContract;
use blockifier::test_utils::CairoVersion;
use pretty_assertions::assert_eq;
use rstest::rstest;

const CAIRO0_FEATURE_CONTRACTS_DIR: &str = "feature_contracts/cairo0";
const CAIRO1_FEATURE_CONTRACTS_DIR: &str = "feature_contracts/cairo1";
Expand Down Expand Up @@ -123,9 +124,15 @@ fn verify_feature_contracts_match_enum() {
assert_eq!(compiled_paths_from_enum, compiled_paths_on_filesystem);
}

#[test]
#[rstest]
#[ignore]
fn verify_feature_contracts() {
fn verify_feature_contracts(
#[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion,
) {
if std::env::var("CI").is_ok() && matches!(cairo_version, CairoVersion::Cairo1) {
// TODO(Dori, 1/6/2024): Support Cairo1 contracts in the CI and remove this `if` statement.
return;
}
let fix_features = std::env::var("FIX_FEATURE_TEST").is_ok();
verify_feature_contracts_compatibility(fix_features, CairoVersion::Cairo0)
verify_feature_contracts_compatibility(fix_features, cairo_version)
}

0 comments on commit 2770631

Please sign in to comment.