From c658194d90fe41a65de6ea62d42f614ca05958aa Mon Sep 17 00:00:00 2001 From: FroyaTheHen Date: Wed, 8 Jan 2025 11:45:46 +0100 Subject: [PATCH 01/71] feat: executable command Add scarb execute extension --- Cargo.lock | 41 ++ Cargo.toml | 3 + extensions/scarb-cairo-execute/Cargo.toml | 34 ++ extensions/scarb-cairo-execute/src/main.rs | 384 ++++++++++++++++++ extensions/scarb-cairo-execute/tests/build.rs | 141 +++++++ 5 files changed, 603 insertions(+) create mode 100644 extensions/scarb-cairo-execute/Cargo.toml create mode 100644 extensions/scarb-cairo-execute/src/main.rs create mode 100644 extensions/scarb-cairo-execute/tests/build.rs diff --git a/Cargo.lock b/Cargo.lock index 0d8c5af44..a404196a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -415,9 +415,19 @@ version = "2.0.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f11ea1a0346b94ef188834a65c068a03aec181c94896d481d7a0a40d85b0ce95" dependencies = [ + "bincode_derive", "serde", ] +[[package]] +name = "bincode_derive" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30759b3b99a1b802a7a3aa21c85c3ded5c28e1c83170d82d70f08bbf7f3e4c" +dependencies = [ + "virtue", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -5180,6 +5190,31 @@ dependencies = [ "semver", ] +[[package]] +name = "scarb-cairo-execute" +version = "2.9.2" +dependencies = [ + "anyhow", + "assert_fs", + "bincode", + "cairo-lang-executable", + "cairo-lang-runner", + "cairo-vm", + "camino", + "clap", + "create-output-dir", + "indoc", + "num-bigint", + "predicates", + "scarb", + "scarb-metadata 1.13.0", + "scarb-test-support", + "scarb-ui", + "serde", + "serde_json", + "snapbox", +] + [[package]] name = "scarb-cairo-language-server" version = "2.9.2" @@ -6603,6 +6638,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "virtue" +version = "0.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dcc60c0624df774c82a0ef104151231d37da4962957d691c011c852b2473314" + [[package]] name = "wait-timeout" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 79281ecf7..21c7e107a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "scarb", "scarb-metadata", "extensions/scarb-doc", + "extensions/scarb-cairo-execute", "extensions/scarb-cairo-language-server", "extensions/scarb-cairo-run", "extensions/scarb-cairo-test", @@ -51,6 +52,7 @@ anyhow = "1" assert_fs = "1" async-trait = "0.1" axum = { version = "0.6", features = ["http2"] } +bincode = "2.0.0-rc.3" cairo-lang-compiler = "*" cairo-lang-defs = "*" cairo-lang-diagnostics = "*" @@ -71,6 +73,7 @@ cairo-lang-test-plugin = "*" cairo-lang-test-runner = "*" cairo-lang-utils = { version = "*", features = ["env_logger"] } cairo-language-server = "*" +cairo-vm = "1.0.1" camino = { version = "1", features = ["serde1"] } cargo_metadata = ">=0.18" clap = { version = "4", features = ["derive", "env", "string"] } diff --git a/extensions/scarb-cairo-execute/Cargo.toml b/extensions/scarb-cairo-execute/Cargo.toml new file mode 100644 index 000000000..878998bb4 --- /dev/null +++ b/extensions/scarb-cairo-execute/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "scarb-cairo-execute" +publish = false + +authors.workspace = true +edition.workspace = true +homepage.workspace = true +license.workspace = true +readme.workspace = true +repository.workspace = true +version.workspace = true + +[dependencies] +anyhow.workspace = true +bincode.workspace = true +cairo-lang-executable.workspace = true +cairo-lang-runner.workspace = true +cairo-vm.workspace = true +camino.workspace = true +clap.workspace = true +create-output-dir = { path = "../../utils/create-output-dir" } +indoc.workspace = true +num-bigint.workspace = true +predicates.workspace = true +scarb = { path = "../../scarb" } +scarb-metadata = { path = "../../scarb-metadata" } +scarb-ui = { path = "../../utils/scarb-ui" } +serde.workspace = true +serde_json.workspace = true + +[dev-dependencies] +assert_fs.workspace = true +scarb-test-support = { path = "../../utils/scarb-test-support" } +snapbox.workspace = true diff --git a/extensions/scarb-cairo-execute/src/main.rs b/extensions/scarb-cairo-execute/src/main.rs new file mode 100644 index 000000000..1c03c31c3 --- /dev/null +++ b/extensions/scarb-cairo-execute/src/main.rs @@ -0,0 +1,384 @@ +use anyhow::{bail, ensure, Context, Result}; +use bincode::enc::write::Writer; +use cairo_lang_executable::executable::{EntryPointKind, Executable}; +use cairo_lang_runner::{build_hints_dict, Arg, CairoHintProcessor}; +use cairo_vm::cairo_run::cairo_run_program; +use cairo_vm::cairo_run::CairoRunConfig; +use cairo_vm::types::layout_name::LayoutName; +use cairo_vm::types::program::Program; +use cairo_vm::types::relocatable::MaybeRelocatable; +use cairo_vm::{cairo_run, Felt252}; +use camino::{Utf8Path, Utf8PathBuf}; +use clap::{arg, Parser, ValueEnum}; +use create_output_dir::create_output_dir; +use indoc::formatdoc; +use num_bigint::BigInt; +use scarb_metadata::{Metadata, MetadataCommand, ScarbCommand}; +use scarb_ui::args::{PackagesFilter, VerbositySpec}; +use scarb_ui::components::Status; +use scarb_ui::Ui; +use std::env; +use std::fs; +use std::fs::OpenOptions; +use std::io::{self, Write}; +use std::process::ExitCode; + +const MAX_ITERATION_COUNT: usize = 10000; + +/// Compiles a Cairo project and runs a function marked `#[executable]`. +/// Exits with 1 if the compilation or run fails, otherwise 0. +#[derive(Parser, Clone, Debug)] +#[clap(version, verbatim_doc_comment)] +struct Args { + /// Name of the package. + #[command(flatten)] + packages_filter: PackagesFilter, + + /// Do not rebuild the package. + #[arg(long, default_value_t = false)] + no_build: bool, + + #[clap(flatten)] + run: ExecutionArgs, + + /// Logging verbosity. + #[command(flatten)] + pub verbose: VerbositySpec, +} + +#[derive(Parser, Clone, Debug)] +struct ExecutionArgs { + /// Serialized arguments to the executable function. + #[arg(long, value_delimiter = ',')] + arguments: Vec, + + /// Desired execution output, either default Standard or CairoPie + #[arg(long, default_value = "standard")] + pub output: OutputFormat, + + /// Execution target. + #[arg(long, default_value = "standalone")] + target: ExecutionTarget, + + /// Whether to print the program outputs. + #[arg(long, default_value_t = false)] + print_program_output: bool, +} + +#[derive(ValueEnum, Clone, Debug)] +enum OutputFormat { + CairoPie, + Standard, +} +impl OutputFormat { + pub fn is_cairo_pie(&self) -> bool { + matches!(self, OutputFormat::CairoPie) + } +} + +#[derive(ValueEnum, Clone, Debug)] +enum ExecutionTarget { + Bootloader, + Standalone, +} + +impl ExecutionTarget { + pub fn is_standalone(&self) -> bool { + matches!(self, ExecutionTarget::Standalone) + } +} + +fn main() -> ExitCode { + let args = Args::parse(); + let ui = Ui::new(args.verbose.clone().into(), scarb_ui::OutputFormat::Text); + + match main_inner(args, ui.clone()) { + Ok(()) => ExitCode::SUCCESS, + Err(error) => { + ui.error(format!("{error:#}")); + ExitCode::FAILURE + } + } +} + +fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> { + ensure!( + !(args.run.output.is_cairo_pie() && args.run.target.is_standalone()), + "Cairo pie output format is not supported for standalone execution target" + ); + + let metadata = MetadataCommand::new().inherit_stderr().exec()?; + let package = args.packages_filter.match_one(&metadata)?; + + if !args.no_build { + let filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); + ScarbCommand::new() + .arg("build") + .env("SCARB_PACKAGES_FILTER", filter.to_env()) + .run()?; + } + + let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); + let scarb_build_dir = scarb_target_dir.join(env::var("SCARB_PROFILE")?); + + ui.print(Status::new("Executing", &package.name)); + let executable = load_prebuilt_executable( + &scarb_build_dir, + format!("{}.executable.json", package.name), + )?; + + let data = executable + .program + .bytecode + .iter() + .map(Felt252::from) + .map(MaybeRelocatable::from) + .collect(); + + let (hints, string_to_hint) = build_hints_dict(&executable.program.hints); + + let program = if args.run.target.is_standalone() { + let entrypoint = executable + .entrypoints + .iter() + .find(|e| matches!(e.kind, EntryPointKind::Standalone)) + .with_context(|| "No `Standalone` entrypoint found.")?; + Program::new_for_proof( + entrypoint.builtins.clone(), + data, + entrypoint.offset, + entrypoint.offset + 4, + hints, + Default::default(), + Default::default(), + vec![], + None, + ) + } else { + let entrypoint = executable + .entrypoints + .iter() + .find(|e| matches!(e.kind, EntryPointKind::Bootloader)) + .with_context(|| "No `Bootloader` entrypoint found.")?; + Program::new( + entrypoint.builtins.clone(), + data, + Some(entrypoint.offset), + hints, + Default::default(), + Default::default(), + vec![], + None, + ) + } + .with_context(|| "Failed setting up program.")?; + + let mut hint_processor = CairoHintProcessor { + runner: None, + user_args: vec![vec![Arg::Array( + args.run + .arguments + .iter() + .map(|v| Arg::Value(v.into())) + .collect(), + )]], + string_to_hint, + starknet_state: Default::default(), + run_resources: Default::default(), + syscalls_used_resources: Default::default(), + no_temporary_segments: false, + }; + + let cairo_run_config = CairoRunConfig { + allow_missing_builtins: Some(true), + layout: LayoutName::all_cairo, + proof_mode: args.run.target.is_standalone(), + relocate_mem: args.run.target.is_standalone(), + secure_run: None, + trace_enabled: true, + ..Default::default() + }; + + let mut runner = cairo_run_program(&program, &cairo_run_config, &mut hint_processor) + .with_context(|| "Cairo program run failed")?; + + if args.run.print_program_output { + let mut output_buffer = "Program Output:\n".to_string(); + runner.vm.write_output(&mut output_buffer)?; + print!("{output_buffer}"); + } + + let output_dir = scarb_target_dir.join("scarb-execute"); + create_output_dir(output_dir.as_std_path())?; + + if args.run.output.is_cairo_pie() { + let output_value = runner.get_cairo_pie()?; + let output_file_path = incremental_create_output_file(&output_dir, package.name, ".zip")?; + ui.print(Status::new( + "Saving output to:", + &display_path(&scarb_target_dir, &output_file_path), + )); + output_value.write_zip_file(output_file_path.as_std_path())?; + } else { + let execution_output_dir = incremental_create_output_dir(&output_dir, package.name)?; + ui.print(Status::new( + "Saving output to:", + &display_path(&scarb_target_dir, &execution_output_dir), + )); + + // Write trace file. + let trace_path = execution_output_dir.join("trace.bin"); + let relocated_trace = runner + .relocated_trace + .as_ref() + .with_context(|| "Trace not relocated.")?; + let mut writer = FileWriter::new(3 * 1024 * 1024, &trace_path)?; + cairo_run::write_encoded_trace(relocated_trace, &mut writer)?; + writer.flush()?; + + // Write memory file. + let memory_path = execution_output_dir.join("memory.bin"); + let mut writer = FileWriter::new(5 * 1024 * 1024, &memory_path)?; + cairo_run::write_encoded_memory(&runner.relocated_memory, &mut writer)?; + writer.flush()?; + + // Write air public input file. + let air_public_input_path = execution_output_dir.join("air_public_input.json"); + let json = runner.get_air_public_input()?.serialize_json()?; + fs::write(air_public_input_path, json)?; + + // Write air private input file. + let air_private_input_path = execution_output_dir.join("air_private_input.json"); + let output_value = runner + .get_air_private_input() + .to_serializable(trace_path.to_string(), memory_path.to_string()) + .serialize_json() + .with_context(|| "Failed serializing private input.")?; + fs::write(air_private_input_path, output_value)?; + } + + Ok(()) +} + +fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { + Utf8PathBuf::from("target") + .join( + output_path + .strip_prefix(scarb_target_dir) + .unwrap_or(output_path), + ) + .to_string() +} + +fn load_prebuilt_executable(path: &Utf8Path, filename: String) -> Result { + let file_path = path.join(&filename); + ensure!( + file_path.exists(), + formatdoc! {r#" + package has not been compiled, file does not exist: {filename} + help: run `scarb build` to compile the package + "#} + ); + let file = fs::File::open(&file_path) + .with_context(|| format!("failed to open executable program: {file_path}"))?; + serde_json::from_reader(file) + .with_context(|| format!("failed to deserialize executable program: {file_path}")) +} + +fn incremental_create_output_file( + path: &Utf8Path, + name: String, + extension: impl AsRef, +) -> Result { + incremental_attempt_io_creation( + path, + name, + extension, + "Failed to create output directory.", + |p| { + OpenOptions::new() + .write(true) + .create_new(true) + .open(p) + .map(|_| ()) + }, + ) +} + +fn incremental_create_output_dir(path: &Utf8Path, name: String) -> Result { + incremental_attempt_io_creation(path, name, "", "Failed to create output directory.", |p| { + fs::create_dir(p) + }) +} + +fn incremental_attempt_io_creation( + path: &Utf8Path, + name: impl AsRef, + extension: impl AsRef, + final_error_message: impl AsRef, + attempt: impl Fn(&Utf8Path) -> io::Result<()>, +) -> Result { + for i in 0..MAX_ITERATION_COUNT { + let number_string = if i == 0 { + "".to_string() + } else { + format!("_{}", i) + }; + let filepath = path.join(format!( + "{}{}{}", + name.as_ref(), + number_string, + extension.as_ref() + )); + let result = attempt(&filepath); + return match result { + Err(e) => { + if e.kind() == io::ErrorKind::AlreadyExists { + continue; + } + Err(e.into()) + } + Ok(_) => Ok(filepath), + }; + } + bail!(final_error_message.as_ref().to_string()); +} + +/// Writer implementation for a file. +struct FileWriter { + buf_writer: io::BufWriter, + bytes_written: usize, +} + +impl Writer for FileWriter { + fn write(&mut self, bytes: &[u8]) -> Result<(), bincode::error::EncodeError> { + self.buf_writer + .write_all(bytes) + .map_err(|e| bincode::error::EncodeError::Io { + inner: e, + index: self.bytes_written, + })?; + + self.bytes_written += bytes.len(); + + Ok(()) + } +} + +impl FileWriter { + /// Create a new instance of `FileWriter` with the given file path. + fn new(capacity: usize, path: &Utf8Path) -> Result { + Ok(Self { + buf_writer: io::BufWriter::with_capacity(capacity, fs::File::create(path)?), + bytes_written: 0, + }) + } + + /// Flush the writer. + /// + /// Would automatically be called when the writer is dropped, but errors are ignored in that + /// case. + fn flush(&mut self) -> io::Result<()> { + self.buf_writer.flush() + } +} diff --git a/extensions/scarb-cairo-execute/tests/build.rs b/extensions/scarb-cairo-execute/tests/build.rs new file mode 100644 index 000000000..1c6410611 --- /dev/null +++ b/extensions/scarb-cairo-execute/tests/build.rs @@ -0,0 +1,141 @@ +use assert_fs::assert::PathAssert; +use assert_fs::fixture::PathChild; +use assert_fs::TempDir; +use indoc::indoc; +use scarb_test_support::command::Scarb; +use scarb_test_support::project_builder::ProjectBuilder; +use snapbox::cmd::OutputAssert; + +fn build_executable_project() -> TempDir { + let t = TempDir::new().unwrap(); + ProjectBuilder::start() + .name("hello") + .version("0.1.0") + .dep_cairo_execute() + .manifest_extra(indoc! {r#" + [executable] + "#}) + .lib_cairo(indoc! {r#" + #[executable] + fn main() -> felt252 { + 42 + } + "#}) + .build(&t); + t +} + +#[test] +fn can_execute_default_main_function_from_executable() { + let t = build_executable_project(); + Scarb::quick_snapbox() + .arg("cairo-execute") + .current_dir(&t) + .assert() + .success() + .stdout_matches(indoc! {r#" + [..]Compiling hello v0.1.0 ([..]Scarb.toml) + [..]Finished `dev` profile target(s) in [..] + [..]Executing hello + Saving output to: target/scarb-execute/hello + "#}); + + t.child("target/scarb-execute/hello/air_private_input.json") + .assert(predicates::path::exists()); + t.child("target/scarb-execute/hello/air_public_input.json") + .assert(predicates::path::exists()); + t.child("target/scarb-execute/hello/memory.bin") + .assert(predicates::path::exists()); + t.child("target/scarb-execute/hello/trace.bin") + .assert(predicates::path::exists()); +} + +#[test] +fn can_execute_prebuilt_executable() { + let t = build_executable_project(); + Scarb::quick_snapbox().arg("build").current_dir(&t).assert(); + Scarb::quick_snapbox() + .arg("cairo-execute") + .arg("--no-build") + .current_dir(&t) + .assert() + .success() + .stdout_matches(indoc! {r#" + [..]Executing hello + Saving output to: target/scarb-execute/hello + "#}); + + t.child("target/scarb-execute/hello/air_private_input.json") + .assert(predicates::path::exists()); + t.child("target/scarb-execute/hello/air_public_input.json") + .assert(predicates::path::exists()); + t.child("target/scarb-execute/hello/memory.bin") + .assert(predicates::path::exists()); + t.child("target/scarb-execute/hello/trace.bin") + .assert(predicates::path::exists()); +} + +#[test] +fn can_produce_cairo_pie_output() { + let t = build_executable_project(); + Scarb::quick_snapbox() + .arg("cairo-execute") + .arg("--target=bootloader") + .arg("--output=cairo-pie") + .current_dir(&t) + .assert() + .success() + .stdout_matches(indoc! {r#" + [..]Compiling hello v0.1.0 ([..]Scarb.toml) + [..]Finished `dev` profile target(s) in [..] + [..]Executing hello + Saving output to: target/scarb-execute/hello.zip + "#}); + + t.child("target/scarb-execute/hello.zip") + .assert(predicates::path::exists()); +} + +#[test] +fn fails_when_target_missing() { + let t = TempDir::new().unwrap(); + ProjectBuilder::start() + .name("hello") + .version("0.1.0") + .dep_cairo_execute() + .manifest_extra(indoc! {r#" + [executable] + "#}) + .lib_cairo(indoc! {r#" + fn main() -> felt252 { + 42 + } + "#}) + .build(&t); + + Scarb::quick_snapbox().arg("build").current_dir(&t).assert(); + + output_assert( + Scarb::quick_snapbox() + .arg("cairo-execute") + .arg("--no-build") + .current_dir(&t) + .assert() + .failure(), + indoc! {r#" + [..]Executing hello + error: package has not been compiled, file does not exist: hello.executable.json + help: run `scarb build` to compile the package + + "#}, + ) +} + +fn output_assert(output: OutputAssert, expected: &str) { + #[cfg(windows)] + output.stdout_matches(format!( + "{expected}error: process did not exit successfully: exit code: 1\n" + )); + #[cfg(not(windows))] + output.stdout_matches(expected); +} From af5414df03ddae078df082ab6f722dea04757bc2 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 17 Jan 2025 03:59:47 +0100 Subject: [PATCH 02/71] Initial `cairo-prove` --- Cargo.lock | 830 +++++++++++++++++++++-- Cargo.toml | 3 +- extensions/scarb-cairo-prove/Cargo.toml | 31 + extensions/scarb-cairo-prove/src/main.rs | 123 ++++ 4 files changed, 943 insertions(+), 44 deletions(-) create mode 100644 extensions/scarb-cairo-prove/Cargo.toml create mode 100644 extensions/scarb-cairo-prove/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index a404196a1..80948bab5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,6 +56,17 @@ dependencies = [ "memchr", ] +[[package]] +name = "air_structs_derive" +version = "0.1.0" +source = "git+https://github.com/starkware-libs/stwo-cairo?rev=a27287c21e8b7e677b07cc40988c8c145533c55d#a27287c21e8b7e677b07cc40988c8c145533c55d" +dependencies = [ + "itertools 0.13.0", + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -77,6 +88,16 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "alloy-rlp" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f542548a609dca89fcd72b3b9f355928cf844d4363c5eed9c5273a3dd225e097" +dependencies = [ + "arrayvec", + "bytes", +] + [[package]] name = "anstream" version = "0.6.14" @@ -144,10 +165,10 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ - "ark-ff", + "ark-ff 0.4.2", "ark-poly", - "ark-serialize", - "ark-std", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "derivative", "hashbrown 0.13.2", "itertools 0.10.5", @@ -155,26 +176,54 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits 0.2.19", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + [[package]] name = "ark-ff" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "derivative", - "digest", + "digest 0.10.7", "itertools 0.10.5", "num-bigint", "num-traits 0.2.19", "paste", - "rustc_version", + "rustc_version 0.4.0", "zeroize", ] +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "ark-ff-asm" version = "0.4.2" @@ -185,6 +234,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits 0.2.19", + "quote", + "syn 1.0.109", +] + [[package]] name = "ark-ff-macros" version = "0.4.2" @@ -204,9 +265,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", "derivative", "hashbrown 0.13.2", ] @@ -218,8 +279,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c02e954eaeb4ddb29613fee20840c2bbc85ca4396d53e33837e11905363c5f2" dependencies = [ "ark-ec", - "ark-ff", - "ark-std", + "ark-ff 0.4.2", + "ark-std 0.4.0", ] [[package]] @@ -229,8 +290,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" dependencies = [ "ark-ec", - "ark-ff", - "ark-std", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", ] [[package]] @@ -240,8 +311,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ "ark-serialize-derive", - "ark-std", - "digest", + "ark-std 0.4.0", + "digest 0.10.7", "num-bigint", ] @@ -256,6 +327,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits 0.2.19", + "rand", +] + [[package]] name = "ark-std" version = "0.4.0" @@ -266,6 +347,12 @@ dependencies = [ "rand", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.4" @@ -327,6 +414,17 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -409,6 +507,18 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bigdecimal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits 0.2.19", + "serde", +] + [[package]] name = "bincode" version = "2.0.0-rc.3" @@ -467,6 +577,28 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake3" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9ec96fe9a81b5e365f9db71fe00edc4fe4ca2cc7dcb7861f0603012a7caa210" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq 0.3.1", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -531,6 +663,26 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +[[package]] +name = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -603,7 +755,7 @@ dependencies = [ "indoc", "rayon", "rust-analyzer-salsa", - "semver", + "semver 1.0.24", "smol_str", "thiserror 1.0.69", ] @@ -690,7 +842,7 @@ dependencies = [ "cairo-lang-sierra-to-casm", "cairo-lang-syntax", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "indoc", "itertools 0.12.1", "serde", @@ -705,7 +857,7 @@ dependencies = [ "cairo-lang-utils", "path-clean", "rust-analyzer-salsa", - "semver", + "semver 1.0.24", "serde", "smol_str", "toml", @@ -883,7 +1035,7 @@ dependencies = [ "cairo-lang-sierra-to-casm", "cairo-lang-sierra-type-size", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.12.1", "thiserror 1.0.69", ] @@ -893,7 +1045,7 @@ name = "cairo-lang-runner" version = "2.9.2" source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" dependencies = [ - "ark-ff", + "ark-ff 0.4.2", "ark-secp256k1", "ark-secp256r1", "cairo-lang-casm", @@ -904,7 +1056,7 @@ dependencies = [ "cairo-lang-sierra-to-casm", "cairo-lang-starknet", "cairo-lang-utils", - "cairo-vm", + "cairo-vm 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.12.1", "keccak", "num-bigint", @@ -1258,7 +1410,7 @@ checksum = "20cb651f2fb6b882fd224f144e450a8d8b12c1a4f85af8c28c5bfbb391ddea5b" dependencies = [ "anyhow", "clap", - "semver", + "semver 1.0.24", "toml_edit 0.22.22", "xshell", ] @@ -1294,6 +1446,37 @@ dependencies = [ "zip", ] +[[package]] +name = "cairo-vm" +version = "1.0.1" +source = "git+https://github.com/lambdaclass/cairo-vm?rev=3fb0344c#3fb0344ce038b3a68cae897c403d1f561cfe8da7" +dependencies = [ + "anyhow", + "bincode", + "bitvec", + "generic-array", + "hashbrown 0.14.5", + "hex", + "keccak", + "lazy_static", + "nom", + "num-bigint", + "num-integer", + "num-prime", + "num-traits 0.2.19", + "rand", + "rust_decimal", + "serde", + "serde_json", + "sha2", + "sha3", + "starknet-crypto", + "starknet-types-core", + "thiserror-no-std", + "wasm-bindgen", + "zip", +] + [[package]] name = "camino" version = "1.1.9" @@ -1320,7 +1503,7 @@ checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" dependencies = [ "camino", "cargo-platform", - "semver", + "semver 1.0.24", "serde", "serde_json", "thiserror 2.0.11", @@ -1466,6 +1649,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "content_inspector" version = "0.2.4" @@ -1779,6 +1968,15 @@ dependencies = [ "nu-ansi-term", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.7" @@ -1867,6 +2065,18 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +[[package]] +name = "educe" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "either" version = "1.12.0" @@ -1897,6 +2107,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "env_filter" version = "0.1.2" @@ -1977,6 +2207,40 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "faststr" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9154486833a83cb5d99de8c4d831314b8ae810dd4ef18d89ceb7a9c7c728dd74" +dependencies = [ + "bytes", + "rkyv", + "serde", + "simdutf8", +] + [[package]] name = "filetime" version = "0.2.23" @@ -1989,6 +2253,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -3234,7 +3510,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -3526,6 +3802,15 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + [[package]] name = "impl-trait-for-tuples" version = "0.2.2" @@ -3667,6 +3952,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -3827,6 +4121,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "libredox" version = "0.1.3" @@ -4049,6 +4349,26 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b52c1b33ff98142aecea13138bd399b68aa7ab5d9546c300988c345004001eea" +[[package]] +name = "munge" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64142d38c84badf60abf06ff9bd80ad2174306a5b11bd4706535090a30a419df" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb5c1d8184f13f7d0ccbeeca0def2f9a181bce2624302793005f5ca8aa62e5e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -4248,6 +4568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -4466,7 +4787,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest", + "digest 0.10.7", "hmac", "password-hash", "sha2", @@ -4478,6 +4799,17 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +dependencies = [ + "memchr", + "thiserror 2.0.11", + "ucd-trie", +] + [[package]] name = "petgraph" version = "0.6.5" @@ -4605,6 +4937,17 @@ dependencies = [ "yansi", ] +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + [[package]] name = "priority-queue" version = "2.1.1" @@ -4647,7 +4990,59 @@ dependencies = [ ] [[package]] -name = "pubgrub" +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bitflags 2.5.0", + "lazy_static", + "num-traits 0.2.19", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.5", + "unarray", +] + +[[package]] +name = "prover_types" +version = "0.1.0" +source = "git+https://github.com/starkware-libs/stwo-cairo?rev=a27287c21e8b7e677b07cc40988c8c145533c55d#a27287c21e8b7e677b07cc40988c8c145533c55d" +dependencies = [ + "bytemuck", + "itertools 0.12.1", + "num-traits 0.2.19", + "ruint", + "serde", + "starknet-ff", + "stwo-cairo-serialize", + "stwo-prover", + "stwo_cairo_utils", +] + +[[package]] +name = "ptr_meta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "pubgrub" version = "0.2.1" source = "git+https://github.com/software-mansion-labs/pubgrub.git?branch=dev#cdae1729d7c47a6194a499d674ccdc96ce0838f1" dependencies = [ @@ -4718,6 +5113,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rancor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" +dependencies = [ + "ptr_meta", +] + [[package]] name = "rand" version = "0.8.5" @@ -4748,6 +5152,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + [[package]] name = "raw-cpuid" version = "11.2.0" @@ -4821,6 +5234,26 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "regex" version = "1.11.0" @@ -4871,6 +5304,12 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" +[[package]] +name = "rend" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" + [[package]] name = "reqwest" version = "0.11.27" @@ -4944,6 +5383,77 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rkyv" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b11a153aec4a6ab60795f8ebe2923c597b16b05bb1504377451e705ef1a45323" +dependencies = [ + "bytes", + "hashbrown 0.15.2", + "indexmap 2.7.0", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beb382a4d9f53bd5c0be86b10d8179c3f8a14c30bf774ff77096ed6581e35981" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5ef8fb1dd8de3870cb8400d51b4c2023854bbafd5431a3ac7e7317243e22d2f" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp 0.3.1", + "fastrlp 0.4.0", + "num-bigint", + "num-integer", + "num-traits 0.2.19", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + [[package]] name = "rust-analyzer-salsa" version = "0.17.0-pre.6" @@ -4995,13 +5505,28 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver", + "semver 1.0.24", ] [[package]] @@ -5149,7 +5674,7 @@ dependencies = [ "scarb-stable-hash 1.0.0", "scarb-test-support", "scarb-ui", - "semver", + "semver 1.0.24", "semver-pubgrub", "serde", "serde-untagged", @@ -5187,7 +5712,7 @@ name = "scarb-build-metadata" version = "2.9.2" dependencies = [ "cargo_metadata", - "semver", + "semver 1.0.24", ] [[package]] @@ -5199,7 +5724,7 @@ dependencies = [ "bincode", "cairo-lang-executable", "cairo-lang-runner", - "cairo-vm", + "cairo-vm 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "camino", "clap", "create-output-dir", @@ -5227,6 +5752,25 @@ dependencies = [ "url", ] +[[package]] +name = "scarb-cairo-prove" +version = "2.9.2" +dependencies = [ + "anyhow", + "assert_fs", + "camino", + "clap", + "create-output-dir", + "indoc", + "scarb-metadata 1.13.0", + "scarb-test-support", + "scarb-ui", + "serde", + "serde_json", + "stwo-prover", + "stwo_cairo_prover", +] + [[package]] name = "scarb-cairo-run" version = "2.9.2" @@ -5310,7 +5854,7 @@ dependencies = [ "cairo-lang-filesystem", "camino", "derive_builder", - "semver", + "semver 1.0.24", "serde", "serde_json", "snapbox", @@ -5324,7 +5868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a8b71f63999dbb6d269fbc6fd61310016ab3a160fb13e52a6511a2b904359f0" dependencies = [ "camino", - "semver", + "semver 1.0.24", "serde", "serde_json", "thiserror 1.0.69", @@ -5386,7 +5930,7 @@ dependencies = [ "scarb-build-metadata", "scarb-proc-macro-server-types 0.1.0", "scarb-ui", - "semver", + "semver 1.0.24", "serde", "serde_json", "sha2", @@ -5486,6 +6030,15 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + [[package]] name = "semver" version = "1.0.24" @@ -5495,13 +6048,22 @@ dependencies = [ "serde", ] +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + [[package]] name = "semver-pubgrub" version = "0.1.0" source = "git+https://github.com/software-mansion-labs/semver-pubgrub.git#6c78141d940cda6d8e69aea794c2bf30cc3402df" dependencies = [ "pubgrub", - "semver", + "semver 1.0.24", ] [[package]] @@ -5627,7 +6189,7 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -5644,7 +6206,7 @@ checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest", + "digest 0.10.7", ] [[package]] @@ -5653,7 +6215,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest", + "digest 0.10.7", "keccak", ] @@ -5691,6 +6253,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "similar" version = "2.5.0" @@ -5783,6 +6351,44 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "sonic-number" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a74044c092f4f43ca7a6cfd62854cf9fb5ac8502b131347c990bf22bef1dfe" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "sonic-rs" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0275f9f2f07d47556fe60c2759da8bc4be6083b047b491b2d476aa0bfa558eb1" +dependencies = [ + "bumpalo", + "bytes", + "cfg-if", + "faststr", + "itoa", + "ref-cast", + "ryu", + "serde", + "simdutf8", + "sonic-number", + "sonic-simd", + "thiserror 2.0.11", +] + +[[package]] +name = "sonic-simd" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940a24e82c9a97483ef66cef06b92160a8fa5cd74042c57c10b24d99d169d2fc" +dependencies = [ + "cfg-if", +] + [[package]] name = "spin" version = "0.5.2" @@ -5867,10 +6473,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abf1b44ec5b18d87c1ae5f54590ca9d0699ef4dd5b2ffa66fc97f24613ec585" dependencies = [ - "ark-ff", + "ark-ff 0.4.2", + "bigdecimal", "crypto-bigint", "getrandom", "hex", + "serde", ] [[package]] @@ -5913,6 +6521,112 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "stwo-air-utils" +version = "0.1.1" +source = "git+https://github.com/starkware-libs/stwo?rev=af5475cb#af5475cb946a29de7d04dfa8c77a17034f888df4" +dependencies = [ + "bytemuck", + "itertools 0.12.1", + "rayon", + "stwo-air-utils-derive", + "stwo-prover", +] + +[[package]] +name = "stwo-air-utils-derive" +version = "0.1.0" +source = "git+https://github.com/starkware-libs/stwo?rev=af5475cb#af5475cb946a29de7d04dfa8c77a17034f888df4" +dependencies = [ + "itertools 0.13.0", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "stwo-cairo-serialize" +version = "0.1.0" +source = "git+https://github.com/starkware-libs/stwo-cairo?rev=a27287c21e8b7e677b07cc40988c8c145533c55d#a27287c21e8b7e677b07cc40988c8c145533c55d" +dependencies = [ + "starknet-ff", + "stwo-cairo-serialize-derive", + "stwo-prover", +] + +[[package]] +name = "stwo-cairo-serialize-derive" +version = "0.1.0" +source = "git+https://github.com/starkware-libs/stwo-cairo?rev=a27287c21e8b7e677b07cc40988c8c145533c55d#a27287c21e8b7e677b07cc40988c8c145533c55d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "stwo-prover" +version = "0.1.1" +source = "git+https://github.com/starkware-libs/stwo?rev=af5475cb#af5475cb946a29de7d04dfa8c77a17034f888df4" +dependencies = [ + "blake2", + "blake3", + "bytemuck", + "cfg-if", + "educe", + "hex", + "itertools 0.12.1", + "num-traits 0.2.19", + "rand", + "rayon", + "serde", + "starknet-crypto", + "starknet-ff", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "stwo_cairo_prover" +version = "0.1.0" +source = "git+https://github.com/starkware-libs/stwo-cairo?rev=a27287c21e8b7e677b07cc40988c8c145533c55d#a27287c21e8b7e677b07cc40988c8c145533c55d" +dependencies = [ + "air_structs_derive", + "bytemuck", + "cairo-lang-casm", + "cairo-vm 1.0.1 (git+https://github.com/lambdaclass/cairo-vm?rev=3fb0344c)", + "hex", + "itertools 0.12.1", + "num-traits 0.2.19", + "paste", + "prover_types", + "rayon", + "serde", + "sonic-rs", + "starknet-ff", + "stwo-air-utils", + "stwo-air-utils-derive", + "stwo-cairo-serialize", + "stwo-prover", + "stwo_cairo_utils", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "stwo_cairo_utils" +version = "0.1.0" +source = "git+https://github.com/starkware-libs/stwo-cairo?rev=a27287c21e8b7e677b07cc40988c8c145533c55d#a27287c21e8b7e677b07cc40988c8c145533c55d" +dependencies = [ + "cairo-vm 1.0.1 (git+https://github.com/lambdaclass/cairo-vm?rev=3fb0344c)", + "clap", + "env_logger", + "log", + "thiserror 1.0.69", + "tracing", + "tracing-subscriber", +] + [[package]] name = "subtle" version = "2.5.0" @@ -6504,6 +7218,24 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "uluru" version = "3.1.0" @@ -6513,6 +7245,12 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unescaper" version = "0.1.4" @@ -6612,6 +7350,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" + [[package]] name = "valuable" version = "0.1.0" @@ -7056,7 +7800,7 @@ dependencies = [ "anyhow", "cairo-toolchain-xtasks", "clap", - "semver", + "semver 1.0.24", "serde_json", "time", "walkdir", @@ -7191,7 +7935,7 @@ dependencies = [ "aes", "byteorder", "bzip2", - "constant_time_eq", + "constant_time_eq 0.1.5", "crc32fast", "crossbeam-utils", "flate2", diff --git a/Cargo.toml b/Cargo.toml index 21c7e107a..5041ca729 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "extensions/scarb-doc", "extensions/scarb-cairo-execute", "extensions/scarb-cairo-language-server", + "extensions/scarb-cairo-prove", "extensions/scarb-cairo-run", "extensions/scarb-cairo-test", "plugins/cairo-lang-macro", @@ -136,7 +137,7 @@ tar = "0.4" target-triple = "0.1" tempfile = "3" test-case = "3" -thiserror = "2" +thiserror = "2.0.10" time = "0.3" tokio = { version = "1", features = ["macros", "io-util", "process", "rt", "rt-multi-thread", "sync"] } tokio-stream = "0.1" diff --git a/extensions/scarb-cairo-prove/Cargo.toml b/extensions/scarb-cairo-prove/Cargo.toml new file mode 100644 index 000000000..b1cea8f91 --- /dev/null +++ b/extensions/scarb-cairo-prove/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "scarb-cairo-prove" +publish = false + +authors.workspace = true +edition.workspace = true +homepage.workspace = true +license.workspace = true +readme.workspace = true +repository.workspace = true +version.workspace = true + +[dependencies] +anyhow.workspace = true +indoc.workspace = true +scarb-metadata = { path = "../../scarb-metadata" } +scarb-ui = { path = "../../utils/scarb-ui" } +clap.workspace = true +serde.workspace = true +camino.workspace = true +serde_json.workspace = true +create-output-dir = { path = "../../utils/create-output-dir" } +stwo_cairo_prover = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "a27287c21e8b7e677b07cc40988c8c145533c55d" } +stwo-prover = { git = "https://github.com/starkware-libs/stwo", rev = "af5475cb", features = [ + "parallel", +] } + +[dev-dependencies] +scarb-test-support = { path = "../../utils/scarb-test-support" } +assert_fs.workspace = true +indoc.workspace = true diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs new file mode 100644 index 000000000..d2c7476bf --- /dev/null +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -0,0 +1,123 @@ +use anyhow::{ensure, Context, Result}; +use camino::Utf8PathBuf; +use clap::Parser; +use create_output_dir::create_output_dir; +use indoc::formatdoc; +use scarb_metadata::MetadataCommand; +use scarb_ui::args::PackagesFilter; +use scarb_ui::components::Status; +use scarb_ui::{OutputFormat, Ui}; +use std::env; +use std::fs; +use std::process::ExitCode; +use stwo_cairo_prover::cairo_air::{prove_cairo, ProverConfig}; +use stwo_cairo_prover::input::vm_import::adapt_vm_output; +use stwo_prover::core::vcs::blake2_merkle::Blake2sMerkleChannel; + +/// Proves `cairo-execute` output using Stwo prover. +#[derive(Parser, Debug)] +#[clap(version, verbatim_doc_comment)] +struct Args { + /// Name of the package. + #[command(flatten)] + packages_filter: PackagesFilter, + + /// Number of `cairo-execute` output for given package, for which to generate proof. + #[arg(long)] + execution: Option, + + /// The AIR public input path. + #[arg(long, value_name = "PUBLIC_INPUT_PATH",required_unless_present_any = ["execution"], conflicts_with_all = ["execution"])] + pub_input: Option, + + /// The AIR private input path. + #[arg(long, value_name = "PRIVATE_INPUT_PATH", required_unless_present_any = ["execution"], conflicts_with_all = ["execution"])] + priv_input: Option, +} + +fn main() -> ExitCode { + let args = Args::parse(); + let ui = Ui::new(Default::default(), OutputFormat::Text); + + match main_inner(args, ui.clone()) { + Ok(()) => ExitCode::SUCCESS, + Err(error) => { + ui.error(format!("{error:#}")); + ExitCode::FAILURE + } + } +} + +fn main_inner(args: Args, ui: Ui) -> Result<()> { + let (pub_input, priv_input, proof_path) = if let Some(execution_num) = args.execution { + // Package-based mode + let metadata = MetadataCommand::new().inherit_stderr().exec()?; + let package = args + .packages_filter + .match_one(&metadata) + .context("Failed to find a matching package in the workspace")?; + + ui.print(Status::new("Proving", &package.name)); + + let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); + let execution_dir = scarb_target_dir + .join("scarb-execute") + .join(&package.name) + .join(format!("execution{}", execution_num)); + + ensure!( + execution_dir.exists(), + formatdoc! {r#" + Execution directory not found: {} + Make sure to run scarb cairo-execute first + "#, execution_dir} + ); + + // Get input files from execution directory + let pub_input = execution_dir.join("air_public_input.json"); + let priv_input = execution_dir.join("air_private_input.json"); + + ensure!( + pub_input.exists() && priv_input.exists(), + formatdoc! {r#" + Missing input files in execution directory: {} + Make sure both air_public_input.json and air_private_input.json exist + "#, execution_dir} + ); + + // Create proof directory inside execution directory + let proof_dir = execution_dir.join("proof"); + create_output_dir(proof_dir.as_std_path())?; + + (pub_input, priv_input, proof_dir.join("proof.json")) + } else { + // Raw file paths mode + let pub_input_path = args.pub_input.unwrap(); + let priv_input_path = args.priv_input.unwrap(); + + ui.print(Status::new("Proving", "Cairo program")); + + ensure!(pub_input_path.exists(), "Public input file not found"); + ensure!(priv_input_path.exists(), "Private input file not found"); + + // Create proof file in current directory + let proof_path = Utf8PathBuf::from("proof.json"); + + (pub_input_path, priv_input_path, proof_path) + }; + + // Generate proof + let prover_input = adapt_vm_output(pub_input.as_std_path(), priv_input.as_std_path(), false) + .context("Failed to adapt VM output")?; + + let config = ProverConfig::builder().build(); + let proof = prove_cairo::(prover_input, config) + .context("Failed to generate proof")?; + + // Save proof output + fs::write(proof_path.as_std_path(), serde_json::to_string(&proof)?) + .context("Failed to write proof file")?; + + ui.print(Status::new("Proof saved to:", proof_path.as_str())); + Ok(()) +} From ccc3aa3871e9831d2138a5ac53b8f95cf209423b Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 17 Jan 2025 04:12:40 +0100 Subject: [PATCH 03/71] Support prover config; Restructure args --- extensions/scarb-cairo-prove/src/main.rs | 36 ++++++++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index d2c7476bf..a5090e0f0 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -15,7 +15,7 @@ use stwo_cairo_prover::input::vm_import::adapt_vm_output; use stwo_prover::core::vcs::blake2_merkle::Blake2sMerkleChannel; /// Proves `cairo-execute` output using Stwo prover. -#[derive(Parser, Debug)] +#[derive(Parser, Clone, Debug)] #[clap(version, verbatim_doc_comment)] struct Args { /// Name of the package. @@ -26,15 +26,35 @@ struct Args { #[arg(long)] execution: Option, + #[command(flatten)] + paths: PathInputArgs, + + #[command(flatten)] + prover: ProverArgs, +} + +#[derive(Parser, Clone, Debug)] +struct PathInputArgs { /// The AIR public input path. - #[arg(long, value_name = "PUBLIC_INPUT_PATH",required_unless_present_any = ["execution"], conflicts_with_all = ["execution"])] + #[arg(long, required_unless_present_any = ["execution"], conflicts_with_all = ["execution"])] pub_input: Option, /// The AIR private input path. - #[arg(long, value_name = "PRIVATE_INPUT_PATH", required_unless_present_any = ["execution"], conflicts_with_all = ["execution"])] + #[arg(long, required_unless_present_any = ["execution"], conflicts_with_all = ["execution"])] priv_input: Option, } +#[derive(Parser, Clone, Debug)] +struct ProverArgs { + /// Track relations during proving. + #[arg(long)] + track_relations: bool, + + /// Display components during proving. + #[arg(long)] + display_components: bool, +} + fn main() -> ExitCode { let args = Args::parse(); let ui = Ui::new(Default::default(), OutputFormat::Text); @@ -92,8 +112,8 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { (pub_input, priv_input, proof_dir.join("proof.json")) } else { // Raw file paths mode - let pub_input_path = args.pub_input.unwrap(); - let priv_input_path = args.priv_input.unwrap(); + let pub_input_path = args.paths.pub_input.unwrap(); + let priv_input_path = args.paths.priv_input.unwrap(); ui.print(Status::new("Proving", "Cairo program")); @@ -110,7 +130,11 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let prover_input = adapt_vm_output(pub_input.as_std_path(), priv_input.as_std_path(), false) .context("Failed to adapt VM output")?; - let config = ProverConfig::builder().build(); + let config = ProverConfig::builder() + .track_relations(args.prover.track_relations) + .display_components(args.prover.display_components) + .build(); + let proof = prove_cairo::(prover_input, config) .context("Failed to generate proof")?; From 972acdd0c51989363cc349fa646a116bdee52718 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 17 Jan 2025 04:36:15 +0100 Subject: [PATCH 04/71] Restructure `cairo-execute` output directories Change output path from `scarb-execute/package_N` to `scarb-execute/package/executionN` --- extensions/scarb-cairo-execute/src/main.rs | 25 ++++++------------- extensions/scarb-cairo-execute/tests/build.rs | 24 +++++++++--------- 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/extensions/scarb-cairo-execute/src/main.rs b/extensions/scarb-cairo-execute/src/main.rs index 1c03c31c3..37755ee34 100644 --- a/extensions/scarb-cairo-execute/src/main.rs +++ b/extensions/scarb-cairo-execute/src/main.rs @@ -208,19 +208,19 @@ fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> { print!("{output_buffer}"); } - let output_dir = scarb_target_dir.join("scarb-execute"); + let output_dir = scarb_target_dir.join("scarb-execute").join(&package.name); create_output_dir(output_dir.as_std_path())?; if args.run.output.is_cairo_pie() { let output_value = runner.get_cairo_pie()?; - let output_file_path = incremental_create_output_file(&output_dir, package.name, ".zip")?; + let output_file_path = incremental_create_output_file(&output_dir, ".zip")?; ui.print(Status::new( "Saving output to:", &display_path(&scarb_target_dir, &output_file_path), )); output_value.write_zip_file(output_file_path.as_std_path())?; } else { - let execution_output_dir = incremental_create_output_dir(&output_dir, package.name)?; + let execution_output_dir = incremental_create_output_dir(&output_dir)?; ui.print(Status::new( "Saving output to:", &display_path(&scarb_target_dir, &execution_output_dir), @@ -287,12 +287,10 @@ fn load_prebuilt_executable(path: &Utf8Path, filename: String) -> Result, ) -> Result { incremental_attempt_io_creation( path, - name, extension, "Failed to create output directory.", |p| { @@ -305,29 +303,22 @@ fn incremental_create_output_file( ) } -fn incremental_create_output_dir(path: &Utf8Path, name: String) -> Result { - incremental_attempt_io_creation(path, name, "", "Failed to create output directory.", |p| { +fn incremental_create_output_dir(path: &Utf8Path) -> Result { + incremental_attempt_io_creation(path, "", "Failed to create output directory.", |p| { fs::create_dir(p) }) } fn incremental_attempt_io_creation( path: &Utf8Path, - name: impl AsRef, extension: impl AsRef, final_error_message: impl AsRef, attempt: impl Fn(&Utf8Path) -> io::Result<()>, ) -> Result { - for i in 0..MAX_ITERATION_COUNT { - let number_string = if i == 0 { - "".to_string() - } else { - format!("_{}", i) - }; + for i in 1..=MAX_ITERATION_COUNT { let filepath = path.join(format!( - "{}{}{}", - name.as_ref(), - number_string, + "execution{}{}", + i, extension.as_ref() )); let result = attempt(&filepath); diff --git a/extensions/scarb-cairo-execute/tests/build.rs b/extensions/scarb-cairo-execute/tests/build.rs index 1c6410611..83dc954f2 100644 --- a/extensions/scarb-cairo-execute/tests/build.rs +++ b/extensions/scarb-cairo-execute/tests/build.rs @@ -37,16 +37,16 @@ fn can_execute_default_main_function_from_executable() { [..]Compiling hello v0.1.0 ([..]Scarb.toml) [..]Finished `dev` profile target(s) in [..] [..]Executing hello - Saving output to: target/scarb-execute/hello + Saving output to: target/scarb-execute/hello/execution1 "#}); - t.child("target/scarb-execute/hello/air_private_input.json") + t.child("target/scarb-execute/hello/execution1/air_private_input.json") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/air_public_input.json") + t.child("target/scarb-execute/hello/execution1/air_public_input.json") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/memory.bin") + t.child("target/scarb-execute/hello/execution1/memory.bin") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/trace.bin") + t.child("target/scarb-execute/hello/execution1/trace.bin") .assert(predicates::path::exists()); } @@ -62,16 +62,16 @@ fn can_execute_prebuilt_executable() { .success() .stdout_matches(indoc! {r#" [..]Executing hello - Saving output to: target/scarb-execute/hello + Saving output to: target/scarb-execute/hello/execution1 "#}); - t.child("target/scarb-execute/hello/air_private_input.json") + t.child("target/scarb-execute/hello/execution1/air_private_input.json") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/air_public_input.json") + t.child("target/scarb-execute/hello/execution1/air_public_input.json") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/memory.bin") + t.child("target/scarb-execute/hello/execution1/memory.bin") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/trace.bin") + t.child("target/scarb-execute/hello/execution1/trace.bin") .assert(predicates::path::exists()); } @@ -89,10 +89,10 @@ fn can_produce_cairo_pie_output() { [..]Compiling hello v0.1.0 ([..]Scarb.toml) [..]Finished `dev` profile target(s) in [..] [..]Executing hello - Saving output to: target/scarb-execute/hello.zip + Saving output to: target/scarb-execute/hello/execution1.zip "#}); - t.child("target/scarb-execute/hello.zip") + t.child("target/scarb-execute/hello/execution1.zip") .assert(predicates::path::exists()); } From 60363298362d78c79f8b3172f6d18862c010bcc8 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 17 Jan 2025 16:19:57 +0100 Subject: [PATCH 05/71] Refactor; Improve error messages; Improve args --- extensions/scarb-cairo-prove/src/main.rs | 80 +++++++++++++++--------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index a5090e0f0..fbd9015dc 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -1,5 +1,5 @@ use anyhow::{ensure, Context, Result}; -use camino::Utf8PathBuf; +use camino::{Utf8Path, Utf8PathBuf}; use clap::Parser; use create_output_dir::create_output_dir; use indoc::formatdoc; @@ -22,26 +22,26 @@ struct Args { #[command(flatten)] packages_filter: PackagesFilter, - /// Number of `cairo-execute` output for given package, for which to generate proof. + /// Number of `cairo-execute` *standard* output for given package, for which to generate proof. #[arg(long)] execution: Option, #[command(flatten)] - paths: PathInputArgs, + files: InputFileArgs, #[command(flatten)] prover: ProverArgs, } #[derive(Parser, Clone, Debug)] -struct PathInputArgs { - /// The AIR public input path. +struct InputFileArgs { + /// AIR public input path. #[arg(long, required_unless_present_any = ["execution"], conflicts_with_all = ["execution"])] - pub_input: Option, + pub_input_file: Option, - /// The AIR private input path. + /// AIR private input path. #[arg(long, required_unless_present_any = ["execution"], conflicts_with_all = ["execution"])] - priv_input: Option, + priv_input_file: Option, } #[derive(Parser, Clone, Debug)] @@ -69,7 +69,10 @@ fn main() -> ExitCode { } fn main_inner(args: Args, ui: Ui) -> Result<()> { - let (pub_input, priv_input, proof_path) = if let Some(execution_num) = args.execution { + let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); + + let (pub_input_path, priv_input_path, proof_path) = if let Some(execution_num) = args.execution + { // Package-based mode let metadata = MetadataCommand::new().inherit_stderr().exec()?; let package = args @@ -79,7 +82,6 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { ui.print(Status::new("Proving", &package.name)); - let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); let execution_dir = scarb_target_dir .join("scarb-execute") .join(&package.name) @@ -88,37 +90,43 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { ensure!( execution_dir.exists(), formatdoc! {r#" - Execution directory not found: {} - Make sure to run scarb cairo-execute first - "#, execution_dir} + Execution directory not found: {} + Make sure to run `scarb cairo-execute` first + "#, execution_dir} ); // Get input files from execution directory - let pub_input = execution_dir.join("air_public_input.json"); - let priv_input = execution_dir.join("air_private_input.json"); - + let pub_input_path = execution_dir.join("air_public_input.json"); + let priv_input_path = execution_dir.join("air_private_input.json"); ensure!( - pub_input.exists() && priv_input.exists(), + pub_input_path.exists() && priv_input_path.exists(), formatdoc! {r#" - Missing input files in execution directory: {} - Make sure both air_public_input.json and air_private_input.json exist + Missing input files in directory: {} + Make sure air_public_input.json and air_private_input.json exist "#, execution_dir} ); - // Create proof directory inside execution directory + // Create proof directory under this execution folder let proof_dir = execution_dir.join("proof"); - create_output_dir(proof_dir.as_std_path())?; + create_output_dir(proof_dir.as_std_path()).context("Failed to create proof directory")?; + let proof_path = proof_dir.join("proof.json"); - (pub_input, priv_input, proof_dir.join("proof.json")) + (pub_input_path, priv_input_path, proof_path) } else { // Raw file paths mode - let pub_input_path = args.paths.pub_input.unwrap(); - let priv_input_path = args.paths.priv_input.unwrap(); + let pub_input_path = args.files.pub_input_file.unwrap(); + let priv_input_path = args.files.priv_input_file.unwrap(); ui.print(Status::new("Proving", "Cairo program")); - ensure!(pub_input_path.exists(), "Public input file not found"); - ensure!(priv_input_path.exists(), "Private input file not found"); + ensure!( + pub_input_path.exists(), + "Public input file does not exist at path: {pub_input_path}" + ); + ensure!( + priv_input_path.exists(), + "Private input file does not exist at path: {priv_input_path}" + ); // Create proof file in current directory let proof_path = Utf8PathBuf::from("proof.json"); @@ -126,9 +134,12 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { (pub_input_path, priv_input_path, proof_path) }; - // Generate proof - let prover_input = adapt_vm_output(pub_input.as_std_path(), priv_input.as_std_path(), false) - .context("Failed to adapt VM output")?; + let prover_input = adapt_vm_output( + pub_input_path.as_std_path(), + priv_input_path.as_std_path(), + false, + ) + .context("Failed to adapt VM output")?; let config = ProverConfig::builder() .track_relations(args.prover.track_relations) @@ -138,10 +149,17 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let proof = prove_cairo::(prover_input, config) .context("Failed to generate proof")?; - // Save proof output + // Save proof + ui.print(Status::new("Saving proof to:", &display_path(&scarb_target_dir, &proof_path))); fs::write(proof_path.as_std_path(), serde_json::to_string(&proof)?) .context("Failed to write proof file")?; - ui.print(Status::new("Proof saved to:", proof_path.as_str())); Ok(()) } + +fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { + match output_path.strip_prefix(scarb_target_dir) { + Ok(stripped) => Utf8PathBuf::from("target").join(stripped).to_string(), + Err(_) => output_path.to_string(), + } +} From 0a404e4ec5554d4da954bfc44c12c08774416db2 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 17 Jan 2025 16:21:55 +0100 Subject: [PATCH 06/71] Add tests --- Cargo.lock | 2 + extensions/scarb-cairo-prove/Cargo.toml | 6 +- extensions/scarb-cairo-prove/tests/build.rs | 182 ++++++++++++++++++++ 3 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 extensions/scarb-cairo-prove/tests/build.rs diff --git a/Cargo.lock b/Cargo.lock index 80948bab5..c30448a26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5762,11 +5762,13 @@ dependencies = [ "clap", "create-output-dir", "indoc", + "predicates", "scarb-metadata 1.13.0", "scarb-test-support", "scarb-ui", "serde", "serde_json", + "snapbox", "stwo-prover", "stwo_cairo_prover", ] diff --git a/extensions/scarb-cairo-prove/Cargo.toml b/extensions/scarb-cairo-prove/Cargo.toml index b1cea8f91..243476ab2 100644 --- a/extensions/scarb-cairo-prove/Cargo.toml +++ b/extensions/scarb-cairo-prove/Cargo.toml @@ -26,6 +26,8 @@ stwo-prover = { git = "https://github.com/starkware-libs/stwo", rev = "af5475cb" ] } [dev-dependencies] -scarb-test-support = { path = "../../utils/scarb-test-support" } assert_fs.workspace = true -indoc.workspace = true +scarb-test-support = { path = "../../utils/scarb-test-support" } +snapbox.workspace = true +predicates.workspace = true + diff --git a/extensions/scarb-cairo-prove/tests/build.rs b/extensions/scarb-cairo-prove/tests/build.rs new file mode 100644 index 000000000..97d03e937 --- /dev/null +++ b/extensions/scarb-cairo-prove/tests/build.rs @@ -0,0 +1,182 @@ +use assert_fs::assert::PathAssert; +use assert_fs::fixture::PathChild; +use assert_fs::TempDir; +use indoc::indoc; +use scarb_test_support::command::Scarb; +use scarb_test_support::project_builder::ProjectBuilder; +use snapbox::cmd::OutputAssert; + +fn build_executable_project() -> TempDir { + let t = TempDir::new().unwrap(); + ProjectBuilder::start() + .name("hello") + .version("0.1.0") + .dep_cairo_execute() + .manifest_extra(indoc! {r#" + [executable] + "#}) + .lib_cairo(indoc! {r#" + #[executable] + fn main() -> felt252 { + 42 + } + "#}) + .build(&t); + t +} + +#[test] +fn prove_from_execution_output() { + let t = build_executable_project(); + + Scarb::quick_snapbox() + .arg("cairo-execute") + .current_dir(&t) + .assert() + .success(); + + Scarb::quick_snapbox() + .arg("cairo-prove") + .arg("--execution=1") + .current_dir(&t) + .assert() + .success() + .stdout_matches(indoc! {r#" + [..]Proving hello + Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json + "#}); + + t.child("target/scarb-execute/hello/execution1/proof/proof.json") + .assert(predicates::path::exists()); +} + +#[test] +fn prove_from_paths() { + let t = build_executable_project(); + + Scarb::quick_snapbox() + .arg("cairo-execute") + .current_dir(&t) + .assert() + .success(); + + Scarb::quick_snapbox() + .arg("cairo-prove") + .arg("--pub-input-file=target/scarb-execute/hello/execution1/air_public_input.json") + .arg("--priv-input-file=target/scarb-execute/hello/execution1/air_private_input.json") + .current_dir(&t) + .assert() + .success() + .stdout_matches(indoc! {r#" + [..]Proving Cairo program + Saving proof to: proof.json + "#}); + + t.child("proof.json").assert(predicates::path::exists()); +} + +#[test] +fn prove_with_relations_summary() { + let t = build_executable_project(); + + Scarb::quick_snapbox() + .arg("cairo-execute") + .current_dir(&t) + .assert() + .success(); + + let cmd = Scarb::quick_snapbox() + .arg("cairo-prove") + .arg("--execution=1") + .arg("--track-relations") + .current_dir(&t) + .assert() + .success(); + let output = cmd.get_output().stdout.clone(); + let stdout = String::from_utf8(output).unwrap(); + + assert!(stdout.contains("Proving hello")); + assert!(stdout.contains("Relations summary:")); + assert!(stdout.contains("Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json")); + + t.child("target/scarb-execute/hello/execution1/proof/proof.json") + .assert(predicates::path::exists()); +} + +#[test] +fn prove_with_display_components() { + let t = build_executable_project(); + + Scarb::quick_snapbox() + .arg("cairo-execute") + .current_dir(&t) + .assert() + .success(); + + let cmd = Scarb::quick_snapbox() + .arg("cairo-prove") + .arg("--execution=1") + .arg("--display-components") + .current_dir(&t) + .assert() + .success(); + + let output = cmd.get_output().stdout.clone(); + let stdout = String::from_utf8(output).unwrap(); + + assert!(stdout.contains("Proving hello")); + assert!(stdout.contains("CairoComponents")); + assert!(stdout.contains("Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json")); + + t.child("target/scarb-execute/hello/execution1/proof/proof.json") + .assert(predicates::path::exists()); +} + + +#[test] +fn prove_fails_when_execution_output_not_found() { + let t = build_executable_project(); + + output_assert( + Scarb::quick_snapbox() + .arg("cairo-prove") + .arg("--execution=1") + .current_dir(&t) + .assert() + .failure(), + indoc! {r#" + [..]Proving hello + error: Execution directory not found: [..]/target/scarb-execute/hello/execution1 + Make sure to run `scarb cairo-execute` first + + "#}, + ) +} + +#[test] +fn prove_fails_when_input_files_not_found() { + let t = build_executable_project(); + + output_assert( + Scarb::quick_snapbox() + .arg("cairo-prove") + .arg("--pub-input-file=nonexistent.json") + .arg("--priv-input-file=nonexistent.json") + .current_dir(&t) + .assert() + .failure(), + indoc! {r#" + [..]Proving Cairo program + error: Public input file does not exist at path: nonexistent.json + "#}, + ) +} + +fn output_assert(output: OutputAssert, expected: &str) { + #[cfg(windows)] + output.stdout_matches(format!( + "{expected}error: process did not exit successfully: exit code: 1\n" + )); + #[cfg(not(windows))] + output.stdout_matches(expected); +} From 55525ede7a1aeefe17af8f2fbf9a2eb635b4e0c8 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 17 Jan 2025 16:58:54 +0100 Subject: [PATCH 07/71] Refactor --- extensions/scarb-cairo-prove/src/main.rs | 116 ++++++++++++----------- 1 file changed, 63 insertions(+), 53 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index fbd9015dc..19754b3f3 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -73,65 +73,16 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let (pub_input_path, priv_input_path, proof_path) = if let Some(execution_num) = args.execution { - // Package-based mode let metadata = MetadataCommand::new().inherit_stderr().exec()?; - let package = args - .packages_filter - .match_one(&metadata) - .context("Failed to find a matching package in the workspace")?; + let package = args.packages_filter.match_one(&metadata)?; ui.print(Status::new("Proving", &package.name)); - let execution_dir = scarb_target_dir - .join("scarb-execute") - .join(&package.name) - .join(format!("execution{}", execution_num)); - - ensure!( - execution_dir.exists(), - formatdoc! {r#" - Execution directory not found: {} - Make sure to run `scarb cairo-execute` first - "#, execution_dir} - ); - - // Get input files from execution directory - let pub_input_path = execution_dir.join("air_public_input.json"); - let priv_input_path = execution_dir.join("air_private_input.json"); - ensure!( - pub_input_path.exists() && priv_input_path.exists(), - formatdoc! {r#" - Missing input files in directory: {} - Make sure air_public_input.json and air_private_input.json exist - "#, execution_dir} - ); - - // Create proof directory under this execution folder - let proof_dir = execution_dir.join("proof"); - create_output_dir(proof_dir.as_std_path()).context("Failed to create proof directory")?; - let proof_path = proof_dir.join("proof.json"); - - (pub_input_path, priv_input_path, proof_path) + resolve_paths_from_package(&scarb_target_dir, &package.name, execution_num)? } else { - // Raw file paths mode - let pub_input_path = args.files.pub_input_file.unwrap(); - let priv_input_path = args.files.priv_input_file.unwrap(); - ui.print(Status::new("Proving", "Cairo program")); - ensure!( - pub_input_path.exists(), - "Public input file does not exist at path: {pub_input_path}" - ); - ensure!( - priv_input_path.exists(), - "Private input file does not exist at path: {priv_input_path}" - ); - - // Create proof file in current directory - let proof_path = Utf8PathBuf::from("proof.json"); - - (pub_input_path, priv_input_path, proof_path) + resolve_paths(&args.files)? }; let prover_input = adapt_vm_output( @@ -150,13 +101,72 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { .context("Failed to generate proof")?; // Save proof - ui.print(Status::new("Saving proof to:", &display_path(&scarb_target_dir, &proof_path))); + ui.print(Status::new( + "Saving proof to:", + &display_path(&scarb_target_dir, &proof_path), + )); fs::write(proof_path.as_std_path(), serde_json::to_string(&proof)?) .context("Failed to write proof file")?; Ok(()) } +fn resolve_paths_from_package( + scarb_target_dir: &Utf8PathBuf, + package_name: &str, + execution_num: u32, +) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf8PathBuf)> { + let execution_dir = scarb_target_dir + .join("scarb-execute") + .join(&package_name) + .join(format!("execution{}", execution_num)); + + ensure!( + execution_dir.exists(), + formatdoc! {r#" + Execution directory not found: {} + Make sure to run `scarb cairo-execute` first + "#, execution_dir} + ); + + // Get input files from execution directory + let pub_input_path = execution_dir.join("air_public_input.json"); + let priv_input_path = execution_dir.join("air_private_input.json"); + ensure!( + pub_input_path.exists() && priv_input_path.exists(), + formatdoc! {r#" + Missing input files in directory: {} + Make sure air_public_input.json and air_private_input.json exist + "#, execution_dir} + ); + + // Create proof directory under this execution folder + let proof_dir = execution_dir.join("proof"); + create_output_dir(proof_dir.as_std_path()).context("Failed to create proof directory")?; + let proof_path = proof_dir.join("proof.json"); + + Ok((pub_input_path, priv_input_path, proof_path)) +} + +fn resolve_paths(files: &InputFileArgs) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf8PathBuf)> { + let pub_input_path = files.pub_input_file.clone().unwrap(); + let priv_input_path = files.priv_input_file.clone().unwrap(); + + ensure!( + pub_input_path.exists(), + "Public input file does not exist at path: {pub_input_path}" + ); + ensure!( + priv_input_path.exists(), + "Private input file does not exist at path: {priv_input_path}" + ); + + // Create proof file in current directory + let proof_path = Utf8PathBuf::from("proof.json"); + + Ok((pub_input_path, priv_input_path, proof_path)) +} + fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { match output_path.strip_prefix(scarb_target_dir) { Ok(stripped) => Utf8PathBuf::from("target").join(stripped).to_string(), From 0da153de12e01e60d5c275456ceef3d46cfa2379 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 17 Jan 2025 16:59:23 +0100 Subject: [PATCH 08/71] Format --- extensions/scarb-cairo-execute/src/main.rs | 25 +++++++-------------- extensions/scarb-cairo-prove/src/main.rs | 6 ++--- extensions/scarb-cairo-prove/tests/build.rs | 9 +++++--- 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/extensions/scarb-cairo-execute/src/main.rs b/extensions/scarb-cairo-execute/src/main.rs index 37755ee34..9fb98b696 100644 --- a/extensions/scarb-cairo-execute/src/main.rs +++ b/extensions/scarb-cairo-execute/src/main.rs @@ -289,18 +289,13 @@ fn incremental_create_output_file( path: &Utf8Path, extension: impl AsRef, ) -> Result { - incremental_attempt_io_creation( - path, - extension, - "Failed to create output directory.", - |p| { - OpenOptions::new() - .write(true) - .create_new(true) - .open(p) - .map(|_| ()) - }, - ) + incremental_attempt_io_creation(path, extension, "Failed to create output directory.", |p| { + OpenOptions::new() + .write(true) + .create_new(true) + .open(p) + .map(|_| ()) + }) } fn incremental_create_output_dir(path: &Utf8Path) -> Result { @@ -316,11 +311,7 @@ fn incremental_attempt_io_creation( attempt: impl Fn(&Utf8Path) -> io::Result<()>, ) -> Result { for i in 1..=MAX_ITERATION_COUNT { - let filepath = path.join(format!( - "execution{}{}", - i, - extension.as_ref() - )); + let filepath = path.join(format!("execution{}{}", i, extension.as_ref())); let result = attempt(&filepath); return match result { Err(e) => { diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index 19754b3f3..595d6ca90 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -47,11 +47,11 @@ struct InputFileArgs { #[derive(Parser, Clone, Debug)] struct ProverArgs { /// Track relations during proving. - #[arg(long)] + #[arg(long, default_value = "false")] track_relations: bool, /// Display components during proving. - #[arg(long)] + #[arg(long, default_value = "false")] display_components: bool, } @@ -118,7 +118,7 @@ fn resolve_paths_from_package( ) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf8PathBuf)> { let execution_dir = scarb_target_dir .join("scarb-execute") - .join(&package_name) + .join(package_name) .join(format!("execution{}", execution_num)); ensure!( diff --git a/extensions/scarb-cairo-prove/tests/build.rs b/extensions/scarb-cairo-prove/tests/build.rs index 97d03e937..444815272 100644 --- a/extensions/scarb-cairo-prove/tests/build.rs +++ b/extensions/scarb-cairo-prove/tests/build.rs @@ -97,7 +97,9 @@ fn prove_with_relations_summary() { assert!(stdout.contains("Proving hello")); assert!(stdout.contains("Relations summary:")); - assert!(stdout.contains("Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json")); + assert!( + stdout.contains("Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json") + ); t.child("target/scarb-execute/hello/execution1/proof/proof.json") .assert(predicates::path::exists()); @@ -126,13 +128,14 @@ fn prove_with_display_components() { assert!(stdout.contains("Proving hello")); assert!(stdout.contains("CairoComponents")); - assert!(stdout.contains("Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json")); + assert!( + stdout.contains("Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json") + ); t.child("target/scarb-execute/hello/execution1/proof/proof.json") .assert(predicates::path::exists()); } - #[test] fn prove_fails_when_execution_output_not_found() { let t = build_executable_project(); From cb4b7fbc139cf8d867c3928d99395d7ee96c5493 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 01:00:44 +0100 Subject: [PATCH 09/71] Add `--execute` flag to run execution before `prove` --- extensions/scarb-cairo-prove/src/main.rs | 74 +++++++++++++++++++-- extensions/scarb-cairo-prove/tests/build.rs | 24 +++++++ scarb-metadata/src/command/scarb_command.rs | 36 +++++++++- 3 files changed, 127 insertions(+), 7 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index 595d6ca90..9a6524388 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -1,9 +1,9 @@ -use anyhow::{ensure, Context, Result}; +use anyhow::{anyhow, ensure, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use clap::Parser; use create_output_dir::create_output_dir; use indoc::formatdoc; -use scarb_metadata::MetadataCommand; +use scarb_metadata::{Metadata, MetadataCommand, ScarbCommand}; use scarb_ui::args::PackagesFilter; use scarb_ui::components::Status; use scarb_ui::{OutputFormat, Ui}; @@ -26,6 +26,14 @@ struct Args { #[arg(long)] execution: Option, + /// Execute the program before proving. + #[arg(long, conflicts_with_all = ["execution", "pub_input_file", "priv_input_file"])] + execute: bool, + + /// Execute the program before proving. + #[command(flatten)] + execute_args: ExecuteArgs, + #[command(flatten)] files: InputFileArgs, @@ -33,14 +41,29 @@ struct Args { prover: ProverArgs, } +#[derive(Parser, Clone, Debug)] +struct ExecuteArgs { + /// Do not build the package before execution. + #[arg(long, requires = "execute")] + no_build: bool, + + /// Arguments to pass to the program during execution. + #[arg(long, requires = "execute")] + arguments: Option, + + /// Target for execution. + #[arg(long, requires = "execute")] + target: Option, +} + #[derive(Parser, Clone, Debug)] struct InputFileArgs { /// AIR public input path. - #[arg(long, required_unless_present_any = ["execution"], conflicts_with_all = ["execution"])] + #[arg(long, required_unless_present_any = ["execution", "execute"], conflicts_with_all = ["execution", "execute"])] pub_input_file: Option, /// AIR private input path. - #[arg(long, required_unless_present_any = ["execution"], conflicts_with_all = ["execution"])] + #[arg(long, required_unless_present_any = ["execution", "execute"], conflicts_with_all = ["execution", "execute"])] priv_input_file: Option, } @@ -71,11 +94,52 @@ fn main() -> ExitCode { fn main_inner(args: Args, ui: Ui) -> Result<()> { let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); - let (pub_input_path, priv_input_path, proof_path) = if let Some(execution_num) = args.execution + let (pub_input_path, priv_input_path, proof_path) = if args.execute || args.execution.is_some() { let metadata = MetadataCommand::new().inherit_stderr().exec()?; let package = args.packages_filter.match_one(&metadata)?; + let execution_num = match args.execution { + Some(execution_num) => execution_num, + None => { + let filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); + let mut cmd = ScarbCommand::new_with_output(); + cmd.arg("cairo-execute") + .env("SCARB_PACKAGES_FILTER", filter.to_env()) + .env("SCARB_TARGET_DIR", &scarb_target_dir); + + if args.execute_args.no_build { + cmd.arg("--no-build"); + } + if let Some(arguments) = &args.execute_args.arguments { + cmd.arg(format!("--arguments={arguments}")); + } + if let Some(target) = &args.execute_args.target { + cmd.arg(format!("--target={target}")); + } + + let output = cmd + .run_with_output() + .context("Failed to run `scarb cairo-execute`")?; + + let stdout = String::from_utf8(output.stdout) + .context("Failed to parse `scarb cairo-execute` output")?; + + stdout + .lines() + .find_map(|line| { + line.trim() + .strip_prefix(&format!( + "Saving output to: target/scarb-execute/{package_name}/execution", + package_name = &package.name, + )) + .and_then(|num| num.parse::().ok()) + }) + .ok_or_else(|| { + anyhow!("Failed to find execution number in cairo-execute output") + })? + } + }; ui.print(Status::new("Proving", &package.name)); resolve_paths_from_package(&scarb_target_dir, &package.name, execution_num)? diff --git a/extensions/scarb-cairo-prove/tests/build.rs b/extensions/scarb-cairo-prove/tests/build.rs index 444815272..14dfc49af 100644 --- a/extensions/scarb-cairo-prove/tests/build.rs +++ b/extensions/scarb-cairo-prove/tests/build.rs @@ -175,6 +175,30 @@ fn prove_fails_when_input_files_not_found() { ) } +#[test] +fn prove_with_execute() { + let t = build_executable_project(); + + Scarb::quick_snapbox() + .arg("cairo-prove") + .arg("--execute") + .arg("--target=standalone") + .current_dir(&t) + .assert() + .success() + .stdout_matches(indoc! {r#" + [..]Compiling hello v0.1.0 ([..]) + [..]Finished `dev` profile target(s) in [..] + [..]Executing hello + Saving output to: target/scarb-execute/hello/execution1 + [..]Proving hello + Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json + "#}); + + t.child("target/scarb-execute/hello/execution1/proof/proof.json") + .assert(predicates::path::exists()); +} + fn output_assert(output: OutputAssert, expected: &str) { #[cfg(windows)] output.stdout_matches(format!( diff --git a/scarb-metadata/src/command/scarb_command.rs b/scarb-metadata/src/command/scarb_command.rs index fd9640c2b..47d3ce4fb 100644 --- a/scarb-metadata/src/command/scarb_command.rs +++ b/scarb-metadata/src/command/scarb_command.rs @@ -1,7 +1,7 @@ use std::ffi::OsStr; use std::io; use std::path::PathBuf; - +use std::process::Output; use crate::command::internal_command::InternalScarbCommandBuilder; use thiserror::Error; @@ -21,6 +21,7 @@ pub enum ScarbCommandError { #[derive(Clone, Debug, Default)] pub struct ScarbCommand { inner: InternalScarbCommandBuilder, + print_stdout: bool, } impl ScarbCommand { @@ -30,7 +31,22 @@ impl ScarbCommand { let mut cmd = InternalScarbCommandBuilder::new(); cmd.inherit_stderr(); cmd.inherit_stdout(); - Self { inner: cmd } + Self { + inner: cmd, + print_stdout: false, + } + } + + /// Creates a `scarb` command that captures output while still printing it to stdout. + pub fn new_with_output() -> Self { + // We can not just use self.inner.inherit_stdout() + // Because it will make output.stdout empty + let mut cmd = InternalScarbCommandBuilder::new(); + cmd.inherit_stderr(); + Self { + inner: cmd, + print_stdout: true, + } } /// Path to `scarb` executable. @@ -110,4 +126,20 @@ impl ScarbCommand { Err(ScarbCommandError::ScarbError) } } + + /// Runs configured `scarb` command and returns its output. + pub fn run_with_output(&self) -> Result { + let mut cmd = self.inner.command(); + let output = cmd.output()?; + + if self.print_stdout { + print!("{}", String::from_utf8_lossy(&output.stdout)); + } + + if output.status.success() { + Ok(output) + } else { + Err(ScarbCommandError::ScarbError) + } + } } From 3946387aaae8af6066103270e551e36b4cb3b40d Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 01:46:04 +0100 Subject: [PATCH 10/71] Refactor: add helper functions; Simplify `execution_number` extraction logic --- extensions/scarb-cairo-prove/src/main.rs | 93 ++++++++++++++---------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index 9a6524388..f1b70664a 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -3,13 +3,13 @@ use camino::{Utf8Path, Utf8PathBuf}; use clap::Parser; use create_output_dir::create_output_dir; use indoc::formatdoc; -use scarb_metadata::{Metadata, MetadataCommand, ScarbCommand}; +use scarb_metadata::{Metadata, MetadataCommand, PackageMetadata, ScarbCommand}; use scarb_ui::args::PackagesFilter; use scarb_ui::components::Status; use scarb_ui::{OutputFormat, Ui}; use std::env; use std::fs; -use std::process::ExitCode; +use std::process::{ExitCode, Output}; use stwo_cairo_prover::cairo_air::{prove_cairo, ProverConfig}; use stwo_cairo_prover::input::vm_import::adapt_vm_output; use stwo_prover::core::vcs::blake2_merkle::Blake2sMerkleChannel; @@ -101,45 +101,9 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let execution_num = match args.execution { Some(execution_num) => execution_num, - None => { - let filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); - let mut cmd = ScarbCommand::new_with_output(); - cmd.arg("cairo-execute") - .env("SCARB_PACKAGES_FILTER", filter.to_env()) - .env("SCARB_TARGET_DIR", &scarb_target_dir); - - if args.execute_args.no_build { - cmd.arg("--no-build"); - } - if let Some(arguments) = &args.execute_args.arguments { - cmd.arg(format!("--arguments={arguments}")); - } - if let Some(target) = &args.execute_args.target { - cmd.arg(format!("--target={target}")); - } - - let output = cmd - .run_with_output() - .context("Failed to run `scarb cairo-execute`")?; - - let stdout = String::from_utf8(output.stdout) - .context("Failed to parse `scarb cairo-execute` output")?; - - stdout - .lines() - .find_map(|line| { - line.trim() - .strip_prefix(&format!( - "Saving output to: target/scarb-execute/{package_name}/execution", - package_name = &package.name, - )) - .and_then(|num| num.parse::().ok()) - }) - .ok_or_else(|| { - anyhow!("Failed to find execution number in cairo-execute output") - })? - } + None => run_cairo_execute(&args.execute_args, &package, &scarb_target_dir)?, }; + ui.print(Status::new("Proving", &package.name)); resolve_paths_from_package(&scarb_target_dir, &package.name, execution_num)? @@ -231,6 +195,55 @@ fn resolve_paths(files: &InputFileArgs) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf Ok((pub_input_path, priv_input_path, proof_path)) } +fn run_cairo_execute( + execution_args: &ExecuteArgs, + package: &PackageMetadata, + scarb_target_dir: &Utf8PathBuf, +) -> Result { + let package_filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); + + let mut cmd = ScarbCommand::new_with_output(); + cmd.arg("cairo-execute") + .env("SCARB_PACKAGES_FILTER", package_filter.to_env()) + .env("SCARB_TARGET_DIR", scarb_target_dir); + + if execution_args.no_build { + cmd.arg("--no-build"); + } + if let Some(arguments) = &execution_args.arguments { + cmd.arg(format!("--arguments={arguments}")); + } + if let Some(target) = &execution_args.target { + cmd.arg(format!("--target={target}")); + } + + let output = cmd + .run_with_output() + .context("Failed to run `scarb cairo-execute`")?; + extract_execution_num(&output) +} + +fn extract_execution_num(output: &Output) -> Result { + let stdout = String::from_utf8(output.stdout.clone()) + .context("Failed to parse `cairo-execute` output")?; + + stdout + .lines() + .find_map(|line| { + line.trim() + .strip_prefix("Saving output to:") + // Isolate the last path component (e.g., "execution1"), strip "execution" prefix, and parse the number + .and_then(|output_path| output_path.trim().split('/').last()) + .and_then(|execution_str| { + execution_str + .trim_start_matches("execution") + .parse::() + .ok() + }) + }) + .ok_or_else(|| anyhow!("Failed to get execution number from `cairo-execute` output")) +} + fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { match output_path.strip_prefix(scarb_target_dir) { Ok(stripped) => Utf8PathBuf::from("target").join(stripped).to_string(), From 951e3d75314131495ec6339b28bba8c125955cd5 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 02:06:00 +0100 Subject: [PATCH 11/71] Improve error messages in line with `scarb execute` changes --- extensions/scarb-cairo-prove/src/main.rs | 39 ++++++++++----------- extensions/scarb-cairo-prove/tests/build.rs | 7 ++-- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index f1b70664a..b90194c31 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -118,7 +118,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { priv_input_path.as_std_path(), false, ) - .context("Failed to adapt VM output")?; + .context("failed to adapt VM output")?; let config = ProverConfig::builder() .track_relations(args.prover.track_relations) @@ -126,15 +126,14 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { .build(); let proof = prove_cairo::(prover_input, config) - .context("Failed to generate proof")?; + .context("failed to generate proof")?; - // Save proof ui.print(Status::new( "Saving proof to:", &display_path(&scarb_target_dir, &proof_path), )); - fs::write(proof_path.as_std_path(), serde_json::to_string(&proof)?) - .context("Failed to write proof file")?; + + fs::write(proof_path.as_std_path(), serde_json::to_string(&proof)?)?; Ok(()) } @@ -152,8 +151,9 @@ fn resolve_paths_from_package( ensure!( execution_dir.exists(), formatdoc! {r#" - Execution directory not found: {} - Make sure to run `scarb cairo-execute` first + execution directory not found: {} + help: make sure to run `scarb cairo-execute` first + and that the execution number is correct "#, execution_dir} ); @@ -161,16 +161,17 @@ fn resolve_paths_from_package( let pub_input_path = execution_dir.join("air_public_input.json"); let priv_input_path = execution_dir.join("air_private_input.json"); ensure!( - pub_input_path.exists() && priv_input_path.exists(), - formatdoc! {r#" - Missing input files in directory: {} - Make sure air_public_input.json and air_private_input.json exist - "#, execution_dir} + pub_input_path.exists(), + format!("public input file does not exist at path: {pub_input_path}") + ); + ensure!( + priv_input_path.exists(), + format!("private input file does not exist at path: {priv_input_path}") ); // Create proof directory under this execution folder let proof_dir = execution_dir.join("proof"); - create_output_dir(proof_dir.as_std_path()).context("Failed to create proof directory")?; + create_output_dir(proof_dir.as_std_path()).context("failed to create proof directory")?; let proof_path = proof_dir.join("proof.json"); Ok((pub_input_path, priv_input_path, proof_path)) @@ -182,11 +183,11 @@ fn resolve_paths(files: &InputFileArgs) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf ensure!( pub_input_path.exists(), - "Public input file does not exist at path: {pub_input_path}" + format!("public input file does not exist at path: {pub_input_path}") ); ensure!( priv_input_path.exists(), - "Private input file does not exist at path: {priv_input_path}" + format!("private input file does not exist at path: {priv_input_path}") ); // Create proof file in current directory @@ -217,15 +218,13 @@ fn run_cairo_execute( cmd.arg(format!("--target={target}")); } - let output = cmd - .run_with_output() - .context("Failed to run `scarb cairo-execute`")?; + let output = cmd.run_with_output()?; extract_execution_num(&output) } fn extract_execution_num(output: &Output) -> Result { let stdout = String::from_utf8(output.stdout.clone()) - .context("Failed to parse `cairo-execute` output")?; + .context("failed to parse `cairo-execute` output")?; stdout .lines() @@ -241,7 +240,7 @@ fn extract_execution_num(output: &Output) -> Result { .ok() }) }) - .ok_or_else(|| anyhow!("Failed to get execution number from `cairo-execute` output")) + .ok_or_else(|| anyhow!("failed to extract execution number from `cairo-execute` output")) } fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { diff --git a/extensions/scarb-cairo-prove/tests/build.rs b/extensions/scarb-cairo-prove/tests/build.rs index 14dfc49af..08ab626ff 100644 --- a/extensions/scarb-cairo-prove/tests/build.rs +++ b/extensions/scarb-cairo-prove/tests/build.rs @@ -149,8 +149,9 @@ fn prove_fails_when_execution_output_not_found() { .failure(), indoc! {r#" [..]Proving hello - error: Execution directory not found: [..]/target/scarb-execute/hello/execution1 - Make sure to run `scarb cairo-execute` first + error: execution directory not found: [..]/target/scarb-execute/hello/execution1 + help: make sure to run `scarb cairo-execute` first + and that the execution number is correct "#}, ) @@ -170,7 +171,7 @@ fn prove_fails_when_input_files_not_found() { .failure(), indoc! {r#" [..]Proving Cairo program - error: Public input file does not exist at path: nonexistent.json + error: public input file does not exist at path: nonexistent.json "#}, ) } From ff83e913cdcd7d9364d9d43ce128f42f507e2a15 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 02:16:10 +0100 Subject: [PATCH 12/71] use lossy utf8 conversion --- extensions/scarb-cairo-prove/src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index b90194c31..5be1336ea 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -223,8 +223,7 @@ fn run_cairo_execute( } fn extract_execution_num(output: &Output) -> Result { - let stdout = String::from_utf8(output.stdout.clone()) - .context("failed to parse `cairo-execute` output")?; + let stdout = String::from_utf8_lossy(&output.stdout); stdout .lines() From 3c31623af43928cddadabaadc7257ce2c3e974e2 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 02:16:38 +0100 Subject: [PATCH 13/71] misc: rename test --- extensions/scarb-cairo-prove/tests/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/scarb-cairo-prove/tests/build.rs b/extensions/scarb-cairo-prove/tests/build.rs index 08ab626ff..a0edb673a 100644 --- a/extensions/scarb-cairo-prove/tests/build.rs +++ b/extensions/scarb-cairo-prove/tests/build.rs @@ -76,7 +76,7 @@ fn prove_from_paths() { } #[test] -fn prove_with_relations_summary() { +fn prove_with_track_relations() { let t = build_executable_project(); Scarb::quick_snapbox() From 5bb34245744b7bb4bfec086e6c303035f8d9bc96 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 02:25:28 +0100 Subject: [PATCH 14/71] rename all "execution number" mentions to `execution_id` --- extensions/scarb-cairo-prove/src/main.rs | 31 ++++++++++----------- extensions/scarb-cairo-prove/tests/build.rs | 2 +- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index 5be1336ea..1f6fe1472 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -22,15 +22,14 @@ struct Args { #[command(flatten)] packages_filter: PackagesFilter, - /// Number of `cairo-execute` *standard* output for given package, for which to generate proof. + /// ID of `cairo-execute` *standard* output for given package, for which to generate proof. #[arg(long)] - execution: Option, + execution_id: Option, /// Execute the program before proving. - #[arg(long, conflicts_with_all = ["execution", "pub_input_file", "priv_input_file"])] + #[arg(long, conflicts_with_all = ["execution_id", "pub_input_file", "priv_input_file"])] execute: bool, - /// Execute the program before proving. #[command(flatten)] execute_args: ExecuteArgs, @@ -59,11 +58,11 @@ struct ExecuteArgs { #[derive(Parser, Clone, Debug)] struct InputFileArgs { /// AIR public input path. - #[arg(long, required_unless_present_any = ["execution", "execute"], conflicts_with_all = ["execution", "execute"])] + #[arg(long, required_unless_present_any = ["execution_id", "execute"], conflicts_with_all = ["execution_id", "execute"])] pub_input_file: Option, /// AIR private input path. - #[arg(long, required_unless_present_any = ["execution", "execute"], conflicts_with_all = ["execution", "execute"])] + #[arg(long, required_unless_present_any = ["execution_id", "execute"], conflicts_with_all = ["execution_id", "execute"])] priv_input_file: Option, } @@ -94,19 +93,19 @@ fn main() -> ExitCode { fn main_inner(args: Args, ui: Ui) -> Result<()> { let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); - let (pub_input_path, priv_input_path, proof_path) = if args.execute || args.execution.is_some() + let (pub_input_path, priv_input_path, proof_path) = if args.execute || args.execution_id.is_some() { let metadata = MetadataCommand::new().inherit_stderr().exec()?; let package = args.packages_filter.match_one(&metadata)?; - let execution_num = match args.execution { - Some(execution_num) => execution_num, + let execution_id = match args.execution_id { + Some(execution_id) => execution_id, None => run_cairo_execute(&args.execute_args, &package, &scarb_target_dir)?, }; ui.print(Status::new("Proving", &package.name)); - resolve_paths_from_package(&scarb_target_dir, &package.name, execution_num)? + resolve_paths_from_package(&scarb_target_dir, &package.name, execution_id)? } else { ui.print(Status::new("Proving", "Cairo program")); @@ -141,19 +140,19 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { fn resolve_paths_from_package( scarb_target_dir: &Utf8PathBuf, package_name: &str, - execution_num: u32, + execution_id: u32, ) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf8PathBuf)> { let execution_dir = scarb_target_dir .join("scarb-execute") .join(package_name) - .join(format!("execution{}", execution_num)); + .join(format!("execution{}", execution_id)); ensure!( execution_dir.exists(), formatdoc! {r#" execution directory not found: {} help: make sure to run `scarb cairo-execute` first - and that the execution number is correct + and that the execution ID is correct "#, execution_dir} ); @@ -219,10 +218,10 @@ fn run_cairo_execute( } let output = cmd.run_with_output()?; - extract_execution_num(&output) + extract_execution_id(&output) } -fn extract_execution_num(output: &Output) -> Result { +fn extract_execution_id(output: &Output) -> Result { let stdout = String::from_utf8_lossy(&output.stdout); stdout @@ -239,7 +238,7 @@ fn extract_execution_num(output: &Output) -> Result { .ok() }) }) - .ok_or_else(|| anyhow!("failed to extract execution number from `cairo-execute` output")) + .ok_or_else(|| anyhow!("failed to extract execution ID from `cairo-execute` output")) } fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { diff --git a/extensions/scarb-cairo-prove/tests/build.rs b/extensions/scarb-cairo-prove/tests/build.rs index a0edb673a..4843dafe2 100644 --- a/extensions/scarb-cairo-prove/tests/build.rs +++ b/extensions/scarb-cairo-prove/tests/build.rs @@ -151,7 +151,7 @@ fn prove_fails_when_execution_output_not_found() { [..]Proving hello error: execution directory not found: [..]/target/scarb-execute/hello/execution1 help: make sure to run `scarb cairo-execute` first - and that the execution number is correct + and that the execution ID is correct "#}, ) From 01070f11b65b93ed3013b5f3a0bd3e4139c65491 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 02:54:46 +0100 Subject: [PATCH 15/71] Add verbosity settings --- extensions/scarb-cairo-prove/src/main.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index 1f6fe1472..0d906cdd0 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -4,7 +4,7 @@ use clap::Parser; use create_output_dir::create_output_dir; use indoc::formatdoc; use scarb_metadata::{Metadata, MetadataCommand, PackageMetadata, ScarbCommand}; -use scarb_ui::args::PackagesFilter; +use scarb_ui::args::{PackagesFilter, VerbositySpec}; use scarb_ui::components::Status; use scarb_ui::{OutputFormat, Ui}; use std::env; @@ -38,6 +38,10 @@ struct Args { #[command(flatten)] prover: ProverArgs, + + /// Logging verbosity. + #[command(flatten)] + pub verbose: VerbositySpec, } #[derive(Parser, Clone, Debug)] @@ -79,7 +83,7 @@ struct ProverArgs { fn main() -> ExitCode { let args = Args::parse(); - let ui = Ui::new(Default::default(), OutputFormat::Text); + let ui = Ui::new(args.verbose.clone().into(), OutputFormat::Text); match main_inner(args, ui.clone()) { Ok(()) => ExitCode::SUCCESS, From e02f52d189228c035c3faebc7eef735411ef89fa Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 03:02:41 +0100 Subject: [PATCH 16/71] fix tests (`--execution-id`) --- extensions/scarb-cairo-prove/tests/build.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/scarb-cairo-prove/tests/build.rs b/extensions/scarb-cairo-prove/tests/build.rs index 4843dafe2..24e6de967 100644 --- a/extensions/scarb-cairo-prove/tests/build.rs +++ b/extensions/scarb-cairo-prove/tests/build.rs @@ -37,7 +37,7 @@ fn prove_from_execution_output() { Scarb::quick_snapbox() .arg("cairo-prove") - .arg("--execution=1") + .arg("--execution-id=1") .current_dir(&t) .assert() .success() @@ -87,7 +87,7 @@ fn prove_with_track_relations() { let cmd = Scarb::quick_snapbox() .arg("cairo-prove") - .arg("--execution=1") + .arg("--execution-id=1") .arg("--track-relations") .current_dir(&t) .assert() @@ -117,7 +117,7 @@ fn prove_with_display_components() { let cmd = Scarb::quick_snapbox() .arg("cairo-prove") - .arg("--execution=1") + .arg("--execution-id=1") .arg("--display-components") .current_dir(&t) .assert() @@ -143,7 +143,7 @@ fn prove_fails_when_execution_output_not_found() { output_assert( Scarb::quick_snapbox() .arg("cairo-prove") - .arg("--execution=1") + .arg("--execution-id=1") .current_dir(&t) .assert() .failure(), From e82596a39214da14d7a7d13fbe6be2d775dd3a86 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 03:06:25 +0100 Subject: [PATCH 17/71] Disable `scarb execute` output for quiet verbosity --- extensions/scarb-cairo-prove/src/main.rs | 8 +++++--- scarb-metadata/src/command/scarb_command.rs | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index 0d906cdd0..1b0eb0a77 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -6,7 +6,7 @@ use indoc::formatdoc; use scarb_metadata::{Metadata, MetadataCommand, PackageMetadata, ScarbCommand}; use scarb_ui::args::{PackagesFilter, VerbositySpec}; use scarb_ui::components::Status; -use scarb_ui::{OutputFormat, Ui}; +use scarb_ui::{OutputFormat, Ui, Verbosity}; use std::env; use std::fs; use std::process::{ExitCode, Output}; @@ -104,7 +104,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let execution_id = match args.execution_id { Some(execution_id) => execution_id, - None => run_cairo_execute(&args.execute_args, &package, &scarb_target_dir)?, + None => run_cairo_execute(&args.execute_args, &package, &scarb_target_dir, &args.verbose)?, }; ui.print(Status::new("Proving", &package.name)); @@ -203,10 +203,12 @@ fn run_cairo_execute( execution_args: &ExecuteArgs, package: &PackageMetadata, scarb_target_dir: &Utf8PathBuf, + verbosity_spec: &VerbositySpec, ) -> Result { let package_filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); - let mut cmd = ScarbCommand::new_with_output(); + let print_stdout = Verbosity::from(verbosity_spec.clone()) != Verbosity::Quiet; + let mut cmd = ScarbCommand::new_with_output(print_stdout); cmd.arg("cairo-execute") .env("SCARB_PACKAGES_FILTER", package_filter.to_env()) .env("SCARB_TARGET_DIR", scarb_target_dir); diff --git a/scarb-metadata/src/command/scarb_command.rs b/scarb-metadata/src/command/scarb_command.rs index 47d3ce4fb..b6e6bed14 100644 --- a/scarb-metadata/src/command/scarb_command.rs +++ b/scarb-metadata/src/command/scarb_command.rs @@ -38,14 +38,14 @@ impl ScarbCommand { } /// Creates a `scarb` command that captures output while still printing it to stdout. - pub fn new_with_output() -> Self { + pub fn new_with_output(print_stdout: bool) -> Self { // We can not just use self.inner.inherit_stdout() // Because it will make output.stdout empty let mut cmd = InternalScarbCommandBuilder::new(); cmd.inherit_stderr(); Self { inner: cmd, - print_stdout: true, + print_stdout, } } From 39f1f70174153b6b2d71316d5f98ca70cf229f87 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 03:59:13 +0100 Subject: [PATCH 18/71] Stream AND write output of subcommand on the fly --- extensions/scarb-cairo-prove/src/main.rs | 14 ++++---- .../src/command/internal_command.rs | 19 ++++++++++ scarb-metadata/src/command/scarb_command.rs | 35 +++++++++++++------ 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index 1b0eb0a77..b7ad2c462 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -9,7 +9,7 @@ use scarb_ui::components::Status; use scarb_ui::{OutputFormat, Ui, Verbosity}; use std::env; use std::fs; -use std::process::{ExitCode, Output}; +use std::process::ExitCode; use stwo_cairo_prover::cairo_air::{prove_cairo, ProverConfig}; use stwo_cairo_prover::input::vm_import::adapt_vm_output; use stwo_prover::core::vcs::blake2_merkle::Blake2sMerkleChannel; @@ -208,7 +208,7 @@ fn run_cairo_execute( let package_filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); let print_stdout = Verbosity::from(verbosity_spec.clone()) != Verbosity::Quiet; - let mut cmd = ScarbCommand::new_with_output(print_stdout); + let mut cmd = ScarbCommand::new_for_output(print_stdout); cmd.arg("cairo-execute") .env("SCARB_PACKAGES_FILTER", package_filter.to_env()) .env("SCARB_TARGET_DIR", scarb_target_dir); @@ -223,15 +223,13 @@ fn run_cairo_execute( cmd.arg(format!("--target={target}")); } - let output = cmd.run_with_output()?; + let output = cmd.output()?; extract_execution_id(&output) } -fn extract_execution_id(output: &Output) -> Result { - let stdout = String::from_utf8_lossy(&output.stdout); - - stdout - .lines() +fn extract_execution_id(output: &[String]) -> Result { + output + .iter() .find_map(|line| { line.trim() .strip_prefix("Saving output to:") diff --git a/scarb-metadata/src/command/internal_command.rs b/scarb-metadata/src/command/internal_command.rs index 668259aff..7a11af90c 100644 --- a/scarb-metadata/src/command/internal_command.rs +++ b/scarb-metadata/src/command/internal_command.rs @@ -13,6 +13,8 @@ pub struct InternalScarbCommandBuilder { env_clear: bool, inherit_stderr: bool, inherit_stdout: bool, + pipe_stderr: bool, + pipe_stdout: bool, json: bool, manifest_path: Option, scarb_path: Option, @@ -117,6 +119,19 @@ impl InternalScarbCommandBuilder { self } + /// Pipe standard error + #[allow(unused)] + pub fn pipe_stderr(&mut self) -> &mut Self { + self.pipe_stderr = true; + self + } + + /// Pipe standard output + pub fn pipe_stdout(&mut self) -> &mut Self { + self.pipe_stdout = true; + self + } + /// Set output format to JSON. pub fn json(&mut self) -> &mut Self { self.json = true; @@ -161,10 +176,14 @@ impl InternalScarbCommandBuilder { if self.inherit_stderr { cmd.stderr(Stdio::inherit()); + } else if self.pipe_stderr { + cmd.stderr(Stdio::piped()); } if self.inherit_stdout { cmd.stdout(Stdio::inherit()); + } else if self.pipe_stdout { + cmd.stdout(Stdio::piped()); } cmd diff --git a/scarb-metadata/src/command/scarb_command.rs b/scarb-metadata/src/command/scarb_command.rs index b6e6bed14..67c00eba3 100644 --- a/scarb-metadata/src/command/scarb_command.rs +++ b/scarb-metadata/src/command/scarb_command.rs @@ -1,7 +1,7 @@ use std::ffi::OsStr; use std::io; +use std::io::{BufRead, BufReader}; use std::path::PathBuf; -use std::process::Output; use crate::command::internal_command::InternalScarbCommandBuilder; use thiserror::Error; @@ -13,7 +13,7 @@ pub enum ScarbCommandError { #[error("failed to read `scarb` output")] Io(#[from] io::Error), /// Error during execution of `scarb` command. - #[error("`scarb metadata` exited with error")] + #[error("`scarb` command exited with error")] ScarbError, } @@ -38,11 +38,12 @@ impl ScarbCommand { } /// Creates a `scarb` command that captures output while still printing it to stdout. - pub fn new_with_output(print_stdout: bool) -> Self { + pub fn new_for_output(print_stdout: bool) -> Self { // We can not just use self.inner.inherit_stdout() // Because it will make output.stdout empty let mut cmd = InternalScarbCommandBuilder::new(); cmd.inherit_stderr(); + cmd.pipe_stdout(); Self { inner: cmd, print_stdout, @@ -127,16 +128,28 @@ impl ScarbCommand { } } - /// Runs configured `scarb` command and returns its output. - pub fn run_with_output(&self) -> Result { + /// Runs configured `scarb` command and returns its stdout output. + pub fn output(&self) -> Result, ScarbCommandError> { let mut cmd = self.inner.command(); - let output = cmd.output()?; - - if self.print_stdout { - print!("{}", String::from_utf8_lossy(&output.stdout)); + let mut child = cmd.spawn()?; + + let stdout = child.stdout.take().ok_or_else(|| { + ScarbCommandError::Io(io::Error::from(io::ErrorKind::BrokenPipe)) + })?; + + let reader = BufReader::new(stdout); + + // Collect and stream stdout lines + let mut output = Vec::new(); + for line in reader.lines() { + let line = line.map_err(|err| ScarbCommandError::Io(err))?; + if self.print_stdout { + println!("{}", line); + } + output.push(line); } - - if output.status.success() { + + if child.wait()?.success() { Ok(output) } else { Err(ScarbCommandError::ScarbError) From de0d76d0e49e08e5a1a0ca4108e5791c0f4c979d Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 03:59:37 +0100 Subject: [PATCH 19/71] Format --- extensions/scarb-cairo-prove/src/main.rs | 39 +++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index b7ad2c462..a78fba2a0 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -97,25 +97,30 @@ fn main() -> ExitCode { fn main_inner(args: Args, ui: Ui) -> Result<()> { let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); - let (pub_input_path, priv_input_path, proof_path) = if args.execute || args.execution_id.is_some() - { - let metadata = MetadataCommand::new().inherit_stderr().exec()?; - let package = args.packages_filter.match_one(&metadata)?; - - let execution_id = match args.execution_id { - Some(execution_id) => execution_id, - None => run_cairo_execute(&args.execute_args, &package, &scarb_target_dir, &args.verbose)?, + let (pub_input_path, priv_input_path, proof_path) = + if args.execute || args.execution_id.is_some() { + let metadata = MetadataCommand::new().inherit_stderr().exec()?; + let package = args.packages_filter.match_one(&metadata)?; + + let execution_id = match args.execution_id { + Some(execution_id) => execution_id, + None => run_cairo_execute( + &args.execute_args, + &package, + &scarb_target_dir, + &args.verbose, + )?, + }; + + ui.print(Status::new("Proving", &package.name)); + + resolve_paths_from_package(&scarb_target_dir, &package.name, execution_id)? + } else { + ui.print(Status::new("Proving", "Cairo program")); + + resolve_paths(&args.files)? }; - ui.print(Status::new("Proving", &package.name)); - - resolve_paths_from_package(&scarb_target_dir, &package.name, execution_id)? - } else { - ui.print(Status::new("Proving", "Cairo program")); - - resolve_paths(&args.files)? - }; - let prover_input = adapt_vm_output( pub_input_path.as_std_path(), priv_input_path.as_std_path(), From 72e223bfc5de44208252843ff4e36708fc4c017d Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 05:03:48 +0100 Subject: [PATCH 20/71] improve approach to streaming stdout of nested commands - Add `UiPrinter` - Cannot use `Ui` directly due to circular dependency --- extensions/scarb-cairo-prove/src/main.rs | 17 ++++++--------- scarb-metadata/src/command/scarb_command.rs | 23 ++++++++++++--------- utils/scarb-ui/src/lib.rs | 19 +++++++++++++++++ 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-cairo-prove/src/main.rs index a78fba2a0..014993d6a 100644 --- a/extensions/scarb-cairo-prove/src/main.rs +++ b/extensions/scarb-cairo-prove/src/main.rs @@ -6,7 +6,7 @@ use indoc::formatdoc; use scarb_metadata::{Metadata, MetadataCommand, PackageMetadata, ScarbCommand}; use scarb_ui::args::{PackagesFilter, VerbositySpec}; use scarb_ui::components::Status; -use scarb_ui::{OutputFormat, Ui, Verbosity}; +use scarb_ui::{OutputFormat, Ui, UiPrinter}; use std::env; use std::fs; use std::process::ExitCode; @@ -104,12 +104,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let execution_id = match args.execution_id { Some(execution_id) => execution_id, - None => run_cairo_execute( - &args.execute_args, - &package, - &scarb_target_dir, - &args.verbose, - )?, + None => run_cairo_execute(&args.execute_args, &package, &scarb_target_dir, &ui)?, }; ui.print(Status::new("Proving", &package.name)); @@ -208,12 +203,11 @@ fn run_cairo_execute( execution_args: &ExecuteArgs, package: &PackageMetadata, scarb_target_dir: &Utf8PathBuf, - verbosity_spec: &VerbositySpec, + ui: &Ui, ) -> Result { let package_filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); - let print_stdout = Verbosity::from(verbosity_spec.clone()) != Verbosity::Quiet; - let mut cmd = ScarbCommand::new_for_output(print_stdout); + let mut cmd = ScarbCommand::new_for_output(); cmd.arg("cairo-execute") .env("SCARB_PACKAGES_FILTER", package_filter.to_env()) .env("SCARB_TARGET_DIR", scarb_target_dir); @@ -228,7 +222,8 @@ fn run_cairo_execute( cmd.arg(format!("--target={target}")); } - let output = cmd.output()?; + let printer = UiPrinter::new(ui); + let output = cmd.output_and_stream(&printer)?; extract_execution_id(&output) } diff --git a/scarb-metadata/src/command/scarb_command.rs b/scarb-metadata/src/command/scarb_command.rs index 67c00eba3..123215aca 100644 --- a/scarb-metadata/src/command/scarb_command.rs +++ b/scarb-metadata/src/command/scarb_command.rs @@ -21,7 +21,6 @@ pub enum ScarbCommandError { #[derive(Clone, Debug, Default)] pub struct ScarbCommand { inner: InternalScarbCommandBuilder, - print_stdout: bool, } impl ScarbCommand { @@ -33,20 +32,18 @@ impl ScarbCommand { cmd.inherit_stdout(); Self { inner: cmd, - print_stdout: false, } } /// Creates a `scarb` command that captures output while still printing it to stdout. - pub fn new_for_output(print_stdout: bool) -> Self { - // We can not just use self.inner.inherit_stdout() - // Because it will make output.stdout empty + pub fn new_for_output() -> Self { let mut cmd = InternalScarbCommandBuilder::new(); cmd.inherit_stderr(); + // We can not just use cmd.inherit_stdout() + // Because it will make output.stdout empty cmd.pipe_stdout(); Self { inner: cmd, - print_stdout, } } @@ -129,7 +126,7 @@ impl ScarbCommand { } /// Runs configured `scarb` command and returns its stdout output. - pub fn output(&self) -> Result, ScarbCommandError> { + pub fn output_and_stream(&self, printer: &impl Printer) -> Result, ScarbCommandError> { let mut cmd = self.inner.command(); let mut child = cmd.spawn()?; @@ -143,9 +140,8 @@ impl ScarbCommand { let mut output = Vec::new(); for line in reader.lines() { let line = line.map_err(|err| ScarbCommandError::Io(err))?; - if self.print_stdout { - println!("{}", line); - } + + printer.print(&line); output.push(line); } @@ -156,3 +152,10 @@ impl ScarbCommand { } } } + +/// Trait for printing messages. +pub trait Printer { + /// Print a message. + fn print(&self, message: &str); +} + diff --git a/utils/scarb-ui/src/lib.rs b/utils/scarb-ui/src/lib.rs index 71682fb2e..59ef94154 100644 --- a/utils/scarb-ui/src/lib.rs +++ b/utils/scarb-ui/src/lib.rs @@ -31,6 +31,7 @@ use std::fmt::Debug; use std::sync::{Arc, RwLock}; pub use message::*; +use scarb_metadata::Printer; pub use verbosity::*; pub use widget::*; @@ -232,3 +233,21 @@ impl Ui { console::colors_enabled_stderr() } } + +/// A printer that forwards messages to a [`Ui`] instance. +pub struct UiPrinter<'a> { + ui: &'a Ui, +} + +impl<'a> UiPrinter<'a> { + /// Create a new [`UiPrinter`] instance. + pub fn new(ui: &'a Ui) -> Self { + Self { ui } + } +} + +impl Printer for UiPrinter<'_> { + fn print(&self, message: &str) { + self.ui.print(message); + } +} From 2ab30cd8df1d45049a77c616c12d807f3140d469 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 05:24:13 +0100 Subject: [PATCH 21/71] refactor: rename scarb-cairo-{execute,prove} to scarb-{execute,prove} --- extensions/{scarb-cairo-execute => scarb-execute}/Cargo.toml | 2 +- extensions/{scarb-cairo-execute => scarb-execute}/src/main.rs | 0 .../{scarb-cairo-execute => scarb-execute}/tests/build.rs | 0 extensions/{scarb-cairo-prove => scarb-prove}/Cargo.toml | 2 +- extensions/{scarb-cairo-prove => scarb-prove}/src/main.rs | 0 extensions/{scarb-cairo-prove => scarb-prove}/tests/build.rs | 0 6 files changed, 2 insertions(+), 2 deletions(-) rename extensions/{scarb-cairo-execute => scarb-execute}/Cargo.toml (96%) rename extensions/{scarb-cairo-execute => scarb-execute}/src/main.rs (100%) rename extensions/{scarb-cairo-execute => scarb-execute}/tests/build.rs (100%) rename extensions/{scarb-cairo-prove => scarb-prove}/Cargo.toml (97%) rename extensions/{scarb-cairo-prove => scarb-prove}/src/main.rs (100%) rename extensions/{scarb-cairo-prove => scarb-prove}/tests/build.rs (100%) diff --git a/extensions/scarb-cairo-execute/Cargo.toml b/extensions/scarb-execute/Cargo.toml similarity index 96% rename from extensions/scarb-cairo-execute/Cargo.toml rename to extensions/scarb-execute/Cargo.toml index 878998bb4..ac3653aa2 100644 --- a/extensions/scarb-cairo-execute/Cargo.toml +++ b/extensions/scarb-execute/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "scarb-cairo-execute" +name = "scarb-execute" publish = false authors.workspace = true diff --git a/extensions/scarb-cairo-execute/src/main.rs b/extensions/scarb-execute/src/main.rs similarity index 100% rename from extensions/scarb-cairo-execute/src/main.rs rename to extensions/scarb-execute/src/main.rs diff --git a/extensions/scarb-cairo-execute/tests/build.rs b/extensions/scarb-execute/tests/build.rs similarity index 100% rename from extensions/scarb-cairo-execute/tests/build.rs rename to extensions/scarb-execute/tests/build.rs diff --git a/extensions/scarb-cairo-prove/Cargo.toml b/extensions/scarb-prove/Cargo.toml similarity index 97% rename from extensions/scarb-cairo-prove/Cargo.toml rename to extensions/scarb-prove/Cargo.toml index 243476ab2..48ec2d68b 100644 --- a/extensions/scarb-cairo-prove/Cargo.toml +++ b/extensions/scarb-prove/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "scarb-cairo-prove" +name = "scarb-prove" publish = false authors.workspace = true diff --git a/extensions/scarb-cairo-prove/src/main.rs b/extensions/scarb-prove/src/main.rs similarity index 100% rename from extensions/scarb-cairo-prove/src/main.rs rename to extensions/scarb-prove/src/main.rs diff --git a/extensions/scarb-cairo-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs similarity index 100% rename from extensions/scarb-cairo-prove/tests/build.rs rename to extensions/scarb-prove/tests/build.rs From e6556de76153c8ab82aa23652ff6a0552fd9cc0a Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 05:55:58 +0100 Subject: [PATCH 22/71] finish `scarb-cairo-{execute,prove}` -> `scarb-{execute,prove}`` --- Cargo.lock | 92 ++++++++++++------------- Cargo.toml | 4 +- extensions/scarb-execute/src/main.rs | 2 +- extensions/scarb-execute/tests/build.rs | 32 ++++----- extensions/scarb-prove/src/main.rs | 16 ++--- extensions/scarb-prove/tests/build.rs | 40 +++++------ 6 files changed, 93 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c30448a26..c918ddadb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5715,31 +5715,6 @@ dependencies = [ "semver 1.0.24", ] -[[package]] -name = "scarb-cairo-execute" -version = "2.9.2" -dependencies = [ - "anyhow", - "assert_fs", - "bincode", - "cairo-lang-executable", - "cairo-lang-runner", - "cairo-vm 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "camino", - "clap", - "create-output-dir", - "indoc", - "num-bigint", - "predicates", - "scarb", - "scarb-metadata 1.13.0", - "scarb-test-support", - "scarb-ui", - "serde", - "serde_json", - "snapbox", -] - [[package]] name = "scarb-cairo-language-server" version = "2.9.2" @@ -5752,27 +5727,6 @@ dependencies = [ "url", ] -[[package]] -name = "scarb-cairo-prove" -version = "2.9.2" -dependencies = [ - "anyhow", - "assert_fs", - "camino", - "clap", - "create-output-dir", - "indoc", - "predicates", - "scarb-metadata 1.13.0", - "scarb-test-support", - "scarb-ui", - "serde", - "serde_json", - "snapbox", - "stwo-prover", - "stwo_cairo_prover", -] - [[package]] name = "scarb-cairo-run" version = "2.9.2" @@ -5848,6 +5802,31 @@ dependencies = [ "walkdir", ] +[[package]] +name = "scarb-execute" +version = "2.9.2" +dependencies = [ + "anyhow", + "assert_fs", + "bincode", + "cairo-lang-executable", + "cairo-lang-runner", + "cairo-vm 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "camino", + "clap", + "create-output-dir", + "indoc", + "num-bigint", + "predicates", + "scarb", + "scarb-metadata 1.13.0", + "scarb-test-support", + "scarb-ui", + "serde", + "serde_json", + "snapbox", +] + [[package]] name = "scarb-metadata" version = "1.13.0" @@ -5896,6 +5875,27 @@ dependencies = [ "serde_json", ] +[[package]] +name = "scarb-prove" +version = "2.9.2" +dependencies = [ + "anyhow", + "assert_fs", + "camino", + "clap", + "create-output-dir", + "indoc", + "predicates", + "scarb-metadata 1.13.0", + "scarb-test-support", + "scarb-ui", + "serde", + "serde_json", + "snapbox", + "stwo-prover", + "stwo_cairo_prover", +] + [[package]] name = "scarb-stable-hash" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 5041ca729..a7d4f6d71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,9 @@ members = [ "scarb", "scarb-metadata", "extensions/scarb-doc", - "extensions/scarb-cairo-execute", + "extensions/scarb-execute", + "extensions/scarb-prove", "extensions/scarb-cairo-language-server", - "extensions/scarb-cairo-prove", "extensions/scarb-cairo-run", "extensions/scarb-cairo-test", "plugins/cairo-lang-macro", diff --git a/extensions/scarb-execute/src/main.rs b/extensions/scarb-execute/src/main.rs index 9fb98b696..58c7a1c46 100644 --- a/extensions/scarb-execute/src/main.rs +++ b/extensions/scarb-execute/src/main.rs @@ -208,7 +208,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> { print!("{output_buffer}"); } - let output_dir = scarb_target_dir.join("scarb-execute").join(&package.name); + let output_dir = scarb_target_dir.join("execute").join(&package.name); create_output_dir(output_dir.as_std_path())?; if args.run.output.is_cairo_pie() { diff --git a/extensions/scarb-execute/tests/build.rs b/extensions/scarb-execute/tests/build.rs index 83dc954f2..545d83e59 100644 --- a/extensions/scarb-execute/tests/build.rs +++ b/extensions/scarb-execute/tests/build.rs @@ -29,7 +29,7 @@ fn build_executable_project() -> TempDir { fn can_execute_default_main_function_from_executable() { let t = build_executable_project(); Scarb::quick_snapbox() - .arg("cairo-execute") + .arg("execute") .current_dir(&t) .assert() .success() @@ -37,16 +37,16 @@ fn can_execute_default_main_function_from_executable() { [..]Compiling hello v0.1.0 ([..]Scarb.toml) [..]Finished `dev` profile target(s) in [..] [..]Executing hello - Saving output to: target/scarb-execute/hello/execution1 + Saving output to: target/execute/hello/execution1 "#}); - t.child("target/scarb-execute/hello/execution1/air_private_input.json") + t.child("target/execute/hello/execution1/air_private_input.json") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/execution1/air_public_input.json") + t.child("target/execute/hello/execution1/air_public_input.json") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/execution1/memory.bin") + t.child("target/execute/hello/execution1/memory.bin") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/execution1/trace.bin") + t.child("target/execute/hello/execution1/trace.bin") .assert(predicates::path::exists()); } @@ -55,23 +55,23 @@ fn can_execute_prebuilt_executable() { let t = build_executable_project(); Scarb::quick_snapbox().arg("build").current_dir(&t).assert(); Scarb::quick_snapbox() - .arg("cairo-execute") + .arg("execute") .arg("--no-build") .current_dir(&t) .assert() .success() .stdout_matches(indoc! {r#" [..]Executing hello - Saving output to: target/scarb-execute/hello/execution1 + Saving output to: target/execute/hello/execution1 "#}); - t.child("target/scarb-execute/hello/execution1/air_private_input.json") + t.child("target/execute/hello/execution1/air_private_input.json") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/execution1/air_public_input.json") + t.child("target/execute/hello/execution1/air_public_input.json") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/execution1/memory.bin") + t.child("target/execute/hello/execution1/memory.bin") .assert(predicates::path::exists()); - t.child("target/scarb-execute/hello/execution1/trace.bin") + t.child("target/execute/hello/execution1/trace.bin") .assert(predicates::path::exists()); } @@ -79,7 +79,7 @@ fn can_execute_prebuilt_executable() { fn can_produce_cairo_pie_output() { let t = build_executable_project(); Scarb::quick_snapbox() - .arg("cairo-execute") + .arg("execute") .arg("--target=bootloader") .arg("--output=cairo-pie") .current_dir(&t) @@ -89,10 +89,10 @@ fn can_produce_cairo_pie_output() { [..]Compiling hello v0.1.0 ([..]Scarb.toml) [..]Finished `dev` profile target(s) in [..] [..]Executing hello - Saving output to: target/scarb-execute/hello/execution1.zip + Saving output to: target/execute/hello/execution1.zip "#}); - t.child("target/scarb-execute/hello/execution1.zip") + t.child("target/execute/hello/execution1.zip") .assert(predicates::path::exists()); } @@ -117,7 +117,7 @@ fn fails_when_target_missing() { output_assert( Scarb::quick_snapbox() - .arg("cairo-execute") + .arg("execute") .arg("--no-build") .current_dir(&t) .assert() diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 014993d6a..490bfa90f 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -14,7 +14,7 @@ use stwo_cairo_prover::cairo_air::{prove_cairo, ProverConfig}; use stwo_cairo_prover::input::vm_import::adapt_vm_output; use stwo_prover::core::vcs::blake2_merkle::Blake2sMerkleChannel; -/// Proves `cairo-execute` output using Stwo prover. +/// Proves `scarb execute` output using Stwo prover. #[derive(Parser, Clone, Debug)] #[clap(version, verbatim_doc_comment)] struct Args { @@ -22,7 +22,7 @@ struct Args { #[command(flatten)] packages_filter: PackagesFilter, - /// ID of `cairo-execute` *standard* output for given package, for which to generate proof. + /// ID of `scarb execute` *standard* output for given package, for which to generate proof. #[arg(long)] execution_id: Option, @@ -104,7 +104,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let execution_id = match args.execution_id { Some(execution_id) => execution_id, - None => run_cairo_execute(&args.execute_args, &package, &scarb_target_dir, &ui)?, + None => run_execute(&args.execute_args, &package, &scarb_target_dir, &ui)?, }; ui.print(Status::new("Proving", &package.name)); @@ -147,7 +147,7 @@ fn resolve_paths_from_package( execution_id: u32, ) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf8PathBuf)> { let execution_dir = scarb_target_dir - .join("scarb-execute") + .join("execute") .join(package_name) .join(format!("execution{}", execution_id)); @@ -155,7 +155,7 @@ fn resolve_paths_from_package( execution_dir.exists(), formatdoc! {r#" execution directory not found: {} - help: make sure to run `scarb cairo-execute` first + help: make sure to run `scarb execute` first and that the execution ID is correct "#, execution_dir} ); @@ -199,7 +199,7 @@ fn resolve_paths(files: &InputFileArgs) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf Ok((pub_input_path, priv_input_path, proof_path)) } -fn run_cairo_execute( +fn run_execute( execution_args: &ExecuteArgs, package: &PackageMetadata, scarb_target_dir: &Utf8PathBuf, @@ -208,7 +208,7 @@ fn run_cairo_execute( let package_filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); let mut cmd = ScarbCommand::new_for_output(); - cmd.arg("cairo-execute") + cmd.arg("execute") .env("SCARB_PACKAGES_FILTER", package_filter.to_env()) .env("SCARB_TARGET_DIR", scarb_target_dir); @@ -242,7 +242,7 @@ fn extract_execution_id(output: &[String]) -> Result { .ok() }) }) - .ok_or_else(|| anyhow!("failed to extract execution ID from `cairo-execute` output")) + .ok_or_else(|| anyhow!("failed to extract execution ID from `scarb execute` output")) } fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index 24e6de967..9214da465 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -30,23 +30,23 @@ fn prove_from_execution_output() { let t = build_executable_project(); Scarb::quick_snapbox() - .arg("cairo-execute") + .arg("execute") .current_dir(&t) .assert() .success(); Scarb::quick_snapbox() - .arg("cairo-prove") + .arg("prove") .arg("--execution-id=1") .current_dir(&t) .assert() .success() .stdout_matches(indoc! {r#" [..]Proving hello - Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json + Saving proof to: target/execute/hello/execution1/proof/proof.json "#}); - t.child("target/scarb-execute/hello/execution1/proof/proof.json") + t.child("target/execute/hello/execution1/proof/proof.json") .assert(predicates::path::exists()); } @@ -55,15 +55,15 @@ fn prove_from_paths() { let t = build_executable_project(); Scarb::quick_snapbox() - .arg("cairo-execute") + .arg("execute") .current_dir(&t) .assert() .success(); Scarb::quick_snapbox() - .arg("cairo-prove") - .arg("--pub-input-file=target/scarb-execute/hello/execution1/air_public_input.json") - .arg("--priv-input-file=target/scarb-execute/hello/execution1/air_private_input.json") + .arg("prove") + .arg("--pub-input-file=target/execute/hello/execution1/air_public_input.json") + .arg("--priv-input-file=target/execute/hello/execution1/air_private_input.json") .current_dir(&t) .assert() .success() @@ -80,13 +80,13 @@ fn prove_with_track_relations() { let t = build_executable_project(); Scarb::quick_snapbox() - .arg("cairo-execute") + .arg("execute") .current_dir(&t) .assert() .success(); let cmd = Scarb::quick_snapbox() - .arg("cairo-prove") + .arg("prove") .arg("--execution-id=1") .arg("--track-relations") .current_dir(&t) @@ -98,10 +98,10 @@ fn prove_with_track_relations() { assert!(stdout.contains("Proving hello")); assert!(stdout.contains("Relations summary:")); assert!( - stdout.contains("Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json") + stdout.contains("Saving proof to: target/execute/hello/execution1/proof/proof.json") ); - t.child("target/scarb-execute/hello/execution1/proof/proof.json") + t.child("target/execute/hello/execution1/proof/proof.json") .assert(predicates::path::exists()); } @@ -142,15 +142,15 @@ fn prove_fails_when_execution_output_not_found() { output_assert( Scarb::quick_snapbox() - .arg("cairo-prove") + .arg("prove") .arg("--execution-id=1") .current_dir(&t) .assert() .failure(), indoc! {r#" [..]Proving hello - error: execution directory not found: [..]/target/scarb-execute/hello/execution1 - help: make sure to run `scarb cairo-execute` first + error: execution directory not found: [..]/target/execute/hello/execution1 + help: make sure to run `scarb execute` first and that the execution ID is correct "#}, @@ -163,7 +163,7 @@ fn prove_fails_when_input_files_not_found() { output_assert( Scarb::quick_snapbox() - .arg("cairo-prove") + .arg("prove") .arg("--pub-input-file=nonexistent.json") .arg("--priv-input-file=nonexistent.json") .current_dir(&t) @@ -181,7 +181,7 @@ fn prove_with_execute() { let t = build_executable_project(); Scarb::quick_snapbox() - .arg("cairo-prove") + .arg("prove") .arg("--execute") .arg("--target=standalone") .current_dir(&t) @@ -191,12 +191,12 @@ fn prove_with_execute() { [..]Compiling hello v0.1.0 ([..]) [..]Finished `dev` profile target(s) in [..] [..]Executing hello - Saving output to: target/scarb-execute/hello/execution1 + Saving output to: target/execute/hello/execution1 [..]Proving hello - Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json + Saving proof to: target/execute/hello/execution1/proof/proof.json "#}); - t.child("target/scarb-execute/hello/execution1/proof/proof.json") + t.child("target/execute/hello/execution1/proof/proof.json") .assert(predicates::path::exists()); } From 242e17933c11314784bb25ae4fe6ddc0dbd40bbe Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 06:22:05 +0100 Subject: [PATCH 23/71] format --- scarb-metadata/src/command/scarb_command.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scarb-metadata/src/command/scarb_command.rs b/scarb-metadata/src/command/scarb_command.rs index 123215aca..0be5c30c2 100644 --- a/scarb-metadata/src/command/scarb_command.rs +++ b/scarb-metadata/src/command/scarb_command.rs @@ -30,9 +30,7 @@ impl ScarbCommand { let mut cmd = InternalScarbCommandBuilder::new(); cmd.inherit_stderr(); cmd.inherit_stdout(); - Self { - inner: cmd, - } + Self { inner: cmd } } /// Creates a `scarb` command that captures output while still printing it to stdout. @@ -42,9 +40,7 @@ impl ScarbCommand { // We can not just use cmd.inherit_stdout() // Because it will make output.stdout empty cmd.pipe_stdout(); - Self { - inner: cmd, - } + Self { inner: cmd } } /// Path to `scarb` executable. From 48a1399d03b7b50e2341336cd879d67240c69eec Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Sat, 18 Jan 2025 06:22:13 +0100 Subject: [PATCH 24/71] lock --- Cargo.lock | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c918ddadb..f989d6a22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,6 +98,16 @@ dependencies = [ "bytes", ] +[[package]] +name = "annotate-snippets" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" +dependencies = [ + "anstyle", + "unicode-width 0.2.0", +] + [[package]] name = "anstream" version = "0.6.14" @@ -1402,6 +1412,26 @@ dependencies = [ "which", ] +[[package]] +name = "cairo-lint-core" +version = "0.1.0" +source = "git+https://github.com/software-mansion/cairo-lint?rev=b95a1949b932e89179c052efdbf4e21002ce6777#b95a1949b932e89179c052efdbf4e21002ce6777" +dependencies = [ + "annotate-snippets", + "anyhow", + "cairo-lang-compiler", + "cairo-lang-defs", + "cairo-lang-diagnostics", + "cairo-lang-filesystem", + "cairo-lang-semantic", + "cairo-lang-syntax", + "cairo-lang-test-plugin", + "cairo-lang-utils", + "if_chain", + "log", + "num-bigint", +] + [[package]] name = "cairo-toolchain-xtasks" version = "1.1.1" @@ -3776,6 +3806,12 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + [[package]] name = "ignore" version = "0.4.23" @@ -5631,6 +5667,7 @@ dependencies = [ "cairo-lang-syntax", "cairo-lang-test-plugin", "cairo-lang-utils", + "cairo-lint-core", "camino", "cargo_metadata", "clap", @@ -5811,6 +5848,7 @@ dependencies = [ "bincode", "cairo-lang-executable", "cairo-lang-runner", + "cairo-lang-utils", "cairo-vm 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "camino", "clap", From 375195ca917d52f5b35cd35136833308809d13f6 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Mon, 20 Jan 2025 23:40:49 +0100 Subject: [PATCH 25/71] update ci --- .github/workflows/ci.yml | 50 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c35a509ed..c0a55d9e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - uses: Swatinem/rust-cache@v2 - uses: taiki-e/install-action@nextest - name: nextest archive - run: cargo nextest archive --workspace --all-features --cargo-profile ci --archive-file 'nextest-archive-${{ matrix.platform.os }}.tar.zst' + run: cargo nextest archive --workspace --all-features --cargo-profile ci --archive-file 'nextest-archive-${{ matrix.platform.os }}.tar.zst' --exclude scarb-prove - uses: actions/upload-artifact@v4 with: name: nextest-archive-${{ matrix.platform.os }} @@ -82,6 +82,28 @@ jobs: - name: run tests run: cargo test -p scarb-metadata + test-scarb-prove: + name: test scarb-prove ${{ matrix.platform.name }} + runs-on: ${{ matrix.platform.os }} + env: + RUST_TOOLCHAIN: "nightly-2025-01-02" + strategy: + fail-fast: false + matrix: + platform: + - name: linux x86-64 + os: ubuntu-latest + - name: windows x86-64 + os: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + - uses: Swatinem/rust-cache@v2 + - name: Run scarb-prove tests + run: cargo +${{ env.RUST_TOOLCHAIN }} test -p scarb-prove + test-prebuilt-plugins: name: test prebuilt plugins ${{ matrix.platform.name }} runs-on: ${{ matrix.platform.os }} @@ -112,14 +134,34 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - - run: cargo fmt --check - - run: cargo clippy --all-targets --all-features -- --no-deps + - run: cargo fmt --check --exclude scarb-prove + - run: cargo clippy --all-targets --all-features --exclude scarb-prove -- --no-deps env: # Make sure CI fails on all warnings, including Clippy lints. RUSTFLAGS: "-Dwarnings" - - run: cargo doc --all-features --no-deps + - run: cargo doc --all-features --no-deps --exclude scarb-prove + env: + # Make sure CI fails on all warnings, including Clippy lints. + RUSTDOCFLAGS: "-Dwarnings" + + check-rust-scarb-prove: + name: check-rust (scarb-prove) + runs-on: ubuntu-latest + env: + RUST_TOOLCHAIN: "nightly-2025-01-02" + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + - uses: Swatinem/rust-cache@v2 + - run: cargo +${{ env.RUST_TOOLCHAIN }} fmt --check -p scarb-prove + - run: cargo +${{ env.RUST_TOOLCHAIN }} clippy --all-targets --all-features -p scarb-prove -- --no-deps env: # Make sure CI fails on all warnings, including Clippy lints. + RUSTFLAGS: "-Dwarnings" + - run: cargo +${{ env.RUST_TOOLCHAIN }} doc --all-features --no-deps -p scarb-prove + env: RUSTDOCFLAGS: "-Dwarnings" check-website: From a9e7e28bf7efa643b0c6cc6d2b88839ffe3ff32a Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 11:51:53 +0100 Subject: [PATCH 26/71] fix `scarb execute` tests --- extensions/scarb-execute/tests/arguments.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/scarb-execute/tests/arguments.rs b/extensions/scarb-execute/tests/arguments.rs index d18899d4c..e322d670f 100644 --- a/extensions/scarb-execute/tests/arguments.rs +++ b/extensions/scarb-execute/tests/arguments.rs @@ -38,7 +38,7 @@ fn can_take_big_number_as_arg() { Program output: 0 1129815197211541481934112806673325772687763881719835256646064516195041515616 - Saving output to: target/execute/hello + Saving output to: target/execute/hello/execution1 "#}); } @@ -79,6 +79,6 @@ fn can_read_arguments_from_file() { Program output: 0 1129815197211541481934112806673325772687763881719835256646064516195041515616 - Saving output to: target/execute/hello + Saving output to: target/execute/hello/execution1 "#}); } From d19a6e1a55bcf8db24ce105b8117b3e3095667eb Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 12:06:00 +0100 Subject: [PATCH 27/71] `--exclude` not supported by rustfmt --- .github/workflows/ci.yml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0a55d9e7..7b49b953c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,7 +134,27 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - - run: cargo fmt --check --exclude scarb-prove + - run: | + cargo fmt --check \ + -p scarb \ + -p scarb-metadata \ + -p scarb-doc \ + -p scarb-execute \ + -p scarb-cairo-language-server \ + -p scarb-cairo-run \ + -p scarb-cairo-test \ + -p cairo-lang-macro \ + -p cairo-lang-macro-attributes \ + -p cairo-lang-macro-stable \ + -p create-output-dir \ + -p once-map \ + -p scarb-proc-macro-server-types \ + -p scarb-build-metadata \ + -p scarb-stable-hash \ + -p scarb-test-support \ + -p scarb-ui \ + -p test-for-each-example \ + -p xtask - run: cargo clippy --all-targets --all-features --exclude scarb-prove -- --no-deps env: # Make sure CI fails on all warnings, including Clippy lints. From 03593e3edd01d9b27e831cb38dc172d64c632b61 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 12:06:16 +0100 Subject: [PATCH 28/71] install components in `check-rust-scarb-prove` --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b49b953c..d203a98a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -174,6 +174,7 @@ jobs: - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_TOOLCHAIN }} + components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 - run: cargo +${{ env.RUST_TOOLCHAIN }} fmt --check -p scarb-prove - run: cargo +${{ env.RUST_TOOLCHAIN }} clippy --all-targets --all-features -p scarb-prove -- --no-deps From e9e2a15763008fcad0b6233fd43fa97fcd4d1c0b Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 12:14:46 +0100 Subject: [PATCH 29/71] Fix build in `test-scarb-prove` --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d203a98a9..009e020de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,7 +100,12 @@ jobs: - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_TOOLCHAIN }} + - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 + - name: Build + run: | + cargo +${{ env.RUST_TOOLCHAIN }} build -p scarb-prove + cargo build --exclude scarb-prove - name: Run scarb-prove tests run: cargo +${{ env.RUST_TOOLCHAIN }} test -p scarb-prove @@ -160,9 +165,6 @@ jobs: # Make sure CI fails on all warnings, including Clippy lints. RUSTFLAGS: "-Dwarnings" - run: cargo doc --all-features --no-deps --exclude scarb-prove - env: - # Make sure CI fails on all warnings, including Clippy lints. - RUSTDOCFLAGS: "-Dwarnings" check-rust-scarb-prove: name: check-rust (scarb-prove) @@ -182,8 +184,6 @@ jobs: # Make sure CI fails on all warnings, including Clippy lints. RUSTFLAGS: "-Dwarnings" - run: cargo +${{ env.RUST_TOOLCHAIN }} doc --all-features --no-deps -p scarb-prove - env: - RUSTDOCFLAGS: "-Dwarnings" check-website: runs-on: ubuntu-latest From 60de69fab0c6a415741091bfbb40c4b4a9d5f938 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 12:23:32 +0100 Subject: [PATCH 30/71] fmt --- extensions/scarb-prove/tests/build.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index 9214da465..19ae51851 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -97,9 +97,7 @@ fn prove_with_track_relations() { assert!(stdout.contains("Proving hello")); assert!(stdout.contains("Relations summary:")); - assert!( - stdout.contains("Saving proof to: target/execute/hello/execution1/proof/proof.json") - ); + assert!(stdout.contains("Saving proof to: target/execute/hello/execution1/proof/proof.json")); t.child("target/execute/hello/execution1/proof/proof.json") .assert(predicates::path::exists()); From e42b9607ba0170d338bb5dc2db9afedd7661c7b8 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 12:26:22 +0100 Subject: [PATCH 31/71] fix `check-rust` --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 009e020de..1679c068f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -152,7 +152,7 @@ jobs: -p cairo-lang-macro-attributes \ -p cairo-lang-macro-stable \ -p create-output-dir \ - -p once-map \ + -p once_map \ -p scarb-proc-macro-server-types \ -p scarb-build-metadata \ -p scarb-stable-hash \ From eea251e2b4dc055124f56d13fec872854756eab8 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 12:27:56 +0100 Subject: [PATCH 32/71] fix test-scarb-prove --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1679c068f..49ed59d08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,8 +104,8 @@ jobs: - uses: Swatinem/rust-cache@v2 - name: Build run: | - cargo +${{ env.RUST_TOOLCHAIN }} build -p scarb-prove - cargo build --exclude scarb-prove + cargo +${{ env.RUST_TOOLCHAIN }} build --all-features -p scarb-prove + cargo build --workspace --all-features --exclude scarb-prove - name: Run scarb-prove tests run: cargo +${{ env.RUST_TOOLCHAIN }} test -p scarb-prove From 21a899c6f5858692c899a2b74265bbadf81802c6 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 12:34:34 +0100 Subject: [PATCH 33/71] fmt --- extensions/scarb-execute/src/main.rs | 19 +++++++------------ scarb-metadata/src/command/scarb_command.rs | 17 ++++++++++------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/extensions/scarb-execute/src/main.rs b/extensions/scarb-execute/src/main.rs index 6fc2da597..1da681876 100644 --- a/extensions/scarb-execute/src/main.rs +++ b/extensions/scarb-execute/src/main.rs @@ -314,18 +314,13 @@ fn incremental_create_output_file( path: &Utf8Path, extension: impl AsRef, ) -> Result { - incremental_attempt_io_creation( - path, - extension, - "failed to create output directory", - |p| { - OpenOptions::new() - .write(true) - .create_new(true) - .open(p) - .map(|_| ()) - }, - ) + incremental_attempt_io_creation(path, extension, "failed to create output directory", |p| { + OpenOptions::new() + .write(true) + .create_new(true) + .open(p) + .map(|_| ()) + }) } fn incremental_create_output_dir(path: &Utf8Path) -> Result { diff --git a/scarb-metadata/src/command/scarb_command.rs b/scarb-metadata/src/command/scarb_command.rs index 0be5c30c2..5191e831e 100644 --- a/scarb-metadata/src/command/scarb_command.rs +++ b/scarb-metadata/src/command/scarb_command.rs @@ -1,8 +1,8 @@ +use crate::command::internal_command::InternalScarbCommandBuilder; use std::ffi::OsStr; use std::io; use std::io::{BufRead, BufReader}; use std::path::PathBuf; -use crate::command::internal_command::InternalScarbCommandBuilder; use thiserror::Error; /// Error thrown while trying to execute `scarb` command. @@ -122,20 +122,24 @@ impl ScarbCommand { } /// Runs configured `scarb` command and returns its stdout output. - pub fn output_and_stream(&self, printer: &impl Printer) -> Result, ScarbCommandError> { + pub fn output_and_stream( + &self, + printer: &impl Printer, + ) -> Result, ScarbCommandError> { let mut cmd = self.inner.command(); let mut child = cmd.spawn()?; - let stdout = child.stdout.take().ok_or_else(|| { - ScarbCommandError::Io(io::Error::from(io::ErrorKind::BrokenPipe)) - })?; + let stdout = child + .stdout + .take() + .ok_or_else(|| ScarbCommandError::Io(io::Error::from(io::ErrorKind::BrokenPipe)))?; let reader = BufReader::new(stdout); // Collect and stream stdout lines let mut output = Vec::new(); for line in reader.lines() { - let line = line.map_err(|err| ScarbCommandError::Io(err))?; + let line = line.map_err(ScarbCommandError::Io)?; printer.print(&line); output.push(line); @@ -154,4 +158,3 @@ pub trait Printer { /// Print a message. fn print(&self, message: &str); } - From a1e1fe21f7789a0321d1d5c8e81592f579e4761e Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 12:34:55 +0100 Subject: [PATCH 34/71] remove config.toml --- .cargo/config.toml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml deleted file mode 100644 index c960c7fbc..000000000 --- a/.cargo/config.toml +++ /dev/null @@ -1,7 +0,0 @@ -[alias] -xtask = "run --quiet --package xtask --" - -# On Windows MSVC, statically link the C runtime so that the resulting EXE does -# not depend on the vcruntime DLL. -[target.'cfg(windows)'] -rustflags = ["-C", "target-feature=+crt-static"] From fa3ddf43deb58aaa36e962d1ccc88aa2ae746766 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 12:35:10 +0100 Subject: [PATCH 35/71] fix clippy ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49ed59d08..d1aac0bbc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -160,7 +160,7 @@ jobs: -p scarb-ui \ -p test-for-each-example \ -p xtask - - run: cargo clippy --all-targets --all-features --exclude scarb-prove -- --no-deps + - run: cargo clippy --all-targets --all-features --workspace --exclude scarb-prove -- --no-deps env: # Make sure CI fails on all warnings, including Clippy lints. RUSTFLAGS: "-Dwarnings" From 69366185824e4733abdcf0b03b52fc80ca1d7036 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 13:23:15 +0100 Subject: [PATCH 36/71] fix tests --- extensions/scarb-prove/tests/build.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index 19ae51851..4d596d199 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -108,13 +108,13 @@ fn prove_with_display_components() { let t = build_executable_project(); Scarb::quick_snapbox() - .arg("cairo-execute") + .arg("execute") .current_dir(&t) .assert() .success(); let cmd = Scarb::quick_snapbox() - .arg("cairo-prove") + .arg("prove") .arg("--execution-id=1") .arg("--display-components") .current_dir(&t) @@ -127,10 +127,10 @@ fn prove_with_display_components() { assert!(stdout.contains("Proving hello")); assert!(stdout.contains("CairoComponents")); assert!( - stdout.contains("Saving proof to: target/scarb-execute/hello/execution1/proof/proof.json") + stdout.contains("Saving proof to: target/execute/hello/execution1/proof/proof.json") ); - t.child("target/scarb-execute/hello/execution1/proof/proof.json") + t.child("target/execute/hello/execution1/proof/proof.json") .assert(predicates::path::exists()); } From a3ce3a4a057044682aa67551f5f83a9732d0a1a8 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 13:24:05 +0100 Subject: [PATCH 37/71] fix ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d1aac0bbc..b368bee8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -164,7 +164,7 @@ jobs: env: # Make sure CI fails on all warnings, including Clippy lints. RUSTFLAGS: "-Dwarnings" - - run: cargo doc --all-features --no-deps --exclude scarb-prove + - run: cargo doc --all-features --no-deps --workspace --exclude scarb-prove check-rust-scarb-prove: name: check-rust (scarb-prove) From d783d0396e4801899ab5f39ba52d6cd16632e20b Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 13:27:42 +0100 Subject: [PATCH 38/71] support arguments file --- extensions/scarb-prove/src/main.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 490bfa90f..e42794699 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -8,6 +8,7 @@ use scarb_ui::args::{PackagesFilter, VerbositySpec}; use scarb_ui::components::Status; use scarb_ui::{OutputFormat, Ui, UiPrinter}; use std::env; +use std::fmt::Arguments; use std::fs; use std::process::ExitCode; use stwo_cairo_prover::cairo_air::{prove_cairo, ProverConfig}; @@ -54,6 +55,10 @@ struct ExecuteArgs { #[arg(long, requires = "execute")] arguments: Option, + /// Arguments to the executable function from a file. + #[arg(long, conflicts_with = "arguments")] + arguments_file: Option, + /// Target for execution. #[arg(long, requires = "execute")] target: Option, @@ -218,6 +223,9 @@ fn run_execute( if let Some(arguments) = &execution_args.arguments { cmd.arg(format!("--arguments={arguments}")); } + if let Some(arguments_file) = &execution_args.arguments_file { + cmd.arg(format!("--arguments-file={arguments_file}")); + } if let Some(target) = &execution_args.target { cmd.arg(format!("--target={target}")); } From 57839d49f0292a3b1a9fec5b8d10028ad825e7c5 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 15:00:02 +0100 Subject: [PATCH 39/71] fmt --- extensions/scarb-prove/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index e42794699..1b5560c60 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -8,7 +8,6 @@ use scarb_ui::args::{PackagesFilter, VerbositySpec}; use scarb_ui::components::Status; use scarb_ui::{OutputFormat, Ui, UiPrinter}; use std::env; -use std::fmt::Arguments; use std::fs; use std::process::ExitCode; use stwo_cairo_prover::cairo_air::{prove_cairo, ProverConfig}; From 1eb0f3427e06e89bd579a2b6a8f45ab42a90f137 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 15:15:01 +0100 Subject: [PATCH 40/71] fmt --- extensions/scarb-prove/tests/build.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index 4d596d199..c07823e51 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -126,9 +126,7 @@ fn prove_with_display_components() { assert!(stdout.contains("Proving hello")); assert!(stdout.contains("CairoComponents")); - assert!( - stdout.contains("Saving proof to: target/execute/hello/execution1/proof/proof.json") - ); + assert!(stdout.contains("Saving proof to: target/execute/hello/execution1/proof/proof.json")); t.child("target/execute/hello/execution1/proof/proof.json") .assert(predicates::path::exists()); From 4218467da76990b59a31e21eaeafb4ee0750e625 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 21 Jan 2025 15:15:14 +0100 Subject: [PATCH 41/71] update `extract_execution_id` --- extensions/scarb-prove/src/main.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 1b5560c60..bb23d0268 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -240,13 +240,10 @@ fn extract_execution_id(output: &[String]) -> Result { .find_map(|line| { line.trim() .strip_prefix("Saving output to:") - // Isolate the last path component (e.g., "execution1"), strip "execution" prefix, and parse the number - .and_then(|output_path| output_path.trim().split('/').last()) - .and_then(|execution_str| { - execution_str - .trim_start_matches("execution") - .parse::() - .ok() + .and_then(|output_path| { + Utf8PathBuf::from(output_path.trim()) + .file_name() + .and_then(|name| name.trim_start_matches("execution").parse::().ok()) }) }) .ok_or_else(|| anyhow!("failed to extract execution ID from `scarb execute` output")) From 67fb1ac9d45d67be6e88c5dadd571f81b74b7001 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 24 Jan 2025 06:43:46 +0100 Subject: [PATCH 42/71] Link #1915 --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b368bee8a..b62cc3e04 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,6 +86,7 @@ jobs: name: test scarb-prove ${{ matrix.platform.name }} runs-on: ${{ matrix.platform.os }} env: + # TODO(#1915): Use stable toolchain once stwo is stable. RUST_TOOLCHAIN: "nightly-2025-01-02" strategy: fail-fast: false @@ -139,6 +140,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 + # TODO(#1915): Build all crates with stable toolchain once stwo is stable. - run: | cargo fmt --check \ -p scarb \ @@ -170,6 +172,7 @@ jobs: name: check-rust (scarb-prove) runs-on: ubuntu-latest env: + # TODO(#1915): Use stable toolchain once stwo is stable. RUST_TOOLCHAIN: "nightly-2025-01-02" steps: - uses: actions/checkout@v4 From 78619feba14523670ab1943a4feea8dc6568d0cb Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 24 Jan 2025 07:17:13 +0100 Subject: [PATCH 43/71] add warning re proof instability --- extensions/scarb-prove/src/main.rs | 2 ++ extensions/scarb-prove/tests/build.rs | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index bb23d0268..904572a5c 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -101,6 +101,8 @@ fn main() -> ExitCode { fn main_inner(args: Args, ui: Ui) -> Result<()> { let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); + ui.warn("soundness of proof is not yet guaranteed by Stwo, use at your own risk"); + let (pub_input_path, priv_input_path, proof_path) = if args.execute || args.execution_id.is_some() { let metadata = MetadataCommand::new().inherit_stderr().exec()?; diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index c07823e51..651aedf5f 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -42,6 +42,7 @@ fn prove_from_execution_output() { .assert() .success() .stdout_matches(indoc! {r#" + [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk [..]Proving hello Saving proof to: target/execute/hello/execution1/proof/proof.json "#}); @@ -68,6 +69,7 @@ fn prove_from_paths() { .assert() .success() .stdout_matches(indoc! {r#" + [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk [..]Proving Cairo program Saving proof to: proof.json "#}); @@ -144,6 +146,7 @@ fn prove_fails_when_execution_output_not_found() { .assert() .failure(), indoc! {r#" + [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk [..]Proving hello error: execution directory not found: [..]/target/execute/hello/execution1 help: make sure to run `scarb execute` first @@ -166,6 +169,7 @@ fn prove_fails_when_input_files_not_found() { .assert() .failure(), indoc! {r#" + [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk [..]Proving Cairo program error: public input file does not exist at path: nonexistent.json "#}, @@ -184,6 +188,7 @@ fn prove_with_execute() { .assert() .success() .stdout_matches(indoc! {r#" + [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk [..]Compiling hello v0.1.0 ([..]) [..]Finished `dev` profile target(s) in [..] [..]Executing hello From f87b63dfeb69f4f98d408e0d41d4f78d99f136e4 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 09:54:36 +0100 Subject: [PATCH 44/71] Revert "remove config.toml" This reverts commit a1e1fe21f7789a0321d1d5c8e81592f579e4761e. --- .cargo/config.toml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 000000000..c960c7fbc --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,7 @@ +[alias] +xtask = "run --quiet --package xtask --" + +# On Windows MSVC, statically link the C runtime so that the resulting EXE does +# not depend on the vcruntime DLL. +[target.'cfg(windows)'] +rustflags = ["-C", "target-feature=+crt-static"] From 4203a8c72295dacb2dddc1433096050ae0ff58a6 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau <43750648+DelevoXDG@users.noreply.github.com> Date: Tue, 28 Jan 2025 10:06:07 +0100 Subject: [PATCH 45/71] add missing env: in ci Co-authored-by: maciektr Signed-off-by: Maksim Zdobnikau <43750648+DelevoXDG@users.noreply.github.com> --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b62cc3e04..817fef4e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -187,6 +187,9 @@ jobs: # Make sure CI fails on all warnings, including Clippy lints. RUSTFLAGS: "-Dwarnings" - run: cargo +${{ env.RUST_TOOLCHAIN }} doc --all-features --no-deps -p scarb-prove + env: + # Make sure CI fails on all warnings, including Clippy lints. + RUSTDOCFLAGS: "-Dwarnings" check-website: runs-on: ubuntu-latest From 063e8a3f669dd43cc627627c0a83fed698f01c21 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau <43750648+DelevoXDG@users.noreply.github.com> Date: Tue, 28 Jan 2025 10:18:59 +0100 Subject: [PATCH 46/71] ensure can format Co-authored-by: maciektr Signed-off-by: Maksim Zdobnikau <43750648+DelevoXDG@users.noreply.github.com> --- extensions/scarb-prove/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 904572a5c..1ca7c133f 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -192,7 +192,7 @@ fn resolve_paths(files: &InputFileArgs) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf ensure!( pub_input_path.exists(), - format!("public input file does not exist at path: {pub_input_path}") + "public input file does not exist at path: {pub_input_path}" ); ensure!( priv_input_path.exists(), From 91a2e0c945dc7dddf6b1cddea769c3141047af2e Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 10:20:52 +0100 Subject: [PATCH 47/71] add requested comment --- extensions/scarb-prove/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 1ca7c133f..4e5f9ca24 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -187,6 +187,7 @@ fn resolve_paths_from_package( } fn resolve_paths(files: &InputFileArgs) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf8PathBuf)> { + // We can unwrap these values thanks to validations handled within the clap parser let pub_input_path = files.pub_input_file.clone().unwrap(); let priv_input_path = files.priv_input_file.clone().unwrap(); From c8fe9630f2cb4d8a40750226c7dda4adc86e07e6 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau <43750648+DelevoXDG@users.noreply.github.com> Date: Tue, 28 Jan 2025 10:26:31 +0100 Subject: [PATCH 48/71] add missing env: in ci Co-authored-by: maciektr Signed-off-by: Maksim Zdobnikau <43750648+DelevoXDG@users.noreply.github.com> --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 817fef4e1..4f18b5834 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -167,6 +167,9 @@ jobs: # Make sure CI fails on all warnings, including Clippy lints. RUSTFLAGS: "-Dwarnings" - run: cargo doc --all-features --no-deps --workspace --exclude scarb-prove + env: + # Make sure CI fails on all warnings, including Clippy lints. + RUSTDOCFLAGS: "-Dwarnings" check-rust-scarb-prove: name: check-rust (scarb-prove) From 662b438607c236579deed9375fc4aa551944a85c Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 10:40:52 +0100 Subject: [PATCH 49/71] run `cargo fmt` inside a single job --- .github/workflows/ci.yml | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f18b5834..8391282a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,28 +140,8 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 + - run: cargo fmt --check # TODO(#1915): Build all crates with stable toolchain once stwo is stable. - - run: | - cargo fmt --check \ - -p scarb \ - -p scarb-metadata \ - -p scarb-doc \ - -p scarb-execute \ - -p scarb-cairo-language-server \ - -p scarb-cairo-run \ - -p scarb-cairo-test \ - -p cairo-lang-macro \ - -p cairo-lang-macro-attributes \ - -p cairo-lang-macro-stable \ - -p create-output-dir \ - -p once_map \ - -p scarb-proc-macro-server-types \ - -p scarb-build-metadata \ - -p scarb-stable-hash \ - -p scarb-test-support \ - -p scarb-ui \ - -p test-for-each-example \ - -p xtask - run: cargo clippy --all-targets --all-features --workspace --exclude scarb-prove -- --no-deps env: # Make sure CI fails on all warnings, including Clippy lints. @@ -184,7 +164,6 @@ jobs: toolchain: ${{ env.RUST_TOOLCHAIN }} components: rustfmt, clippy - uses: Swatinem/rust-cache@v2 - - run: cargo +${{ env.RUST_TOOLCHAIN }} fmt --check -p scarb-prove - run: cargo +${{ env.RUST_TOOLCHAIN }} clippy --all-targets --all-features -p scarb-prove -- --no-deps env: # Make sure CI fails on all warnings, including Clippy lints. From ce6c534ad4d61512a100407ad7f1f3b5463edea4 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 11:21:19 +0100 Subject: [PATCH 50/71] ci: remove unnecessary build step in `test-scarb-prove` --- .github/workflows/ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8391282a8..3f3a82e03 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -104,9 +104,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - name: Build - run: | - cargo +${{ env.RUST_TOOLCHAIN }} build --all-features -p scarb-prove - cargo build --workspace --all-features --exclude scarb-prove + run: cargo build --workspace --all-features --exclude scarb-prove - name: Run scarb-prove tests run: cargo +${{ env.RUST_TOOLCHAIN }} test -p scarb-prove From e50f09c23539fda8419280843e340159787153ad Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 13:09:25 +0100 Subject: [PATCH 51/71] lock --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index f989d6a22..f0185e67c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5966,6 +5966,7 @@ dependencies = [ "hyper", "indoc", "itertools 0.14.0", + "predicates", "scarb", "scarb-build-metadata", "scarb-proc-macro-server-types 0.1.0", From 7b2c5ebd14ef33ac777e2d54d7dde44231d24bd9 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 13:09:39 +0100 Subject: [PATCH 52/71] remove support for path inputs --- extensions/scarb-prove/src/main.rs | 67 +++++++-------------------- extensions/scarb-prove/tests/build.rs | 46 ------------------ 2 files changed, 16 insertions(+), 97 deletions(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 4e5f9ca24..c9fc691c8 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -27,15 +27,12 @@ struct Args { execution_id: Option, /// Execute the program before proving. - #[arg(long, conflicts_with_all = ["execution_id", "pub_input_file", "priv_input_file"])] + #[arg(long, conflicts_with = "execution_id")] execute: bool, #[command(flatten)] execute_args: ExecuteArgs, - #[command(flatten)] - files: InputFileArgs, - #[command(flatten)] prover: ProverArgs, @@ -63,17 +60,6 @@ struct ExecuteArgs { target: Option, } -#[derive(Parser, Clone, Debug)] -struct InputFileArgs { - /// AIR public input path. - #[arg(long, required_unless_present_any = ["execution_id", "execute"], conflicts_with_all = ["execution_id", "execute"])] - pub_input_file: Option, - - /// AIR private input path. - #[arg(long, required_unless_present_any = ["execution_id", "execute"], conflicts_with_all = ["execution_id", "execute"])] - priv_input_file: Option, -} - #[derive(Parser, Clone, Debug)] struct ProverArgs { /// Track relations during proving. @@ -103,24 +89,23 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { ui.warn("soundness of proof is not yet guaranteed by Stwo, use at your own risk"); - let (pub_input_path, priv_input_path, proof_path) = - if args.execute || args.execution_id.is_some() { - let metadata = MetadataCommand::new().inherit_stderr().exec()?; - let package = args.packages_filter.match_one(&metadata)?; - - let execution_id = match args.execution_id { - Some(execution_id) => execution_id, - None => run_execute(&args.execute_args, &package, &scarb_target_dir, &ui)?, - }; - - ui.print(Status::new("Proving", &package.name)); + let metadata = MetadataCommand::new().inherit_stderr().exec()?; + let package = args.packages_filter.match_one(&metadata)?; + let execution_id = match args.execution_id { + Some(id) => id, + None => { + ensure!( + args.execute, + "either `--execution-id` or `--execute` must be provided" + ); + run_execute(&args.execute_args, &package, &scarb_target_dir, &ui)? + } + }; - resolve_paths_from_package(&scarb_target_dir, &package.name, execution_id)? - } else { - ui.print(Status::new("Proving", "Cairo program")); + let (pub_input_path, priv_input_path, proof_path) = + resolve_paths_from_package(&scarb_target_dir, &package.name, execution_id)?; - resolve_paths(&args.files)? - }; + ui.print(Status::new("Proving", &package.name)); let prover_input = adapt_vm_output( pub_input_path.as_std_path(), @@ -186,26 +171,6 @@ fn resolve_paths_from_package( Ok((pub_input_path, priv_input_path, proof_path)) } -fn resolve_paths(files: &InputFileArgs) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf8PathBuf)> { - // We can unwrap these values thanks to validations handled within the clap parser - let pub_input_path = files.pub_input_file.clone().unwrap(); - let priv_input_path = files.priv_input_file.clone().unwrap(); - - ensure!( - pub_input_path.exists(), - "public input file does not exist at path: {pub_input_path}" - ); - ensure!( - priv_input_path.exists(), - format!("private input file does not exist at path: {priv_input_path}") - ); - - // Create proof file in current directory - let proof_path = Utf8PathBuf::from("proof.json"); - - Ok((pub_input_path, priv_input_path, proof_path)) -} - fn run_execute( execution_args: &ExecuteArgs, package: &PackageMetadata, diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index 651aedf5f..7c06e3258 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -51,32 +51,6 @@ fn prove_from_execution_output() { .assert(predicates::path::exists()); } -#[test] -fn prove_from_paths() { - let t = build_executable_project(); - - Scarb::quick_snapbox() - .arg("execute") - .current_dir(&t) - .assert() - .success(); - - Scarb::quick_snapbox() - .arg("prove") - .arg("--pub-input-file=target/execute/hello/execution1/air_public_input.json") - .arg("--priv-input-file=target/execute/hello/execution1/air_private_input.json") - .current_dir(&t) - .assert() - .success() - .stdout_matches(indoc! {r#" - [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk - [..]Proving Cairo program - Saving proof to: proof.json - "#}); - - t.child("proof.json").assert(predicates::path::exists()); -} - #[test] fn prove_with_track_relations() { let t = build_executable_project(); @@ -156,26 +130,6 @@ fn prove_fails_when_execution_output_not_found() { ) } -#[test] -fn prove_fails_when_input_files_not_found() { - let t = build_executable_project(); - - output_assert( - Scarb::quick_snapbox() - .arg("prove") - .arg("--pub-input-file=nonexistent.json") - .arg("--priv-input-file=nonexistent.json") - .current_dir(&t) - .assert() - .failure(), - indoc! {r#" - [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk - [..]Proving Cairo program - error: public input file does not exist at path: nonexistent.json - "#}, - ) -} - #[test] fn prove_with_execute() { let t = build_executable_project(); From 8231ae55bb30683c460c0ed73f7670d654fb4fe1 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 13:51:24 +0100 Subject: [PATCH 53/71] require `--execute` as default arg --- extensions/scarb-prove/src/main.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index c9fc691c8..c2bc8a1e5 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -27,7 +27,12 @@ struct Args { execution_id: Option, /// Execute the program before proving. - #[arg(long, conflicts_with = "execution_id")] + #[arg( + long, + default_value_t = false, + conflicts_with = "execution_id", + required_unless_present = "execution_id" + )] execute: bool, #[command(flatten)] @@ -94,10 +99,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let execution_id = match args.execution_id { Some(id) => id, None => { - ensure!( - args.execute, - "either `--execution-id` or `--execute` must be provided" - ); + ensure!(args.execute); run_execute(&args.execute_args, &package, &scarb_target_dir, &ui)? } }; From 8f6d6ca28f7adc09e779fc243c93d39c2ebd9be6 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 13:51:37 +0100 Subject: [PATCH 54/71] fix order of "proving" msg --- extensions/scarb-prove/src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index c2bc8a1e5..0b35f2c0c 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -103,12 +103,11 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { run_execute(&args.execute_args, &package, &scarb_target_dir, &ui)? } }; + ui.print(Status::new("Proving", &package.name)); let (pub_input_path, priv_input_path, proof_path) = resolve_paths_from_package(&scarb_target_dir, &package.name, execution_id)?; - ui.print(Status::new("Proving", &package.name)); - let prover_input = adapt_vm_output( pub_input_path.as_std_path(), priv_input_path.as_std_path(), From a000eebcb0e796491c65b85eece070746fbb1211 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 15:45:25 +0100 Subject: [PATCH 55/71] split cairo-execute into subfiles --- extensions/scarb-execute/src/args.rs | 104 ++++++++ extensions/scarb-execute/src/lib.rs | 282 ++++++++++++++++++++ extensions/scarb-execute/src/main.rs | 382 +-------------------------- 3 files changed, 389 insertions(+), 379 deletions(-) create mode 100644 extensions/scarb-execute/src/args.rs create mode 100644 extensions/scarb-execute/src/lib.rs diff --git a/extensions/scarb-execute/src/args.rs b/extensions/scarb-execute/src/args.rs new file mode 100644 index 000000000..2c0747f09 --- /dev/null +++ b/extensions/scarb-execute/src/args.rs @@ -0,0 +1,104 @@ +use anyhow::{Context, Result}; +use cairo_lang_runner::Arg; +use cairo_lang_utils::bigint::BigUintAsHex; +use camino::Utf8PathBuf; +use clap::{arg, Parser, ValueEnum}; +use num_bigint::BigInt; +use scarb_ui::args::{PackagesFilter, VerbositySpec}; +use std::fs; + +/// Compiles a Cairo project and runs a function marked `#[executable]`. +/// Exits with 1 if the compilation or run fails, otherwise 0. +#[derive(Parser, Clone, Debug)] +#[clap(version, verbatim_doc_comment)] +pub struct Args { + /// Name of the package. + #[command(flatten)] + pub packages_filter: PackagesFilter, + + /// Do not rebuild the package. + #[arg(long, default_value_t = false)] + pub no_build: bool, + + #[clap(flatten)] + pub run: ExecutionArgs, + + /// Logging verbosity. + #[command(flatten)] + pub verbose: VerbositySpec, +} + +#[derive(Parser, Clone, Debug)] +pub struct ExecutionArgs { + #[command(flatten)] + pub arguments: ProgramArguments, + + /// Desired execution output, either default Standard or CairoPie + #[arg(long, default_value = "standard")] + pub output: OutputFormat, + + /// Execution target. + #[arg(long, default_value = "standalone")] + pub target: ExecutionTarget, + + /// Whether to print the program outputs. + #[arg(long, default_value_t = false)] + pub print_program_output: bool, +} + +#[derive(Parser, Debug, Clone)] +pub struct ProgramArguments { + /// Serialized arguments to the executable function. + #[arg(long, value_delimiter = ',')] + pub arguments: Vec, + + /// Serialized arguments to the executable function from a file. + #[arg(long, conflicts_with = "arguments")] + pub arguments_file: Option, +} + +impl ProgramArguments { + pub fn read_arguments(self) -> Result> { + if let Some(path) = self.arguments_file { + let file = fs::File::open(&path).with_context(|| "reading arguments file failed")?; + let as_vec: Vec = serde_json::from_reader(file) + .with_context(|| "deserializing arguments file failed")?; + Ok(as_vec + .into_iter() + .map(|v| Arg::Value(v.value.into())) + .collect()) + } else { + Ok(self + .arguments + .iter() + .map(|v| Arg::Value(v.into())) + .collect()) + } + } +} + +#[derive(ValueEnum, Clone, Debug)] +pub enum OutputFormat { + CairoPie, + Standard, +} +impl OutputFormat { + pub fn is_standard(&self) -> bool { + matches!(self, OutputFormat::Standard) + } + pub fn is_cairo_pie(&self) -> bool { + matches!(self, OutputFormat::CairoPie) + } +} + +#[derive(ValueEnum, Clone, Debug)] +pub enum ExecutionTarget { + Bootloader, + Standalone, +} + +impl ExecutionTarget { + pub fn is_standalone(&self) -> bool { + matches!(self, ExecutionTarget::Standalone) + } +} diff --git a/extensions/scarb-execute/src/lib.rs b/extensions/scarb-execute/src/lib.rs new file mode 100644 index 000000000..a60e63c58 --- /dev/null +++ b/extensions/scarb-execute/src/lib.rs @@ -0,0 +1,282 @@ +use anyhow::{bail, ensure, Context, Result}; +use bincode::enc::write::Writer; +use cairo_lang_executable::executable::{EntryPointKind, Executable}; +use cairo_lang_runner::{build_hints_dict, Arg, CairoHintProcessor}; +use cairo_vm::cairo_run::cairo_run_program; +use cairo_vm::cairo_run::CairoRunConfig; +use cairo_vm::types::layout_name::LayoutName; +use cairo_vm::types::program::Program; +use cairo_vm::types::relocatable::MaybeRelocatable; +use cairo_vm::{cairo_run, Felt252}; +use camino::{Utf8Path, Utf8PathBuf}; +use create_output_dir::create_output_dir; +use indoc::formatdoc; +use scarb_metadata::{Metadata, MetadataCommand, ScarbCommand}; +use scarb_ui::args::PackagesFilter; +use scarb_ui::components::Status; +use scarb_ui::Ui; +use std::env; +use std::fs; +use std::fs::OpenOptions; +use std::io::{self, Write}; + +pub mod args; +const MAX_ITERATION_COUNT: usize = 10000; + +pub fn main_inner(args: args::Args, ui: Ui) -> Result<(), anyhow::Error> { + ensure!( + !(args.run.output.is_cairo_pie() && args.run.target.is_standalone()), + "Cairo pie output format is not supported for standalone execution target" + ); + + let metadata = MetadataCommand::new().inherit_stderr().exec()?; + let package = args.packages_filter.match_one(&metadata)?; + + if !args.no_build { + let filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); + ScarbCommand::new() + .arg("build") + .env("SCARB_PACKAGES_FILTER", filter.to_env()) + .run()?; + } + + let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); + let scarb_build_dir = scarb_target_dir.join(env::var("SCARB_PROFILE")?); + + ui.print(Status::new("Executing", &package.name)); + let executable = load_prebuilt_executable( + &scarb_build_dir, + format!("{}.executable.json", package.name), + )?; + + let data = executable + .program + .bytecode + .iter() + .map(Felt252::from) + .map(MaybeRelocatable::from) + .collect(); + + let (hints, string_to_hint) = build_hints_dict(&executable.program.hints); + + let program = if args.run.target.is_standalone() { + let entrypoint = executable + .entrypoints + .iter() + .find(|e| matches!(e.kind, EntryPointKind::Standalone)) + .with_context(|| "no `Standalone` entrypoint found")?; + Program::new_for_proof( + entrypoint.builtins.clone(), + data, + entrypoint.offset, + entrypoint.offset + 4, + hints, + Default::default(), + Default::default(), + vec![], + None, + ) + } else { + let entrypoint = executable + .entrypoints + .iter() + .find(|e| matches!(e.kind, EntryPointKind::Bootloader)) + .with_context(|| "no `Bootloader` entrypoint found")?; + Program::new( + entrypoint.builtins.clone(), + data, + Some(entrypoint.offset), + hints, + Default::default(), + Default::default(), + vec![], + None, + ) + } + .with_context(|| "failed setting up program")?; + + let mut hint_processor = CairoHintProcessor { + runner: None, + user_args: vec![vec![Arg::Array(args.run.arguments.read_arguments()?)]], + string_to_hint, + starknet_state: Default::default(), + run_resources: Default::default(), + syscalls_used_resources: Default::default(), + no_temporary_segments: false, + }; + + let cairo_run_config = CairoRunConfig { + allow_missing_builtins: Some(true), + layout: LayoutName::all_cairo, + proof_mode: args.run.target.is_standalone(), + secure_run: None, + relocate_mem: args.run.output.is_standard(), + trace_enabled: args.run.output.is_standard(), + ..Default::default() + }; + + let mut runner = cairo_run_program(&program, &cairo_run_config, &mut hint_processor) + .with_context(|| "Cairo program run failed")?; + + if args.run.print_program_output { + let mut output_buffer = "Program output:\n".to_string(); + runner.vm.write_output(&mut output_buffer)?; + ui.print(output_buffer.trim_end()); + } + + let output_dir = scarb_target_dir.join("execute").join(&package.name); + create_output_dir(output_dir.as_std_path())?; + + if args.run.output.is_cairo_pie() { + let output_value = runner.get_cairo_pie()?; + let output_file_path = incremental_create_output_file(&output_dir, ".zip")?; + ui.print(Status::new( + "Saving output to:", + &display_path(&scarb_target_dir, &output_file_path), + )); + output_value.write_zip_file(output_file_path.as_std_path())?; + } else { + let execution_output_dir = incremental_create_output_dir(&output_dir)?; + ui.print(Status::new( + "Saving output to:", + &display_path(&scarb_target_dir, &execution_output_dir), + )); + + // Write trace file. + let trace_path = execution_output_dir.join("trace.bin"); + let relocated_trace = runner + .relocated_trace + .as_ref() + .with_context(|| "trace not relocated")?; + let mut writer = FileWriter::new(3 * 1024 * 1024, &trace_path)?; + cairo_run::write_encoded_trace(relocated_trace, &mut writer)?; + writer.flush()?; + + // Write memory file. + let memory_path = execution_output_dir.join("memory.bin"); + let mut writer = FileWriter::new(5 * 1024 * 1024, &memory_path)?; + cairo_run::write_encoded_memory(&runner.relocated_memory, &mut writer)?; + writer.flush()?; + + // Write air public input file. + let air_public_input_path = execution_output_dir.join("air_public_input.json"); + let json = runner.get_air_public_input()?.serialize_json()?; + fs::write(air_public_input_path, json)?; + + // Write air private input file. + let air_private_input_path = execution_output_dir.join("air_private_input.json"); + let output_value = runner + .get_air_private_input() + .to_serializable(trace_path.to_string(), memory_path.to_string()) + .serialize_json() + .with_context(|| "failed serializing private input")?; + fs::write(air_private_input_path, output_value)?; + } + + Ok(()) +} + +fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { + Utf8PathBuf::from("target") + .join( + output_path + .strip_prefix(scarb_target_dir) + .unwrap_or(output_path), + ) + .to_string() +} + +fn load_prebuilt_executable(path: &Utf8Path, filename: String) -> Result { + let file_path = path.join(&filename); + ensure!( + file_path.exists(), + formatdoc! {r#" + package has not been compiled, file does not exist: `{filename}` + help: run `scarb build` to compile the package + "#} + ); + let file = fs::File::open(&file_path) + .with_context(|| format!("failed to open executable program: `{file_path}`"))?; + serde_json::from_reader(file) + .with_context(|| format!("failed to deserialize executable program: `{file_path}`")) +} + +fn incremental_create_output_file( + path: &Utf8Path, + extension: impl AsRef, +) -> Result { + incremental_attempt_io_creation(path, extension, "failed to create output directory", |p| { + OpenOptions::new() + .write(true) + .create_new(true) + .open(p) + .map(|_| ()) + }) +} + +fn incremental_create_output_dir(path: &Utf8Path) -> Result { + incremental_attempt_io_creation(path, "", "failed to create output directory", |p| { + fs::create_dir(p) + }) +} + +fn incremental_attempt_io_creation( + path: &Utf8Path, + extension: impl AsRef, + final_error_message: impl AsRef, + attempt: impl Fn(&Utf8Path) -> io::Result<()>, +) -> Result { + for i in 1..=MAX_ITERATION_COUNT { + let filepath = path.join(format!("execution{}{}", i, extension.as_ref())); + let result = attempt(&filepath); + return match result { + Err(e) => { + if e.kind() == io::ErrorKind::AlreadyExists { + continue; + } + Err(e.into()) + } + Ok(_) => Ok(filepath), + }; + } + bail!(final_error_message.as_ref().to_string()); +} + +/// Writer implementation for a file. +struct FileWriter { + buf_writer: io::BufWriter, + bytes_written: usize, +} + +impl Writer for FileWriter { + fn write(&mut self, bytes: &[u8]) -> Result<(), bincode::error::EncodeError> { + self.buf_writer + .write_all(bytes) + .map_err(|e| bincode::error::EncodeError::Io { + inner: e, + index: self.bytes_written, + })?; + + self.bytes_written += bytes.len(); + + Ok(()) + } +} + +impl FileWriter { + /// Create a new instance of `FileWriter` with the given file path. + fn new(capacity: usize, path: &Utf8Path) -> Result { + Ok(Self { + buf_writer: io::BufWriter::with_capacity(capacity, fs::File::create(path)?), + bytes_written: 0, + }) + } + + /// Flush the writer. + /// + /// Would automatically be called when the writer is dropped, but errors are ignored in that + /// case. + fn flush(&mut self) -> io::Result<()> { + self.buf_writer.flush() + } +} diff --git a/extensions/scarb-execute/src/main.rs b/extensions/scarb-execute/src/main.rs index 482187324..925bb2b63 100644 --- a/extensions/scarb-execute/src/main.rs +++ b/extensions/scarb-execute/src/main.rs @@ -1,127 +1,9 @@ -use anyhow::{bail, ensure, Context, Result}; -use bincode::enc::write::Writer; -use cairo_lang_executable::executable::{EntryPointKind, Executable}; -use cairo_lang_runner::{build_hints_dict, Arg, CairoHintProcessor}; -use cairo_lang_utils::bigint::BigUintAsHex; -use cairo_vm::cairo_run::cairo_run_program; -use cairo_vm::cairo_run::CairoRunConfig; -use cairo_vm::types::layout_name::LayoutName; -use cairo_vm::types::program::Program; -use cairo_vm::types::relocatable::MaybeRelocatable; -use cairo_vm::{cairo_run, Felt252}; -use camino::{Utf8Path, Utf8PathBuf}; -use clap::{arg, Parser, ValueEnum}; -use create_output_dir::create_output_dir; -use indoc::formatdoc; -use num_bigint::BigInt; -use scarb_metadata::{Metadata, MetadataCommand, ScarbCommand}; -use scarb_ui::args::{PackagesFilter, VerbositySpec}; -use scarb_ui::components::Status; +use clap::Parser; +use scarb_execute::args::Args; +use scarb_execute::main_inner; use scarb_ui::Ui; -use std::env; -use std::fs; -use std::fs::OpenOptions; -use std::io::{self, Write}; use std::process::ExitCode; -const MAX_ITERATION_COUNT: usize = 10000; - -/// Compiles a Cairo project and runs a function marked `#[executable]`. -/// Exits with 1 if the compilation or run fails, otherwise 0. -#[derive(Parser, Clone, Debug)] -#[clap(version, verbatim_doc_comment)] -struct Args { - /// Name of the package. - #[command(flatten)] - packages_filter: PackagesFilter, - - /// Do not rebuild the package. - #[arg(long, default_value_t = false)] - no_build: bool, - - #[clap(flatten)] - run: ExecutionArgs, - - /// Logging verbosity. - #[command(flatten)] - pub verbose: VerbositySpec, -} - -#[derive(Parser, Clone, Debug)] -struct ExecutionArgs { - #[command(flatten)] - pub arguments: ProgramArguments, - - /// Desired execution output, either default Standard or CairoPie - #[arg(long, default_value = "standard")] - pub output: OutputFormat, - - /// Execution target. - #[arg(long, default_value = "standalone")] - target: ExecutionTarget, - - /// Whether to print the program outputs. - #[arg(long, default_value_t = false)] - print_program_output: bool, -} - -#[derive(Parser, Debug, Clone)] -pub struct ProgramArguments { - /// Serialized arguments to the executable function. - #[arg(long, value_delimiter = ',')] - arguments: Vec, - - /// Serialized arguments to the executable function from a file. - #[arg(long, conflicts_with = "arguments")] - arguments_file: Option, -} - -impl ProgramArguments { - pub fn read_arguments(self) -> Result> { - if let Some(path) = self.arguments_file { - let file = fs::File::open(&path).with_context(|| "reading arguments file failed")?; - let as_vec: Vec = serde_json::from_reader(file) - .with_context(|| "deserializing arguments file failed")?; - Ok(as_vec - .into_iter() - .map(|v| Arg::Value(v.value.into())) - .collect()) - } else { - Ok(self - .arguments - .iter() - .map(|v| Arg::Value(v.into())) - .collect()) - } - } -} - -#[derive(ValueEnum, Clone, Debug)] -enum OutputFormat { - CairoPie, - Standard, -} -impl OutputFormat { - pub fn is_standard(&self) -> bool { - matches!(self, OutputFormat::Standard) - } - pub fn is_cairo_pie(&self) -> bool { - matches!(self, OutputFormat::CairoPie) - } -} - -#[derive(ValueEnum, Clone, Debug)] -enum ExecutionTarget { - Bootloader, - Standalone, -} - -impl ExecutionTarget { - pub fn is_standalone(&self) -> bool { - matches!(self, ExecutionTarget::Standalone) - } -} - fn main() -> ExitCode { let args = Args::parse(); let ui = Ui::new(args.verbose.clone().into(), scarb_ui::OutputFormat::Text); @@ -134,261 +16,3 @@ fn main() -> ExitCode { } } } - -fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> { - ensure!( - !(args.run.output.is_cairo_pie() && args.run.target.is_standalone()), - "Cairo pie output format is not supported for standalone execution target" - ); - - let metadata = MetadataCommand::new().inherit_stderr().exec()?; - let package = args.packages_filter.match_one(&metadata)?; - - if !args.no_build { - let filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); - ScarbCommand::new() - .arg("build") - .env("SCARB_PACKAGES_FILTER", filter.to_env()) - .run()?; - } - - let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); - let scarb_build_dir = scarb_target_dir.join(env::var("SCARB_PROFILE")?); - - ui.print(Status::new("Executing", &package.name)); - let executable = load_prebuilt_executable( - &scarb_build_dir, - format!("{}.executable.json", package.name), - )?; - - let data = executable - .program - .bytecode - .iter() - .map(Felt252::from) - .map(MaybeRelocatable::from) - .collect(); - - let (hints, string_to_hint) = build_hints_dict(&executable.program.hints); - - let program = if args.run.target.is_standalone() { - let entrypoint = executable - .entrypoints - .iter() - .find(|e| matches!(e.kind, EntryPointKind::Standalone)) - .with_context(|| "no `Standalone` entrypoint found")?; - Program::new_for_proof( - entrypoint.builtins.clone(), - data, - entrypoint.offset, - entrypoint.offset + 4, - hints, - Default::default(), - Default::default(), - vec![], - None, - ) - } else { - let entrypoint = executable - .entrypoints - .iter() - .find(|e| matches!(e.kind, EntryPointKind::Bootloader)) - .with_context(|| "no `Bootloader` entrypoint found")?; - Program::new( - entrypoint.builtins.clone(), - data, - Some(entrypoint.offset), - hints, - Default::default(), - Default::default(), - vec![], - None, - ) - } - .with_context(|| "failed setting up program")?; - - let mut hint_processor = CairoHintProcessor { - runner: None, - user_args: vec![vec![Arg::Array(args.run.arguments.read_arguments()?)]], - string_to_hint, - starknet_state: Default::default(), - run_resources: Default::default(), - syscalls_used_resources: Default::default(), - no_temporary_segments: false, - }; - - let cairo_run_config = CairoRunConfig { - allow_missing_builtins: Some(true), - layout: LayoutName::all_cairo, - proof_mode: args.run.target.is_standalone(), - secure_run: None, - relocate_mem: args.run.output.is_standard(), - trace_enabled: args.run.output.is_standard(), - ..Default::default() - }; - - let mut runner = cairo_run_program(&program, &cairo_run_config, &mut hint_processor) - .with_context(|| "Cairo program run failed")?; - - if args.run.print_program_output { - let mut output_buffer = "Program output:\n".to_string(); - runner.vm.write_output(&mut output_buffer)?; - ui.print(output_buffer.trim_end()); - } - - let output_dir = scarb_target_dir.join("execute").join(&package.name); - create_output_dir(output_dir.as_std_path())?; - - if args.run.output.is_cairo_pie() { - let output_value = runner.get_cairo_pie()?; - let output_file_path = incremental_create_output_file(&output_dir, ".zip")?; - ui.print(Status::new( - "Saving output to:", - &display_path(&scarb_target_dir, &output_file_path), - )); - output_value.write_zip_file(output_file_path.as_std_path())?; - } else { - let execution_output_dir = incremental_create_output_dir(&output_dir)?; - ui.print(Status::new( - "Saving output to:", - &display_path(&scarb_target_dir, &execution_output_dir), - )); - - // Write trace file. - let trace_path = execution_output_dir.join("trace.bin"); - let relocated_trace = runner - .relocated_trace - .as_ref() - .with_context(|| "trace not relocated")?; - let mut writer = FileWriter::new(3 * 1024 * 1024, &trace_path)?; - cairo_run::write_encoded_trace(relocated_trace, &mut writer)?; - writer.flush()?; - - // Write memory file. - let memory_path = execution_output_dir.join("memory.bin"); - let mut writer = FileWriter::new(5 * 1024 * 1024, &memory_path)?; - cairo_run::write_encoded_memory(&runner.relocated_memory, &mut writer)?; - writer.flush()?; - - // Write air public input file. - let air_public_input_path = execution_output_dir.join("air_public_input.json"); - let json = runner.get_air_public_input()?.serialize_json()?; - fs::write(air_public_input_path, json)?; - - // Write air private input file. - let air_private_input_path = execution_output_dir.join("air_private_input.json"); - let output_value = runner - .get_air_private_input() - .to_serializable(trace_path.to_string(), memory_path.to_string()) - .serialize_json() - .with_context(|| "failed serializing private input")?; - fs::write(air_private_input_path, output_value)?; - } - - Ok(()) -} - -fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { - Utf8PathBuf::from("target") - .join( - output_path - .strip_prefix(scarb_target_dir) - .unwrap_or(output_path), - ) - .to_string() -} - -fn load_prebuilt_executable(path: &Utf8Path, filename: String) -> Result { - let file_path = path.join(&filename); - ensure!( - file_path.exists(), - formatdoc! {r#" - package has not been compiled, file does not exist: `{filename}` - help: run `scarb build` to compile the package - "#} - ); - let file = fs::File::open(&file_path) - .with_context(|| format!("failed to open executable program: `{file_path}`"))?; - serde_json::from_reader(file) - .with_context(|| format!("failed to deserialize executable program: `{file_path}`")) -} - -fn incremental_create_output_file( - path: &Utf8Path, - extension: impl AsRef, -) -> Result { - incremental_attempt_io_creation(path, extension, "failed to create output directory", |p| { - OpenOptions::new() - .write(true) - .create_new(true) - .open(p) - .map(|_| ()) - }) -} - -fn incremental_create_output_dir(path: &Utf8Path) -> Result { - incremental_attempt_io_creation(path, "", "failed to create output directory", |p| { - fs::create_dir(p) - }) -} - -fn incremental_attempt_io_creation( - path: &Utf8Path, - extension: impl AsRef, - final_error_message: impl AsRef, - attempt: impl Fn(&Utf8Path) -> io::Result<()>, -) -> Result { - for i in 1..=MAX_ITERATION_COUNT { - let filepath = path.join(format!("execution{}{}", i, extension.as_ref())); - let result = attempt(&filepath); - return match result { - Err(e) => { - if e.kind() == io::ErrorKind::AlreadyExists { - continue; - } - Err(e.into()) - } - Ok(_) => Ok(filepath), - }; - } - bail!(final_error_message.as_ref().to_string()); -} - -/// Writer implementation for a file. -struct FileWriter { - buf_writer: io::BufWriter, - bytes_written: usize, -} - -impl Writer for FileWriter { - fn write(&mut self, bytes: &[u8]) -> Result<(), bincode::error::EncodeError> { - self.buf_writer - .write_all(bytes) - .map_err(|e| bincode::error::EncodeError::Io { - inner: e, - index: self.bytes_written, - })?; - - self.bytes_written += bytes.len(); - - Ok(()) - } -} - -impl FileWriter { - /// Create a new instance of `FileWriter` with the given file path. - fn new(capacity: usize, path: &Utf8Path) -> Result { - Ok(Self { - buf_writer: io::BufWriter::with_capacity(capacity, fs::File::create(path)?), - bytes_written: 0, - }) - } - - /// Flush the writer. - /// - /// Would automatically be called when the writer is dropped, but errors are ignored in that - /// case. - fn flush(&mut self) -> io::Result<()> { - self.buf_writer.flush() - } -} From a969fce39603df25cee3b5d191a2db49f4eaaab2 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 16:08:36 +0100 Subject: [PATCH 56/71] split scarb-execute into subfiles --- extensions/scarb-execute/src/args.rs | 104 +++++++ extensions/scarb-execute/src/lib.rs | 300 ++++++++++++++++++++ extensions/scarb-execute/src/main.rs | 400 +-------------------------- 3 files changed, 407 insertions(+), 397 deletions(-) create mode 100644 extensions/scarb-execute/src/args.rs create mode 100644 extensions/scarb-execute/src/lib.rs diff --git a/extensions/scarb-execute/src/args.rs b/extensions/scarb-execute/src/args.rs new file mode 100644 index 000000000..2c0747f09 --- /dev/null +++ b/extensions/scarb-execute/src/args.rs @@ -0,0 +1,104 @@ +use anyhow::{Context, Result}; +use cairo_lang_runner::Arg; +use cairo_lang_utils::bigint::BigUintAsHex; +use camino::Utf8PathBuf; +use clap::{arg, Parser, ValueEnum}; +use num_bigint::BigInt; +use scarb_ui::args::{PackagesFilter, VerbositySpec}; +use std::fs; + +/// Compiles a Cairo project and runs a function marked `#[executable]`. +/// Exits with 1 if the compilation or run fails, otherwise 0. +#[derive(Parser, Clone, Debug)] +#[clap(version, verbatim_doc_comment)] +pub struct Args { + /// Name of the package. + #[command(flatten)] + pub packages_filter: PackagesFilter, + + /// Do not rebuild the package. + #[arg(long, default_value_t = false)] + pub no_build: bool, + + #[clap(flatten)] + pub run: ExecutionArgs, + + /// Logging verbosity. + #[command(flatten)] + pub verbose: VerbositySpec, +} + +#[derive(Parser, Clone, Debug)] +pub struct ExecutionArgs { + #[command(flatten)] + pub arguments: ProgramArguments, + + /// Desired execution output, either default Standard or CairoPie + #[arg(long, default_value = "standard")] + pub output: OutputFormat, + + /// Execution target. + #[arg(long, default_value = "standalone")] + pub target: ExecutionTarget, + + /// Whether to print the program outputs. + #[arg(long, default_value_t = false)] + pub print_program_output: bool, +} + +#[derive(Parser, Debug, Clone)] +pub struct ProgramArguments { + /// Serialized arguments to the executable function. + #[arg(long, value_delimiter = ',')] + pub arguments: Vec, + + /// Serialized arguments to the executable function from a file. + #[arg(long, conflicts_with = "arguments")] + pub arguments_file: Option, +} + +impl ProgramArguments { + pub fn read_arguments(self) -> Result> { + if let Some(path) = self.arguments_file { + let file = fs::File::open(&path).with_context(|| "reading arguments file failed")?; + let as_vec: Vec = serde_json::from_reader(file) + .with_context(|| "deserializing arguments file failed")?; + Ok(as_vec + .into_iter() + .map(|v| Arg::Value(v.value.into())) + .collect()) + } else { + Ok(self + .arguments + .iter() + .map(|v| Arg::Value(v.into())) + .collect()) + } + } +} + +#[derive(ValueEnum, Clone, Debug)] +pub enum OutputFormat { + CairoPie, + Standard, +} +impl OutputFormat { + pub fn is_standard(&self) -> bool { + matches!(self, OutputFormat::Standard) + } + pub fn is_cairo_pie(&self) -> bool { + matches!(self, OutputFormat::CairoPie) + } +} + +#[derive(ValueEnum, Clone, Debug)] +pub enum ExecutionTarget { + Bootloader, + Standalone, +} + +impl ExecutionTarget { + pub fn is_standalone(&self) -> bool { + matches!(self, ExecutionTarget::Standalone) + } +} diff --git a/extensions/scarb-execute/src/lib.rs b/extensions/scarb-execute/src/lib.rs new file mode 100644 index 000000000..dc2d491ab --- /dev/null +++ b/extensions/scarb-execute/src/lib.rs @@ -0,0 +1,300 @@ +use anyhow::{bail, ensure, Context, Result}; +use bincode::enc::write::Writer; +use cairo_lang_executable::executable::{EntryPointKind, Executable}; +use cairo_lang_runner::{build_hints_dict, Arg, CairoHintProcessor}; +use cairo_vm::cairo_run::cairo_run_program; +use cairo_vm::cairo_run::CairoRunConfig; +use cairo_vm::types::layout_name::LayoutName; +use cairo_vm::types::program::Program; +use cairo_vm::types::relocatable::MaybeRelocatable; +use cairo_vm::{cairo_run, Felt252}; +use camino::{Utf8Path, Utf8PathBuf}; +use create_output_dir::create_output_dir; +use indoc::formatdoc; +use scarb_metadata::{Metadata, MetadataCommand, ScarbCommand}; +use scarb_ui::args::PackagesFilter; +use scarb_ui::components::Status; +use scarb_ui::Ui; +use std::env; +use std::fs; +use std::fs::OpenOptions; +use std::io::{self, Write}; + +pub mod args; +const MAX_ITERATION_COUNT: usize = 10000; + +pub fn main_inner(args: args::Args, ui: Ui) -> Result<(), anyhow::Error> { + ensure!( + !(args.run.output.is_cairo_pie() && args.run.target.is_standalone()), + "Cairo pie output format is not supported for standalone execution target" + ); + + let metadata = MetadataCommand::new().inherit_stderr().exec()?; + let package = args.packages_filter.match_one(&metadata)?; + + if !args.no_build { + let filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); + ScarbCommand::new() + .arg("build") + .env("SCARB_PACKAGES_FILTER", filter.to_env()) + .run()?; + } + + let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); + let scarb_build_dir = scarb_target_dir.join(env::var("SCARB_PROFILE")?); + + ui.print(Status::new("Executing", &package.name)); + let executable = load_prebuilt_executable( + &scarb_build_dir, + format!("{}.executable.json", package.name), + )?; + + let data = executable + .program + .bytecode + .iter() + .map(Felt252::from) + .map(MaybeRelocatable::from) + .collect(); + + let (hints, string_to_hint) = build_hints_dict(&executable.program.hints); + + let program = if args.run.target.is_standalone() { + let entrypoint = executable + .entrypoints + .iter() + .find(|e| matches!(e.kind, EntryPointKind::Standalone)) + .with_context(|| "no `Standalone` entrypoint found")?; + Program::new_for_proof( + entrypoint.builtins.clone(), + data, + entrypoint.offset, + entrypoint.offset + 4, + hints, + Default::default(), + Default::default(), + vec![], + None, + ) + } else { + let entrypoint = executable + .entrypoints + .iter() + .find(|e| matches!(e.kind, EntryPointKind::Bootloader)) + .with_context(|| "no `Bootloader` entrypoint found")?; + Program::new( + entrypoint.builtins.clone(), + data, + Some(entrypoint.offset), + hints, + Default::default(), + Default::default(), + vec![], + None, + ) + } + .with_context(|| "failed setting up program")?; + + let mut hint_processor = CairoHintProcessor { + runner: None, + user_args: vec![vec![Arg::Array(args.run.arguments.read_arguments()?)]], + string_to_hint, + starknet_state: Default::default(), + run_resources: Default::default(), + syscalls_used_resources: Default::default(), + no_temporary_segments: false, + }; + + let cairo_run_config = CairoRunConfig { + allow_missing_builtins: Some(true), + layout: LayoutName::all_cairo, + proof_mode: args.run.target.is_standalone(), + secure_run: None, + relocate_mem: args.run.output.is_standard(), + trace_enabled: args.run.output.is_standard(), + ..Default::default() + }; + + let mut runner = cairo_run_program(&program, &cairo_run_config, &mut hint_processor) + .with_context(|| "Cairo program run failed")?; + + if args.run.print_program_output { + let mut output_buffer = "Program output:\n".to_string(); + runner.vm.write_output(&mut output_buffer)?; + ui.print(output_buffer.trim_end()); + } + + let output_dir = scarb_target_dir.join("execute"); + create_output_dir(output_dir.as_std_path())?; + + if args.run.output.is_cairo_pie() { + let output_value = runner.get_cairo_pie()?; + let output_file_path = incremental_create_output_file(&output_dir, package.name, ".zip")?; + ui.print(Status::new( + "Saving output to:", + &display_path(&scarb_target_dir, &output_file_path), + )); + output_value.write_zip_file(output_file_path.as_std_path())?; + } else { + let execution_output_dir = incremental_create_output_dir(&output_dir, package.name)?; + ui.print(Status::new( + "Saving output to:", + &display_path(&scarb_target_dir, &execution_output_dir), + )); + + // Write trace file. + let trace_path = execution_output_dir.join("trace.bin"); + let relocated_trace = runner + .relocated_trace + .as_ref() + .with_context(|| "trace not relocated")?; + let mut writer = FileWriter::new(3 * 1024 * 1024, &trace_path)?; + cairo_run::write_encoded_trace(relocated_trace, &mut writer)?; + writer.flush()?; + + // Write memory file. + let memory_path = execution_output_dir.join("memory.bin"); + let mut writer = FileWriter::new(5 * 1024 * 1024, &memory_path)?; + cairo_run::write_encoded_memory(&runner.relocated_memory, &mut writer)?; + writer.flush()?; + + // Write air public input file. + let air_public_input_path = execution_output_dir.join("air_public_input.json"); + let json = runner.get_air_public_input()?.serialize_json()?; + fs::write(air_public_input_path, json)?; + + // Write air private input file. + let air_private_input_path = execution_output_dir.join("air_private_input.json"); + let output_value = runner + .get_air_private_input() + .to_serializable(trace_path.to_string(), memory_path.to_string()) + .serialize_json() + .with_context(|| "failed serializing private input")?; + fs::write(air_private_input_path, output_value)?; + } + + Ok(()) +} + +fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { + Utf8PathBuf::from("target") + .join( + output_path + .strip_prefix(scarb_target_dir) + .unwrap_or(output_path), + ) + .to_string() +} + +fn load_prebuilt_executable(path: &Utf8Path, filename: String) -> Result { + let file_path = path.join(&filename); + ensure!( + file_path.exists(), + formatdoc! {r#" + package has not been compiled, file does not exist: `{filename}` + help: run `scarb build` to compile the package + "#} + ); + let file = fs::File::open(&file_path) + .with_context(|| format!("failed to open executable program: `{file_path}`"))?; + serde_json::from_reader(file) + .with_context(|| format!("failed to deserialize executable program: `{file_path}`")) +} + +fn incremental_create_output_file( + path: &Utf8Path, + name: String, + extension: impl AsRef, +) -> Result { + incremental_attempt_io_creation( + path, + name, + extension, + "failed to create output directory", + |p| { + OpenOptions::new() + .write(true) + .create_new(true) + .open(p) + .map(|_| ()) + }, + ) +} + +fn incremental_create_output_dir(path: &Utf8Path, name: String) -> anyhow::Result { + incremental_attempt_io_creation(path, name, "", "failed to create output directory", |p| { + fs::create_dir(p) + }) +} + +fn incremental_attempt_io_creation( + path: &Utf8Path, + name: impl AsRef, + extension: impl AsRef, + final_error_message: impl AsRef, + attempt: impl Fn(&Utf8Path) -> io::Result<()>, +) -> anyhow::Result { + for i in 0..MAX_ITERATION_COUNT { + let number_string = if i == 0 { + "".to_string() + } else { + format!("_{}", i) + }; + let filepath = path.join(format!( + "{}{}{}", + name.as_ref(), + number_string, + extension.as_ref() + )); + let result = attempt(&filepath); + return match result { + Err(e) => { + if e.kind() == io::ErrorKind::AlreadyExists { + continue; + } + Err(e.into()) + } + Ok(_) => Ok(filepath), + }; + } + bail!(final_error_message.as_ref().to_string()); +} + +/// Writer implementation for a file. +struct FileWriter { + buf_writer: io::BufWriter, + bytes_written: usize, +} + +impl Writer for FileWriter { + fn write(&mut self, bytes: &[u8]) -> Result<(), bincode::error::EncodeError> { + self.buf_writer + .write_all(bytes) + .map_err(|e| bincode::error::EncodeError::Io { + inner: e, + index: self.bytes_written, + })?; + + self.bytes_written += bytes.len(); + + Ok(()) + } +} + +impl FileWriter { + /// Create a new instance of `FileWriter` with the given file path. + fn new(capacity: usize, path: &Utf8Path) -> Result { + Ok(Self { + buf_writer: io::BufWriter::with_capacity(capacity, fs::File::create(path)?), + bytes_written: 0, + }) + } + + /// Flush the writer. + /// + /// Would automatically be called when the writer is dropped, but errors are ignored in that + /// case. + fn flush(&mut self) -> io::Result<()> { + self.buf_writer.flush() + } +} diff --git a/extensions/scarb-execute/src/main.rs b/extensions/scarb-execute/src/main.rs index e9c7bbe33..925bb2b63 100644 --- a/extensions/scarb-execute/src/main.rs +++ b/extensions/scarb-execute/src/main.rs @@ -1,127 +1,9 @@ -use anyhow::{bail, ensure, Context, Result}; -use bincode::enc::write::Writer; -use cairo_lang_executable::executable::{EntryPointKind, Executable}; -use cairo_lang_runner::{build_hints_dict, Arg, CairoHintProcessor}; -use cairo_lang_utils::bigint::BigUintAsHex; -use cairo_vm::cairo_run::cairo_run_program; -use cairo_vm::cairo_run::CairoRunConfig; -use cairo_vm::types::layout_name::LayoutName; -use cairo_vm::types::program::Program; -use cairo_vm::types::relocatable::MaybeRelocatable; -use cairo_vm::{cairo_run, Felt252}; -use camino::{Utf8Path, Utf8PathBuf}; -use clap::{arg, Parser, ValueEnum}; -use create_output_dir::create_output_dir; -use indoc::formatdoc; -use num_bigint::BigInt; -use scarb_metadata::{Metadata, MetadataCommand, ScarbCommand}; -use scarb_ui::args::{PackagesFilter, VerbositySpec}; -use scarb_ui::components::Status; +use clap::Parser; +use scarb_execute::args::Args; +use scarb_execute::main_inner; use scarb_ui::Ui; -use std::env; -use std::fs; -use std::fs::OpenOptions; -use std::io::{self, Write}; use std::process::ExitCode; -const MAX_ITERATION_COUNT: usize = 10000; - -/// Compiles a Cairo project and runs a function marked `#[executable]`. -/// Exits with 1 if the compilation or run fails, otherwise 0. -#[derive(Parser, Clone, Debug)] -#[clap(version, verbatim_doc_comment)] -struct Args { - /// Name of the package. - #[command(flatten)] - packages_filter: PackagesFilter, - - /// Do not rebuild the package. - #[arg(long, default_value_t = false)] - no_build: bool, - - #[clap(flatten)] - run: ExecutionArgs, - - /// Logging verbosity. - #[command(flatten)] - pub verbose: VerbositySpec, -} - -#[derive(Parser, Clone, Debug)] -struct ExecutionArgs { - #[command(flatten)] - pub arguments: ProgramArguments, - - /// Desired execution output, either default Standard or CairoPie - #[arg(long, default_value = "standard")] - pub output: OutputFormat, - - /// Execution target. - #[arg(long, default_value = "standalone")] - target: ExecutionTarget, - - /// Whether to print the program outputs. - #[arg(long, default_value_t = false)] - print_program_output: bool, -} - -#[derive(Parser, Debug, Clone)] -pub struct ProgramArguments { - /// Serialized arguments to the executable function. - #[arg(long, value_delimiter = ',')] - arguments: Vec, - - /// Serialized arguments to the executable function from a file. - #[arg(long, conflicts_with = "arguments")] - arguments_file: Option, -} - -impl ProgramArguments { - pub fn read_arguments(self) -> Result> { - if let Some(path) = self.arguments_file { - let file = fs::File::open(&path).with_context(|| "reading arguments file failed")?; - let as_vec: Vec = serde_json::from_reader(file) - .with_context(|| "deserializing arguments file failed")?; - Ok(as_vec - .into_iter() - .map(|v| Arg::Value(v.value.into())) - .collect()) - } else { - Ok(self - .arguments - .iter() - .map(|v| Arg::Value(v.into())) - .collect()) - } - } -} - -#[derive(ValueEnum, Clone, Debug)] -enum OutputFormat { - CairoPie, - Standard, -} -impl OutputFormat { - pub fn is_standard(&self) -> bool { - matches!(self, OutputFormat::Standard) - } - pub fn is_cairo_pie(&self) -> bool { - matches!(self, OutputFormat::CairoPie) - } -} - -#[derive(ValueEnum, Clone, Debug)] -enum ExecutionTarget { - Bootloader, - Standalone, -} - -impl ExecutionTarget { - pub fn is_standalone(&self) -> bool { - matches!(self, ExecutionTarget::Standalone) - } -} - fn main() -> ExitCode { let args = Args::parse(); let ui = Ui::new(args.verbose.clone().into(), scarb_ui::OutputFormat::Text); @@ -134,279 +16,3 @@ fn main() -> ExitCode { } } } - -fn main_inner(args: Args, ui: Ui) -> Result<(), anyhow::Error> { - ensure!( - !(args.run.output.is_cairo_pie() && args.run.target.is_standalone()), - "Cairo pie output format is not supported for standalone execution target" - ); - - let metadata = MetadataCommand::new().inherit_stderr().exec()?; - let package = args.packages_filter.match_one(&metadata)?; - - if !args.no_build { - let filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); - ScarbCommand::new() - .arg("build") - .env("SCARB_PACKAGES_FILTER", filter.to_env()) - .run()?; - } - - let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); - let scarb_build_dir = scarb_target_dir.join(env::var("SCARB_PROFILE")?); - - ui.print(Status::new("Executing", &package.name)); - let executable = load_prebuilt_executable( - &scarb_build_dir, - format!("{}.executable.json", package.name), - )?; - - let data = executable - .program - .bytecode - .iter() - .map(Felt252::from) - .map(MaybeRelocatable::from) - .collect(); - - let (hints, string_to_hint) = build_hints_dict(&executable.program.hints); - - let program = if args.run.target.is_standalone() { - let entrypoint = executable - .entrypoints - .iter() - .find(|e| matches!(e.kind, EntryPointKind::Standalone)) - .with_context(|| "no `Standalone` entrypoint found")?; - Program::new_for_proof( - entrypoint.builtins.clone(), - data, - entrypoint.offset, - entrypoint.offset + 4, - hints, - Default::default(), - Default::default(), - vec![], - None, - ) - } else { - let entrypoint = executable - .entrypoints - .iter() - .find(|e| matches!(e.kind, EntryPointKind::Bootloader)) - .with_context(|| "no `Bootloader` entrypoint found")?; - Program::new( - entrypoint.builtins.clone(), - data, - Some(entrypoint.offset), - hints, - Default::default(), - Default::default(), - vec![], - None, - ) - } - .with_context(|| "failed setting up program")?; - - let mut hint_processor = CairoHintProcessor { - runner: None, - user_args: vec![vec![Arg::Array(args.run.arguments.read_arguments()?)]], - string_to_hint, - starknet_state: Default::default(), - run_resources: Default::default(), - syscalls_used_resources: Default::default(), - no_temporary_segments: false, - }; - - let cairo_run_config = CairoRunConfig { - allow_missing_builtins: Some(true), - layout: LayoutName::all_cairo, - proof_mode: args.run.target.is_standalone(), - secure_run: None, - relocate_mem: args.run.output.is_standard(), - trace_enabled: args.run.output.is_standard(), - ..Default::default() - }; - - let mut runner = cairo_run_program(&program, &cairo_run_config, &mut hint_processor) - .with_context(|| "Cairo program run failed")?; - - if args.run.print_program_output { - let mut output_buffer = "Program output:\n".to_string(); - runner.vm.write_output(&mut output_buffer)?; - ui.print(output_buffer.trim_end()); - } - - let output_dir = scarb_target_dir.join("execute"); - create_output_dir(output_dir.as_std_path())?; - - if args.run.output.is_cairo_pie() { - let output_value = runner.get_cairo_pie()?; - let output_file_path = incremental_create_output_file(&output_dir, package.name, ".zip")?; - ui.print(Status::new( - "Saving output to:", - &display_path(&scarb_target_dir, &output_file_path), - )); - output_value.write_zip_file(output_file_path.as_std_path())?; - } else { - let execution_output_dir = incremental_create_output_dir(&output_dir, package.name)?; - ui.print(Status::new( - "Saving output to:", - &display_path(&scarb_target_dir, &execution_output_dir), - )); - - // Write trace file. - let trace_path = execution_output_dir.join("trace.bin"); - let relocated_trace = runner - .relocated_trace - .as_ref() - .with_context(|| "trace not relocated")?; - let mut writer = FileWriter::new(3 * 1024 * 1024, &trace_path)?; - cairo_run::write_encoded_trace(relocated_trace, &mut writer)?; - writer.flush()?; - - // Write memory file. - let memory_path = execution_output_dir.join("memory.bin"); - let mut writer = FileWriter::new(5 * 1024 * 1024, &memory_path)?; - cairo_run::write_encoded_memory(&runner.relocated_memory, &mut writer)?; - writer.flush()?; - - // Write air public input file. - let air_public_input_path = execution_output_dir.join("air_public_input.json"); - let json = runner.get_air_public_input()?.serialize_json()?; - fs::write(air_public_input_path, json)?; - - // Write air private input file. - let air_private_input_path = execution_output_dir.join("air_private_input.json"); - let output_value = runner - .get_air_private_input() - .to_serializable(trace_path.to_string(), memory_path.to_string()) - .serialize_json() - .with_context(|| "failed serializing private input")?; - fs::write(air_private_input_path, output_value)?; - } - - Ok(()) -} - -fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { - Utf8PathBuf::from("target") - .join( - output_path - .strip_prefix(scarb_target_dir) - .unwrap_or(output_path), - ) - .to_string() -} - -fn load_prebuilt_executable(path: &Utf8Path, filename: String) -> Result { - let file_path = path.join(&filename); - ensure!( - file_path.exists(), - formatdoc! {r#" - package has not been compiled, file does not exist: `{filename}` - help: run `scarb build` to compile the package - "#} - ); - let file = fs::File::open(&file_path) - .with_context(|| format!("failed to open executable program: `{file_path}`"))?; - serde_json::from_reader(file) - .with_context(|| format!("failed to deserialize executable program: `{file_path}`")) -} - -fn incremental_create_output_file( - path: &Utf8Path, - name: String, - extension: impl AsRef, -) -> Result { - incremental_attempt_io_creation( - path, - name, - extension, - "failed to create output directory", - |p| { - OpenOptions::new() - .write(true) - .create_new(true) - .open(p) - .map(|_| ()) - }, - ) -} - -fn incremental_create_output_dir(path: &Utf8Path, name: String) -> Result { - incremental_attempt_io_creation(path, name, "", "failed to create output directory", |p| { - fs::create_dir(p) - }) -} - -fn incremental_attempt_io_creation( - path: &Utf8Path, - name: impl AsRef, - extension: impl AsRef, - final_error_message: impl AsRef, - attempt: impl Fn(&Utf8Path) -> io::Result<()>, -) -> Result { - for i in 0..MAX_ITERATION_COUNT { - let number_string = if i == 0 { - "".to_string() - } else { - format!("_{}", i) - }; - let filepath = path.join(format!( - "{}{}{}", - name.as_ref(), - number_string, - extension.as_ref() - )); - let result = attempt(&filepath); - return match result { - Err(e) => { - if e.kind() == io::ErrorKind::AlreadyExists { - continue; - } - Err(e.into()) - } - Ok(_) => Ok(filepath), - }; - } - bail!(final_error_message.as_ref().to_string()); -} - -/// Writer implementation for a file. -struct FileWriter { - buf_writer: io::BufWriter, - bytes_written: usize, -} - -impl Writer for FileWriter { - fn write(&mut self, bytes: &[u8]) -> Result<(), bincode::error::EncodeError> { - self.buf_writer - .write_all(bytes) - .map_err(|e| bincode::error::EncodeError::Io { - inner: e, - index: self.bytes_written, - })?; - - self.bytes_written += bytes.len(); - - Ok(()) - } -} - -impl FileWriter { - /// Create a new instance of `FileWriter` with the given file path. - fn new(capacity: usize, path: &Utf8Path) -> Result { - Ok(Self { - buf_writer: io::BufWriter::with_capacity(capacity, fs::File::create(path)?), - bytes_written: 0, - }) - } - - /// Flush the writer. - /// - /// Would automatically be called when the writer is dropped, but errors are ignored in that - /// case. - fn flush(&mut self) -> io::Result<()> { - self.buf_writer.flush() - } -} From cef46014736609f52283c3b349a8a33ceb9156b5 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 16:27:50 +0100 Subject: [PATCH 57/71] refactor `execute` args --- extensions/scarb-execute/src/args.rs | 18 ++++++++++++------ extensions/scarb-execute/src/lib.rs | 20 +++++++++++--------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/extensions/scarb-execute/src/args.rs b/extensions/scarb-execute/src/args.rs index 2c0747f09..838e18e7c 100644 --- a/extensions/scarb-execute/src/args.rs +++ b/extensions/scarb-execute/src/args.rs @@ -16,12 +16,8 @@ pub struct Args { #[command(flatten)] pub packages_filter: PackagesFilter, - /// Do not rebuild the package. - #[arg(long, default_value_t = false)] - pub no_build: bool, - - #[clap(flatten)] - pub run: ExecutionArgs, + #[command(flatten)] + pub execution: ExecutionArgs, /// Logging verbosity. #[command(flatten)] @@ -30,6 +26,16 @@ pub struct Args { #[derive(Parser, Clone, Debug)] pub struct ExecutionArgs { + /// Do not rebuild the package. + #[arg(long, default_value_t = false)] + pub no_build: bool, + + #[command(flatten)] + pub run: RunArgs, +} + +#[derive(Parser, Clone, Debug)] +pub struct RunArgs { #[command(flatten)] pub arguments: ProgramArguments, diff --git a/extensions/scarb-execute/src/lib.rs b/extensions/scarb-execute/src/lib.rs index a60e63c58..e18a3e350 100644 --- a/extensions/scarb-execute/src/lib.rs +++ b/extensions/scarb-execute/src/lib.rs @@ -25,14 +25,14 @@ const MAX_ITERATION_COUNT: usize = 10000; pub fn main_inner(args: args::Args, ui: Ui) -> Result<(), anyhow::Error> { ensure!( - !(args.run.output.is_cairo_pie() && args.run.target.is_standalone()), + !(args.execution.run.output.is_cairo_pie() && args.execution.run.target.is_standalone()), "Cairo pie output format is not supported for standalone execution target" ); let metadata = MetadataCommand::new().inherit_stderr().exec()?; let package = args.packages_filter.match_one(&metadata)?; - if !args.no_build { + if !args.execution.no_build { let filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); ScarbCommand::new() .arg("build") @@ -59,7 +59,7 @@ pub fn main_inner(args: args::Args, ui: Ui) -> Result<(), anyhow::Error> { let (hints, string_to_hint) = build_hints_dict(&executable.program.hints); - let program = if args.run.target.is_standalone() { + let program = if args.execution.run.target.is_standalone() { let entrypoint = executable .entrypoints .iter() @@ -97,7 +97,9 @@ pub fn main_inner(args: args::Args, ui: Ui) -> Result<(), anyhow::Error> { let mut hint_processor = CairoHintProcessor { runner: None, - user_args: vec![vec![Arg::Array(args.run.arguments.read_arguments()?)]], + user_args: vec![vec![Arg::Array( + args.execution.run.arguments.read_arguments()?, + )]], string_to_hint, starknet_state: Default::default(), run_resources: Default::default(), @@ -108,17 +110,17 @@ pub fn main_inner(args: args::Args, ui: Ui) -> Result<(), anyhow::Error> { let cairo_run_config = CairoRunConfig { allow_missing_builtins: Some(true), layout: LayoutName::all_cairo, - proof_mode: args.run.target.is_standalone(), + proof_mode: args.execution.run.target.is_standalone(), secure_run: None, - relocate_mem: args.run.output.is_standard(), - trace_enabled: args.run.output.is_standard(), + relocate_mem: args.execution.run.output.is_standard(), + trace_enabled: args.execution.run.output.is_standard(), ..Default::default() }; let mut runner = cairo_run_program(&program, &cairo_run_config, &mut hint_processor) .with_context(|| "Cairo program run failed")?; - if args.run.print_program_output { + if args.execution.run.print_program_output { let mut output_buffer = "Program output:\n".to_string(); runner.vm.write_output(&mut output_buffer)?; ui.print(output_buffer.trim_end()); @@ -127,7 +129,7 @@ pub fn main_inner(args: args::Args, ui: Ui) -> Result<(), anyhow::Error> { let output_dir = scarb_target_dir.join("execute").join(&package.name); create_output_dir(output_dir.as_std_path())?; - if args.run.output.is_cairo_pie() { + if args.execution.run.output.is_cairo_pie() { let output_value = runner.get_cairo_pie()?; let output_file_path = incremental_create_output_file(&output_dir, ".zip")?; ui.print(Status::new( From 50482edf4dc60553c6a4f0b03ee3a3096f11b018 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 16:54:21 +0100 Subject: [PATCH 58/71] update scarb-execute::main_inner to return execution_id --- extensions/scarb-execute/src/lib.rs | 19 ++++++++++--------- extensions/scarb-execute/src/main.rs | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/extensions/scarb-execute/src/lib.rs b/extensions/scarb-execute/src/lib.rs index e18a3e350..37f4aa5fb 100644 --- a/extensions/scarb-execute/src/lib.rs +++ b/extensions/scarb-execute/src/lib.rs @@ -23,7 +23,7 @@ use std::io::{self, Write}; pub mod args; const MAX_ITERATION_COUNT: usize = 10000; -pub fn main_inner(args: args::Args, ui: Ui) -> Result<(), anyhow::Error> { +pub fn main_inner(args: args::Args, ui: Ui) -> Result { ensure!( !(args.execution.run.output.is_cairo_pie() && args.execution.run.target.is_standalone()), "Cairo pie output format is not supported for standalone execution target" @@ -131,14 +131,15 @@ pub fn main_inner(args: args::Args, ui: Ui) -> Result<(), anyhow::Error> { if args.execution.run.output.is_cairo_pie() { let output_value = runner.get_cairo_pie()?; - let output_file_path = incremental_create_output_file(&output_dir, ".zip")?; + let (output_file_path, execution_id) = incremental_create_output_file(&output_dir, ".zip")?; ui.print(Status::new( "Saving output to:", &display_path(&scarb_target_dir, &output_file_path), )); output_value.write_zip_file(output_file_path.as_std_path())?; + Ok(execution_id) } else { - let execution_output_dir = incremental_create_output_dir(&output_dir)?; + let (execution_output_dir, execution_id) = incremental_create_output_dir(&output_dir)?; ui.print(Status::new( "Saving output to:", &display_path(&scarb_target_dir, &execution_output_dir), @@ -173,9 +174,9 @@ pub fn main_inner(args: args::Args, ui: Ui) -> Result<(), anyhow::Error> { .serialize_json() .with_context(|| "failed serializing private input")?; fs::write(air_private_input_path, output_value)?; - } - Ok(()) + Ok(execution_id) + } } fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { @@ -206,7 +207,7 @@ fn load_prebuilt_executable(path: &Utf8Path, filename: String) -> Result, -) -> Result { +) -> Result<(Utf8PathBuf, usize)> { incremental_attempt_io_creation(path, extension, "failed to create output directory", |p| { OpenOptions::new() .write(true) @@ -216,7 +217,7 @@ fn incremental_create_output_file( }) } -fn incremental_create_output_dir(path: &Utf8Path) -> Result { +fn incremental_create_output_dir(path: &Utf8Path) -> Result<(Utf8PathBuf, usize)> { incremental_attempt_io_creation(path, "", "failed to create output directory", |p| { fs::create_dir(p) }) @@ -227,7 +228,7 @@ fn incremental_attempt_io_creation( extension: impl AsRef, final_error_message: impl AsRef, attempt: impl Fn(&Utf8Path) -> io::Result<()>, -) -> Result { +) -> Result<(Utf8PathBuf, usize)> { for i in 1..=MAX_ITERATION_COUNT { let filepath = path.join(format!("execution{}{}", i, extension.as_ref())); let result = attempt(&filepath); @@ -238,7 +239,7 @@ fn incremental_attempt_io_creation( } Err(e.into()) } - Ok(_) => Ok(filepath), + Ok(_) => Ok((filepath, i)), }; } bail!(final_error_message.as_ref().to_string()); diff --git a/extensions/scarb-execute/src/main.rs b/extensions/scarb-execute/src/main.rs index 925bb2b63..a8726715d 100644 --- a/extensions/scarb-execute/src/main.rs +++ b/extensions/scarb-execute/src/main.rs @@ -9,7 +9,7 @@ fn main() -> ExitCode { let ui = Ui::new(args.verbose.clone().into(), scarb_ui::OutputFormat::Text); match main_inner(args, ui.clone()) { - Ok(()) => ExitCode::SUCCESS, + Ok(_execution_id) => ExitCode::SUCCESS, Err(error) => { ui.error(format!("{error:#}")); ExitCode::FAILURE From cdac8544d40ab5ae01b90d522b4c2e169f551a62 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 16:54:52 +0100 Subject: [PATCH 59/71] call scarb-execute directly in scarb-prove to retireve execution_id --- Cargo.lock | 1 + extensions/scarb-prove/Cargo.toml | 1 + extensions/scarb-prove/src/main.rs | 92 +++++++----------------------- 3 files changed, 22 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f0185e67c..91996e7a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5924,6 +5924,7 @@ dependencies = [ "create-output-dir", "indoc", "predicates", + "scarb-execute", "scarb-metadata 1.13.0", "scarb-test-support", "scarb-ui", diff --git a/extensions/scarb-prove/Cargo.toml b/extensions/scarb-prove/Cargo.toml index 48ec2d68b..564d35164 100644 --- a/extensions/scarb-prove/Cargo.toml +++ b/extensions/scarb-prove/Cargo.toml @@ -24,6 +24,7 @@ stwo_cairo_prover = { git = "https://github.com/starkware-libs/stwo-cairo", rev stwo-prover = { git = "https://github.com/starkware-libs/stwo", rev = "af5475cb", features = [ "parallel", ] } +scarb-execute = { path = "../scarb-execute" } [dev-dependencies] assert_fs.workspace = true diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 0b35f2c0c..5681252e0 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -1,12 +1,13 @@ -use anyhow::{anyhow, ensure, Context, Result}; +use anyhow::{ensure, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use clap::Parser; use create_output_dir::create_output_dir; use indoc::formatdoc; -use scarb_metadata::{Metadata, MetadataCommand, PackageMetadata, ScarbCommand}; +use scarb_execute::args::{Args as ExecuteArgs, ExecutionArgs}; +use scarb_metadata::MetadataCommand; use scarb_ui::args::{PackagesFilter, VerbositySpec}; use scarb_ui::components::Status; -use scarb_ui::{OutputFormat, Ui, UiPrinter}; +use scarb_ui::{OutputFormat, Ui}; use std::env; use std::fs; use std::process::ExitCode; @@ -24,7 +25,7 @@ struct Args { /// ID of `scarb execute` *standard* output for given package, for which to generate proof. #[arg(long)] - execution_id: Option, + execution_id: Option, /// Execute the program before proving. #[arg( @@ -36,7 +37,7 @@ struct Args { execute: bool, #[command(flatten)] - execute_args: ExecuteArgs, + execute_args: ExecutionArgs, #[command(flatten)] prover: ProverArgs, @@ -46,25 +47,6 @@ struct Args { pub verbose: VerbositySpec, } -#[derive(Parser, Clone, Debug)] -struct ExecuteArgs { - /// Do not build the package before execution. - #[arg(long, requires = "execute")] - no_build: bool, - - /// Arguments to pass to the program during execution. - #[arg(long, requires = "execute")] - arguments: Option, - - /// Arguments to the executable function from a file. - #[arg(long, conflicts_with = "arguments")] - arguments_file: Option, - - /// Target for execution. - #[arg(long, requires = "execute")] - target: Option, -} - #[derive(Parser, Clone, Debug)] struct ProverArgs { /// Track relations during proving. @@ -96,11 +78,12 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let metadata = MetadataCommand::new().inherit_stderr().exec()?; let package = args.packages_filter.match_one(&metadata)?; + let execution_id = match args.execution_id { Some(id) => id, None => { ensure!(args.execute); - run_execute(&args.execute_args, &package, &scarb_target_dir, &ui)? + run_execute(&args, &ui)? } }; ui.print(Status::new("Proving", &package.name)); @@ -133,10 +116,21 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { Ok(()) } +fn run_execute(args: &Args, ui: &Ui) -> Result { + let args = ExecuteArgs { + packages_filter: args.packages_filter.clone(), + execution: args.execute_args.clone(), + verbose: args.verbose.clone(), + }; + let execution_id = scarb_execute::main_inner(args, ui.clone())?; + + Ok(execution_id) +} + fn resolve_paths_from_package( scarb_target_dir: &Utf8PathBuf, package_name: &str, - execution_id: u32, + execution_id: usize, ) -> Result<(Utf8PathBuf, Utf8PathBuf, Utf8PathBuf)> { let execution_dir = scarb_target_dir .join("execute") @@ -172,52 +166,6 @@ fn resolve_paths_from_package( Ok((pub_input_path, priv_input_path, proof_path)) } -fn run_execute( - execution_args: &ExecuteArgs, - package: &PackageMetadata, - scarb_target_dir: &Utf8PathBuf, - ui: &Ui, -) -> Result { - let package_filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); - - let mut cmd = ScarbCommand::new_for_output(); - cmd.arg("execute") - .env("SCARB_PACKAGES_FILTER", package_filter.to_env()) - .env("SCARB_TARGET_DIR", scarb_target_dir); - - if execution_args.no_build { - cmd.arg("--no-build"); - } - if let Some(arguments) = &execution_args.arguments { - cmd.arg(format!("--arguments={arguments}")); - } - if let Some(arguments_file) = &execution_args.arguments_file { - cmd.arg(format!("--arguments-file={arguments_file}")); - } - if let Some(target) = &execution_args.target { - cmd.arg(format!("--target={target}")); - } - - let printer = UiPrinter::new(ui); - let output = cmd.output_and_stream(&printer)?; - extract_execution_id(&output) -} - -fn extract_execution_id(output: &[String]) -> Result { - output - .iter() - .find_map(|line| { - line.trim() - .strip_prefix("Saving output to:") - .and_then(|output_path| { - Utf8PathBuf::from(output_path.trim()) - .file_name() - .and_then(|name| name.trim_start_matches("execution").parse::().ok()) - }) - }) - .ok_or_else(|| anyhow!("failed to extract execution ID from `scarb execute` output")) -} - fn display_path(scarb_target_dir: &Utf8Path, output_path: &Utf8Path) -> String { match output_path.strip_prefix(scarb_target_dir) { Ok(stripped) => Utf8PathBuf::from("target").join(stripped).to_string(), From bd6886726c4529f6f3e0eaa49ae3d4f143e99991 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 17:12:20 +0100 Subject: [PATCH 60/71] ci: cache on nightly in `test-scarb-prove` --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f3a82e03..8a707245d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,13 +98,13 @@ jobs: os: windows-latest steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ env.RUST_TOOLCHAIN }} - - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - name: Build - run: cargo build --workspace --all-features --exclude scarb-prove + run: cargo +stable build --workspace --all-features --exclude scarb-prove - name: Run scarb-prove tests run: cargo +${{ env.RUST_TOOLCHAIN }} test -p scarb-prove From e31ae82970de89dc54271796b8484568565212d5 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 18:01:25 +0100 Subject: [PATCH 61/71] remove unnecessary changes related to stdout execution_id extraction --- .../src/command/internal_command.rs | 19 ------- scarb-metadata/src/command/scarb_command.rs | 53 ++----------------- utils/scarb-ui/src/lib.rs | 19 ------- 3 files changed, 3 insertions(+), 88 deletions(-) diff --git a/scarb-metadata/src/command/internal_command.rs b/scarb-metadata/src/command/internal_command.rs index 7a11af90c..668259aff 100644 --- a/scarb-metadata/src/command/internal_command.rs +++ b/scarb-metadata/src/command/internal_command.rs @@ -13,8 +13,6 @@ pub struct InternalScarbCommandBuilder { env_clear: bool, inherit_stderr: bool, inherit_stdout: bool, - pipe_stderr: bool, - pipe_stdout: bool, json: bool, manifest_path: Option, scarb_path: Option, @@ -119,19 +117,6 @@ impl InternalScarbCommandBuilder { self } - /// Pipe standard error - #[allow(unused)] - pub fn pipe_stderr(&mut self) -> &mut Self { - self.pipe_stderr = true; - self - } - - /// Pipe standard output - pub fn pipe_stdout(&mut self) -> &mut Self { - self.pipe_stdout = true; - self - } - /// Set output format to JSON. pub fn json(&mut self) -> &mut Self { self.json = true; @@ -176,14 +161,10 @@ impl InternalScarbCommandBuilder { if self.inherit_stderr { cmd.stderr(Stdio::inherit()); - } else if self.pipe_stderr { - cmd.stderr(Stdio::piped()); } if self.inherit_stdout { cmd.stdout(Stdio::inherit()); - } else if self.pipe_stdout { - cmd.stdout(Stdio::piped()); } cmd diff --git a/scarb-metadata/src/command/scarb_command.rs b/scarb-metadata/src/command/scarb_command.rs index 5191e831e..fd9640c2b 100644 --- a/scarb-metadata/src/command/scarb_command.rs +++ b/scarb-metadata/src/command/scarb_command.rs @@ -1,8 +1,8 @@ -use crate::command::internal_command::InternalScarbCommandBuilder; use std::ffi::OsStr; use std::io; -use std::io::{BufRead, BufReader}; use std::path::PathBuf; + +use crate::command::internal_command::InternalScarbCommandBuilder; use thiserror::Error; /// Error thrown while trying to execute `scarb` command. @@ -13,7 +13,7 @@ pub enum ScarbCommandError { #[error("failed to read `scarb` output")] Io(#[from] io::Error), /// Error during execution of `scarb` command. - #[error("`scarb` command exited with error")] + #[error("`scarb metadata` exited with error")] ScarbError, } @@ -33,16 +33,6 @@ impl ScarbCommand { Self { inner: cmd } } - /// Creates a `scarb` command that captures output while still printing it to stdout. - pub fn new_for_output() -> Self { - let mut cmd = InternalScarbCommandBuilder::new(); - cmd.inherit_stderr(); - // We can not just use cmd.inherit_stdout() - // Because it will make output.stdout empty - cmd.pipe_stdout(); - Self { inner: cmd } - } - /// Path to `scarb` executable. /// /// If not set, this will use the `$SCARB` environment variable, and if that is not set, it @@ -120,41 +110,4 @@ impl ScarbCommand { Err(ScarbCommandError::ScarbError) } } - - /// Runs configured `scarb` command and returns its stdout output. - pub fn output_and_stream( - &self, - printer: &impl Printer, - ) -> Result, ScarbCommandError> { - let mut cmd = self.inner.command(); - let mut child = cmd.spawn()?; - - let stdout = child - .stdout - .take() - .ok_or_else(|| ScarbCommandError::Io(io::Error::from(io::ErrorKind::BrokenPipe)))?; - - let reader = BufReader::new(stdout); - - // Collect and stream stdout lines - let mut output = Vec::new(); - for line in reader.lines() { - let line = line.map_err(ScarbCommandError::Io)?; - - printer.print(&line); - output.push(line); - } - - if child.wait()?.success() { - Ok(output) - } else { - Err(ScarbCommandError::ScarbError) - } - } -} - -/// Trait for printing messages. -pub trait Printer { - /// Print a message. - fn print(&self, message: &str); } diff --git a/utils/scarb-ui/src/lib.rs b/utils/scarb-ui/src/lib.rs index 59ef94154..71682fb2e 100644 --- a/utils/scarb-ui/src/lib.rs +++ b/utils/scarb-ui/src/lib.rs @@ -31,7 +31,6 @@ use std::fmt::Debug; use std::sync::{Arc, RwLock}; pub use message::*; -use scarb_metadata::Printer; pub use verbosity::*; pub use widget::*; @@ -233,21 +232,3 @@ impl Ui { console::colors_enabled_stderr() } } - -/// A printer that forwards messages to a [`Ui`] instance. -pub struct UiPrinter<'a> { - ui: &'a Ui, -} - -impl<'a> UiPrinter<'a> { - /// Create a new [`UiPrinter`] instance. - pub fn new(ui: &'a Ui) -> Self { - Self { ui } - } -} - -impl Printer for UiPrinter<'_> { - fn print(&self, message: &str) { - self.ui.print(message); - } -} From b2493e1dd07616a6d346062e1608eb30274cc89e Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Tue, 28 Jan 2025 18:39:22 +0100 Subject: [PATCH 62/71] handle cairo-pie output explicitly --- extensions/scarb-prove/src/main.rs | 29 ++++++++++++++++-------- extensions/scarb-prove/tests/build.rs | 32 ++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 5681252e0..91e69e3f3 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -1,4 +1,4 @@ -use anyhow::{ensure, Context, Result}; +use anyhow::{bail, ensure, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use clap::Parser; use create_output_dir::create_output_dir; @@ -137,14 +137,25 @@ fn resolve_paths_from_package( .join(package_name) .join(format!("execution{}", execution_id)); - ensure!( - execution_dir.exists(), - formatdoc! {r#" - execution directory not found: {} - help: make sure to run `scarb execute` first - and that the execution ID is correct - "#, execution_dir} - ); + if !execution_dir.exists() { + let execution_archive = scarb_target_dir + .join("execute") + .join(package_name) + .join(format!("execution{}.zip", execution_id)); + if execution_archive.exists() { + bail!(formatdoc! {r#" + proving cairo pie output is not supported: {} + help: run `scarb execute --output=standard` first + and then run `scarb prove` with correct execution ID + "#, execution_archive}); + } else { + bail!(formatdoc! {r#" + execution directory not found: {} + help: make sure to run `scarb execute` first + and then run `scarb prove` with correct execution ID + "#, execution_dir}); + } + } // Get input files from execution directory let pub_input_path = execution_dir.join("air_public_input.json"); diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index 7c06e3258..240522bf2 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -124,7 +124,37 @@ fn prove_fails_when_execution_output_not_found() { [..]Proving hello error: execution directory not found: [..]/target/execute/hello/execution1 help: make sure to run `scarb execute` first - and that the execution ID is correct + and then run `scarb prove` with correct execution ID + + "#}, + ) +} + +#[test] +fn prove_fails_when_cairo_pie_output() { + let t = build_executable_project(); + + Scarb::quick_snapbox() + .arg("execute") + .arg("--target=bootloader") + .arg("--output=cairo-pie") + .current_dir(&t) + .assert() + .success(); + + output_assert( + Scarb::quick_snapbox() + .arg("prove") + .arg("--execution-id=1") + .current_dir(&t) + .assert() + .failure(), + indoc! {r#" + [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk + [..]Proving hello + error: proving cairo pie output is not supported: [..]/target/execute/hello/execution1.zip + help: run `scarb execute --output=standard` first + and then run `scarb prove` with correct execution ID "#}, ) From 650363684512c04eba5c2500fc2eabfd6e9ea33f Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 31 Jan 2025 11:17:28 +0100 Subject: [PATCH 63/71] use assert instead of ensure --- extensions/scarb-prove/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 91e69e3f3..13e0194d9 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -82,7 +82,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let execution_id = match args.execution_id { Some(id) => id, None => { - ensure!(args.execute); + assert!(args.execute); run_execute(&args, &ui)? } }; From f23c96876303f5a89410a449af1f73fbfe2502a8 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 31 Jan 2025 12:24:42 +0100 Subject: [PATCH 64/71] apply suggestions re. `scarb-execute` re-use --- extensions/scarb-execute/src/lib.rs | 33 +++++++++++++++++------------ extensions/scarb-prove/src/main.rs | 15 ++----------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/extensions/scarb-execute/src/lib.rs b/extensions/scarb-execute/src/lib.rs index 37f4aa5fb..714649d7b 100644 --- a/extensions/scarb-execute/src/lib.rs +++ b/extensions/scarb-execute/src/lib.rs @@ -11,7 +11,7 @@ use cairo_vm::{cairo_run, Felt252}; use camino::{Utf8Path, Utf8PathBuf}; use create_output_dir::create_output_dir; use indoc::formatdoc; -use scarb_metadata::{Metadata, MetadataCommand, ScarbCommand}; +use scarb_metadata::{Metadata, MetadataCommand, PackageMetadata, ScarbCommand}; use scarb_ui::args::PackagesFilter; use scarb_ui::components::Status; use scarb_ui::Ui; @@ -24,15 +24,22 @@ pub mod args; const MAX_ITERATION_COUNT: usize = 10000; pub fn main_inner(args: args::Args, ui: Ui) -> Result { + let metadata = MetadataCommand::new().inherit_stderr().exec()?; + let package = args.packages_filter.match_one(&metadata)?; + execute(&package, &args.execution, &ui) +} + +pub fn execute( + package: &PackageMetadata, + args: &args::ExecutionArgs, + ui: &Ui, +) -> Result { ensure!( - !(args.execution.run.output.is_cairo_pie() && args.execution.run.target.is_standalone()), + !(args.run.output.is_cairo_pie() && args.run.target.is_standalone()), "Cairo pie output format is not supported for standalone execution target" ); - let metadata = MetadataCommand::new().inherit_stderr().exec()?; - let package = args.packages_filter.match_one(&metadata)?; - - if !args.execution.no_build { + if !args.no_build { let filter = PackagesFilter::generate_for::(vec![package.clone()].iter()); ScarbCommand::new() .arg("build") @@ -59,7 +66,7 @@ pub fn main_inner(args: args::Args, ui: Ui) -> Result { let (hints, string_to_hint) = build_hints_dict(&executable.program.hints); - let program = if args.execution.run.target.is_standalone() { + let program = if args.run.target.is_standalone() { let entrypoint = executable .entrypoints .iter() @@ -98,7 +105,7 @@ pub fn main_inner(args: args::Args, ui: Ui) -> Result { let mut hint_processor = CairoHintProcessor { runner: None, user_args: vec![vec![Arg::Array( - args.execution.run.arguments.read_arguments()?, + args.run.arguments.clone().read_arguments()?, )]], string_to_hint, starknet_state: Default::default(), @@ -110,17 +117,17 @@ pub fn main_inner(args: args::Args, ui: Ui) -> Result { let cairo_run_config = CairoRunConfig { allow_missing_builtins: Some(true), layout: LayoutName::all_cairo, - proof_mode: args.execution.run.target.is_standalone(), + proof_mode: args.run.target.is_standalone(), secure_run: None, - relocate_mem: args.execution.run.output.is_standard(), - trace_enabled: args.execution.run.output.is_standard(), + relocate_mem: args.run.output.is_standard(), + trace_enabled: args.run.output.is_standard(), ..Default::default() }; let mut runner = cairo_run_program(&program, &cairo_run_config, &mut hint_processor) .with_context(|| "Cairo program run failed")?; - if args.execution.run.print_program_output { + if args.run.print_program_output { let mut output_buffer = "Program output:\n".to_string(); runner.vm.write_output(&mut output_buffer)?; ui.print(output_buffer.trim_end()); @@ -129,7 +136,7 @@ pub fn main_inner(args: args::Args, ui: Ui) -> Result { let output_dir = scarb_target_dir.join("execute").join(&package.name); create_output_dir(output_dir.as_std_path())?; - if args.execution.run.output.is_cairo_pie() { + if args.run.output.is_cairo_pie() { let output_value = runner.get_cairo_pie()?; let (output_file_path, execution_id) = incremental_create_output_file(&output_dir, ".zip")?; ui.print(Status::new( diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 13e0194d9..c724ae6cc 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -3,7 +3,7 @@ use camino::{Utf8Path, Utf8PathBuf}; use clap::Parser; use create_output_dir::create_output_dir; use indoc::formatdoc; -use scarb_execute::args::{Args as ExecuteArgs, ExecutionArgs}; +use scarb_execute::args::ExecutionArgs; use scarb_metadata::MetadataCommand; use scarb_ui::args::{PackagesFilter, VerbositySpec}; use scarb_ui::components::Status; @@ -83,7 +83,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { Some(id) => id, None => { assert!(args.execute); - run_execute(&args, &ui)? + scarb_execute::execute(&package, &args.execute_args, &ui)? } }; ui.print(Status::new("Proving", &package.name)); @@ -116,17 +116,6 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { Ok(()) } -fn run_execute(args: &Args, ui: &Ui) -> Result { - let args = ExecuteArgs { - packages_filter: args.packages_filter.clone(), - execution: args.execute_args.clone(), - verbose: args.verbose.clone(), - }; - let execution_id = scarb_execute::main_inner(args, ui.clone())?; - - Ok(execution_id) -} - fn resolve_paths_from_package( scarb_target_dir: &Utf8PathBuf, package_name: &str, From d6f9446a8fcc3fb0f93f958632ba89e8af9ee11a Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 31 Jan 2025 12:50:23 +0100 Subject: [PATCH 65/71] cairo-pie.zip --- extensions/scarb-execute/src/lib.rs | 5 ++-- extensions/scarb-execute/tests/build.rs | 4 ++-- extensions/scarb-prove/src/main.rs | 31 +++++++++++-------------- extensions/scarb-prove/tests/build.rs | 5 +++- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/extensions/scarb-execute/src/lib.rs b/extensions/scarb-execute/src/lib.rs index 714649d7b..e1a20b1b0 100644 --- a/extensions/scarb-execute/src/lib.rs +++ b/extensions/scarb-execute/src/lib.rs @@ -136,9 +136,11 @@ pub fn execute( let output_dir = scarb_target_dir.join("execute").join(&package.name); create_output_dir(output_dir.as_std_path())?; + let (execution_output_dir, execution_id) = incremental_create_output_dir(&output_dir)?; + if args.run.output.is_cairo_pie() { let output_value = runner.get_cairo_pie()?; - let (output_file_path, execution_id) = incremental_create_output_file(&output_dir, ".zip")?; + let output_file_path = execution_output_dir.join("cairo_pie.zip"); ui.print(Status::new( "Saving output to:", &display_path(&scarb_target_dir, &output_file_path), @@ -146,7 +148,6 @@ pub fn execute( output_value.write_zip_file(output_file_path.as_std_path())?; Ok(execution_id) } else { - let (execution_output_dir, execution_id) = incremental_create_output_dir(&output_dir)?; ui.print(Status::new( "Saving output to:", &display_path(&scarb_target_dir, &execution_output_dir), diff --git a/extensions/scarb-execute/tests/build.rs b/extensions/scarb-execute/tests/build.rs index 113a57606..7339125e6 100644 --- a/extensions/scarb-execute/tests/build.rs +++ b/extensions/scarb-execute/tests/build.rs @@ -118,10 +118,10 @@ fn can_produce_cairo_pie_output() { [..]Compiling hello v0.1.0 ([..]Scarb.toml) [..]Finished `dev` profile target(s) in [..] [..]Executing hello - Saving output to: target/execute/hello/execution1.zip + Saving output to: target/execute/hello/execution1/cairo_pie.zip "#}); - t.child("target/execute/hello/execution1.zip") + t.child("target/execute/hello/execution1/cairo_pie.zip") .assert(predicates::path::exists()); } diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index c724ae6cc..62e14b23e 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -127,23 +127,20 @@ fn resolve_paths_from_package( .join(format!("execution{}", execution_id)); if !execution_dir.exists() { - let execution_archive = scarb_target_dir - .join("execute") - .join(package_name) - .join(format!("execution{}.zip", execution_id)); - if execution_archive.exists() { - bail!(formatdoc! {r#" - proving cairo pie output is not supported: {} - help: run `scarb execute --output=standard` first - and then run `scarb prove` with correct execution ID - "#, execution_archive}); - } else { - bail!(formatdoc! {r#" - execution directory not found: {} - help: make sure to run `scarb execute` first - and then run `scarb prove` with correct execution ID - "#, execution_dir}); - } + bail!(formatdoc! {r#" + execution directory not found: {} + help: make sure to run `scarb execute` first + and then run `scarb prove` with correct execution ID + "#, execution_dir}); + } + + let cairo_pie_path = execution_dir.join("cairo_pie.zip"); + if cairo_pie_path.exists() { + bail!(formatdoc! {r#" + proving cairo pie output is not supported: {} + help: run `scarb execute --output=standard` first + and then run `scarb prove` with correct execution ID + "#, cairo_pie_path}); } // Get input files from execution directory diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index 240522bf2..e93999ce1 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -142,6 +142,9 @@ fn prove_fails_when_cairo_pie_output() { .assert() .success(); + t.child("target/execute/hello/execution1/cairo_pie.zip") + .assert(predicates::path::exists()); + output_assert( Scarb::quick_snapbox() .arg("prove") @@ -152,7 +155,7 @@ fn prove_fails_when_cairo_pie_output() { indoc! {r#" [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk [..]Proving hello - error: proving cairo pie output is not supported: [..]/target/execute/hello/execution1.zip + error: proving cairo pie output is not supported: [..]/target/execute/hello/execution1/cairo_pie.zip help: run `scarb execute --output=standard` first and then run `scarb prove` with correct execution ID From 1864fe28fb5f6d471c3dfa9fd7ce9f7cac30f64f Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 31 Jan 2025 13:03:49 +0100 Subject: [PATCH 66/71] cairo-pie.zip: refactor cleanup - ensure! - remove `incremental_create_output_file` --- extensions/scarb-execute/src/lib.rs | 31 +++-------------------------- extensions/scarb-prove/src/main.rs | 20 ++++++++++--------- 2 files changed, 14 insertions(+), 37 deletions(-) diff --git a/extensions/scarb-execute/src/lib.rs b/extensions/scarb-execute/src/lib.rs index e1a20b1b0..3a2e39851 100644 --- a/extensions/scarb-execute/src/lib.rs +++ b/extensions/scarb-execute/src/lib.rs @@ -17,7 +17,6 @@ use scarb_ui::components::Status; use scarb_ui::Ui; use std::env; use std::fs; -use std::fs::OpenOptions; use std::io::{self, Write}; pub mod args; @@ -212,34 +211,10 @@ fn load_prebuilt_executable(path: &Utf8Path, filename: String) -> Result, -) -> Result<(Utf8PathBuf, usize)> { - incremental_attempt_io_creation(path, extension, "failed to create output directory", |p| { - OpenOptions::new() - .write(true) - .create_new(true) - .open(p) - .map(|_| ()) - }) -} - fn incremental_create_output_dir(path: &Utf8Path) -> Result<(Utf8PathBuf, usize)> { - incremental_attempt_io_creation(path, "", "failed to create output directory", |p| { - fs::create_dir(p) - }) -} - -fn incremental_attempt_io_creation( - path: &Utf8Path, - extension: impl AsRef, - final_error_message: impl AsRef, - attempt: impl Fn(&Utf8Path) -> io::Result<()>, -) -> Result<(Utf8PathBuf, usize)> { for i in 1..=MAX_ITERATION_COUNT { - let filepath = path.join(format!("execution{}{}", i, extension.as_ref())); - let result = attempt(&filepath); + let filepath = path.join(format!("execution{}", i)); + let result = fs::create_dir(&filepath); return match result { Err(e) => { if e.kind() == io::ErrorKind::AlreadyExists { @@ -250,7 +225,7 @@ fn incremental_attempt_io_creation( Ok(_) => Ok((filepath, i)), }; } - bail!(final_error_message.as_ref().to_string()); + bail!("failed to create output directory") } /// Writer implementation for a file. diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 62e14b23e..b8fce47d3 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -1,4 +1,4 @@ -use anyhow::{bail, ensure, Context, Result}; +use anyhow::{ensure, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use clap::Parser; use create_output_dir::create_output_dir; @@ -126,22 +126,24 @@ fn resolve_paths_from_package( .join(package_name) .join(format!("execution{}", execution_id)); - if !execution_dir.exists() { - bail!(formatdoc! {r#" + ensure!( + execution_dir.exists(), + formatdoc! {r#" execution directory not found: {} help: make sure to run `scarb execute` first and then run `scarb prove` with correct execution ID - "#, execution_dir}); - } + "#, execution_dir} + ); let cairo_pie_path = execution_dir.join("cairo_pie.zip"); - if cairo_pie_path.exists() { - bail!(formatdoc! {r#" + ensure!( + !cairo_pie_path.exists(), + formatdoc! {r#" proving cairo pie output is not supported: {} help: run `scarb execute --output=standard` first and then run `scarb prove` with correct execution ID - "#, cairo_pie_path}); - } + "#, cairo_pie_path} + ); // Get input files from execution directory let pub_input_path = execution_dir.join("air_public_input.json"); From 21a278900a267123b10d607116378cfa934a6206 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 31 Jan 2025 14:06:22 +0100 Subject: [PATCH 67/71] post-merge fixes --- Cargo.lock | 236 ++++++++++++------------ extensions/scarb-execute/tests/build.rs | 10 +- extensions/scarb-prove/tests/build.rs | 3 + 3 files changed, 130 insertions(+), 119 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91996e7a4..b009b1f19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,7 +64,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -90,9 +90,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-rlp" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f542548a609dca89fcd72b3b9f355928cf844d4363c5eed9c5273a3dd225e097" +checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" dependencies = [ "arrayvec", "bytes", @@ -415,24 +415,24 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.85" +version = "0.1.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +checksum = "1b1244b10dcd56c92219da4e14caa97e312079e185f04ba3eea25061561dc0a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] name = "auto_impl" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -598,9 +598,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.3" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9ec96fe9a81b5e365f9db71fe00edc4fe4ca2cc7dcb7861f0603012a7caa210" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -690,7 +690,7 @@ checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -735,7 +735,7 @@ dependencies = [ [[package]] name = "cairo-lang-casm" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-utils", "indoc", @@ -748,7 +748,7 @@ dependencies = [ [[package]] name = "cairo-lang-compiler" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "anyhow", "cairo-lang-defs", @@ -773,7 +773,7 @@ dependencies = [ [[package]] name = "cairo-lang-debug" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-utils", ] @@ -781,7 +781,7 @@ dependencies = [ [[package]] name = "cairo-lang-defs" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-debug", "cairo-lang-diagnostics", @@ -797,7 +797,7 @@ dependencies = [ [[package]] name = "cairo-lang-diagnostics" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -808,7 +808,7 @@ dependencies = [ [[package]] name = "cairo-lang-doc" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -828,7 +828,7 @@ dependencies = [ [[package]] name = "cairo-lang-eq-solver" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-utils", "good_lp", @@ -837,11 +837,12 @@ dependencies = [ [[package]] name = "cairo-lang-executable" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "anyhow", "cairo-lang-casm", "cairo-lang-compiler", + "cairo-lang-debug", "cairo-lang-defs", "cairo-lang-filesystem", "cairo-lang-lowering", @@ -861,7 +862,7 @@ dependencies = [ [[package]] name = "cairo-lang-filesystem" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-debug", "cairo-lang-utils", @@ -876,7 +877,7 @@ dependencies = [ [[package]] name = "cairo-lang-formatter" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "anyhow", "cairo-lang-diagnostics", @@ -895,7 +896,7 @@ dependencies = [ [[package]] name = "cairo-lang-lowering" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -913,7 +914,6 @@ dependencies = [ "num-integer", "num-traits 0.2.19", "rust-analyzer-salsa", - "smol_str", ] [[package]] @@ -945,7 +945,7 @@ version = "0.1.0" dependencies = [ "quote", "scarb-stable-hash 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -956,7 +956,7 @@ checksum = "e32e958decd95ae122ee64daa26721da2f76e83231047f947fd9cdc5d3c90cc6" dependencies = [ "quote", "scarb-stable-hash 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -972,7 +972,7 @@ checksum = "c49906d6b1c215e5814be7c5c65ecf2328898b335bee8c2409ec07cfb5530daf" [[package]] name = "cairo-lang-parser" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-diagnostics", "cairo-lang-filesystem", @@ -991,7 +991,7 @@ dependencies = [ [[package]] name = "cairo-lang-plugins" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-defs", "cairo-lang-diagnostics", @@ -1009,22 +1009,22 @@ dependencies = [ [[package]] name = "cairo-lang-primitive-token" version = "1.0.0" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" [[package]] name = "cairo-lang-proc-macros" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-debug", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] name = "cairo-lang-project" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-filesystem", "cairo-lang-utils", @@ -1036,7 +1036,7 @@ dependencies = [ [[package]] name = "cairo-lang-runnable-utils" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-casm", "cairo-lang-sierra", @@ -1053,7 +1053,7 @@ dependencies = [ [[package]] name = "cairo-lang-runner" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "ark-ff 0.4.2", "ark-secp256k1", @@ -1082,7 +1082,7 @@ dependencies = [ [[package]] name = "cairo-lang-semantic" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -1108,7 +1108,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "anyhow", "cairo-lang-utils", @@ -1134,7 +1134,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-ap-change" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -1149,7 +1149,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-gas" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-eq-solver", "cairo-lang-sierra", @@ -1164,7 +1164,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-generator" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-debug", "cairo-lang-defs", @@ -1187,7 +1187,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-to-casm" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "assert_matches", "cairo-lang-casm", @@ -1207,7 +1207,7 @@ dependencies = [ [[package]] name = "cairo-lang-sierra-type-size" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-sierra", "cairo-lang-utils", @@ -1216,7 +1216,7 @@ dependencies = [ [[package]] name = "cairo-lang-starknet" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -1245,7 +1245,7 @@ dependencies = [ [[package]] name = "cairo-lang-starknet-classes" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-casm", "cairo-lang-sierra", @@ -1267,7 +1267,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-debug", "cairo-lang-filesystem", @@ -1283,7 +1283,7 @@ dependencies = [ [[package]] name = "cairo-lang-syntax-codegen" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "genco", "xshell", @@ -1292,7 +1292,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-plugin" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -1318,7 +1318,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-runner" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "anyhow", "cairo-lang-compiler", @@ -1340,7 +1340,7 @@ dependencies = [ [[package]] name = "cairo-lang-test-utils" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "cairo-lang-formatter", "cairo-lang-utils", @@ -1352,7 +1352,7 @@ dependencies = [ [[package]] name = "cairo-lang-utils" version = "2.9.2" -source = "git+https://github.com/starkware-libs/cairo?rev=03944ce36c4b37ef954d7f462d23edce8669e692#03944ce36c4b37ef954d7f462d23edce8669e692" +source = "git+https://github.com/starkware-libs/cairo?rev=1510dbf57cbb2117069c83832f615f0447d0ec12#1510dbf57cbb2117069c83832f615f0447d0ec12" dependencies = [ "env_logger", "hashbrown 0.14.5", @@ -1369,13 +1369,14 @@ dependencies = [ [[package]] name = "cairo-language-server" version = "2.9.2" -source = "git+https://github.com/software-mansion/cairols?rev=6432886fea7564816078ed140434addf50bbaa23#6432886fea7564816078ed140434addf50bbaa23" +source = "git+https://github.com/software-mansion/cairols?rev=6cdca03964273518687d2e2253ff731d8f2e9fd0#6cdca03964273518687d2e2253ff731d8f2e9fd0" dependencies = [ "anyhow", "cairo-lang-compiler", "cairo-lang-defs", "cairo-lang-diagnostics", "cairo-lang-doc", + "cairo-lang-executable", "cairo-lang-filesystem", "cairo-lang-formatter", "cairo-lang-lowering", @@ -1397,6 +1398,7 @@ dependencies = [ "libc", "lsp-server", "lsp-types", + "memchr", "rust-analyzer-salsa", "scarb-metadata 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "scarb-proc-macro-server-types 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1414,8 +1416,8 @@ dependencies = [ [[package]] name = "cairo-lint-core" -version = "0.1.0" -source = "git+https://github.com/software-mansion/cairo-lint?rev=b95a1949b932e89179c052efdbf4e21002ce6777#b95a1949b932e89179c052efdbf4e21002ce6777" +version = "2.9.2" +source = "git+https://github.com/software-mansion/cairo-lint?rev=20a858bcfba2319edfd92021e243e6cf95543330#20a858bcfba2319edfd92021e243e6cf95543330" dependencies = [ "annotate-snippets", "anyhow", @@ -1541,13 +1543,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.98" +version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "jobserver", "libc", - "once_cell", + "shlex", ] [[package]] @@ -1603,7 +1605,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -1861,7 +1863,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -1872,7 +1874,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -1951,7 +1953,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -1961,7 +1963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -2068,7 +2070,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -2104,7 +2106,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -2154,7 +2156,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -2431,7 +2433,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -2489,7 +2491,7 @@ checksum = "553630feadf7b76442b0849fd25fdf89b860d933623aec9693fed19af0400c78" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -3770,7 +3772,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -4201,7 +4203,7 @@ checksum = "edbe595006d355eaf9ae11db92707d4338cd2384d16866131cc1afdbdd35d8d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -4299,14 +4301,14 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -4402,7 +4404,7 @@ checksum = "1bb5c1d8184f13f7d0ccbeeca0def2f9a181bce2624302793005f5ca8aa62e5e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -4675,7 +4677,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -4888,7 +4890,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -5006,9 +5008,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.93" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -5074,7 +5076,7 @@ checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -5287,7 +5289,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -5421,9 +5423,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b11a153aec4a6ab60795f8ebe2923c597b16b05bb1504377451e705ef1a45323" +checksum = "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65" dependencies = [ "bytes", "hashbrown 0.15.2", @@ -5439,13 +5441,13 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb382a4d9f53bd5c0be86b10d8179c3f8a14c30bf774ff77096ed6581e35981" +checksum = "246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -5516,7 +5518,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6030,7 +6032,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6146,7 +6148,7 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6157,7 +6159,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6190,7 +6192,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6276,6 +6278,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -6497,7 +6505,7 @@ checksum = "bbc159a1934c7be9761c237333a57febe060ace2bc9e3b337a59a37af206d19f" dependencies = [ "starknet-curve", "starknet-ff", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6583,7 +6591,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6603,7 +6611,7 @@ source = "git+https://github.com/starkware-libs/stwo-cairo?rev=a27287c21e8b7e677 dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6688,9 +6696,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.96" +version = "2.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a" dependencies = [ "proc-macro2", "quote", @@ -6711,7 +6719,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6806,7 +6814,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6817,7 +6825,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", "test-case-core", ] @@ -6829,7 +6837,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6858,7 +6866,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6869,7 +6877,7 @@ checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -6971,9 +6979,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.43.0" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -6988,13 +6996,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -7159,7 +7167,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -7245,7 +7253,7 @@ checksum = "560b82d656506509d43abe30e0ba64c56b1953ab3d4fe7ba5902747a7a3cedd5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -7394,9 +7402,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" [[package]] name = "valuable" @@ -7485,7 +7493,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", "wasm-bindgen-shared", ] @@ -7519,7 +7527,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7881,7 +7889,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", "synstructure", ] @@ -7902,7 +7910,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -7922,7 +7930,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", "synstructure", ] @@ -7943,7 +7951,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] @@ -7965,7 +7973,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.96", + "syn 2.0.95", ] [[package]] diff --git a/extensions/scarb-execute/tests/build.rs b/extensions/scarb-execute/tests/build.rs index cd54a2482..e9f34b0ff 100644 --- a/extensions/scarb-execute/tests/build.rs +++ b/extensions/scarb-execute/tests/build.rs @@ -206,15 +206,15 @@ fn can_print_panic_reason() { Program output: 1 Panicked with "abcd". - Saving output to: target/execute/hello + Saving output to: target/execute/hello/execution1 "#}); - t.child("target/execute/hello/air_private_input.json") + t.child("target/execute/hello/execution1/air_private_input.json") .assert_is_json::(); - t.child("target/execute/hello/air_public_input.json") + t.child("target/execute/hello/execution1/air_public_input.json") .assert_is_json::(); - t.child("target/execute/hello/memory.bin") + t.child("target/execute/hello/execution1/memory.bin") .assert(predicates::path::exists().and(is_file_empty().not())); - t.child("target/execute/hello/trace.bin") + t.child("target/execute/hello/execution1/trace.bin") .assert(predicates::path::exists().and(is_file_empty().not())); } diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index e93999ce1..17bb8545c 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -14,6 +14,9 @@ fn build_executable_project() -> TempDir { .dep_cairo_execute() .manifest_extra(indoc! {r#" [executable] + + [cairo] + enable-gas = false "#}) .lib_cairo(indoc! {r#" #[executable] From 3f678ddb424d9dbf82744e9752ed1642f4c16e62 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 31 Jan 2025 11:39:12 +0100 Subject: [PATCH 68/71] drop windows support --- extensions/scarb-prove/src/main.rs | 11 ++++++++++- extensions/scarb-prove/tests/build.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index b8fce47d3..37f5783b1 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -2,7 +2,7 @@ use anyhow::{ensure, Context, Result}; use camino::{Utf8Path, Utf8PathBuf}; use clap::Parser; use create_output_dir::create_output_dir; -use indoc::formatdoc; +use indoc::{formatdoc, indoc}; use scarb_execute::args::ExecutionArgs; use scarb_metadata::MetadataCommand; use scarb_ui::args::{PackagesFilter, VerbositySpec}; @@ -72,6 +72,15 @@ fn main() -> ExitCode { } fn main_inner(args: Args, ui: Ui) -> Result<()> { + ensure!( + !cfg!(windows), + indoc! {r#" + `scarb prove` is not supported on Windows + help: use WSL or a Linux/macOS machine instead + "# + } + ); + let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); ui.warn("soundness of proof is not yet guaranteed by Stwo, use at your own risk"); diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index 17bb8545c..eecd85886 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -29,6 +29,7 @@ fn build_executable_project() -> TempDir { } #[test] +#[cfg(not(windows))] fn prove_from_execution_output() { let t = build_executable_project(); @@ -55,6 +56,7 @@ fn prove_from_execution_output() { } #[test] +#[cfg(not(windows))] fn prove_with_track_relations() { let t = build_executable_project(); @@ -83,6 +85,7 @@ fn prove_with_track_relations() { } #[test] +#[cfg(not(windows))] fn prove_with_display_components() { let t = build_executable_project(); @@ -112,6 +115,7 @@ fn prove_with_display_components() { } #[test] +#[cfg(not(windows))] fn prove_fails_when_execution_output_not_found() { let t = build_executable_project(); @@ -134,6 +138,7 @@ fn prove_fails_when_execution_output_not_found() { } #[test] +#[cfg(not(windows))] fn prove_fails_when_cairo_pie_output() { let t = build_executable_project(); @@ -167,6 +172,7 @@ fn prove_fails_when_cairo_pie_output() { } #[test] +#[cfg(not(windows))] fn prove_with_execute() { let t = build_executable_project(); @@ -191,6 +197,26 @@ fn prove_with_execute() { .assert(predicates::path::exists()); } +#[test] +#[cfg(windows)] +fn prove_fails_on_windows() { + let t = build_executable_project(); + + output_assert( + Scarb::quick_snapbox() + .arg("prove") + .arg("--execute") + .current_dir(&t) + .assert() + .failure(), + indoc! {r#" + error: `scarb prove` is not supported on Windows + help: use WSL or a Linux/macOS machine instead + + "#}, + ) +} + fn output_assert(output: OutputAssert, expected: &str) { #[cfg(windows)] output.stdout_matches(format!( From 97e321ee5c2f5d4b45e7ca133c7440799efc17ce Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 31 Jan 2025 14:26:19 +0100 Subject: [PATCH 69/71] revert thiserror dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5db128b94..857061669 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -138,7 +138,7 @@ tar = "0.4" target-triple = "0.1" tempfile = "3" test-case = "3" -thiserror = "2.0.10" +thiserror = "2" time = "0.3" tokio = { version = "1", features = ["macros", "io-util", "process", "rt", "rt-multi-thread", "sync"] } tokio-stream = "0.1" From ce83714ebd76543ae480e72768ac90295bf9875f Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 31 Jan 2025 14:37:09 +0100 Subject: [PATCH 70/71] relocate warning --- extensions/scarb-prove/src/main.rs | 3 +-- extensions/scarb-prove/tests/build.rs | 12 +++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 37f5783b1..6888d030a 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -83,8 +83,6 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { let scarb_target_dir = Utf8PathBuf::from(env::var("SCARB_TARGET_DIR")?); - ui.warn("soundness of proof is not yet guaranteed by Stwo, use at your own risk"); - let metadata = MetadataCommand::new().inherit_stderr().exec()?; let package = args.packages_filter.match_one(&metadata)?; @@ -96,6 +94,7 @@ fn main_inner(args: Args, ui: Ui) -> Result<()> { } }; ui.print(Status::new("Proving", &package.name)); + ui.warn("soundness of proof is not yet guaranteed by Stwo, use at your own risk"); let (pub_input_path, priv_input_path, proof_path) = resolve_paths_from_package(&scarb_target_dir, &package.name, execution_id)?; diff --git a/extensions/scarb-prove/tests/build.rs b/extensions/scarb-prove/tests/build.rs index eecd85886..191e432f4 100644 --- a/extensions/scarb-prove/tests/build.rs +++ b/extensions/scarb-prove/tests/build.rs @@ -46,8 +46,8 @@ fn prove_from_execution_output() { .assert() .success() .stdout_matches(indoc! {r#" - [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk [..]Proving hello + warn: soundness of proof is not yet guaranteed by Stwo, use at your own risk Saving proof to: target/execute/hello/execution1/proof/proof.json "#}); @@ -127,8 +127,8 @@ fn prove_fails_when_execution_output_not_found() { .assert() .failure(), indoc! {r#" - [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk [..]Proving hello + warn: soundness of proof is not yet guaranteed by Stwo, use at your own risk error: execution directory not found: [..]/target/execute/hello/execution1 help: make sure to run `scarb execute` first and then run `scarb prove` with correct execution ID @@ -142,6 +142,7 @@ fn prove_fails_when_execution_output_not_found() { fn prove_fails_when_cairo_pie_output() { let t = build_executable_project(); + // First create a cairo pie output Scarb::quick_snapbox() .arg("execute") .arg("--target=bootloader") @@ -153,6 +154,7 @@ fn prove_fails_when_cairo_pie_output() { t.child("target/execute/hello/execution1/cairo_pie.zip") .assert(predicates::path::exists()); + // Then try to prove it output_assert( Scarb::quick_snapbox() .arg("prove") @@ -161,14 +163,14 @@ fn prove_fails_when_cairo_pie_output() { .assert() .failure(), indoc! {r#" - [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk [..]Proving hello + warn: soundness of proof is not yet guaranteed by Stwo, use at your own risk error: proving cairo pie output is not supported: [..]/target/execute/hello/execution1/cairo_pie.zip help: run `scarb execute --output=standard` first and then run `scarb prove` with correct execution ID "#}, - ) + ); } #[test] @@ -184,12 +186,12 @@ fn prove_with_execute() { .assert() .success() .stdout_matches(indoc! {r#" - [..]soundness of proof is not yet guaranteed by Stwo, use at your own risk [..]Compiling hello v0.1.0 ([..]) [..]Finished `dev` profile target(s) in [..] [..]Executing hello Saving output to: target/execute/hello/execution1 [..]Proving hello + warn: soundness of proof is not yet guaranteed by Stwo, use at your own risk Saving proof to: target/execute/hello/execution1/proof/proof.json "#}); From 47eb48519bc279c522631445b935be42df865c9e Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau Date: Fri, 31 Jan 2025 16:59:30 +0100 Subject: [PATCH 71/71] update arg conflicts --- extensions/scarb-prove/src/main.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/extensions/scarb-prove/src/main.rs b/extensions/scarb-prove/src/main.rs index 6888d030a..be97a0854 100644 --- a/extensions/scarb-prove/src/main.rs +++ b/extensions/scarb-prove/src/main.rs @@ -24,14 +24,24 @@ struct Args { packages_filter: PackagesFilter, /// ID of `scarb execute` *standard* output for given package, for which to generate proof. - #[arg(long)] + #[arg( + long, + conflicts_with_all = [ + "execute", + "no_build", + "arguments", + "arguments_file", + "output", + "target", + "print_program_output" + ] + )] execution_id: Option, /// Execute the program before proving. #[arg( long, default_value_t = false, - conflicts_with = "execution_id", required_unless_present = "execution_id" )] execute: bool,