From 1b0719d0600dea182535e1806701e5491a81552b Mon Sep 17 00:00:00 2001 From: Dori Medini Date: Tue, 7 May 2024 13:11:03 +0300 Subject: [PATCH] ci: support Cairo1 recompile in CI Signed-off-by: Dori Medini --- .github/workflows/compiled_cairo.yml | 54 +++++++++++++++++-- .../src/test_utils/cairo_compile.rs | 1 - crates/blockifier/src/test_utils/contracts.rs | 10 ++-- .../feature_contracts_compatibility_test.rs | 46 +++++++++++++--- 4 files changed, 94 insertions(+), 17 deletions(-) diff --git a/.github/workflows/compiled_cairo.yml b/.github/workflows/compiled_cairo.yml index 747c6349cf..33129236d5 100644 --- a/.github/workflows/compiled_cairo.yml +++ b/.github/workflows/compiled_cairo.yml @@ -14,21 +14,67 @@ on: - synchronize paths: - 'crates/blockifier/feature_contracts/cairo0/**' + - 'crates/blockifier/feature_contracts/cairo1/**' + - 'crates/blockifier/tests/feature_contracts_compatibility_test.rs' jobs: verify_cairo_file_dependencies: runs-on: ubuntu-latest + steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master + # Checkout blockifier into a dedicated directory - technical requirement in order to be able to checkout `cairo` in a sibling directory. + - name: checkout blockifier into `blockifier` directory. + uses: actions/checkout@v4 + with: + repository: 'starkware-libs/blockifier' + path: 'blockifier' + + - name: Read Cairo1 Tag to compile contracts with from Blockifier. + id: read-tag + # GITHUB_ENV is a variable github allocates for dynamic stuff inside workflow like our usage, name not customizable. + run: echo "TAG=$(cat blockifier/crates/blockifier/tests/cairo1_compiler_tag.txt)" >> $GITHUB_ENV + + - name: Read legacy Cairo1 Tag to compile the legacy contract with. + id: read-tag + # GITHUB_ENV is a variable github allocates for dynamic stuff inside workflow like our usage, name not customizable. + run: echo "LEGACY_TAG=$(cat blockifier/crates/blockifier/tests/legacy_cairo1_compiler_tag.txt)" >> $GITHUB_ENV + + - name: checkout cairo1 repo in order to compile cairo1 contracts. + uses: actions/checkout@v4 + with: + repository: 'starkware-libs/cairo' + fetch-tags: tags + ref: ${{ env.TAG }} + path: 'cairo' + + - uses: actions-rs/toolchain@master with: components: rustfmt - toolchain: nightly-2024-01-12 + toolchain: nightly-2023-07-05 - uses: Swatinem/rust-cache@v2 - uses: actions/setup-python@v4 with: python-version: '3.9' cache: 'pip' - run: - pip install -r crates/blockifier/tests/requirements.txt; + cd blockifier && + pip install -r crates/blockifier/tests/requirements.txt && cargo test verify_feature_contracts -- --include-ignored + + - name: checkout legacy tag of cairo1 repo in order to compile the legacy contract. + uses: actions/checkout@v4 + with: + repository: 'starkware-libs/cairo' + fetch-tags: tags + ref: ${{ env.LEGACY_TAG }} + path: 'cairo' + + - name: Verify the legacy contract. + uses: actions-rs/toolchain@master + with: + components: rustfmt + toolchain: nightly-2023-07-05 + - uses: Swatinem/rust-cache@v2 + - run: + cd blockifier && + LEGACY=1 cargo test verify_feature_contracts -- --include-ignored diff --git a/crates/blockifier/src/test_utils/cairo_compile.rs b/crates/blockifier/src/test_utils/cairo_compile.rs index be66c009a7..2fee3815b6 100644 --- a/crates/blockifier/src/test_utils/cairo_compile.rs +++ b/crates/blockifier/src/test_utils/cairo_compile.rs @@ -169,7 +169,6 @@ fn verify_cairo1_compiler_deps(git_tag_override: Option) { // Checkout the required version in the compiler repo. run_and_verify_output(Command::new("git").args([ "-C", - // TODO(Dori, 1/6/2024): Handle CI case (repo path will be different). cairo_repo_path.to_str().unwrap(), "checkout", &tag, diff --git a/crates/blockifier/src/test_utils/contracts.rs b/crates/blockifier/src/test_utils/contracts.rs index 30de54d111..77f975858d 100644 --- a/crates/blockifier/src/test_utils/contracts.rs +++ b/crates/blockifier/src/test_utils/contracts.rs @@ -105,6 +105,10 @@ impl FeatureContract { } } + pub fn is_legacy(&self) -> bool { + matches!(self, Self::LegacyTestContract) + } + /// Unique integer representing each unique contract. Used to derive "class hash" and "address". fn get_integer_base(self) -> u32 { self.get_cairo_version_bit() @@ -191,10 +195,8 @@ impl FeatureContract { cairo0_compile(self.get_source_path(), extra_arg, false) } CairoVersion::Cairo1 => { - let tag_override = match self { - Self::LegacyTestContract => Some(LEGACY_CONTRACT_COMPILER_TAG.into()), - _ => None, - }; + let tag_override = + if self.is_legacy() { Some(LEGACY_CONTRACT_COMPILER_TAG.into()) } else { None }; cairo1_compile(self.get_source_path(), tag_override) } } diff --git a/crates/blockifier/tests/feature_contracts_compatibility_test.rs b/crates/blockifier/tests/feature_contracts_compatibility_test.rs index 34546d3572..38e232a38a 100644 --- a/crates/blockifier/tests/feature_contracts_compatibility_test.rs +++ b/crates/blockifier/tests/feature_contracts_compatibility_test.rs @@ -11,6 +11,28 @@ 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"; +enum ContractFilter { + Cairo0, + Cairo1, + Legacy, + NonLegacy, +} + +impl ContractFilter { + pub fn filter(&self, contract: &FeatureContract) -> bool { + match self { + ContractFilter::Cairo0 => matches!(contract.cairo_version(), CairoVersion::Cairo0), + ContractFilter::Cairo1 => matches!(contract.cairo_version(), CairoVersion::Cairo1), + ContractFilter::Legacy => { + matches!(contract.cairo_version(), CairoVersion::Cairo1) && contract.is_legacy() + } + ContractFilter::NonLegacy => { + matches!(contract.cairo_version(), CairoVersion::Cairo1) && !contract.is_legacy() + } + } + } +} + // To fix Cairo0 feature contracts, first enter a python venv and install the requirements: // ``` // python -m venv tmp_venv @@ -41,9 +63,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, cairo_version: CairoVersion) { - for contract in FeatureContract::all_feature_contracts() - .filter(|contract| contract.cairo_version() == cairo_version) +fn verify_feature_contracts_compatibility(fix: bool, contract_filter: ContractFilter) { + for contract in + FeatureContract::all_feature_contracts().filter(|contract| contract_filter.filter(contract)) { // Compare output of cairo-file on file with existing compiled file. let expected_compiled_output = contract.compile(); @@ -140,10 +162,18 @@ fn verify_feature_contracts_match_enum() { fn verify_feature_contracts( #[values(CairoVersion::Cairo0, CairoVersion::Cairo1)] cairo_version: CairoVersion, ) { - if std::env::var("CI").is_ok() && matches!(cairo_version, CairoVersion::Cairo1) { - // TODO(Dori, 1/6/2024): Support Cairo1 contracts in the CI and remove this `if` statement. - return; - } let fix_features = std::env::var("FIX_FEATURE_TEST").is_ok(); - verify_feature_contracts_compatibility(fix_features, cairo_version) + let legacy_mode = std::env::var("LEGACY").is_ok(); + let contract_filter = if matches!(cairo_version, CairoVersion::Cairo0) { + // There is no legacy contract in Cairo0. + ContractFilter::Cairo0 + } else if std::env::var("CI").is_err() { + // Non-CI mode, we can dynamically checkout the correct cairo compiler version. + ContractFilter::Cairo1 + } else { + // In the CI we cannot dynamically checkout the correct cairo compiler version, so either + // legacy or non-legacy contracts can be tested, but not both. + if legacy_mode { ContractFilter::Legacy } else { ContractFilter::NonLegacy } + }; + verify_feature_contracts_compatibility(fix_features, contract_filter) }