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

Compare air_public_inputs against python vm + Fix how public memory is built #1391

Merged
merged 28 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7c76701
Remove cairo1 & cairo2 folders in `clean` makefile target
fmoletta Aug 18, 2023
bbb98a9
Make public inputs similar to python output
fmoletta Aug 22, 2023
4937b17
Rename field
fmoletta Aug 22, 2023
6106826
Fix finalize method
fmoletta Aug 22, 2023
54902c6
Fix get_public_memory logic (minus error handling)
fmoletta Aug 22, 2023
67bba6d
Add error handling
fmoletta Aug 22, 2023
69cb1ef
Add comparison script
fmoletta Aug 22, 2023
c9b6a5e
Fix tests
fmoletta Aug 22, 2023
ba88442
Add air_public_input argument to comparison script
fmoletta Aug 22, 2023
215c78e
Add air public input comparison
fmoletta Aug 22, 2023
68e40a6
Fix finalize segments of output builtin
fmoletta Aug 22, 2023
feace8a
Fix
fmoletta Aug 22, 2023
8279193
Add makefile targets
fmoletta Aug 22, 2023
a9b27a0
Add new targets to phony
fmoletta Aug 22, 2023
dd62a17
Clean public input files
fmoletta Aug 22, 2023
da5dc2d
Fix compilation in makefile
fmoletta Aug 22, 2023
d6092ad
Add changelog
fmoletta Aug 22, 2023
7f580a3
Merge branch 'main' into compare-public-inputs
fmoletta Aug 22, 2023
558e13d
fmt
fmoletta Aug 22, 2023
7ea9e69
Merge branch 'main' of github.com:lambdaclass/cairo-vm into compare-p…
fmoletta Aug 23, 2023
a2736f7
Rename makefile targets
fmoletta Aug 23, 2023
76102f9
Merge branch 'main' into compare-public-inputs
fmoletta Aug 24, 2023
f9c39cf
Merge branch 'main' into compare-public-inputs
fmoletta Aug 28, 2023
5b8568f
Compare air_public_inputs in CI (#1394)
fmoletta Aug 28, 2023
126a40f
Merge branch 'main' into compare-public-inputs
fmoletta Aug 28, 2023
4c5a3a5
Add .air_public_input to .gitignore
fmoletta Aug 29, 2023
ffa4628
Merge branch 'main' into compare-public-inputs
fmoletta Aug 29, 2023
e860e0e
Merge branch 'main' into compare-public-inputs
fmoletta Aug 29, 2023
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
10 changes: 8 additions & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ jobs:
path: |
cairo_programs/**/*.memory
cairo_programs/**/*.trace
cairo_programs/**/*.air_public_input
key: ${{ matrix.program-target }}-reference-trace-cache-${{ hashFiles('cairo_programs/**/*.cairo', 'examples/wasm-demo/src/array_sum.cairo') }}
restore-keys: ${{ matrix.program-target }}-reference-trace-cache-

Expand Down Expand Up @@ -354,7 +355,7 @@ jobs:
include:
- program-target: cairo_proof_programs
programs-dir: cairo_programs/proof_programs
extra-args: '--proof_mode'
extra-args: '--proof_mode --air_public_input {program}.rs.air_public_input '
- program-target: cairo_test_programs
programs-dir: cairo_programs
extra-args: ''
Expand Down Expand Up @@ -392,6 +393,7 @@ jobs:
path: |
cairo_programs/**/*.memory
cairo_programs/**/*.trace
cairo_programs/**/*.air_public_input
key: ${{ matrix.program-target }}-release-trace-cache-${{ github.sha }}


Expand Down Expand Up @@ -466,6 +468,7 @@ jobs:
path: |
cairo_programs/**/*.memory
cairo_programs/**/*.trace
cairo_programs/**/*.air_public_input
key: ${{ matrix.program-target }}-reference-trace-cache-${{ hashFiles('cairo_programs/**/*.cairo', 'examples/wasm-demo/src/array_sum.cairo') }}
fail-on-cache-miss: true

Expand All @@ -475,14 +478,17 @@ jobs:
path: |
cairo_programs/**/*.memory
cairo_programs/**/*.trace
cairo_programs/**/*.air_public_input
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_mode
PROOF=proof_mode
AIR_PUBLIC_INPUT=air_public_input
fi
./vm/src/tests/compare_vm_state.sh trace memory $PROOF $AIR_PUBLIC_INPUT
./vm/src/tests/compare_vm_state.sh trace memory $PROOF

wasm-demo:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
**/*.sierra
**/*.trace
**/*.memory
**/*.air_public_input
**/*.swp
bench/results
.python-version
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@

* feat: Implement `CairoRunner.get_cairo_pie`[#1375](https://github.com/lambdaclass/cairo-vm/pull/1375)

* fix: Compare air_public_inputs against python vm + Fix how public memory is built [#391](https://github.com/lambdaclass/cairo-vm/pull/1391)

BugFixes:

* `CairoRunner.finalize_segments` now builds the output builtin's public memory (if applicable).
* `MemorySegmentManager.get_public_memory_addresses` logic fixed.
* `MemorySegmentManager.finalize` no longer skips segments when their public memory is None

Minor changes:

* `VirtualMachine.get_public_memory_addresses` now strips the "_builtin" suffix from builtin names
* `MemorySegmentAddresses.stop_address` renamed to `stop_ptr`

Overall these changes make the the air public input file (obtained through the --air_public_input flag) equivalent to the ones outputted by the cairo-lang version

* fix: Fix `SPLIT_FELT` hint [#1387](https://github.com/lambdaclass/cairo-vm/pull/1387)

* refactor: combine `Program.hints` and `Program.hints_ranges` into custom collection [#1366](https://github.com/lambdaclass/cairo-vm/pull/1366)
Expand Down
25 changes: 18 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ STARKNET_SIERRA_COMPILE_CAIRO_2:=cairo2/bin/starknet-sierra-compile
deps deps-macos cargo-deps build run check test clippy coverage benchmark flamegraph \
compare_benchmarks_deps compare_benchmarks docs clean \
compare_vm_output compare_trace_memory compare_trace compare_memory \
compare_trace_memory_proof compare_trace_proof compare_memory_proof \
compare_trace_memory_proof compare_all_proof compare_trace_proof compare_memory_proof compare_air_public_input \
cairo_bench_programs cairo_proof_programs cairo_test_programs cairo_1_test_contracts cairo_2_test_contracts \
cairo_trace cairo-vm_trace cairo_proof_trace cairo-vm_proof_trace \
$(RELBIN) $(DBGBIN)
Expand All @@ -27,10 +27,14 @@ STARKNET_SIERRA_COMPILE_CAIRO_2:=cairo2/bin/starknet-sierra-compile
TEST_PROOF_DIR=cairo_programs/proof_programs
TEST_PROOF_FILES:=$(wildcard $(TEST_PROOF_DIR)/*.cairo)
COMPILED_PROOF_TESTS:=$(patsubst $(TEST_PROOF_DIR)/%.cairo, $(TEST_PROOF_DIR)/%.json, $(TEST_PROOF_FILES))

CAIRO_MEM_PROOF:=$(patsubst $(TEST_PROOF_DIR)/%.json, $(TEST_PROOF_DIR)/%.memory, $(COMPILED_PROOF_TESTS))
CAIRO_TRACE_PROOF:=$(patsubst $(TEST_PROOF_DIR)/%.json, $(TEST_PROOF_DIR)/%.trace, $(COMPILED_PROOF_TESTS))
CAIRO_AIR_PUBLIC_INPUT:=$(patsubst $(TEST_PROOF_DIR)/%.json, $(TEST_PROOF_DIR)/%.air_public_input, $(COMPILED_PROOF_TESTS))

CAIRO_RS_MEM_PROOF:=$(patsubst $(TEST_PROOF_DIR)/%.json, $(TEST_PROOF_DIR)/%.rs.memory, $(COMPILED_PROOF_TESTS))
CAIRO_RS_TRACE_PROOF:=$(patsubst $(TEST_PROOF_DIR)/%.json, $(TEST_PROOF_DIR)/%.rs.trace, $(COMPILED_PROOF_TESTS))
CAIRO_RS_AIR_PUBLIC_INPUT:=$(patsubst $(TEST_PROOF_DIR)/%.json, $(TEST_PROOF_DIR)/%.rs.air_public_input, $(COMPILED_PROOF_TESTS))

PROOF_BENCH_DIR=cairo_programs/benchmarks
PROOF_BENCH_FILES:=$(wildcard $(PROOF_BENCH_DIR)/*.cairo)
Expand All @@ -39,11 +43,11 @@ PROOF_COMPILED_BENCHES:=$(patsubst $(PROOF_BENCH_DIR)/%.cairo, $(PROOF_BENCH_DIR
$(TEST_PROOF_DIR)/%.json: $(TEST_PROOF_DIR)/%.cairo
cairo-compile --cairo_path="$(TEST_PROOF_DIR):$(PROOF_BENCH_DIR)" $< --output $@ --proof_mode

$(TEST_PROOF_DIR)/%.rs.trace $(TEST_PROOF_DIR)/%.rs.memory: $(TEST_PROOF_DIR)/%.json $(RELBIN)
cargo llvm-cov run -p cairo-vm-cli --release --no-report -- --layout starknet_with_keccak --proof_mode $< --trace_file $@ --memory_file $(@D)/$(*F).rs.memory
$(TEST_PROOF_DIR)/%.rs.trace $(TEST_PROOF_DIR)/%.rs.memory $(TEST_PROOF_DIR)/%.rs.air_public_input: $(TEST_PROOF_DIR)/%.json $(RELBIN)
cargo llvm-cov run -p cairo-vm-cli --release --no-report -- --layout starknet_with_keccak --proof_mode $< --trace_file $@ --memory_file $(@D)/$(*F).rs.memory --air_public_input $(@D)/$(*F).rs.air_public_input

$(TEST_PROOF_DIR)/%.trace $(TEST_PROOF_DIR)/%.memory: $(TEST_PROOF_DIR)/%.json
cairo-run --layout starknet_with_keccak --proof_mode --program $< --trace_file $@ --memory_file $(@D)/$(*F).memory
$(TEST_PROOF_DIR)/%.trace $(TEST_PROOF_DIR)/%.memory $(TEST_PROOF_DIR)/%.air_public_input: $(TEST_PROOF_DIR)/%.json
cairo-run --layout starknet_with_keccak --proof_mode --program $< --trace_file $(@D)/$(*F).trace --air_public_input $(@D)/$(*F).air_public_input --memory_file $(@D)/$(*F).memory

$(PROOF_BENCH_DIR)/%.json: $(PROOF_BENCH_DIR)/%.cairo
cairo-compile --cairo_path="$(TEST_PROOF_DIR):$(PROOF_BENCH_DIR)" $< --output $@ --proof_mode
Expand Down Expand Up @@ -215,8 +219,8 @@ cairo_bench_programs: $(COMPILED_BENCHES)
cairo_1_test_contracts: $(CAIRO_1_COMPILED_CASM_CONTRACTS)
cairo_2_test_contracts: $(CAIRO_2_COMPILED_CASM_CONTRACTS)

cairo_proof_trace: $(CAIRO_TRACE_PROOF) $(CAIRO_MEM_PROOF)
cairo-vm_proof_trace: $(CAIRO_RS_TRACE_PROOF) $(CAIRO_RS_MEM_PROOF)
cairo_proof_trace: $(CAIRO_TRACE_PROOF) $(CAIRO_MEM_PROOF) $(CAIRO_AIR_PUBLIC_INPUT)
cairo-vm_proof_trace: $(CAIRO_RS_TRACE_PROOF) $(CAIRO_RS_MEM_PROOF) $(CAIRO_RS_AIR_PUBLIC_INPUT)

cairo_trace: $(CAIRO_TRACE) $(CAIRO_MEM)
cairo-vm_trace: $(CAIRO_RS_TRACE) $(CAIRO_RS_MEM)
Expand Down Expand Up @@ -271,12 +275,18 @@ compare_memory: $(CAIRO_RS_MEM) $(CAIRO_MEM)
compare_trace_memory_proof: $(COMPILED_PROOF_TESTS) $(CAIRO_RS_TRACE_PROOF) $(CAIRO_TRACE_PROOF) $(CAIRO_RS_MEM_PROOF) $(CAIRO_MEM_PROOF)
cd vm/src/tests; ./compare_vm_state.sh trace memory proof_mode

compare_all_proof: $(COMPILED_PROOF_TESTS) $(CAIRO_RS_TRACE_PROOF) $(CAIRO_TRACE_PROOF) $(CAIRO_RS_MEM_PROOF) $(CAIRO_MEM_PROOF) $(CAIRO_RS_AIR_PUBLIC_INPUT) $(CAIRO_AIR_PUBLIC_INPUT)
cd vm/src/tests; ./compare_vm_state.sh trace memory proof_mode air_public_input

compare_trace_proof: $(CAIRO_RS_TRACE_PROOF) $(CAIRO_TRACE_PROOF)
cd vm/src/tests; ./compare_vm_state.sh trace proof_mode

compare_memory_proof: $(CAIRO_RS_MEM_PROOF) $(CAIRO_MEM_PROOF)
cd vm/src/tests; ./compare_vm_state.sh memory proof_mode

compare_air_public_input: $(CAIRO_RS_AIR_PUBLIC_INPUT) $(CAIRO_AIR_PUBLIC_INPUT)
cd vm/src/tests; ./compare_vm_state.sh memory proof_mode air_public_input

# Run with nightly enable the `doc_cfg` feature wich let us provide clear explaination about which parts of the code are behind a feature flag
docs:
RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --verbose --release --locked --no-deps --all-features --open
Expand All @@ -292,6 +302,7 @@ clean:
rm -f $(TEST_PROOF_DIR)/*.json
rm -f $(TEST_PROOF_DIR)/*.memory
rm -f $(TEST_PROOF_DIR)/*.trace
rm -f $(TEST_PROOF_DIR)/*.air_public_input
rm -rf cairo-vm-env
rm -rf cairo-vm-pypy-env
rm -rf cairo
Expand Down
8 changes: 4 additions & 4 deletions vm/src/air_public_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ use crate::{
#[derive(Serialize, Debug)]
pub struct PublicMemoryEntry {
address: usize,
page: usize,
#[serde(serialize_with = "mem_value_serde::serialize")]
value: Option<Felt252>,
page: usize,
}

mod mem_value_serde {
Expand All @@ -41,15 +41,15 @@ mod mem_value_serde {
#[derive(Serialize, Debug)]
struct MemorySegmentAddresses {
begin_addr: usize,
stop_addr: usize,
stop_ptr: usize,
}

impl From<(usize, usize)> for MemorySegmentAddresses {
fn from(addresses: (usize, usize)) -> Self {
let (begin_addr, stop_addr) = addresses;
let (begin_addr, stop_ptr) = addresses;
MemorySegmentAddresses {
begin_addr,
stop_addr,
stop_ptr,
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions vm/src/tests/air_public_input_comparator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env python3

import sys
import json


filename1 = sys.argv[1]
filename2 = sys.argv[2]

with open(filename1, 'r') as cairo_lang_input_file, open(filename2, 'r') as cairo_vm_input_file:
cairo_lang_input = json.load(cairo_lang_input_file)
cairo_vm_input = json.load(cairo_vm_input_file)

if cairo_lang_input == cairo_vm_input:

print(f"Comparison succesful for {filename1} vs {filename2}")
else:
print(f"Comparison unsuccesful for {filename1} vs {filename2}")
exit(1)

21 changes: 21 additions & 0 deletions vm/src/tests/compare_vm_state.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ proof_tests_path="${tests_path}/proof_programs"
exit_code=0
trace=false
memory=false
air_public_input=false
passed_tests=0
failed_tests=0

Expand All @@ -22,11 +23,21 @@ for i in $@; do
"proof_mode") tests_path=$proof_tests_path
echo "Requested proof mode usage"
;;
"air_public_input") air_public_input=true
echo "Requested air_public_input comparison"
;;
*)
;;
esac
done

if $air_public_input; then
if [ $tests_path != $proof_tests_path ]; then
echo "Can't compare air_public_input without proof_mode"
exit 1
fi
fi

files=$(ls $tests_path)
EXIT_CODE=$?
if [ ${EXIT_CODE} != 0 ]; then
Expand Down Expand Up @@ -55,6 +66,16 @@ for file in $(ls $tests_path | grep .cairo$ | sed -E 's/\.cairo$//'); do
passed_tests=$((passed_tests + 1))
fi
fi

if $air_public_input; then
if ! ./air_public_input_comparator.py $path_file.air_public_input $path_file.rs.air_public_input; then
echo "Air Public Input differs for $file"
exit_code=1
failed_tests=$((failed_tests + 1))
else
passed_tests=$((passed_tests + 1))
fi
fi
done

if test $failed_tests != 0; then
Expand Down
2 changes: 2 additions & 0 deletions vm/src/vm/errors/memory_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ pub enum MemoryError {
VecCapacityExceeded,
#[error("Memory wasn't relocated")]
UnrelocatedMemory,
#[error("Malformed public memory")]
MalformedPublicMemory,
}

#[derive(Debug, PartialEq, Eq, Error)]
Expand Down
12 changes: 9 additions & 3 deletions vm/src/vm/runners/cairo_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use num_traits::{ToPrimitive, Zero};
use serde::Deserialize;

use super::{
builtin_runner::{KeccakBuiltinRunner, PoseidonBuiltinRunner},
builtin_runner::{KeccakBuiltinRunner, PoseidonBuiltinRunner, OUTPUT_BUILTIN_NAME},
cairo_pie::{self, CairoPie, CairoPieMetadata},
};

Expand Down Expand Up @@ -938,8 +938,14 @@ impl CairoRunner {
let (_, size) = builtin_runner
.get_used_cells_and_allocated_size(vm)
.map_err(RunnerError::FinalizeSegements)?;
vm.segments
.finalize(Some(size), builtin_runner.base(), None)
if builtin_runner.name() == OUTPUT_BUILTIN_NAME {
let public_memory = (0..size).map(|i| (i, 0)).collect();
vm.segments
.finalize(Some(size), builtin_runner.base(), Some(&public_memory))
} else {
vm.segments
.finalize(Some(size), builtin_runner.base(), None)
}
}
self.segments_finalized = true;
Ok(())
Expand Down
9 changes: 7 additions & 2 deletions vm/src/vm/vm_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,9 @@ impl VirtualMachine {
/// Returns a list of addresses of memory cells that constitute the public memory.
pub fn get_public_memory_addresses(&self) -> Result<Vec<(usize, usize)>, VirtualMachineError> {
if let Some(relocation_table) = &self.relocation_table {
Ok(self.segments.get_public_memory_addresses(relocation_table))
self.segments
.get_public_memory_addresses(relocation_table)
.map_err(VirtualMachineError::Memory)
} else {
Err(MemoryError::UnrelocatedMemory.into())
}
Expand Down Expand Up @@ -1028,7 +1030,10 @@ impl VirtualMachine {
return Err(RunnerError::NoStopPointer(Box::new(builtin.name())).into());
};

Ok((builtin.name(), relocate(addresses)?))
Ok((
builtin.name().strip_suffix("_builtin").unwrap_or_default(),
relocate(addresses)?,
))
})
.collect()
}
Expand Down
38 changes: 20 additions & 18 deletions vm/src/vm/vm_memory/memory_segments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,21 +215,25 @@ impl MemorySegmentManager {

/// Returns a list of addresses of memory cells that constitute the public memory.
/// segment_offsets is the result of self.relocate_segments()
pub fn get_public_memory_addresses(&self, segment_offsets: &[usize]) -> Vec<(usize, usize)> {
let len = self.num_segments().min(self.public_memory_offsets.len());
let mut addresses = Vec::with_capacity(len);

for (offsets, segment_start) in self
.public_memory_offsets
.values()
.zip(segment_offsets.iter())
.take(len)
{
pub fn get_public_memory_addresses(
&self,
segment_offsets: &[usize],
) -> Result<Vec<(usize, usize)>, MemoryError> {
let mut addresses = Vec::with_capacity(self.num_segments());
let empty_vec = vec![];
for segment_index in 0..self.num_segments() {
let offsets = &self
.public_memory_offsets
.get(&segment_index)
.unwrap_or(&empty_vec);
let segment_start = segment_offsets
.get(segment_index)
.ok_or(MemoryError::MalformedPublicMemory)?;
for (offset, page_id) in offsets.iter() {
addresses.push((segment_start + offset, *page_id));
}
}
addresses
Ok(addresses)
}

// Writes the following information for the given segment:
Expand All @@ -245,10 +249,8 @@ impl MemorySegmentManager {
if let Some(size) = size {
self.segment_sizes.insert(segment_index, size);
}
if let Some(public_memory) = public_memory {
self.public_memory_offsets
.insert(segment_index, public_memory.clone());
}
self.public_memory_offsets
.insert(segment_index, public_memory.cloned().unwrap_or_default());
}
}

Expand Down Expand Up @@ -828,12 +830,12 @@ mod tests {

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn finalize_no_size_nor_memory_no_change() {
fn finalize_no_size_nor_memory() {
let mut segments = MemorySegmentManager::new();
segments.finalize(None, 0, None);
assert!(segments.memory.data.is_empty());
assert!(segments.memory.temp_data.is_empty());
assert!(segments.public_memory_offsets.is_empty());
assert_eq!(segments.public_memory_offsets, HashMap::from([(0, vec![])]));
assert_eq!(segments.num_segments(), 0);
assert_eq!(segments.num_temp_segments(), 0);
}
Expand All @@ -843,7 +845,7 @@ mod tests {
fn finalize_no_memory() {
let mut segments = MemorySegmentManager::new();
segments.finalize(Some(42), 0, None);
assert!(segments.public_memory_offsets.is_empty());
assert_eq!(segments.public_memory_offsets, HashMap::from([(0, vec![])]));
assert_eq!(segments.segment_sizes, HashMap::from([(0, 42)]));
}

Expand Down