diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 427795144c..021d02b14e 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -21,7 +21,7 @@ jobs: run: touch target/doc/.nojekyll - name: Set short sha output id: short_sha - run: echo "::set-output name=sha::$(git rev-parse --short HEAD)" + run: echo ":name=sha::$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Checkout gh-pages uses: actions/checkout@v3 with: diff --git a/.github/workflows/hyperfine.yml b/.github/workflows/hyperfine.yml index e6b627463b..af3a80735c 100644 --- a/.github/workflows/hyperfine.yml +++ b/.github/workflows/hyperfine.yml @@ -31,7 +31,7 @@ jobs: uses: actions/cache@v3 id: cache with: - path: ${{ matrix.branch }}_programs/*.json + path: ${{ matrix.branch }}_programs/*.json key: benchmarks-${{ matrix.branch }}-${{ hashFiles( 'cairo_programs/benchmarks/*.cairo' ) }} restore-keys: benchmarks-${{ matrix.branch }}- diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2ed548b405..2f3109af40 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,4 +1,4 @@ -name: rust +name: QA on: merge_group: @@ -11,80 +11,360 @@ env: CARGO_TERM_COLOR: always jobs: - build: - runs-on: ubuntu-20.04 + build-programs: + strategy: + matrix: + # NOTE: we build cairo_proof_programs so clippy can check the benchmarks too + program-target: [ cairo_bench_programs, cairo_proof_programs, cairo_test_programs ] + name: Build Cairo programs + runs-on: ubuntu-22.04 steps: - - name: Install Rust 1.66.1 - uses: actions-rs/toolchain@v1 + - name: Checkout + uses: actions/checkout@v3 + + - name: Fetch from cache + uses: actions/cache@v3 + id: cache-programs with: - toolchain: 1.66.1 - override: true - components: rustfmt, clippy + path: cairo_programs/**/*.json + key: ${{ matrix.program-target }}-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + restore-keys: ${{ matrix.program-target }}-cache- + - name: Python3 Build + if: ${{ steps.cache-programs.outputs.cache-hit != 'true' }} uses: actions/setup-python@v4 with: python-version: '3.9' + cache: 'pip' + - name: Install cairo-lang and deps + if: ${{ steps.cache-programs.outputs.cache-hit != 'true' }} + run: pip install -r requirements.txt + + - name: Build programs + if: ${{ steps.cache-programs.outputs.cache-hit != 'true' }} + run: make -j ${{ matrix.program-target }} - - name: Install Nextest - uses: taiki-e/install-action@nextest - - name: Install cargo-llvm-cov - uses: taiki-e/install-action@cargo-llvm-cov - - name: Install wasm-bindgen-cli - uses: jetli/wasm-pack-action@v0.4.0 - with: - version: "v0.10.3" + lint: + needs: build-programs + name: Run Lints + runs-on: ubuntu-22.04 + steps: + - name: Install Rust 1.69.0 + uses: dtolnay/rust-toolchain@1.69.0 + with: + components: rustfmt, clippy - name: Set up cargo cache uses: Swatinem/rust-cache@v2 - name: Checkout uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Install test dependencies - run: pip install -r requirements.txt + - name: Format run: cargo fmt --all -- --check + + - name: Fetch test programs + uses: actions/cache/restore@v3 + with: + path: cairo_programs/**/*.json + key: cairo_test_programs-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + - name: Fetch proof programs + uses: actions/cache/restore@v3 + with: + path: cairo_programs/**/*.json + key: cairo_proof_programs-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + - name: Fetch bench programs + uses: actions/cache/restore@v3 + with: + path: cairo_programs/**/*.json + key: cairo_bench_programs-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + - name: Run clippy + run: make clippy + + + # NOTE: the term "smoke test" comes from electronics design: the minimal + # expectations anyone has in their device is to not catch fire on boot. + smoke: + needs: build-programs + name: Make sure all builds work + runs-on: ubuntu-22.04 + steps: + - name: Install Rust 1.69.0 + uses: dtolnay/rust-toolchain@1.69.0 + - name: Set up cargo cache + uses: Swatinem/rust-cache@v2 + - name: Install cargo-all-features + uses: taiki-e/install-action@v2 + with: + tool: cargo-all-features + - name: Checkout + uses: actions/checkout@v3 + + - name: Fetch test programs + uses: actions/cache/restore@v3 + with: + path: cairo_programs/**/*.json + key: cairo_test_programs-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + - name: Fetch proof programs + uses: actions/cache/restore@v3 + with: + path: cairo_programs/**/*.json + key: cairo_proof_programs-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + - name: Fetch bench programs + uses: actions/cache/restore@v3 + with: + path: cairo_programs/**/*.json + key: cairo_bench_programs-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + + - name: Check + run: cargo check-all-features --workspace --all-targets + + + tests: + needs: build-programs + strategy: + fail-fast: false + matrix: + target: [ test, test-no_std, test-wasm ] + # TODO: features + name: Run tests + runs-on: ubuntu-22.04 + steps: + - name: Install Rust 1.69.0 + uses: dtolnay/rust-toolchain@1.69.0 + with: + components: llvm-tools-preview + - name: Set up cargo cache + uses: Swatinem/rust-cache@v2 + - name: Checkout + uses: actions/checkout@v3 + with: + depth: 0 + # This is not pretty, but we need `make` to see the compiled programs are + # actually newer than the sources, otherwise it will try to rebuild them + - name: Restore timestamps + uses: chetan/git-restore-mtime-action@v1 + + - name: Fetch test programs + uses: actions/cache/restore@v3 + with: + path: cairo_programs/**/*.json + key: cairo_test_programs-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + - name: Fetch proof programs + uses: actions/cache/restore@v3 + with: + path: cairo_programs/**/*.json + key: cairo_proof_programs-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + + - name: Install testing tools + uses: taiki-e/install-action@v2 + with: + tool: cargo-nextest,cargo-llvm-cov,wasm-pack + - name: Run + run: + # FIXME: we need to update the Makefile to do this correctly + case ${{ matrix.target }} in + 'test') + cargo llvm-cov nextest --lcov --output-path lcov-${{ matrix.target }}.info --workspace --features test_utils + ;; + 'test-no_std') + cargo llvm-cov nextest --lcov --output-path lcov-${{ matrix.target }}.info --workspace --features test_utils --no-default-features + ;; + 'test-wasm') + wasm-pack test --node --no-default-features + ;; + esac + + - name: Save coverage + if: matrix.target != 'test-wasm' + uses: actions/cache/save@v3 + with: + path: lcov-${{ matrix.target }}.info + key: codecov-cache-${{ matrix.target }}-${{ github.sha }} + + + build-release: + name: Build release binary for comparisons + runs-on: ubuntu-22.04 + steps: + - name: Install Rust 1.69.0 + uses: dtolnay/rust-toolchain@1.69.0 + - name: Set up cargo cache + uses: Swatinem/rust-cache@v2 + - name: Checkout + uses: actions/checkout@v3 - name: Build - run: make build - - name: Populate cache + run: cargo b --release -p cairo-vm-cli + # We don't read from cache because it should always miss + - name: Store in cache + uses: actions/cache/save@v3 + with: + key: cli-bin-rel-${{ github.sha }} + path: target/release/cairo-vm-cli + + + run-cairo-reference: + strategy: + matrix: + include: + - program-target: cairo_proof_programs + programs-dir: cairo_programs/proof_programs + nprocs: 1 + extra-args: '--proof_mode' + - program-target: cairo_test_programs + programs-dir: cairo_programs + nprocs: 2 + extra-args: '' + name: Compute memory and execution traces with cairo-lang + needs: build-programs + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Check cache uses: actions/cache@v3 - id: cache-cairo-programs + id: trace-cache with: path: | - cairo_programs/*.json - cairo_programs/*.memory - cairo_programs/*.trace - !cairo_programs/*.rs.* - cairo_programs/*/*.json - cairo_programs/*/*.memory - cairo_programs/*/*.trace - !cairo_programs/*/*.rs.* - key: cairo-cache-${{ hashFiles( 'cairo_programs/*.cairo', 'cairo_programs/*/*.cairo' ) }} - restore-keys: cairo-cache- - - name: Restore timestamps - uses: chetan/git-restore-mtime-action@v1 - - name: Install dependencies + cairo_programs/**/*.memory + cairo_programs/**/*.trace + key: ${{ matrix.program-target }}-reference-trace-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + + - name: Python3 Build + if: steps.trace-cache.outputs.cache-hit != 'true' + uses: actions/setup-python@v4 + with: + python-version: '3.9' + cache: 'pip' + - name: Install cairo-lang and deps + if: steps.trace-cache.outputs.cache-hit != 'true' run: pip install -r requirements.txt - - name: Run tests - run: make -j test - - name: Run tests no_std - run: make -j test-no_std - - name: Run wasm tests - run: make -j test-wasm - - name: Compare trace and memory - run: make -j compare_trace_memory - - name: Compare trace and memory with proof mode - run: make -j compare_trace_memory_proof - - name: Run clippy - run: make clippy - - name: Coverage - run: make coverage + + - name: Fetch programs + if: ${{ steps.trace-cache.outputs.cache-hit != 'true' }} + uses: actions/cache/restore@v3 + with: + path: cairo_programs/**/*.json + key: ${{ matrix.program-target }}-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + fail-on-cache-miss: true + + - name: Generate traces + if: ${{ steps.trace-cache.outputs.cache-hit != 'true' }} + run: | + ls ${{ matrix.programs-dir }}/*.json | cut -f1 -d'.' | \ + xargs -P ${{ matrix.nprocs }} -I '{program}' \ + cairo-run --program '{program}'.json --layout starknet_with_keccak \ + --memory_file '{program}'.memory --trace_file '{program}'.trace \ + ${{ matrix.extra-args }} + + + run-cairo-release: + strategy: + matrix: + include: + - program-target: cairo_proof_programs + programs-dir: cairo_programs/proof_programs + extra-args: '--proof_mode' + - program-target: cairo_test_programs + programs-dir: cairo_programs + extra-args: '' + name: Compute memory and execution traces with cairo-rs + needs: [ build-programs, build-release ] + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Fetch release binary + uses: actions/cache/restore@v3 + with: + key: cli-bin-rel-${{ github.sha }} + path: target/release/cairo-vm-cli + fail-on-cache-miss: true + + - name: Fetch programs + uses: actions/cache/restore@v3 + with: + path: cairo_programs/**/*.json + key: ${{ matrix.program-target }}-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + fail-on-cache-miss: true + + - name: Generate traces + run: | + ls ${{ matrix.programs-dir }}/*.json | cut -f1 -d'.' | \ + xargs -P 2 -I '{program}' \ + ./target/release/cairo-vm-cli '{program}'.json --layout starknet_with_keccak \ + --memory_file '{program}'.rs.memory --trace_file '{program}'.rs.trace \ + ${{ matrix.extra-args }} + - name: Update cache + uses: actions/cache/save@v3 + with: + path: | + cairo_programs/**/*.memory + cairo_programs/**/*.trace + key: ${{ matrix.program-target }}-release-trace-cache-${{ github.sha }} + + + upload-coverage: + name: Upload coverage results to codecov.io + needs: tests + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Fetch results for tests with stdlib + uses: actions/cache/restore@v3 + with: + path: lcov-test.info + key: codecov-cache-test-${{ github.sha }} + fail-on-cache-miss: true + - name: Fetch results for tests without stdlib + uses: actions/cache/restore@v3 + with: + path: lcov-test-no_std.info + key: codecov-cache-test-no_std-${{ github.sha }} + fail-on-cache-miss: true + - name: Upload coverage to codecov.io uses: codecov/codecov-action@v3 with: - token: ${{ secrets.CODECOV_TOKEN }} - files: lcov.info - fail_ci_if_error: true - # NB: the following step is needed so caching doesn't cause misleading coverage in later runs - - name: Clean coverage artifacts - run: make coverage-clean + files: '*.info' + fail_ci_if_error: true + + + compare-memory-and-trace: + strategy: + matrix: + program-target: [ cairo_proof_programs, cairo_test_programs ] + name: Compare memory and execution traces from cairo-lang and cairo-rs + needs: [ run-cairo-reference, run-cairo-release ] + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Fetch traces for cairo-lang + uses: actions/cache/restore@v3 + with: + path: | + cairo_programs/**/*.memory + cairo_programs/**/*.trace + key: ${{ matrix.program-target }}-reference-trace-cache-${{ hashFiles( 'cairo_programs/**/*.cairo' ) }} + fail-on-cache-miss: true + + - name: Fetch traces for cairo-rs + uses: actions/cache/restore@v3 + with: + path: | + cairo_programs/**/*.memory + cairo_programs/**/*.trace + key: ${{ matrix.program-target }}-release-trace-cache-${{ github.sha }} + fail-on-cache-miss: true + + - name: Run comparison script + run: | + if [ ${{ matrix.program-target }} = cairo_proof_programs ]; then + PROOF=proof + fi + ./src/tests/compare_vm_state.sh trace memory $PROOF diff --git a/Makefile b/Makefile index 3ffec8df5c..91636d609f 100644 --- a/Makefile +++ b/Makefile @@ -130,7 +130,7 @@ run: check: cargo check -cairo_test_programs: $(COMPILED_TESTS) $(COMPILED_BAD_TESTS) +cairo_test_programs: $(COMPILED_TESTS) $(COMPILED_BAD_TESTS) $(COMPILED_NORETROCOMPAT_TESTS) cairo_proof_programs: $(COMPILED_PROOF_TESTS) cairo_bench_programs: $(COMPILED_BENCHES) @@ -145,7 +145,7 @@ test-wasm: $(COMPILED_PROOF_TESTS) $(COMPILED_TESTS) $(COMPILED_BAD_TESTS) $(COM wasm-pack test --node --no-default-features clippy: - cargo clippy --tests --examples --all-features -- -D warnings + cargo clippy --all --all-features --benches --examples --tests -- -D warnings coverage: cargo llvm-cov report --lcov --output-path lcov.info diff --git a/cairo-vm-cli/src/main.rs b/cairo-vm-cli/src/main.rs index 354732f2e2..ac816e9fbc 100644 --- a/cairo-vm-cli/src/main.rs +++ b/cairo-vm-cli/src/main.rs @@ -57,7 +57,7 @@ fn validate_layout(value: &str) -> Result<(), String> { #[derive(Debug, Error)] enum Error { #[error("Invalid arguments")] - CLI(#[from] clap::Error), + Cli(#[from] clap::Error), #[error("Failed to interact with the file system")] IO(#[from] std::io::Error), #[error("The cairo program execution failed")] @@ -109,7 +109,7 @@ fn run(args: impl Iterator) -> Result<(), Error> { Ok(args) => args, Err(error) => { eprintln!("{error}"); - return Err(Error::CLI(error.into())); + return Err(Error::Cli(error)); } }; let trace_enabled = args.trace_file.is_some(); @@ -123,7 +123,7 @@ fn run(args: impl Iterator) -> Result<(), Error> { secure_run: args.secure_run, }; - let program_content = std::fs::read(args.filename).map_err(|e| Error::IO(e))?; + let program_content = std::fs::read(args.filename).map_err(Error::IO)?; let (cairo_runner, mut vm) = match cairo_run::cairo_run(&program_content, &cairo_run_config, &mut hint_executor) { @@ -177,15 +177,15 @@ mod tests { #[case([].as_slice())] #[case(["cairo-vm-cli"].as_slice())] fn test_run_missing_mandatory_args(#[case] args: &[&str]) { - let args = args.into_iter().cloned().map(String::from); - assert_matches!(run(args), Err(Error::CLI(_))); + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Err(Error::Cli(_))); } #[rstest] #[case(["cairo-vm-cli", "--layout", "broken_layout", "../cairo_programs/fibonacci.json"].as_slice())] fn test_run_invalid_args(#[case] args: &[&str]) { - let args = args.into_iter().cloned().map(String::from); - assert_matches!(run(args), Err(Error::CLI(_))); + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Err(Error::Cli(_))); } #[rstest] diff --git a/felt/src/bigint_felt.rs b/felt/src/bigint_felt.rs index 4433203acf..8e3ad92039 100644 --- a/felt/src/bigint_felt.rs +++ b/felt/src/bigint_felt.rs @@ -1087,7 +1087,7 @@ mod tests { let p = &CAIRO_PRIME_BIGUINT; let result = x + y; let as_uint = &result.to_biguint(); - prop_assert!(as_uint < &p, "{}", as_uint); + prop_assert!(as_uint < p, "{}", as_uint); } #[test] @@ -1098,7 +1098,7 @@ mod tests { let p = &CAIRO_PRIME_BIGUINT; x += y; let as_uint = &x.to_biguint(); - prop_assert!(as_uint < &p, "{}", as_uint); + prop_assert!(as_uint < p, "{}", as_uint); } #[test] @@ -1211,10 +1211,10 @@ mod tests { let y = FeltBigInt::::parse_bytes(y.as_bytes(), 10).unwrap(); let z = FeltBigInt::::parse_bytes(z.as_bytes(), 10).unwrap(); let p:BigUint = BigUint::parse_bytes(CAIRO_PRIME_BIGUINT.to_string().as_bytes(), 16).unwrap(); - let v = vec![x.clone(), y, z]; + let v = vec![x, y, z]; let result: FeltBigInt = v.into_iter().sum(); let as_uint = result.to_biguint(); - prop_assert!(&as_uint < &p, "{}", as_uint); + prop_assert!(as_uint < p, "{}", as_uint); } } } diff --git a/felt/src/lib.rs b/felt/src/lib.rs index bc7470b785..c562faea1f 100644 --- a/felt/src/lib.rs +++ b/felt/src/lib.rs @@ -51,7 +51,6 @@ pub(crate) trait FeltOps { #[cfg(any(feature = "std", feature = "alloc"))] fn to_str_radix(&self, radix: u32) -> String; - #[deprecated] /// Converts [`Felt252`] into a [`BigInt`] number in the range: `(- FIELD / 2, FIELD / 2)`. /// /// # Examples @@ -68,7 +67,6 @@ pub(crate) trait FeltOps { /// ``` fn to_bigint(&self) -> BigInt; - #[deprecated] /// Converts [`Felt252`] into a [`BigUint`] number. /// /// # Examples diff --git a/hint_accountant/src/main.rs b/hint_accountant/src/main.rs index 973c78ef8b..31100ad5c3 100644 --- a/hint_accountant/src/main.rs +++ b/hint_accountant/src/main.rs @@ -11,10 +11,9 @@ use cairo_vm::{ with_std::collections::{HashMap, HashSet}, }; use serde::Deserialize; -use serde_json; use serde_json::Value; -const WHITELISTS: [&'static str; 15] = [ +const WHITELISTS: [&str; 15] = [ include_str!("../whitelists/0.10.3.json"), include_str!("../whitelists/0.6.0.json"), include_str!("../whitelists/0.8.2.json"), @@ -65,7 +64,7 @@ fn run() { .map(|ahe| ahe.hint_lines.join("\n")) .filter(|h| { let hint_data = hint_executor - .compile_hint(&h, &ap_tracking_data, &reference_ids, &references) + .compile_hint(h, &ap_tracking_data, &reference_ids, &references) .expect("this implementation is infallible"); matches!( hint_executor.execute_hint(&mut vm, &mut exec_scopes, &hint_data, &constants), @@ -76,7 +75,7 @@ fn run() { println!("{} missing hints:", missing_hints.len()); for hint in missing_hints.iter() { - println!(""); + println!(); println!("```"); println!("%{{"); println!("{hint}"); diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index fc46be00b4..0000000000 --- a/rust-toolchain +++ /dev/null @@ -1,4 +0,0 @@ -[toolchain] -channel = "1.66.1" -components = ["rustfmt", "clippy"] -profile = "minimal" diff --git a/src/vm/errors/vm_exception.rs b/src/vm/errors/vm_exception.rs index 1949d19460..f845ec3f49 100644 --- a/src/vm/errors/vm_exception.rs +++ b/src/vm/errors/vm_exception.rs @@ -271,7 +271,7 @@ impl Location { if !(0 < self.start_line && ((self.start_line - 1) as usize) < split_lines.len()) { return String::new(); } - let start_line = split_lines[((self.start_line - 1) as usize)]; + let start_line = split_lines[(self.start_line - 1) as usize]; let start_col = self.start_col as usize; let mut result = format!("{start_line}\n"); let end_col = if self.start_line == self.end_line {