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

Commit

Permalink
test: test feature contract files structure and consistency with rust (
Browse files Browse the repository at this point in the history
…#1866)

Signed-off-by: Dori Medini <[email protected]>
  • Loading branch information
dorimedini-starkware authored May 21, 2024
1 parent 63c8b7e commit 4bdfda2
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 33 deletions.
7 changes: 7 additions & 0 deletions crates/blockifier/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ impl CairoVersion {
_ => panic!("Transaction version {:?} is not supported.", tx_version),
}
}

pub fn other(&self) -> Self {
match self {
Self::Cairo0 => Self::Cairo1,
Self::Cairo1 => Self::Cairo0,
}
}
}

// Storage keys.
Expand Down
33 changes: 30 additions & 3 deletions crates/blockifier/src/test_utils/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use starknet_api::deprecated_contract_class::{
};
use starknet_api::hash::StarkHash;
use starknet_api::{class_hash, contract_address, patricia_key};
use strum::IntoEnumIterator;
use strum_macros::EnumIter;

use crate::abi::abi_utils::selector_from_name;
use crate::abi::constants::CONSTRUCTOR_ENTRY_POINT_NAME;
Expand Down Expand Up @@ -58,7 +60,7 @@ const ERC20_CONTRACT_PATH: &str =

/// Enum representing all feature contracts.
/// The contracts that are implemented in both Cairo versions include a version field.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, EnumIter)]
pub enum FeatureContract {
AccountWithLongValidate(CairoVersion),
AccountWithoutValidations(CairoVersion),
Expand All @@ -83,6 +85,17 @@ impl FeatureContract {
}
}

fn has_two_versions(&self) -> bool {
match self {
Self::AccountWithLongValidate(_)
| Self::AccountWithoutValidations(_)
| Self::Empty(_)
| Self::FaultyAccount(_)
| Self::TestContract(_) => true,
Self::SecurityTests | Self::ERC20 | Self::LegacyTestContract => false,
}
}

