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

Commit 756aaef

Browse files
feat: cairo1 recompilation support
Signed-off-by: Dori Medini <dori@starkware.co>
1 parent 51a949c commit 756aaef

5 files changed

Lines changed: 87 additions & 7 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/blockifier/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ starknet-crypto.workspace = true
4747
starknet_api = { workspace = true, features = ["testing"] }
4848
strum.workspace = true
4949
strum_macros.workspace = true
50+
tempfile.workspace = true
5051
thiserror.workspace = true
5152
toml.workspace = true
5253

crates/blockifier/src/test_utils/cairo_compile.rs

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
use std::process::Command;
1+
use std::io::Write;
2+
use std::path::{Path, PathBuf};
3+
use std::process::{Command, Output};
24
use std::{env, fs};
35

46
use cached::proc_macro::cached;
57
use serde::{Deserialize, Serialize};
8+
use tempfile::NamedTempFile;
69

710
const CAIRO0_PIP_REQUIREMENTS_FILE: &str = "tests/requirements.txt";
11+
const LOCAL_CAIRO1_REPO_RELATIVE_PATH: &str = "../../../cairo";
812

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

59+
/// Returns the path to the local Cairo1 compiler repository.
60+
fn local_cairo1_compiler_repo_path() -> PathBuf {
61+
// Location of blockifier's Cargo.toml.
62+
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
63+
64+
// Returns <blockifier_crate_root>/<RELATIVE_PATH_TO_CAIRO_REPO>.
65+
Path::new(&manifest_dir).join(LOCAL_CAIRO1_REPO_RELATIVE_PATH)
66+
}
67+
68+
/// Run a command, assert exit code is zero (otherwise panic with stderr output).
69+
fn run_and_verify_output(command: &mut Command) -> Output {
70+
let output = command.output().unwrap();
71+
if !output.status.success() {
72+
let stderr_output = String::from_utf8(output.stderr).unwrap();
73+
panic!("{stderr_output}");
74+
}
75+
output
76+
}
77+
5578
/// Compiles a Cairo0 program using the deprecated compiler.
5679
pub fn cairo0_compile(path: String, extra_arg: Option<String>, debug_info: bool) -> Vec<u8> {
5780
verify_cairo0_compiler_deps();
@@ -69,8 +92,34 @@ pub fn cairo0_compile(path: String, extra_arg: Option<String>, debug_info: bool)
6992
}
7093

7194
/// Compiles a Cairo1 program using the compiler version set in the Cargo.toml.
72-
pub fn cairo1_compile(_path: String) -> Vec<u8> {
73-
todo!();
95+
pub fn cairo1_compile(path: String, git_tag_override: Option<String>) -> Vec<u8> {
96+
verify_cairo1_compiler_deps(git_tag_override);
97+
let cairo1_compiler_path = local_cairo1_compiler_repo_path();
98+
let mut cargo_command = Command::new("cargo");
99+
let sierra_output = run_and_verify_output(cargo_command.args([
100+
"run",
101+
&format!("--manifest-path={}/Cargo.toml", cairo1_compiler_path.to_string_lossy()),
102+
"--bin",
103+
"starknet-compile",
104+
"--",
105+
"--single-file",
106+
&path,
107+
]));
108+
let mut temp_file = NamedTempFile::new().unwrap();
109+
110+
temp_file.write_all(&sierra_output.stdout).unwrap();
111+
let temp_path_str = temp_file.into_temp_path();
112+
113+
let mut cargo_command = Command::new("cargo");
114+
let casm_output = run_and_verify_output(cargo_command.args([
115+
"run",
116+
&format!("--manifest-path={}/Cargo.toml", cairo1_compiler_path.to_string_lossy()),
117+
"--bin",
118+
"starknet-sierra-compile",
119+
temp_path_str.to_str().unwrap(),
120+
]));
121+
122+
casm_output.stdout
74123
}
75124

76125
/// Verifies that the required dependencies are available before compiling.
@@ -97,3 +146,16 @@ fn verify_cairo0_compiler_deps() {
97146
CAIRO0_PIP_REQUIREMENTS_FILE
98147
);
99148
}
149+
150+
fn verify_cairo1_compiler_deps(git_tag_override: Option<String>) {
151+
// TODO(Dori, 1/6/2024): Check repo exists.
152+
let tag = git_tag_override.unwrap_or(format!("v{}", cairo1_compiler_version()));
153+
// Checkout the required version in the compiler repo.
154+
run_and_verify_output(Command::new("git").args([
155+
"-C",
156+
// TODO(Dori, 1/6/2024): Handle CI case (repo path will be different).
157+
local_cairo1_compiler_repo_path().to_str().unwrap(),
158+
"checkout",
159+
&tag,
160+
]));
161+
}

crates/blockifier/src/test_utils/contracts.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ const ERC20_CONTRACT_PATH: &str =
5757
"./ERC20_without_some_syscalls/ERC20/erc20_contract_without_some_syscalls_compiled.json";
5858
const ERC20_CONTRACT_SOURCE_PATH: &str = "./ERC20_without_some_syscalls/ERC20/ERC20.cairo";
5959

60+
// Legacy contract is compiled with a fixed version of the compiler.
61+
const LEGACY_CONTRACT_COMPILER_TAG: &str = "v2.1.0";
62+
6063
/// Enum representing all feature contracts.
6164
/// The contracts that are implemented in both Cairo versions include a version field.
6265
#[derive(Clone, Copy, Debug, EnumIter)]
@@ -187,7 +190,13 @@ impl FeatureContract {
187190
};
188191
cairo0_compile(self.get_source_path(), extra_arg, false)
189192
}
190-
CairoVersion::Cairo1 => cairo1_compile(self.get_source_path()),
193+
CairoVersion::Cairo1 => {
194+
let tag_override = match self {
195+
Self::LegacyTestContract => Some(LEGACY_CONTRACT_COMPILER_TAG.into()),
196+
_ => None,
197+
};
198+
cairo1_compile(self.get_source_path(), tag_override)
199+
}
191200
}
192201
}
193202

crates/blockifier/tests/feature_contracts_compatibility_test.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::fs;
33
use blockifier::test_utils::contracts::FeatureContract;
44
use blockifier::test_utils::CairoVersion;
55
use pretty_assertions::assert_eq;
6+
use rstest::rstest;
67

78
const CAIRO0_FEATURE_CONTRACTS_DIR: &str = "feature_contracts/cairo0";
89
const CAIRO1_FEATURE_CONTRACTS_DIR: &str = "feature_contracts/cairo1";
@@ -123,9 +124,15 @@ fn verify_feature_contracts_match_enum() {
123124
assert_eq!(compiled_paths_from_enum, compiled_paths_on_filesystem);
124125
}
125126

126-
#[test]
127+
#[rstest]
127128
#[ignore]
128-
fn verify_feature_contracts() {
129+
fn verify_feature_contracts(
130+
#[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion,
131+
) {
132+
if std::env::var("CI").is_ok() && matches!(cairo_version, CairoVersion::Cairo1) {
133+
// TODO(Dori, 1/6/2024): Support Cairo1 contracts in the CI and remove this `if` statement.
134+
return;
135+
}
129136
let fix_features = std::env::var("FIX_FEATURE_TEST").is_ok();
130-
verify_feature_contracts_compatibility(fix_features, CairoVersion::Cairo0)
137+
verify_feature_contracts_compatibility(fix_features, cairo_version)
131138
}

0 commit comments

Comments
 (0)