Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(blockifier): split feature contracts to groups based on their… #2236

Merged
merged 1 commit into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions crates/blockifier/src/test_utils/cairo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ pub fn starknet_compile(
cargo_nightly_arg: Option<String>,
base_compile_args: &mut Vec<String>,
) -> Vec<u8> {
prepare_cairo1_compiler_deps(git_tag_override);
verify_cairo1_compiler_deps(git_tag_override);

let cairo1_compiler_path = local_cairo1_compiler_repo_path();

Expand Down Expand Up @@ -204,10 +204,9 @@ fn verify_cairo0_compiler_deps() {
);
}

fn prepare_cairo1_compiler_deps(git_tag_override: Option<String>) {
let cairo_repo_path = local_cairo1_compiler_repo_path();
fn get_tag_and_repo_file_path(git_tag_override: Option<String>) -> (String, PathBuf) {
let tag = git_tag_override.unwrap_or(cairo1_compiler_tag());

let cairo_repo_path = local_cairo1_compiler_repo_path();
// Check if the path is a directory.
assert!(
cairo_repo_path.is_dir(),
Expand All @@ -216,13 +215,22 @@ fn prepare_cairo1_compiler_deps(git_tag_override: Option<String>) {
cairo_repo_path.to_string_lossy(),
);

(tag, cairo_repo_path)
}

pub fn prepare_group_tag_compiler_deps(git_tag_override: Option<String>) {
let (tag, cairo_repo_path) = get_tag_and_repo_file_path(git_tag_override);
// Checkout the required version in the compiler repo.
run_and_verify_output(Command::new("git").args([
"-C",
cairo_repo_path.to_str().unwrap(),
"checkout",
&tag,
]));
}

fn verify_cairo1_compiler_deps(git_tag_override: Option<String>) {
let (tag, cairo_repo_path) = get_tag_and_repo_file_path(git_tag_override);

// Verify that the checked out tag is as expected.
run_and_verify_output(Command::new("git").args([
Expand Down
15 changes: 14 additions & 1 deletion crates/blockifier/src/test_utils/contracts.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::collections::HashMap;

use cairo_lang_starknet_classes::casm_contract_class::CasmContractClass;
use itertools::Itertools;
use starknet_api::abi::abi_utils::selector_from_name;
use starknet_api::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME;
use starknet_api::contract_class::{ContractClass, EntryPointType};
Expand Down Expand Up @@ -86,6 +89,9 @@ const LEGACY_CONTRACT_RUST_TOOLCHAIN: &str = "2023-07-05";
const CAIRO_STEPS_TEST_CONTRACT_COMPILER_TAG: &str = "v2.7.0";
const CAIRO_STEPS_TEST_CONTRACT_RUST_TOOLCHAIN: &str = "2024-04-29";

pub type TagAndToolchain = (Option<String>, Option<String>);
pub type TagToContractsMapping = HashMap<TagAndToolchain, Vec<FeatureContract>>;

/// Enum representing all feature contracts.
/// The contracts that are implemented in both Cairo versions include a version field.
#[derive(Clone, Copy, Debug, EnumIter, Hash, PartialEq, Eq)]
Expand Down Expand Up @@ -212,7 +218,7 @@ impl FeatureContract {
/// Some contracts are designed to test behavior of code compiled with a
/// specific (old) compiler tag. To run the (old) compiler, older rust
/// version is required.
pub fn fixed_tag_and_rust_toolchain(&self) -> (Option<String>, Option<String>) {
pub fn fixed_tag_and_rust_toolchain(&self) -> TagAndToolchain {
match self {
Self::LegacyTestContract => (
Some(LEGACY_CONTRACT_COMPILER_TAG.into()),
Expand Down Expand Up @@ -427,4 +433,11 @@ impl FeatureContract {
// ERC20 is a special case - not in the feature_contracts directory.
Self::all_contracts().filter(|contract| !matches!(contract, Self::ERC20(_)))
}

pub fn cairo1_feature_contracts_by_tag() -> TagToContractsMapping {
Self::all_feature_contracts()
.filter(|contract| contract.cairo_version() != CairoVersion::Cairo0)
.map(|contract| (contract.fixed_tag_and_rust_toolchain(), contract))
.into_group_map()
}
}
60 changes: 42 additions & 18 deletions crates/blockifier/tests/feature_contracts_compatibility_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fs;

use blockifier::test_utils::cairo_compile::prepare_group_tag_compiler_deps;
use blockifier::test_utils::contracts::FeatureContract;
use blockifier::test_utils::CairoVersion;
use pretty_assertions::assert_eq;
Expand Down Expand Up @@ -36,29 +37,52 @@ const FIX_COMMAND: &str = "FIX_FEATURE_TEST=1 cargo test -p blockifier --test \
// `COMPILED_CONTRACTS_SUBDIR` which equals `starknet-compile-deprecated X.cairo --no_debug_info`.
fn verify_feature_contracts_compatibility(fix: bool, cairo_version: CairoVersion) {
// TODO(Dori, 1/10/2024): Parallelize this test.
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 expected_compiled_output = contract.compile();
let existing_compiled_path = contract.get_compiled_path();

if fix {
fs::write(&existing_compiled_path, &expected_compiled_output).unwrap();
match cairo_version {
CairoVersion::Cairo0 => {
for contract in FeatureContract::all_feature_contracts()
.filter(|contract| contract.cairo_version() == cairo_version)
{
verify_feature_contracts_compatibility_logic(&contract, fix);
}
}
let existing_compiled_contents = fs::read_to_string(&existing_compiled_path)
.unwrap_or_else(|_| panic!("Cannot read {existing_compiled_path}."));

if String::from_utf8(expected_compiled_output).unwrap() != existing_compiled_contents {
panic!(
"{} does not compile to {existing_compiled_path}.\nRun `{FIX_COMMAND}` to fix the \
existing file according to locally installed `starknet-compile-deprecated`.\n",
contract.get_source_path()
);
// TODO(Meshi 01/01/2025) Make this explicit when we will only have two cairo versions.
_ => {
for (tag_and_tool_chain, feature_contracts) in
FeatureContract::cairo1_feature_contracts_by_tag()
{
prepare_group_tag_compiler_deps(tag_and_tool_chain.0.clone());
// TODO(Meshi 01/01/2025) Make this loop concurrent
for contract in feature_contracts
.into_iter()
.filter(|contract| contract.cairo_version() == cairo_version)
{
verify_feature_contracts_compatibility_logic(&contract, fix);
}
}
}
}
}

fn verify_feature_contracts_compatibility_logic(contract: &FeatureContract, fix: bool) {
// Compare output of cairo-file on file with existing compiled file.
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();
}
let existing_compiled_contents = fs::read_to_string(&existing_compiled_path)
.unwrap_or_else(|_| panic!("Cannot read {existing_compiled_path}."));

if String::from_utf8(expected_compiled_output).unwrap() != existing_compiled_contents {
panic!(
"{} does not compile to {existing_compiled_path}.\nRun `{FIX_COMMAND}` to fix the \
existing file according to locally installed `starknet-compile-deprecated`.\n",
contract.get_source_path()
);
}
}

/// Verifies that the feature contracts directory contains the expected contents, and returns a list
/// of pairs (source_path, base_filename, compiled_path) for each contract.
fn verify_and_get_files(cairo_version: CairoVersion) -> Vec<(String, String, String)> {
Expand Down
Loading