Skip to content

Commit

Permalink
Test: compare output segment binary (#414)
Browse files Browse the repository at this point in the history
* wip output segment check

* wip output segment check

* wip output segment check

* remove logs

* clp

* add log for correct execution

* add reference pies

* add reference pies

* add script for executing all pies

* format + clippy

* add bash script

* clean up binary

* remove reference pie zips

* fix conflicts

* fix conflicts

* remove unused dep

* use env variables

* enhacements

* enhacements

* fmt + clippy

* complete reference for output segment

* use constant defined in lib.rs
  • Loading branch information
HermanObst authored Nov 1, 2024
1 parent e0f92c9 commit 20b57b9
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 18 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ resolver = "2"

members = [
"crates/bin/hint_tool",
"crates/bin/output_segment",
"crates/bin/prove_block",
"crates/cairo-type-derive",
"crates/rpc-client",
Expand Down
73 changes: 73 additions & 0 deletions compare_output.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/bin/bash

# Usage: compare_output.sh <SFTP_USER> <SFTP_SERVER> <REMOTE_PATH> <RPC_PROVIDER>
# SFTP_USER="" SFTP_SERVER="" REMOTE_PATH="" RPC_PROVIDER="" ./compare_output.sh

# Check Configuration is supplied
if [[ -z "$SFTP_USER" ]]; then
echo "Please provide the SFTP_USER."
exit 1
fi

if [[ -z "$SFTP_SERVER" ]]; then
echo "Please provide the SFTP_SERVER"
exit 1
fi

if [[ -z "$REMOTE_PATH" ]]; then
echo "Please provide the REMOTE_PATH"
exit 1
fi

if [[ -z "$RPC_PROVIDER" ]]; then
echo "Please provide the RPC_PROVIDER"
exit 1
fi

LOCAL_DIR="./downloaded_files"
LOG_FILE="./snos_run.log"

# Create local directory if it does not exist
mkdir -p "$LOCAL_DIR"

# Start the SFTP session to list files
# echo "Starting SFTP session to list files..." | tee -a "$LOG_FILE"
# sftp $SFTP_USER@$SFTP_SERVER << EOF > temp_file_list.txt
# cd $REMOTE_PATH
# ls
# EOF

# Read each line in the file list as a file to download and process
while read -r file; do
echo "Processing $file..."

# Download the file
sftp $SFTP_USER@$SFTP_SERVER << EOF
cd $REMOTE_PATH
lcd $LOCAL_DIR
get $file
EOF

# Check if download succeeded
if [ $? -eq 0 ]; then
echo "Successfully downloaded $file"

# Run the Rust program with the downloaded file using the specified command
if RUST_LOG="debug,minilp::solver=info" cargo run -p output_segment --release -- --rpc-provider $RPC_PROVIDER --pie-path "$LOCAL_DIR/$file"; then
echo "Successfully processed $file" | tee -a "$LOG_FILE"
else
echo "Failed to process $file" | tee -a "$LOG_FILE"
fi

# Delete the file after processing
rm "$LOCAL_DIR/$file"
echo "Deleted $file after processing."
else
echo "Failed to download $file" | tee -a "$LOG_FILE"
fi
done < temp_file_list.txt

# Clean up
rm temp_file_list.txt
echo "Script execution completed." | tee -a "$LOG_FILE"

36 changes: 36 additions & 0 deletions crates/bin/output_segment/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "output_segment"
version.workspace = true
edition.workspace = true
repository.workspace = true
license-file.workspace = true


[dependencies]
anyhow = { workspace = true }
blockifier = { workspace = true }
cairo-lang-starknet-classes = { workspace = true }
cairo-lang-utils = { workspace = true }
cairo-vm = { workspace = true }
clap = { workspace = true }
log = { workspace = true }
env_logger = { workspace = true }
futures-core = { workspace = true }
pathfinder-common = { workspace = true }
pathfinder-crypto = { workspace = true }
pathfinder-serde = { workspace = true }
prove_block = { path = "../prove_block" }
reqwest = { workspace = true }
rpc-client = { workspace = true }
rpc-replay = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
serde_with = { workspace = true }
starknet_api = { workspace = true }
starknet = { workspace = true }
starknet-os = { workspace = true }
starknet-os-types = { workspace = true }
starknet-types-core = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true }
num-bigint = { workspace = true }
Binary file not shown.
89 changes: 89 additions & 0 deletions crates/bin/output_segment/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use std::fs;
use std::path::PathBuf;

use cairo_vm::hint_processor::hint_processor_utils::felt_to_usize;
use cairo_vm::types::layout_name::LayoutName;
use cairo_vm::vm::runners::cairo_pie::CairoPie;
use cairo_vm::Felt252;
use clap::Parser;
use prove_block::{debug_prove_error, get_memory_segment, prove_block, DEFAULT_COMPILED_OS};

#[derive(Parser, Debug)]
struct Args {
/// Pie-zip to compare.
#[arg(long = "pie-path")]
zip_pie_path: PathBuf,

/// RPC endpoint to use for fact fetching
#[arg(long = "rpc-provider", default_value = "http://localhost:9545")]
rpc_provider: String,
}

fn init_logging() {
env_logger::builder()
.filter_level(log::LevelFilter::Debug)
.format_timestamp(None)
.try_init()
.expect("Failed to configure env_logger");
}

#[tokio::main]
async fn main() {
init_logging();

let args = Args::parse();

let zip_pie_path = args.zip_pie_path;
let endpoint = args.rpc_provider;

let reference_pie_bytes = fs::read(zip_pie_path).expect("Read Reference PIE");
let reference_pie = CairoPie::from_bytes(&reference_pie_bytes).expect("reference PIE");
reference_pie.run_validity_checks().expect("Valid reference PIE");

let block_number: u64 =
felt_to_usize(&get_pie_block_number(&reference_pie)).unwrap().try_into().expect("Block number is too big");

log::info!("Runnin SNOS for block number: {}", block_number);

let (snos_pie, _snos_output) =
prove_block(DEFAULT_COMPILED_OS, block_number, &endpoint, LayoutName::all_cairo, true)
.await
.map_err(debug_prove_error)
.expect("OS generate Cairo PIE");

snos_pie.run_validity_checks().expect("Valid SNOS PIE");

// While initializing cairo-vm, the first segment is the the one containing the program instructions. The second one is the execution segment.
// After that, the builtins are loaded in order. The first one is always the output builtin
// References:
// https://github.com/lambdaclass/cairo-vm/blob/159f67da19964cc54a95423a69470a26e534a13d/vm/src/vm/runners/cairo_runner.rs#L249-L279
// https://github.com/lambdaclass/cairo-vm/blob/159f67da19964cc54a95423a69470a26e534a13d/vm/src/vm/runners/cairo_runner.rs#L456-L466
// cairo-vm test output segment:
// https://github.com/lambdaclass/cairo-vm/blob/159f67da19964cc54a95423a69470a26e534a13d/cairo1-run/src/cairo_run.rs#L1732
let output_segment_index = 2;

assert_eq!(
get_memory_segment(&reference_pie, output_segment_index),
get_memory_segment(&snos_pie, output_segment_index)
);

log::info!("✅ SNOS Pie has the same output as reference pie");
}

fn get_pie_block_number(cairo_pie: &CairoPie) -> Felt252 {
// We know that current block number is on position (2,3)
// Output segment, position 3.
let output_segment_index = 2_usize;
let current_block_index = 3_usize;
let block_number = cairo_pie
.memory
.0
.iter()
.find(|((segment_index, offset), _value)| {
*segment_index == output_segment_index && *offset == current_block_index
})
.map(|((_segment_index, _offset), value)| value.clone())
.expect("Block number not found in CairoPie memory.");

block_number.get_int().expect("Block number is a Int")
}
14 changes: 14 additions & 0 deletions crates/bin/prove_block/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::rc::Rc;

use blockifier::state::cached_state::CachedState;
use cairo_vm::types::layout_name::LayoutName;
use cairo_vm::types::relocatable::MaybeRelocatable;
use cairo_vm::vm::errors::cairo_run_errors::CairoRunError;
use cairo_vm::vm::runners::cairo_pie::CairoPie;
use cairo_vm::Felt252;
Expand Down Expand Up @@ -46,6 +47,8 @@ mod state_utils;
mod types;
mod utils;

pub const DEFAULT_COMPILED_OS: &[u8] = include_bytes!("../../../../build/os_latest.json");

#[derive(Debug, Error)]
pub enum ProveBlockError {
#[error("RPC Error: {0}")]
Expand Down Expand Up @@ -359,3 +362,14 @@ pub fn debug_prove_error(err: ProveBlockError) -> ProveBlockError {
}
err
}

pub fn get_memory_segment(pie: &CairoPie, index: usize) -> Vec<(usize, &MaybeRelocatable)> {
let mut segment = pie
.memory
.0
.iter()
.filter_map(|((segment_index, offset), value)| (*segment_index == index).then_some((*offset, value)))
.collect::<Vec<_>>();
segment.sort_by(|(offset1, _), (offset2, _)| offset1.cmp(offset2));
segment
}
4 changes: 1 addition & 3 deletions crates/bin/prove_block/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use cairo_vm::types::layout_name::LayoutName;
use clap::Parser;
use prove_block::debug_prove_error;

pub const DEFAULT_COMPILED_OS: &[u8] = include_bytes!("../../../../build/os_latest.json");
use prove_block::{debug_prove_error, DEFAULT_COMPILED_OS};

#[derive(Parser, Debug)]
struct Args {
Expand Down
16 changes: 1 addition & 15 deletions crates/bin/prove_block/tests/prove_block.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
use cairo_vm::types::layout_name::LayoutName;
use cairo_vm::types::relocatable::MaybeRelocatable;
use cairo_vm::vm::runners::cairo_pie::CairoPie;
use prove_block::{debug_prove_error, prove_block};
use prove_block::{debug_prove_error, get_memory_segment, prove_block, DEFAULT_COMPILED_OS};
use rstest::rstest;

pub const DEFAULT_COMPILED_OS: &[u8] = include_bytes!("../../../../build/os_latest.json");

// # These blocks verify the following issues:
// # * 76793: the first block that we managed to prove, only has a few invoke txs
// # * 76766 / 76775: additional basic blocks
Expand Down Expand Up @@ -94,14 +91,3 @@ fn get_reference_pie_bytes(block_number: u64) -> Option<Vec<u8>> {
_ => None,
}
}

fn get_memory_segment(pie: &CairoPie, index: usize) -> Vec<(usize, &MaybeRelocatable)> {
let mut segment = pie
.memory
.0
.iter()
.filter_map(|((segment_index, offset), value)| (*segment_index == index).then_some((*offset, value)))
.collect::<Vec<_>>();
segment.sort_by(|(offset1, _), (offset2, _)| offset1.cmp(offset2));
segment
}

0 comments on commit 20b57b9

Please sign in to comment.