fn get_cairo_version_bit(&self) -> u32 {
match self.cairo_version() {
CairoVersion::Cairo0 => 0,
Expand All @@ -105,7 +118,7 @@ impl FeatureContract {
}
}

fn get_compiled_path(&self) -> String {
pub fn get_compiled_path(&self) -> String {
let cairo_version = self.cairo_version();
let contract_name = match self {
Self::AccountWithLongValidate(_) => ACCOUNT_LONG_VALIDATE_NAME,
Expand All @@ -119,7 +132,7 @@ impl FeatureContract {
Self::ERC20 => return ERC20_CONTRACT_PATH.into(),
};
format!(
"./feature_contracts/cairo{}/compiled/{}{}.json",
"feature_contracts/cairo{}/compiled/{}{}.json",
match cairo_version {
CairoVersion::Cairo0 => "0",
CairoVersion::Cairo1 => "1",
Expand Down Expand Up @@ -228,4 +241,18 @@ impl FeatureContract {
entry_point_selector.unwrap_or(selector_from_name(CONSTRUCTOR_ENTRY_POINT_NAME));
self.get_offset(selector, EntryPointType::Constructor)
}

pub fn all_contracts() -> impl Iterator<Item = Self> {
// EnumIter iterates over all variants with Default::default() as the cairo
// version.
Self::iter().flat_map(|contract| {
if contract.has_two_versions() {
let mut other_contract = contract;
other_contract.set_cairo_version(contract.cairo_version().other());
vec![contract, other_contract].into_iter()
} else {
vec![contract].into_iter()
}
})
}
}
101 changes: 71 additions & 30 deletions crates/blockifier/tests/feature_contracts_compatibility_test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
use std::fs;
use std::process::Command;

const FEATURE_CONTRACTS_DIR: &str = "feature_contracts/cairo0";
use blockifier::test_utils::contracts::FeatureContract;
use blockifier::test_utils::CairoVersion;
use pretty_assertions::assert_eq;

const CAIRO0_FEATURE_CONTRACTS_DIR: &str = "feature_contracts/cairo0";
const CAIRO1_FEATURE_CONTRACTS_DIR: &str = "feature_contracts/cairo1";
const COMPILED_CONTRACTS_SUBDIR: &str = "compiled";
const FIX_COMMAND: &str = "FIX_FEATURE_TEST=1 cargo test -- --ignored";

Expand Down Expand Up @@ -35,35 +40,9 @@ const FIX_COMMAND: &str = "FIX_FEATURE_TEST=1 cargo test -- --ignored";
// `COMPILED_CONTRACTS_SUBDIR`.
// 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) {
for file in fs::read_dir(FEATURE_CONTRACTS_DIR).unwrap() {
let path = file.unwrap().path();

// Test `TEST_CONTRACTS` file and directory structure.
if !path.is_file() {
if let Some(dir_name) = path.file_name() {
assert_eq!(
dir_name,
COMPILED_CONTRACTS_SUBDIR,
"Found directory '{}' in `{FEATURE_CONTRACTS_DIR}`, which should contain only \
the `{COMPILED_CONTRACTS_SUBDIR}` directory.",
dir_name.to_string_lossy()
);
continue;
}
}
let path_str = path.to_string_lossy();
assert_eq!(
path.extension().unwrap(),
"cairo",
"Found a non-Cairo file '{path_str}' in `{FEATURE_CONTRACTS_DIR}`"
);

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) {
// Compare output of cairo-file on file with existing compiled file.
let file_name = path.file_stem().unwrap().to_string_lossy();
let existing_compiled_path = format!(
"{FEATURE_CONTRACTS_DIR}/{COMPILED_CONTRACTS_SUBDIR}/{file_name}_compiled.json"
);
let mut command = Command::new("starknet-compile-deprecated");
command.args([&path_str, "--no_debug_info"]);
if file_name.starts_with("account") {
Expand Down Expand Up @@ -93,9 +72,71 @@ fn verify_feature_contracts_compatibility(fix: bool) {
}
}

/// 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)> {
let mut paths = vec![];
let directory = match cairo_version {
CairoVersion::Cairo0 => CAIRO0_FEATURE_CONTRACTS_DIR,
CairoVersion::Cairo1 => CAIRO1_FEATURE_CONTRACTS_DIR,
};
let compiled_extension = match cairo_version {
CairoVersion::Cairo0 => "_compiled.json",
CairoVersion::Cairo1 => ".casm.json",
};
for file in fs::read_dir(directory).unwrap() {
let path = file.unwrap().path();

// Verify `TEST_CONTRACTS` file and directory structure.
if !path.is_file() {
if let Some(dir_name) = path.file_name() {
assert_eq!(
dir_name,
COMPILED_CONTRACTS_SUBDIR,
"Found directory '{}' in `{directory}`, which should contain only the \
`{COMPILED_CONTRACTS_SUBDIR}` directory.",
dir_name.to_string_lossy()
);
continue;
}
}
let path_str = path.to_string_lossy();
assert_eq!(
path.extension().unwrap(),
"cairo",
"Found a non-Cairo file '{path_str}' in `{directory}`"
);

let file_name = path.file_stem().unwrap().to_string_lossy();
let existing_compiled_path =
format!("{directory}/{COMPILED_CONTRACTS_SUBDIR}/{file_name}{compiled_extension}");

paths.push((path_str.to_string(), file_name.to_string(), existing_compiled_path));
}

paths
}

#[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))
.map(|contract| contract.get_compiled_path())
.collect();
let mut compiled_paths_on_filesystem: Vec<String> = verify_and_get_files(CairoVersion::Cairo0)
.into_iter()
.chain(verify_and_get_files(CairoVersion::Cairo1))
.map(|(_, _, compiled_path)| compiled_path)
.collect();
compiled_paths_from_enum.sort();
compiled_paths_on_filesystem.sort();
assert_eq!(compiled_paths_from_enum, compiled_paths_on_filesystem);
}

#[test]
#[ignore]
fn verify_feature_contracts() {
let fix_features = std::env::var("FIX_FEATURE_TEST").is_ok();
verify_feature_contracts_compatibility(fix_features)
verify_feature_contracts_compatibility(fix_features, CairoVersion::Cairo0)
}

0 comments on commit 4bdfda2

Please sign in to comment.