Skip to content

Commit

Permalink
chore(blockifier): move contract compilation logic to separate module…
Browse files Browse the repository at this point in the history
… + contracts.rs
  • Loading branch information
dorimedini-starkware committed Aug 11, 2024
1 parent e4fc399 commit 11f058a
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 21 deletions.
1 change: 1 addition & 0 deletions crates/blockifier/src/test_utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod cairo_compile;
pub mod contracts;
pub mod declare;
pub mod deploy_account;
Expand Down
22 changes: 22 additions & 0 deletions crates/blockifier/src/test_utils/cairo_compile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use std::process::Command;

/// Compiles a Cairo0 program using the deprecated compiler.
pub fn cairo0_compile(path: String, extra_arg: Option<String>, debug_info: bool) -> Vec<u8> {
let mut command = Command::new("starknet-compile-deprecated");
command.arg(&path);
if let Some(extra_arg) = extra_arg {
command.arg(extra_arg);
}
if !debug_info {
command.arg("--no_debug_info");
}
let compile_output = command.output().unwrap();
let stderr_output = String::from_utf8(compile_output.stderr).unwrap();
assert!(compile_output.status.success(), "{stderr_output}");
compile_output.stdout
}

/// Compiles a Cairo1 program using the compiler version set in the Cargo.toml.
pub fn cairo1_compile(_path: String) -> Vec<u8> {
todo!();
}
31 changes: 31 additions & 0 deletions crates/blockifier/src/test_utils/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use strum_macros::EnumIter;
use crate::abi::abi_utils::selector_from_name;
use crate::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME;
use crate::execution::contract_class::{ContractClass, ContractClassV0, ContractClassV1};
use crate::test_utils::cairo_compile::{cairo0_compile, cairo1_compile};
use crate::test_utils::{get_raw_contract_class, CairoVersion};

// This file contains featured contracts, used for tests. Use the function 'test_state' in
Expand Down Expand Up @@ -253,6 +254,31 @@ impl FeatureContract {
}
}

/// Compiles the feature contract and returns the compiled contract as a byte vector.
/// Panics if the contract is ERC20, as ERC20 contract recompilation is not supported.
pub fn compile(&self) -> Vec<u8> {
if matches!(self, Self::ERC20(_)) {
panic!("ERC20 contract recompilation not supported.");
}
match self.cairo_version() {
CairoVersion::Cairo0 => {
let extra_arg: Option<String> = match self {
// Account contracts require the account_contract flag.
FeatureContract::AccountWithLongValidate(_)
| FeatureContract::AccountWithoutValidations(_)
| FeatureContract::FaultyAccount(_) => Some("--account_contract".into()),
FeatureContract::SecurityTests => Some("--disable_hint_validation".into()),
FeatureContract::Empty(_)
| FeatureContract::TestContract(_)
| FeatureContract::LegacyTestContract => None,
FeatureContract::ERC20(_) => unreachable!(),
};
cairo0_compile(self.get_source_path(), extra_arg, false)
}
CairoVersion::Cairo1 => cairo1_compile(self.get_source_path()),
}
}

/// Fetch PC locations from the compiled contract to compute the expected PC locations in the
/// traceback. Computation is not robust, but as long as the cairo function itself is not
/// edited, this computation should be stable.
Expand Down Expand Up @@ -314,4 +340,9 @@ impl FeatureContract {
}
})
}

pub fn all_feature_contracts() -> impl Iterator<Item = Self> {
// ERC20 is a special case - not in the feature_contracts directory.
Self::all_contracts().filter(|contract| !matches!(contract, Self::ERC20(_)))
}
}
30 changes: 9 additions & 21 deletions crates/blockifier/tests/feature_contracts_compatibility_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::fs;
use std::process::Command;

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

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

if String::from_utf8(expected_compiled_output).unwrap() != existing_compiled_contents {
panic!(
"{path_str} does not compile to {existing_compiled_path}.\nRun `{FIX_COMMAND}` to \
fix the expected test according to locally installed \
`starknet-compile-deprecated`.\n"
"{} does not compile to {existing_compiled_path}.\nRun `{FIX_COMMAND}` to fix the \
expected test according to locally installed `starknet-compile-deprecated`.\n",
contract.get_source_path()
);
}
}
Expand Down Expand Up @@ -119,10 +110,7 @@ fn verify_and_get_files(cairo_version: CairoVersion) -> Vec<(String, String, Str

#[test]
fn verify_feature_contracts_match_enum() {
let mut compiled_paths_from_enum: Vec<String> = FeatureContract::all_contracts()
// ERC20 is a special case - not in the feature_contracts directory.
.filter(|contract| !matches!(contract, FeatureContract::ERC20(CairoVersion::Cairo0) |
FeatureContract::ERC20(CairoVersion::Cairo1)))
let mut compiled_paths_from_enum: Vec<String> = FeatureContract::all_feature_contracts()
.map(|contract| contract.get_compiled_path())
.collect();
let mut compiled_paths_on_filesystem: Vec<String> = verify_and_get_files(CairoVersion::Cairo0)
Expand Down

0 comments on commit 11f058a

Please sign in to comment.