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

Commit 7fba16f

Browse files
chore: move compilation logic to FeatureContracts enum
Signed-off-by: Dori Medini <[email protected]>
1 parent 3c6d246 commit 7fba16f

File tree

4 files changed

+91
-25
lines changed

4 files changed

+91
-25
lines changed

crates/blockifier/src/test_utils.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod cairo_compile;
12
pub mod contracts;
23
pub mod declare;
34
pub mod deploy_account;
@@ -49,7 +50,7 @@ pub const TEST_ERC20_CONTRACT_CLASS_HASH: &str = "0x1010";
4950
pub const ERC20_CONTRACT_PATH: &str =
5051
"./ERC20_without_some_syscalls/ERC20/erc20_contract_without_some_syscalls_compiled.json";
5152

52-
#[derive(Clone, Copy, Debug)]
53+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5354
pub enum CairoVersion {
5455
Cairo0,
5556
Cairo1,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use std::process::Command;
2+
3+
/// Compiles a Cairo0 program using the deprecated compiler.
4+
pub fn cairo0_compile(path: String, extra_arg: Option<String>, debug_info: bool) -> Vec<u8> {
5+
let mut command = Command::new("starknet-compile-deprecated");
6+
if let Some(extra_arg) = extra_arg {
7+
command.arg(extra_arg);
8+
}
9+
if !debug_info {
10+
command.args([&path, "--no_debug_info"]);
11+
}
12+
let compile_output = command.output().unwrap();
13+
let stderr_output = String::from_utf8(compile_output.stderr).unwrap();
14+
assert!(compile_output.status.success(), "{stderr_output}");
15+
compile_output.stdout
16+
}
17+
18+
/// Compiles a Cairo1 program using the compiler version set in the Cargo.toml.
19+
pub fn cairo1_compile(_path: String) -> Vec<u8> {
20+
todo!();
21+
}

crates/blockifier/src/test_utils/contracts.rs

+59-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use strum::IntoEnumIterator;
66
use strum_macros::EnumIter;
77

88
use crate::execution::contract_class::{ContractClass, ContractClassV0, ContractClassV1};
9+
use crate::test_utils::cairo_compile::{cairo0_compile, cairo1_compile};
910
use crate::test_utils::{get_raw_contract_class, CairoVersion};
1011

1112
// This file contains featured contracts, used for tests. Use the function 'test_state' in
@@ -51,8 +52,10 @@ const SECURITY_TEST_CONTRACT_NAME: &str = "security_tests_contract";
5152
const TEST_CONTRACT_NAME: &str = "test_contract";
5253

5354
// ERC20 contract is in a unique location.
55+
const ERC20_BASE_NAME: &str = "ERC20";
5456
const ERC20_CONTRACT_PATH: &str =
5557
"./ERC20_without_some_syscalls/ERC20/erc20_contract_without_some_syscalls_compiled.json";
58+
const ERC20_CONTRACT_SOURCE_PATH: &str = "./ERC20_without_some_syscalls/ERC20/ERC20.cairo";
5659

5760
/// Enum representing all feature contracts.
5861
/// The contracts that are implemented in both Cairo versions include a version field.
@@ -69,7 +72,7 @@ pub enum FeatureContract {
6972
}
7073

7174
impl FeatureContract {
72-
fn cairo_version(&self) -> CairoVersion {
75+
pub fn cairo_version(&self) -> CairoVersion {
7376
match self {
7477
Self::AccountWithLongValidate(version)
7578
| Self::AccountWithoutValidations(version)
@@ -114,18 +117,40 @@ impl FeatureContract {
114117
}
115118
}
116119

117-
pub fn get_compiled_path(&self) -> String {
118-
let cairo_version = self.cairo_version();
119-
let contract_name = match self {
120+
fn contract_base_name(&self) -> &str {
121+
match self {
120122
Self::AccountWithLongValidate(_) => ACCOUNT_LONG_VALIDATE_NAME,
121123
Self::AccountWithoutValidations(_) => ACCOUNT_WITHOUT_VALIDATIONS_NAME,
122124
Self::Empty(_) => EMPTY_CONTRACT_NAME,
123125
Self::FaultyAccount(_) => FAULTY_ACCOUNT_NAME,
124126
Self::LegacyTestContract => LEGACY_CONTRACT_NAME,
125127
Self::SecurityTests => SECURITY_TEST_CONTRACT_NAME,
126128
Self::TestContract(_) => TEST_CONTRACT_NAME,
129+
Self::ERC20 => ERC20_BASE_NAME,
130+
}
131+
}
132+
133+
pub fn get_source_path(&self) -> String {
134+
match self {
135+
// Special case: ERC20 contract in a different location.
136+
Self::ERC20 => ERC20_CONTRACT_SOURCE_PATH.into(),
137+
_not_erc20 => format!(
138+
"feature_contracts/cairo{}/{}.cairo",
139+
match self.cairo_version() {
140+
CairoVersion::Cairo0 => "0",
141+
CairoVersion::Cairo1 => "1",
142+
},
143+
self.contract_base_name()
144+
),
145+
}
146+
}
147+
148+
pub fn get_compiled_path(&self) -> String {
149+
let cairo_version = self.cairo_version();
150+
let contract_name = match self {
127151
// ERC20 is a special case - not in the feature_contracts directory.
128152
Self::ERC20 => return ERC20_CONTRACT_PATH.into(),
153+
_not_erc20 => self.contract_base_name(),
129154
};
130155
format!(
131156
"feature_contracts/cairo{}/compiled/{}{}.json",
@@ -141,6 +166,31 @@ impl FeatureContract {
141166
)
142167
}
143168

169+
/// Compiles the feature contract and returns the compiled contract as a byte vector.
170+
/// Panics if the contract is ERC20, as ERC20 contract recompilation is not supported.
171+
pub fn compile(&self) -> Vec<u8> {
172+
if matches!(self, Self::ERC20) {
173+
panic!("ERC20 contract recompilation not supported.");
174+
}
175+
match self.cairo_version() {
176+
CairoVersion::Cairo0 => {
177+
let extra_arg: Option<String> = match self {
178+
// Account contracts require the account_contract flag.
179+
FeatureContract::AccountWithLongValidate(_)
180+
| FeatureContract::AccountWithoutValidations(_)
181+
| FeatureContract::FaultyAccount(_) => Some("--account_contract".into()),
182+
FeatureContract::SecurityTests => Some("--disable_hint_validation".into()),
183+
FeatureContract::Empty(_)
184+
| FeatureContract::TestContract(_)
185+
| FeatureContract::LegacyTestContract => None,
186+
FeatureContract::ERC20 => unreachable!(),
187+
};
188+
cairo0_compile(self.get_source_path(), extra_arg, false)
189+
}
190+
CairoVersion::Cairo1 => cairo1_compile(self.get_source_path()),
191+
}
192+
}
193+
144194
pub fn set_cairo_version(&mut self, version: CairoVersion) {
145195
match self {
146196
Self::AccountWithLongValidate(v)
@@ -203,4 +253,9 @@ impl FeatureContract {
203253
}
204254
})
205255
}
256+
257+
pub fn all_feature_contracts() -> impl Iterator<Item = Self> {
258+
// ERC20 is a special case - not in the feature_contracts directory.
259+
Self::all_contracts().filter(|contract| !matches!(contract, Self::ERC20))
260+
}
206261
}

crates/blockifier/tests/feature_contracts_compatibility_test.rs

+9-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use std::fs;
2-
use std::process::Command;
32

43
use blockifier::test_utils::contracts::FeatureContract;
54
use blockifier::test_utils::CairoVersion;
@@ -41,20 +40,12 @@ const FIX_COMMAND: &str = "FIX_FEATURE_TEST=1 cargo test -- --ignored";
4140
// 2. for each `X.cairo` file in `TEST_CONTRACTS` there exists an `X_compiled.json` file in
4241
// `COMPILED_CONTRACTS_SUBDIR` which equals `starknet-compile-deprecated X.cairo --no_debug_info`.
4342
fn verify_feature_contracts_compatibility(fix: bool, cairo_version: CairoVersion) {
44-
for (path_str, file_name, existing_compiled_path) in verify_and_get_files(cairo_version) {
43+
for contract in FeatureContract::all_feature_contracts()
44+
.filter(|contract| contract.cairo_version() == cairo_version)
45+
{
4546
// Compare output of cairo-file on file with existing compiled file.
46-
let mut command = Command::new("starknet-compile-deprecated");
47-
command.args([&path_str, "--no_debug_info"]);
48-
if file_name.starts_with("account") {
49-
command.arg("--account_contract");
50-
}
51-
if file_name.starts_with("security") {
52-
command.arg("--disable_hint_validation");
53-
}
54-
let compile_output = command.output().unwrap();
55-
let stderr_output = String::from_utf8(compile_output.stderr).unwrap();
56-
assert!(compile_output.status.success(), "{stderr_output}");
57-
let expected_compiled_output = compile_output.stdout;
47+
let expected_compiled_output = contract.compile();
48+
let existing_compiled_path = contract.get_compiled_path();
5849

5950
if fix {
6051
fs::write(&existing_compiled_path, &expected_compiled_output).unwrap();
@@ -64,9 +55,9 @@ fn verify_feature_contracts_compatibility(fix: bool, cairo_version: CairoVersion
6455

6556
if String::from_utf8(expected_compiled_output).unwrap() != existing_compiled_contents {
6657
panic!(
67-
"{path_str} does not compile to {existing_compiled_path}.\nRun `{FIX_COMMAND}` to \
68-
fix the expected test according to locally installed \
69-
`starknet-compile-deprecated`.\n"
58+
"{} does not compile to {existing_compiled_path}.\nRun `{FIX_COMMAND}` to fix the \
59+
expected test according to locally installed `starknet-compile-deprecated`.\n",
60+
contract.get_source_path()
7061
);
7162
}
7263
}
@@ -119,9 +110,7 @@ fn verify_and_get_files(cairo_version: CairoVersion) -> Vec<(String, String, Str
119110

120111
#[test]
121112
fn verify_feature_contracts_match_enum() {
122-
let mut compiled_paths_from_enum: Vec<String> = FeatureContract::all_contracts()
123-
// ERC20 is a special case - not in the feature_contracts directory.
124-
.filter(|contract| !matches!(contract, FeatureContract::ERC20))
113+
let mut compiled_paths_from_enum: Vec<String> = FeatureContract::all_feature_contracts()
125114
.map(|contract| contract.get_compiled_path())
126115
.collect();
127116
let mut compiled_paths_on_filesystem: Vec<String> = verify_and_get_files(CairoVersion::Cairo0)

0 commit comments

Comments
 (0)